docker、触ってたけどちゃんとデプロイとかしたことなかったのでこのひと月しこしこ作業しては失敗し直しては失敗しを繰り返してて、この週末やっとデプロイした。yapcasia.orgのことなんですけどね。

以下ベストプラクティスかどうかは知らないけど、とりあえず俺が通った道筋:


最初コンテナ同士のつながりをどう定義するといいのか全然わからなくて困っていた。例えばサイトの基本はMovableTypeで構築しているんだけど、その人は当然mysqlと話すから、MT→mysqlの接続を定義するのにどういうふうに名前やポート番号を解決するの?とかnginxからMTへの接続の解決は…?とか

dockerコンテナの内容はimmutableであっても、コンテナのインスタンス自体は揮発性が高いものであるから、できればシンボリックな形でそれぞれのコンテナやデーモン等の接続情報を提供して動的に解決したいわけだが、どうもドキュメントを探しててもいい感じのものがない。多分これはdockerはもっと大きいスケールのデプロイとかに向いていて、VPS一台の中で完結するマイクロなシステム用に使う必然性がないからだと思われる。ちなみに今回はその辺りはわかっていて、敢えて (1) システム構築の手順を残す (2) やってみたかった という名目でこういうことをした次第。

で、ドキュメントを読んでいて見つけたのでまず試したのが、docker runに対する --linkオプション。これはコンテナの名前を明示してコンテナ同士を「結合」させるもの。--linkを使うとコンテナのインスタンス名称でDNS解決ができたりとわりとよさそうな感じだったので色々試してみた。

結果としては、これはfailure detectionとそこからのリカバリがかなり高度に自動化されていないとあまり意味がない。なぜなら --linkで指定したリンクは、依存しているコンテナが落ちて再起動した場合とかに自動的に修復はされないから。

だから例えば MT → mysqlへのリンクを貼っていても、mysqlコンテナをメンテナンスや設定変更で再起動したらそのリンクは切れたままで、MT側も再起動するしかない。俺がほしかったのはそういうのじゃないよ!

で、その後serf使ってみたりして結局serf自体に名前解決が必要だったりとまぁ色々失敗して、結果的にはこういう形にした
  1. コンテナは全てスクリプト経由で起動。
  2. docker runが成功したあとで必ず docker inspect -f '{{ .NetworkSettings.IPAddress }}' を使い、コンテナのIPアドレスを取得
  3. dnsmasqを起動させておいて、そこにこのIPアドレスを動的に追加、dnsmasqに設定をリロードさせる
このようにしておくと、コンテナ名で全てのサービスのホスト名を解決できる。もちろんそれぞれのサービスでホスト名解決は変にキャッシュとかしないようにしておく。(例えばnginxでは set $host "コンテナ名"; proxy_pass $host;というふうにしないと、ホスト名の解決結果がキャッシュされるので望んだ結果にならない)

あとこの流れでmysqlはdockerコンテナじゃなくてホスト側で普通に立ち上げる事にしたのだが、その際bind-addressを0.0.0.0にしないとdocker側から見えないという… もちろん認証は設定してたのだけど、後で言われておっとっとととiptablesで 172.17.*と127.0.0.1以外からはmysqlが見えないようにした。これ、ひょっとすると UNIXソケット設定すればよかったのかな、と今思ってる。

ともあれ、システム構成はだいたいこんな感じになった

001
まぁエレガントとは言いがたいが、とりあえずこれでうまく行った。MovableTypeも6になった。今後はdocker run --linkがもう少しDWIMになってくれるといいなー。以上、わからんけどとりあえずやってみてそれなりうまく動いた、レポでした。