Terraformで作成したEC2にPublic DNSがつかない

今回はHow-to系でも、問題解決系でもなく、率直に思ったことを書く。

これはTerraformに限った話ではないと思うんだけど、EC2を作成してPublicIPを割り当ててもPublicDNSに値がないことがある。
別に困りはしないんだけど、ちょっと調べてみたら、こんな記事が見つかる。
AWSでPublic DNS(パブリックDNS)が割り当てられない時の解決法

これの通りなら、TerraformでもVPC定義のオプションを見直せば割り当てられるんじゃないかなと。
出社してから試してみる。

Rack::CorsでCORSの設定

SinatraやRailsでCORSの設定をする時に、よくRack::Corsを利用します。
その時の設定と注意点を。

SinatraでRack::Corsを使う

SinatraでRack::Corsを使う時は、READMEに書かれている通りです。

www.khasegawa.netからのリクエストを許可する

例として、このサイト(www.khasegawa.net)からのリクエストを許可するようにしてみます。
originsにwww.khasegawa.netと単一で指定するだけですね。

use Rack::Cors do
  allow do
    origins 'www.khasegawa.net'
    resource '*', methods: %i[get]
  end
end

これでリクエストが通るようになりました。
この時のAccess-Control-Allow–Originは、https://www.khasegawa.netになり、期待する値になっていることも確認出来ますね。

他のドメインからも許可する

他のドメイン(example.com)からもリクエストを許可します。
originsメソッドの引数は、可変長引数となっているため、example.comを追加します。

use Rack::Cors do
  allow do
    origins 'www.khasegawa.net', 'example.com'
    resource '*', methods: %i[get]
  end
end

これでリクエストが通るようになりました。
簡単ですね。

この時のAccess-Control-Allow–Originは、「www.khasegawa.net」からリクエストした場合、https://www.khasegawa.netになり、「example.com」からのリクエストの場合は、https://example.comという期待する値になっていることも確認出来ます。

複数指定した場合は、マッチしたホストが設定されています。(正確にはschemeやポートを含めてものだが)

www.khasegawa.netとsub.khasegawa.netを許可する

Rack::Corsでは、引数に正規表現を指定することも出来るので、それを利用します。

use Rack::Cors do
  allow do
    origins /\Ahttps:\/\/(www|sub)\.khasegawa\.net\z/
    resource '*', methods: %i[get]
  end
end

正規表現で指定する場合の注意点としては、セキュリティを考慮し、schemeを含めた完全一致にすることをオススメします。

この時のAccess-Control-Allow–Originは、「www.khasegawa.net」からリクエストした場合、https://www.khasegawa.netになり、「sub.khasegawa.com」からのリクエストの場合は、https://sub.khasegawa.comという期待する値になっていることも確認出来ますね。

正規表現を指定した場合は、マッチしたホストを返却するようになっています。

挙動から分かる注意点

これらから分かることはなんでしょうか。
どれだけ指定しても、Access-Control-Allow-Originに設定される値は、1つなのです。(許可されていない場合は何も設定されない)
ということは、どこかでレスポンスをキャッシュすると不都合が出そうです。

これは、READMEのCommon Gotchasに書いてあることからも分かります。
Common GotchasのCachingでは、Rack::Cacheの話しか出ていませんが、要はキャッシュさせないでっていうことですね。

こういうのは、見落としがちだったりするので要注意ですね。

reattach-to-user-namespaceが無くてもTmuxを起動させる

最近、自宅の開発環境にUbuntuデスクトップを迎えました。
その環境では、普段使っている.tmux.confだと、reattach-to-user-namespaceを要求してしまい起動しなかったので、起動させるために条件分岐させました。

環境

まず、環境。

  • Tmux … 2.1
  • Zsh … 5.1.1

条件分岐させる

とりあえず変更前の.tmux.conf

# Window
set-window-option -g mouse on
bind -n WheelUpPane if-shell -F -t = "#{mouse_any_flag}" "send-keys -M" "if -Ft= '#{pane_in_mode}' 'send-keys -M' 'copy-mode -e'"
set -g default-command "reattach-to-user-namespace -l ${SHELL}" # ここ
set-option -g renumber-windows on

# Status Line
set-option -g default-terminal xterm-256color
set -g status-bg default
set -g status-fg colour253
set-window-option -g xterm-keys on
set-window-option -g window-status-fg default
set-window-option -g window-status-bg default
set-window-option -g window-status-current-fg colour178
set-window-option -g window-status-current-bg default
set-option -g status-position top
set-option -g status on
set-option -g status-interval 2
# set-option -g status-utf8 on
set-option -g status-justify "centre"
set-option -g status-left-length 60
set-option -g status-right-length 90

# Neovim
set -s escape-time 0

default-commandで指定してますね。
ここで落ちます。
だって、reattach-to-user-namespace入れてないし。

というわけで、以下の条件を満たす場合のみ、default-command先程の行を実行させようと思います。

まずは条件から。

  • reattach-to-user-namespaceが実行可能である

実行可能ではなかったり、参照出来ないのであれば、する必要はないですからね。
これで条件の洗い出しは終わり。
本当はもう少し検討した方がいいのかもしれないけど、今の使っている複数の環境では困ってないからOK。

次に、条件分岐のさせ方。
Tmuxには、条件分岐させるために、if-shellというコマンドがあり、今回はこいつを使う。
第一引数には、条件となるコマンドを文字列で指定。
第二引数には、条件が真となる場合に実行される処理を文字列で指定。

これらを元に書くと、対象の行を書き換える。

if-shell "test -x reattach-to-user-namespace" 'set -g default-command "reattach-to-user-namespace -l ${SHELL}"'

これで動くようになった。
良かった良かった。

if-shellを使うのは今回が初めてなんだが、ハマりどころがないことを祈りたい。
便利だからね。

CircleCIのキャッシュにハマった

タイトル通り、CircleCIのキャッシュにハマったのである。
CircleCIのキャッシュについては、こちらのドキュメントを参照してください。

環境変数が取得できない

CircleCIではキャッシュ機能が存在しており、特定のディレクトリをキャッシュしておくことが出来る。
その際のキャッシュのキーに、ブランチ名やリビジョン、ファイルのチェックサムなどを利用することが出来る。
そして、これらの中に環境変数が利用出来ると書いてあるのだが、まあ動かない。
{{ .Environment.variableName }}という名前のものなのだが、RAILS_ENVを取得しようとして、{{ .Environment.RAILS_ENV }}を書いたところで、<no value>が返ってくる。

この問題についてのディスカッション

これに関してのディスカッションは、ここに書いてある。
色々書いてあるのだが、CircleCIの従業員曰く、

At this time, that is expected functionality. We do not yet fully support environment variables throughout the configuration file. This thread is a feature request not a bug report

とのこと。
要は、「ドキュメントに書いてあることは、理想であって実装しているわけではない。そして、これはバグリポートではなく機能追加ということらしい。
どう考えてもドキュメントバグだろ…

まあ、その後に

The docs should definitely be updated- the phrasing is unclear. It supports any env var we supply, not any arbitrary env var.

と書いてあるので、一部の環境変数は使用可能なのだろうか。
時間がある時に検証してみようと思う。

ちなみにキャッシュについてのドキュメントは更新されていないが、configuration-referenceの方は更新されている。

Slackerのバグ修正版0.3.4をリリース

どうやら、いくつかのDBだと、動作しないようだったので、それのバグ修正版をリリースしました。
Stashはサポートを切り、BitbucketServerの4系のみサポートという形しました。

インストールする際は、こちらから。

Timezoneを設定するPlaybook

マシンのTimezoneの設定もPlaybbook化してみる。
CentOS7では、timedatectlというコマンド経由で設定出来るので、それを利用する。

---
- hosts: all
  become: true
  become_user: root
  vars:
    timezone: Asia/Tokyo
  tasks:
    - name: 'タイムゾーンを確認'
      shell: timedatectl status | grep "Time zone" | sed -e "s/.*:\s\(.*\)\s(.*)/\1/" | tr -d '\n'
      changed_when: false
      register: current_timezone
    - name: 'タイムゾーンの設定'
      shell: timedatectl set-timezone {{ timezone }}
      when: current_timezone.stdout != timezone

Chronyをインストールする時のPlaybook

Chronyをインストールする箇所もPlaybook化。
基本的に初期設定のままなので、何もいじらず書けばいい。

---
- hosts: all
  become: true
  become_user: root
  tasks:
    - name: 'chronyのインストール'
      yum:
        name: chrony
    - name: 'chronydをsystemdに登録'
      systemd:
        name: chronyd
        enabled: true
        daemon_reload: true
        state: restarted
      changed_when: false

今のところ複雑なプレイブック書いてないので、NTPサーバーを指定して、テンプレートを展開するようなタスクを追加してみようかなと思ったり。

ファイルの中身をコピーする時に、pbcopyが打つのが面倒

ファイルの中身をコピーする時に、毎回cat file | pbcopyって打つのが面倒だったので、zshrcに関数を定義しました。

function clip() {
    cat $1 | pbcopy
}

柔軟性はないけど、とりあえずはこれで十分かな。