概要
Swarm と組み合わせることで、Compose(Fig) がマルチホスト環境下で使えるようになるという話。
Sinatra コンテナと Redis コンテナからなるアプリケーションを複数の Docker ホストにまたがって配置する。
マルチホスト環境での Compose
Swarm クラスタの構築
を参考に 3 台の Docker ホストを用意する。
$ docker -H core-01:2377 info
Containers: 4
Nodes: 3
core-01: core-01:2375
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 998 MiB
core-03: core-03:2375
└ Containers: 1
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 998 MiB
core-02: core-02:2375
└ Containers: 1
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 998 MiB
それぞれ 2375
ポートから Docker Remote API が使える状態。
- core-01:
tcp://core-01:2375
- core-02:
tcp://core-02:2375
- core-03:
tcp://core-03:2375
$ docker -H core-01:2377 ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8a6d378fd434 swarm:latest "/swarm join --addr= 7 seconds ago Up About a minute 2375/tcp core-02/swarm-agent-core-02
0cd3fbda1f31 swarm:latest "/swarm join --addr= About a minute ago Up About a minute 2375/tcp core-03/swarm-agent-core-03
62b93d0e9f7c swarm:latest "/swarm join --addr= 7 minutes ago Up 7 minutes 2375/tcp core-01/swarm-agent-core-01
df7b39a2eeba swarm:latest "/swarm manage --tls 8 minutes ago Up 8 minutes 172.17.8.101:2377->2375/tcp core-01/swarm-manager
Swarm マネージャは core-01 に立っていて、core-01:2377
がエンドポイント。(だから $ docker -H core-01:2377
としている)
Swarm エージェントは各ノードにそれぞれいる。
- core-01
- swarm manager
- swarm agent 01
- core-02
- swarm agent 02
- core-03
- swarm agent 03
Compose をシングルホスト環境で使う
まずはシングルホスト環境下で Compose を使ってみる。
を参考に compose をインストールし、
で使った構成をベースに使う
# docker-compose.yml
web:
image: quay.io/spesnova/sinatra-hello-world
command: bundle exec ruby app.rb
ports:
- 4567
links:
- redis
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
redis:
image: redis:latest
ポイント 3 つ
- コンテナのスケールをする際のポートの衝突を避けるために
web
サービスのports
は80:4567
から4567
に変える - どの Docker ホストからでもイメージが取得できるよう
build
の代わりにimage
を指定する(イメージも push しておく) - 開発時は手元のコードをコンテナと共有したいので VOLUME を使っていたが、今回はできたイメージを使うので
web
サービスコンテナのvolumes
を外す
起動してみる
# at core-01
$ cd sample
$ docker-compose up -d
Creating sample_redis_1...
Creating sample_web_1...
こんな状態
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------
sample_redis_1 /entrypoint.sh redis-server Up 6379/tcp
sample_web_1 bundle exec ruby app.rb Up 172.17.8.101:49153->4567/tcp
スケールしてみる
$ docker-compose scale web=2
Creating sample_web_2...
Starting sample_web_2...
$ docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------
sample_redis_1 /entrypoint.sh redis-server Up 6379/tcp
sample_web_1 bundle exec ruby app.rb Up 0.0.0.0:49155->4567/tcp
sample_web_2 bundle exec ruby app.rb Up 0.0.0.0:49156->4567/tcp
当たり前だけど core-01 に web
サービスコンテナが 2 つ起動している。
一旦コンテナは停止、削除しておく
$ docker-compose kill && docker-compose rm
Killing sample_web_2...
Killing sample_web_1...
Killing sample_redis_1...
Going to remove sample_web_2, sample_web_1, sample_redis_1
Are you sure? [yN] y
Removing sample_redis_1...
Removing sample_web_2...
Removing sample_web_1...
Swarm を利用して Compose(Fig) をマルチホスト環境で使う
Swarm API は既存の Docker API と互換性があるように作られているので、core-01 の Docker API の代わりに Swarm API を使うことができる。
Swarm API を使うと、たとえば、docker run busybox echo hello world
するとマルチホストのどこかで busybox コンテナが実行される。同じように Compose から使えば、 Sinatra コンテナ+ Redis コンテナの組み合わせがマルチホストのどこかで起動するということ。
図にするとこういうこと
# シングルホスト環境での Compose の利用
Compose ---> Docker Remote API (Docker Host, core-01)
# マルチホスト環境での Compose の利用
---> Docker Remote API(Docker Host, core-01)
/
Compose ---> Swarm API --- ---> Docker Remote API(Docker Host, core-02)
\---> Docker Remote API(Docker Host, core-03)
Swarm 用に docker-compose.yml の編集
デフォルトで Swarm API を使うように設定する
$ export DOCKER_HOST=tcp://core-01:2377
さらに docker-compose.yml
をいじる
web:
image: quay.io/spesnova/sinatra-hello-world
command: bundle exec ruby app.rb
ports:
- 4567
environment:
- REDIS_HOST=172.17.8.101 # 追加
- REDIS_PORT=6379
- affinity:container!=sample_web_* # 追加
redis:
image: redis:latest
ports:
- 6379:6379 # 追加
environment:
- constraint:node==core-01 # 追加
マルチホストで web
サービスコンテナを動かす場合 LINK で連携はできないので、
-
web
サービスコンテナからlink
を外す -
web
サービスコンテナの Redis ホストをcore-01
に向ける -
redis
サービスコンテナのポートを外部にさらす -
redis
コンテナが core-01 で動くように Swarm 用にcontraint
を設定
さらに web
サービスコンテナ同士は別々の Docker ホストで起動するような設定を付けた。affinity:container!=sample_web_*
は sample_web_*
という名前のコンテナがいたらそこでは web
サービスコンテナは立てないという条件。
Swarm を使ってスケール
docker-compose up -d
してみる
$ docker-compose up -d
Creating sample_redis_1...
Creating sample_web_1...
docker-compose ps
と docker ps
してみる
$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------
sample_redis_1 /entrypoint.sh redis-server Up 6379/tcp
sample_web_1 bundle exec ruby app.rb Up 172.17.8.101:80->4567/tcp
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0fa8b600d765 redis:latest "/entrypoint.sh redi 9 seconds ago Up Less than a second 6379/tcp core-01/sample_redis_1
599a99f51659 sample_web:latest "bundle exec ruby ap 9 seconds ago Up Less than a second 172.17.8.101:80->4567/tcp core-01/sample_web_1
docker-compose コマンドを実行しているホストと同じ core-01 でコンテナが立ったもよう。ここまでは普通。
web
サービスコンテナをスケールしてみる
$ docker-compose scale web=2
Creating sample_web_2...
Starting sample_web_2...
web_2
が core-03 に立った
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23d5276ef844 quay.io/spesnova/sinatra-hello-world:latest "bundle exec ruby ap 3 seconds ago Up Less than a second 172.17.8.103:49155->4567/tcp core-03/sample_web_2
f94b9cf27ba3 redis:latest "/entrypoint.sh redi 43 seconds ago Up 16 seconds 172.17.8.101:6379->6379/tcp core-01/sample_redis_1
8469bdd81f5a quay.io/spesnova/sinatra-hello-world:latest "bundle exec ruby ap 43 seconds ago Up 17 seconds 172.17.8.101:49165->4567/tcp core-01/sample_web_1
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------
sample_redis_1 /entrypoint.sh redis-server Up 172.17.8.101:6379->6379/tcp
sample_web_1 bundle exec ruby app.rb Up 172.17.8.101:49165->4567/tcp
sample_web_2 bundle exec ruby app.rb Up 172.17.8.103:49155->4567/tcp
で Hello World 及びアクセス数のインクリメントができる
さらにスケールする
$ docker-compose scale web=3
Creating sample_web_3...
Starting sample_web_3...
今度は core-02 に立った
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
737f31bf1d0a quay.io/spesnova/sinatra-hello-world:latest "bundle exec ruby ap Less than a second ago Up Less than a second 172.17.8.102:49153->4567/tcp core-02/sample_web_3
23d5276ef844 quay.io/spesnova/sinatra-hello-world:latest "bundle exec ruby ap 2 minutes ago Up 2 minutes 172.17.8.103:49155->4567/tcp core-03/sample_web_2
f94b9cf27ba3 redis:latest "/entrypoint.sh redi 3 minutes ago Up 2 minutes 172.17.8.101:6379->6379/tcp core-01/sample_redis_1
8469bdd81f5a quay.io/spesnova/sinatra-hello-world:latest "bundle exec ruby ap 3 minutes ago Up 2 minutes 172.17.8.101:49165->4567/tcp core-01/sample_web_1
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------
sample_redis_1 /entrypoint.sh redis-server Up 172.17.8.101:6379->6379/tcp
sample_web_1 bundle exec ruby app.rb Up 172.17.8.101:49165->4567/tcp
sample_web_2 bundle exec ruby app.rb Up 172.17.8.103:49155->4567/tcp
sample_web_3 bundle exec ruby app.rb Up 172.17.8.102:49153->4567/tcp
さらにスケールすると
$ docker-compose scale web=4
Creating sample_web_4...
unable to find a node that satisfies container!=sample_web_*
web
コンテナがいない Docker ホストが見つからないので立てられないよというメッセージ。affinity
がちゃんと動いている
マルチホスト環境でもまとめてログが見られる
$ docker-compose logs