[2013-05-19-1] にインストールしたUbuntu 12.04はうっかり32bit版でした。。仕方がないのでUbuntu 14.04へのアップグレードがてら、クリーンインストールすることにしました。
管理画面からポチポチしてOSのインストールは完了。CookはあらかじめVirtualBoxとEC2で確認していたので万全です(キリッ
と思いきや、いつまでたってもRecipeが処理されません…。
$ knife solo cook masutaka.net
Running Chef on masutaka.net...
Checking Chef version...
Uploading the kitchen...
Generating solo config...
Running Chef...
Starting Chef Client, version 11.16.2
(ここでダンマリ)
これまた仕方がないので、サーバ側の/opt/chef/embedded/lib/ruby/gems/1.9.1/gems以下をprintfデバッグ(というかpデバッグか)で調べたところ、Chefがサーバ情報を取得するときに使うOhaiのGCEプラグインから返ってこないことがわかりました。GCEとはGoogle Compute Engineです。なんでChefが?
で、結論から言うと、GCEプラグインをOFFにしたら解決しました。
knife solo prepareのあとに/opt/chefが作られるので、/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/ohai-7.4.0/lib/ohai/config.rbを以下のように修正。あとはknife solo cookするだけです。knife solo bootstrapは出来ないことになります。
default :disabled_plugins, []
↓
default :disabled_plugins, [:GCE]
knife soloはchef-soloをリモートから実行するコマンドで、
/opt/chef/embedded/bin/ruby /usr/bin/chef-solo -c /home/masutaka/chef-solo/solo.rb -j /home/masutaka/chef-solo/dna.json
のようなchef-soloコマンドを実行します。root権限だったかな?
この/home/masutaka/chef-solo/solo.rbに
Ohai::Config[:disabled_plugins] = [:GCE]
を書き、前述のchef-soloコマンドを実行すれば/opt/chef以下を修正する必要はありませんが、残念ながらこのファイルはknife solo cook時に自動生成されます。
ローカルの.chef/knife.rbに書いても無視されました。残念。そういうわけで、今はprepareをした後はサーバにログインしてファイルを書き換え、そのあとにcookというイマイチなことをしています。
ではなぜ、さくらのVPSだけダンマリになるのか?
/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/ohai-7.4.0/lib/ohai/mixin/gce_metadata.rbのここに違いがありました。
def can_metadata_connect?(addr, port, timeout=2)
t = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
saddr = Socket.pack_sockaddr_in(port, addr)
# さくらはこの行に来る。
connected = false
portは80、addrはmetadata.google.internalです。
さくら以外はおそらくSocket.pack_sockaddr_inで例外が発生して、それ以降処理されないのでしょう。さくらはそれ以降処理され、無限ループに入り込んでしまいます。
irbでも再現出来ました。さくら以外は例外が発生しています。さくらは壊れた文字列が返ってきます。
# さくら以外(Cookできる)
$ irb -r socket
irb(main):001:0> Socket.pack_sockaddr_in(80, 'metadata.google.internal')
SocketError: getaddrinfo: nodename nor servname provided, or not known
from (irb):1:in `pack_sockaddr_in'
from (irb):1
from /Users/masutaka/.rbenv/versions/2.1.2/bin/irb:11:in `<main>'
# さくら(Cookでダンマリ)
$ irb -r socket
irb(main):001:0> Socket.pack_sockaddr_in(80, 'metadata.google.internal')
=> "\x02\x00\x00PE\xAC\xC9\xD0\x00\x00\x00\x00\x00\x00\x00\x00"
irb(main):002:0> require 'nkf'
irb(main):003:0> NKF.nkf('-w8', Socket.pack_sockaddr_in(80, 'metadata.google.internal'))
=> "\u0002\u0000\u0000PEャノミ\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
pingでも違いあり。
# さくら以外(Cookできる)
$ ping metadata.google.internal
ping: cannot resolve metadata.google.internal: Unknown host
# さくら(Cookでダンマリ)
$ ping metadata.google.internal
PING metadata.google.internal.net (69.172.201.208) 56(84) bytes of data.
さくらのDNSサーバはさくら奨励の133.242.0.3と133.242.0.4を指定。Google Public DNS (8.8.8.8と8.8.4.4)に変えても変わらず。
ここで調査は行き詰まり。cookが面倒になってしまったのは残念。
ブラジルの人も困っていました。
GCE Plugin infinite loop · Issue #382 · opscode/ohai
追記(2016-07-19):
職場の同僚が EC2 で同じ現象でハマっていて、この記事の方法で回避できたそうです。