Docker Swarmでクラスタを構築すると、複数のホストを1つのホストのように扱うことができます。
複数のコンテナを連携する機能であるリンクやボリュームがクラスタでも使えるのか調べて見ます。
準備
Docker Swarmのクラスタを構築します。構築方法はREADMEや以前書いた記事を参照してください。
swarm manage
を実行している端末でエラーがでていないことと、swarm list
でノードのIPアドレスが表示されることを確認します。
$ swarm list --token e7c4acc2096712987b041645b7b6290a
10.3.0.184:2375
10.3.0.64:2375
node01
でDOCKER_HOST
の設定も忘れずに行っておきます。
$ export DOCKER_HOST=tcp://<node01のプライベートIP>:2375
Docker Swarmの制限
Docker Swarm経由では一部のコマンドやオプションに制限があります。
コンテナをdaemonモードで起動する必要がある
-d
オプションを付けないと以下のように怒られてしまいます。
figもこれに引っかかって動かせませんでした。
$ docker run -it --rm --link redis:redis relateiq/redis-cli
FATA[0000] Error response from daemon: Attach is not supported in clustering mode, use -d.
一部のコマンドが実行できない
docker images
など一部のコマンドはDocker Swarmでは使えないようです。
$ docker images
FATA[0000] Error response from daemon: Not supported in clustering mode.
リンク
1つめのコンテナを起動します。
$ docker run -d --name redis crosbymichael/redis
3416288ab10b5d18496b3905f18598c6f2d081ba04c83db13ce1f2675050d13f
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3416288ab10b crosbymichael/redis:latest "redis-server --bind 6 seconds ago Up Less than a second 6379/tcp VM-68ec7bff-77e2-4b95-bd34-50735f4a4ea3.csecidcfcloud.internal/redis
redisコンテナをリンクして新しいコンテナを起動し環境変数が設定されていることを確認します。
$ docker run -d --link redis:redis dockerfile/redis 'env'
f3b9225ce639ad224df16a9310e3ad231eef1064b4599287c99b69284ca5a6d6
$ docker logs f3b
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=f3b9225ce639
REDIS_PORT=tcp://172.17.0.21:6379
REDIS_PORT_6379_TCP=tcp://172.17.0.21:6379
REDIS_PORT_6379_TCP_ADDR=172.17.0.21
REDIS_PORT_6379_TCP_PORT=6379
REDIS_PORT_6379_TCP_PROTO=tcp
REDIS_NAME=/pensive_fermi/redis
HOME=/root
期待通り設定されているのでredis-cli
コマンドを実行してみます。
応答が返ってきて連携がとれているのがわかります。
$ docker run -d --link redis:redis dockerfile/redis bash -c 'redis-cli -h redis ping'
88a191b504d1eccf1d29fec57f818308821419cc6005d12c5a41bead2d73405a
$ docker logs 88a
PONG
redisコンテナが乗っているノードを落としてみます。
# node02 or node03
# Ctrl-Cでswap joinをとめる
$ service docker stop
redisコンテナとリンクしてコンテナを起動させようとすると以下のようにエラーとなります。
$ docker run -d --link redis:redis dockerfile/redis bash -c 'redis-cli -h redis ping'
FATA[0000] Error response from daemon: 500 Internal Server Error: Could not find entity for redis
リンクさせなければ起動しているノードで実行されます。
$ docker run -d dockerfile/redis bash -c 'redis-cli -h redis ping'
bf7b396167536be3cfe2708e572f612802a7a4a0436dc35f816f7526016211e3
$ docker logs bf7b
Could not connect to Redis at redis:6379: Name or service not known
落としたノードをクラスタに復帰させます。
$ service docker start
docker start/running, process 6727
$ swarm join --token 71cb3861bd4d2d2e2a16c9c37807e955 --addr 10.3.0.184:2375
swarm manage
を実行している端末に次のようなメッセージが表示され復帰したことがわかります。
INFO[1260] [D7R4:KWCD:QGET:MZTH:QLLF:GW2X:RBVS:BCE3:CD6T:KNAA:JI72:E7BF/VM-68ec7bff-77e2-4b95-bd34-50735f4a4ea3.csecidcfcloud.internal] Node came back to life. Hooray!
redisコンテナを再度起動し、redis-cli ping
で応答が返ってくることを確認します。
$ docker start 3416288ab10b
$ docker run -d --link redis:redis dockerfile/redis bash -c 'redis-cli -h redis ping'
a9cfba6683b48c42091062ebce63a25e87140766c37749c4e5928c20c018c7f5
$ docker logs a9c
PONG
ボリューム
Swarmクラスタでも通常と同様にコンテナにボリュームを追加できます。
# node01で実行
$ docker run -d -P --name web -v /webapp training/webapp python app.py
85e0df543e2db9e3b3ea77e74c350548b52d08c972d42872b90b9b7ca72075f3
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85e0df543e2d training/webapp:latest "python app.py" 17 minutes ago Up 17 minutes 10.3.0.184:49153->5000/tcp VM-68ec7bff-77e2-4b95-bd34-50735f4a4ea3.csecidcfcloud.internal/web
$ curl http://10.3.0.184:49153
Hello world!
ホストマシンのディレクトリ参照
ホストマシンのディレクトリを参照することもできます。ただし、参照されるディレクトリはノードのディレクトリとなります。webappコンテナを正しく動かすためnode02、node03でディレクトリの用意をしておきます。
# node02, node03で実行
$ git clone https://github.com/docker-training/webapp.git
$ mkdir -p /src/webapp
$ cp webapp/webapp/* /src/webapp/
# node01で実行
$ docker run -d -P --name web2 -v /src/webapp:/opt/webapp training/webapp python app.py
eab2a9d2c34e8815b0268c258c37d73e0c44c99869c3f1256084cb36f79d8ef4
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ca0c9f171ef training/webapp:latest "python app.py" 3 minutes ago Up 3 minutes 10.3.0.184:49156->5000/tcp VM-68ec7bff-77e2-4b95-bd34-50735f4a4ea3.csecidcfcloud.internal/web2
85e0df543e2d training/webapp:latest "python app.py" 17 minutes ago Up 17 minutes 10.3.0.184:49153->5000/tcp VM-68ec7bff-77e2-4b95-bd34-50735f4a4ea3.csecidcfcloud.internal/web
$ ls /src
ls: cannot access /src: No such file or directory
$ curl http://10.3.0.184:49156
Hello world!
他のコンテナのボリュームをマウント
他のコンテナのボリュームをマウントすることもできます。
# node01で実行
# ボリューム用のコンテナを作成
$ docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
# dbdataのボリュームをbackup.tarに書き出す
# daemonモードシカ使えないので-dモードを付けておく
$ docker run -d --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
4f33ec202c9de26ca0d3e3ec484887aa264d948063b638e4b5af3a81001d1e86
node02, node03のいずれかにtarファイルが作成されているのが確認できます。
# node02 or node03
$ tar tvf backup.tar
drwxr-xr-x root/root 0 2014-12-14 12:32 dbdata/
dbdataを持っているコンテナが乗っているノードを落としてみます。
# node02 or node03
# Ctrl-Cでswap joinをとめる
$ service docker stop
dbdataのマウントができなくなります。
# node01
$ docker run -d --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
FATA[0000] Error response from daemon: 406 Not Acceptable: Container dbdata not found. Impossible to mount its volumes
ノードをクラスタに復帰させます。swarm manager
に復帰したことを示すメッセージが出ることを確認します。
$ service docker start
$ swarm join --token 09a5b19db4814aecaa09bf5434dfb720 --addr 10.3.0.64:2375
再びマウントdbdataをマウントしてみると再び成功するようになっています。
$ docker run -d --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
cf434576e679c9a3e99a2065964c68614d054744fe2bf57658a50d9ea2c63112
まとめ
Docker Swarmでもリンクやボリュームの機能を使うことはできることがわかりました。リンクしたり、ボリュームをマウントしているものについては同じノードで実行されるようです。
一部使えないコマンドもあり、Dockerと連携しているツールがそのまま使えるまでにはもうしばらくかかるのかもしれません。
引き続きチェックしていきたいと思います。