Docker、CoreOS、Google Compute Engine:やめたほうがいい事 6連発

最近、Docker・Google Compute Engineで分散3Dレイトレーシングといった物のネットワークまわりをいじらせてもらっている。

lighttransport/francine

ところで、DockerもCoreOSもGoogle Compute Engineも全然枯れていないだけに、やってはいけないとは書いてないにも関わらず、うっかりやろうとすると本当に面倒くさい事態に陥る事柄が非常に多い。そういった訳で、この記事では、自分でうっかりやってひどい目にあったパターンをいくつかご紹介したいと思う。何かの参考にしていただければ幸いである。

Dockerでexport / importしてはいけない

Dockerの公式ドキュメントには、当然できる事のような顔をして、Docker containerをexportしてtar.gzにし、それを再びimportするといった手順が示されている。
しかし、例えば手元であるDocker Containerをexportして他のマシンでimportするとこんなひどい怒られ方をする。

$ sudo docker import - peryaudo/hogehoge < peryaudo_hogehoge.tar.gz
2014/05/05 23:42:15 write unix /var/run/docker.sock: broken pipe

このエラーが出る基準はよく分からない。最初はサイズかと思ったが、tarを展開する時に怒られているようだ?

ともかく、やめたほうがいい。素直に、private repositoryを立てよう。

CoreOSをGoogle Compute Engineのデフォルトのディスクサイズのまま使ってはいけない

さて、private repositoryを立ててコンテナをやりとりしよう。
だが、ここで問題がある。Google Compute Engineのデフォルトのディスクサイズは6GB(gcutilコマンド)、10GB(REST API経由)と比較的小さい。
Dockerはtar.gzに落とし込んだコンテナより差分を全部含むコンテナのほうが圧倒的にでかいので、private repositoryでコンテナをやり取りするなどしているとあっという間にこの程度の容量は使い切ってしまう。

gcutilであれば--boot_disk_size_gbなどでサイズをでかくして使おう。CoreOSであれば、ここでディスクサイズを大きくするだけで、自動でパーティションをリサイズしてくれる。

Buildroot製コンテナ内などで、複数のディストリビューションでビルドしたバイナリを実行してはいけない

Buildrootを使うと、極めて小さいサイズのDocker Containerを作成する事ができる。大規模環境でデプロイするに当たってはこれは嬉しい事だ。
しかし、リンクされているlibcによって細かい詳細が違うため、他でコンパイルしたバイナリをそのまま実行すると怒られるので、LD_LIBRARY_PATHなどで、コンパイルした環境と一致するlibcなどのsoファイルを入れておく必要がある。
しかし、ここで、複数のディストリビューションでビルドしたバイナリなどを同居させると、もうにっちもさっちもいかなくなる。

こんな時の対処法として、どうしても他の人がビルドしたバイナリと自分のビルドするバイナリを同居させる必要があり、かつ自分が今のディストリビューションを使い続けたい時、どうすればいいだろうか。もちろん、答えはDockerである。

francineではworkerコンテナのビルドに、「workerコンテナをビルドするためのコンテナ」を作ることで対処している。

CoreOSが勝手に再起動しないと思ってはいけない

CoreOSは独特のセキュリティへのこだわりを持ったOSだが、その特徴の1つとして、完全に自動でOSを最新版にアップデートしてくれるという点がある。

しかしこれはすなわち知らない間に勝手にOSがリブートするという事である。

セットアップスクリプトなどを書く時は、あらかじめこの事を頭に入れた上で書く必要がある。

また、この時、デフォルトではCoreOSは、前回終了時に起動していたコンテナは起動してくれない。これはsystemdでサービス管理をしろという意味なので、下手な事をしないで素直にcloud-config.yamlにsystemdの設定を書こう。Google Compute Engineはインスタンス作成時に、metadataとしてcloud-config.yamlを渡すことができる。

gcutil addinstanceでcloud-config.yamlを使ってインスタンスを立て、直後にgcutil sshで繋いではいけない

cloud-config.yamlは、CloudInit由来のYAML形式による設定ファイルをCoreOSが模倣したもので、完全ではないがCloudInitと同様の設定を使うことができる。
これにより各インスタンスの設定を楽に行うことができるが、これを渡してインスタンスを立ち上げた直後にgcutil sshで繋ごうとすると存在しないパスワードを聞いてくるような謎挙動があるのでやめよう。
といってもcloud-configを使わない訳にもいかないのでうまくワークアラウンドしましょう。
追記(5/12):ゾーンによって再現度に差があるようだ。

Dockerで同じコンテナ内のプロセスのポートをホストにマップして繋いではいけない

同じコンテナ内にあるプログラムは、仮にホストにポートをマップしていてかつホストを経由しても、繋ぐことはできない。
観念してコンテナを分けよう。

(おまけ 5/12)fleetについて

ドキュメントの「アーキテクチャ」の項目に書いてある事で、現状できない事が存在していて、まだ未熟な印象を受けるし、今回の用途(死んだインスタンスには勝手に生き返ってほしくないしインスタンスとジョブを固定したい)の場合にfleetを使ってもあまり便利にならないと踏んだので現状francineではfleetは使っていない。