knife zeroをawsで扱う際にsshが切断されてしまう問題と解決策

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を働かせるように修正します。

https://github.com/kackyt/chef/pull/1/commits/8b6bfd586774b754108b0a1d03f9db21e8543553

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同様の実装を追加しました。

https://github.com/kackyt/net-ssh-multi/commit/19c3efba675c61c50a6468f5200f7e52efdfcc04

これでようやくcookbookが長引いてもちゃんと処理が完了するようになりました。やったね。

TODO

もろもろ落ち着いたらpull request書きます