awsでknife zero convergeを使うと起きる問題
awsでknife zeroを使う場合、shellが長い間応答しないコマンドが走るとフリーズしてしまいます。具体的にはdokkuをインストールしようとしましたが、この辺でsshが応答しなくなり、Ctrl+Cでキルするしかなくなります。
Importing herokuish into docker (around 5 minutes)
原因
awsはsshで長い間通信されない場合にインフラ側で自動的にルーティングを切ってしまうようです。ssh-clientやsshdは生きていますが通信が通らないという状態に陥ります。
この状態を回避するために、~/.ssh/configに定期的に通信して切られないよう設定を追加するという方法が提案されています。
http://qiita.com/euno7/items/00ef56244b7b193d2455
しかし、knife zeroではこの方法が働きません。
解決策
knife zeroで~/.ssh/configが働かない課題には2つの要因があり、それらの解決策について解説します。
knife sshでコンソールのssh_configが反映されていない
chefのソースコード上(chef/lib/chef/knife/ssh.rb)で、~/.ssh/configを読み込む処理がありますが、user,forward_agent,portくらいしか使われていませんでした。そこでServerAliveIntervalを働かせるように修正します。
Net::SSH::Multiでkeepaliveパケットが流れない
これでうまくいったーと正直私も思いましたが上だけでは解決しませんでした。Net::SSHでは動作しますが、knife zero(knife ssh)ではNet::SSHから派生したNet::SSH:Multiというclassが使われています。これにはNet::SSHでは実装されているServerAliveIntervalに対応するkeepaliveパケットを送信する実装が入っていませんでした。そこでNet::SSH:MultiにNet::SSH同様の実装を追加しました。
これでようやくcookbookが長引いてもちゃんと処理が完了するようになりました。やったね。
TODO
もろもろ落ち着いたらpull request書きます