調子にのってDocker化しまくったらしんどかった話

<img src="http://nikuniku.me/wp-content/uploads/docker.png" alt="Docker" title="docker.png" border="0" width="200" height="200">
前回Sentryというエラートラッキングツールのplaybookを書きました。
[もってけエンジニア！エラートラッキングツール【Sentry】のplaybookを書いたよ](
http://qiita.com/maaaato/items/7470d53cca40cf2ce4af)

このSentryをDocker化してしまえ！と思い、Dockerで構築してみたのですが、<strong>しんどいことに気づいた</strong>ので、メモっておきます。

※Kubernetes,composeとか使えば楽になるんじゃないかと思います。あくまでもDockerのみでやろうとした時の感想です。
<h2>結論 --linkだらけにすると地獄をみる</h2>

githubに上げました。MySQLはsentryのmigration済みのデータが入っています。

MySQLの容量が300MBあったので、上げれませんでした^^;なんか方法考えます。。。
<a href="https://github.com/maaaato/docker-lab/tree/master/sentry" taget="_blank">https://github.com/maaaato/docker-lab/tree/master/sentry</a>
※一応リンク。

どういう構成でDocker化したか図を載せます。
<img src="http://nikuniku.me/wp-content/uploads/docker-sentry.png" alt="docker sentry" title="docker sentry.png" border="0" width="588" height="359">

インターネットからのアクセスはnginxで受け、バックエンドのsentryサーバへproxyする形です。
あとはsentryで必要なMySQL(PostgreSQL)、Redisを用意しています。

これらをコンテナ化しましたが、図を見て頂くとわかると通りにコンテナ同士を通信させる必要があります。

Dockerのコンテナ同士の通信には
<pre><code>docker run -d --link CONTAINER_NAME:ALIASE IMAGE_NAME</code></pre>
といった様に
<pre><code>--link</code></pre>
オプションが必要になります。

図の例で言いますと、nginxはsentryサーバへproxyさせています。この時どのようなconfになっているかと言うと、
<pre><code>
upstream sentry {
    server sentry-docker:9000;
}


server {
    listen 80;
    location / {
        proxy_redirect     off;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;

        proxy_pass http://sentry;
    }
}</code></pre>
proxyさせる先をsentry-dockerといった様に書いています。

--linkでCONTAINER_NAME:ALIASEで、ALIASEをsentry-dockerと指定してdocker runさせています。
こうすることでnginxのコンテナ内の/etc/hostsには、
<pre><code>
172.17.0.9      2b312db7e6b4
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.8      sentry-docker 1f4c972658c2 sentry
</code></pre>
このようにsentryサーバのIPアドレスが書き込まれます。
sentryサーバの--linkも同様で、MySQL、Redisも同じように各コンテナのIPが/etc/hostsに登録されます。

※docker psの結果
<pre>CONTAINER ID        IMAGE                  COMMAND                CREATED             STATUS              PORTS                NAMES
2b312db7e6b4        maaaato/nginx          "/bin/sh -c '/usr/sb   4 minutes ago       Up 4 minutes        0.0.0.0:80-&gt;80/tcp   nginx
1f4c972658c2        maaaato/sentry         "sentry --config=/et   5 minutes ago       Up 5 minutes        9000/tcp             sentry
5473ad46ec96        maaaato/redis          "/entrypoint.sh redi   17 minutes ago      Up 17 minutes       6379/tcp             redis-docker
cdb6a0adf437        maaaato/mysql-sentry   "/usr/bin/mysqld_saf   18 minutes ago      Up 18 minutes       3306/tcp             mysql-docker
</pre>
<h2>つまり！！</h2>
ここでMySQLのコンテナをstopし、新規にrunしたらどうなるでしょうか？
MySQLのコンテナが新規に立ち上がるので、新たにIPが割り振られます。

つまり！MySQLへlinkしているコンテナはIPが変わった事なんてしらないので、あれ？接続できないぞ。。。となってしまいます。南無。
まぁ当たり前か。。。

先ほどの図では、sentryコンテナからMySQLコンテナに接続していました。これを再び接続し直すには、sentryコンテナをrestartして、nginxコンテナもrestartが必要です。
restartでうまくいかない場合は、コンテナの作り直しが発生してしまいます。
<h2>まとめ</h2>
Dockerでlinkさせまくると一カ所が死んだときに影響範囲が大きくなってしまう可能性があります。
Docker化を進めるにあたり、Docker化にするところしないところをしっかり設計する必要があると感じました。
Kubernetes,composeはまだ試していないのですが、Dockerの管理が楽になるもの？だと思いますので、次は試してみます。
<h2>参考サイト</h2>
Dockerのネットワークについてはこちらの記事がとても分かりやすいです。
<a href="http://deeeet.com/writing/2014/05/11/docker-network/" target="_blank">Dockerのネットワークの基礎</a>
<a href="http://deeeet.com/writing/2014/03/20/docker-link-container/" target="_blank">Dockerコンテナ間のlink，database.ymlの書き方</a>