Posted at

過去最大のupdateと聞いてDocker1.12を試してみた

More than 3 years have passed since last update.

ということで、タイトル通り、過去最大のupdateと言われているDocker1.12の気になる機能を試しました。

meetup等でDocker社の人の話を聞いた内容や公式ドキュメントベースで気になった箇所のみ試します。

ちなみに後方互換性は保たれているので、以下で出てくるswarm init等のコマンドを使わない限り今まで通り使えるそうです。

自分が気になったところを試しただけなので、網羅的な更新一覧および、内部の仕組みは公式ページなり、いつも訳して下さっている前佛さんの日本語訳を参考にしてください。

あとはDockerConの動画とかも沢山あるけど多すぎるので、先日行われたオンラインmeetupの動画がまとまっててオススメです。

というか、このポストはほぼオンラインmeetup及び、ほぼ同じ内容のSanta Claraのmeetupで紹介されてた機能の紹介ですw


環境

以下の環境はLinuxで行いました。dockerはインストール済みと仮定します。dockerrepoを追加していれば、aptでもdnfでも最新版が入るはずです。以下のデモではDigitalOceanを使いますがVirtualBoxでもAWSでも何でも大丈夫かと思います。DigitalOceanの場合はこちらから登録すると今回動かす分くらいのクレジットは貰えます。(私にもクレジットが入るのでそーゆーのがイヤな方は普通にトップから登録してください)

また、以下のポートが開いている必要があります。(DigitalOceanでは設定不要ですが、ipv6有効になってたりするとトラブルかもしれません)


  • TCP: 2377, 7946, 4789

  • UDP: 7946, 4789


Swarm modeのチュートリアルを一通りやってみる

まずはチュートリアルにあるswarm modeの使い方を一通り試してみます。

全く同じではないですが、既にやった方はここは読まなくて大丈夫です。

チュートリアルでは各ノードでdockerコマンド叩いてますが、sshしたりするのが面倒なのでdocker-machineを使いたいと思います。


docker-machineのインストール

curl -L https://github.com/docker/machine/releases/download/v0.8.0/docker-machine-`uname -s`-`uname -m` >~/path/to/docker-machine && chmod +x ~/path/to/docker-machine


まずはmanagerとなるノードを作成します。DIGITALOCEAN_API_TOKENは適宜設定してください。(以後同様)

docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} manager

swarmモードで起動します。--advertise-addrではmanagerのIPを指定しますので、docker-machine ls等で調べておいてください。

eval $(docker-machine env manager)

docker swarm init --advertise-addr 192.241.219.207

以下のようなworker、managerそれぞれの追加方法が出力として得られます。


実行結果

Swarm initialized: current node (djvtufr82caej8ebysdbsj0ov) is now a manager.

To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-46kek56vwx6f7y9d0tqci7zrly11b2h8u0k31xhx0kaxx4f70o-6k4xdghyave5qci4o94s8b433 \
192.241.219.207:2377

To add a manager to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-46kek56vwx6f7y9d0tqci7zrly11b2h8u0k31xhx0kaxx4f70o-dxsejlrazkr0jaznx4u9o8yl7 \
192.241.219.207:2377


docker infoでSwarmモードがactive、IsManagerがtrueになってることが確認できます。

docker info

Swarm: active
IsManager: true

docker node lsコマンドでもノードの状態が確認できます。

$ docker node ls

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
djvtufr82caej8ebysdbsj0ov * manager Ready Active Leader

続いてworker用のマシンを2台作ります。

docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker1

docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker2

先ほどmanagerを作ったときに得られた結果を参考に、workerを追加してみます。

eval $(docker-machine env worker1)

docker swarm join --token SWMTKN-1-46kek56vwx6f7y9d0tqci7zrly11b2h8u0k31xhx0kaxx4f70o-6k4xdghyave5qci4o94s8b433 192.241.219.207:2377

eval $(docker-machine env worker2)
docker swarm join --token SWMTKN-1-46kek56vwx6f7y9d0tqci7zrly11b2h8u0k31xhx0kaxx4f70o-6k4xdghyave5qci4o94s8b433 192.241.219.207:2377

再びmanagerでdocker node lsを実行して結果を確認しておきます。

eval $(docker-machine env manager)

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
as3dl417gpz9795aedxa970th worker2 Ready Active
asqs3rls6pc32izn74zkkiysd worker1 Ready Active
djvtufr82caej8ebysdbsj0ov * manager Ready Active Leader

次にサービスを作ります。

docker service create --replicas 1 --name helloworld alpine ping docker.com

1コンテナのみのhelloworldという名前のサービスで、alpineのイメージを使い、ping docker.comという内容を実行する、というサービスです。

色々なコマンドで結果を確認します。

$ docker service ls

ID NAME REPLICAS IMAGE COMMAND
16hidqk9zown helloworld 1/1 alpine ping docker.com

$ docker service inspect --pretty helloworld
ID: 16hidqk9zown8qpqt424yzwxc
Name: helloworld
Mode: Replicated
Replicas: 1
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
ContainerSpec:
Image: alpine
Args: ping docker.com
Resources:

$ docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bdbz6k194232czgn0rrvkklkw helloworld.1 alpine manager Running Running 2 minutes ago

スケールさせてみます。

$ docker service scale helloworld=5

helloworld scaled to 5

$ docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bdbz6k194232czgn0rrvkklkw helloworld.1 alpine manager Running Running 7 minutes ago
6qhabtifgay4zzzduqabiiwhe helloworld.2 alpine worker1 Running Running 12 seconds ago
33zyifha6z47dvnve8g48g9dh helloworld.3 alpine manager Running Running 13 seconds ago
7cobt9a7umy33h1flgzor0j1s helloworld.4 alpine worker2 Running Running 11 seconds ago
d8jnt9u5yn85t8bjcfp58cmau helloworld.5 alpine worker1 Running Running 12 seconds ago

サービスを削除します。

$ docker service rm helloworld

helloworld

サービスの状態を確認しようとすると削除済みのためエラーになります。

$ docker service ps helloworld

Error: No such service: helloworld

続いてローリングアップデートを試してみます。

まずはredisを3コンテナ動かし、update-delayを10秒に設定します。

$ docker service create \

--replicas 3 \
--name redis \
--update-delay 10s \
redis:3.0.6

状態確認します。

$ docker service ps redis

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bq9xwhwbryx7i180fx1zw6pb2 redis.1 redis:3.0.6 worker2 Running Preparing 16 seconds ago
86mgm09e7vb8hzp7aki87fxcd redis.2 redis:3.0.6 worker1 Running Running 4 seconds ago
0aphe5lz4w3mrn9wx2rmdnykh redis.3 redis:3.0.6 manager Running Running 3 seconds ago

$ docker service inspect redis --pretty
ID: 6ue7ncgimxwsnarvvdgw7431d
Name: redis
Mode: Replicated
Replicas: 3
Placement:
UpdateConfig:
Parallelism: 1
Delay: 10s
On failure: pause
ContainerSpec:
Image: redis:3.0.6
Resources:

redis3.0.7にローリングアップデートしてみます。

$ docker service update --image redis:3.0.7 redis

まずは以下でUpdateが進行中なのが分かります。

$ docker service inspect redis --pretty

ID: 6ue7ncgimxwsnarvvdgw7431d
Name: redis
Mode: Replicated
Replicas: 3
Update status:
State: updating
Started: 9 seconds ago
Message: update in progress
Placement:
UpdateConfig:
Parallelism: 1
Delay: 10s
On failure: pause
ContainerSpec:
Image: redis:3.0.7
Resources:

10秒間隔のローリングアップデートなので、適宜時間を空けて結果を確認すると以下のようにローリングアップデートされているのが分かります。

$ docker service ps redis

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bq9xwhwbryx7i180fx1zw6pb2 redis.1 redis:3.0.6 worker2 Running Running 2 minutes ago
86mgm09e7vb8hzp7aki87fxcd redis.2 redis:3.0.6 worker1 Running Running 2 minutes ago
1kdq4xygokkeeycdhgw1f9zpc redis.3 redis:3.0.7 manager Running Running 4 seconds ago
0aphe5lz4w3mrn9wx2rmdnykh \_ redis.3 redis:3.0.6 manager Shutdown Shutdown 16 seconds ago

$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bq9xwhwbryx7i180fx1zw6pb2 redis.1 redis:3.0.6 worker2 Running Running 2 minutes ago
5tn67yo2r8rdt9sx4tbmk6h3x redis.2 redis:3.0.7 worker2 Running Running 9 seconds ago
86mgm09e7vb8hzp7aki87fxcd \_ redis.2 redis:3.0.6 worker1 Shutdown Shutdown 25 seconds ago
1kdq4xygokkeeycdhgw1f9zpc redis.3 redis:3.0.7 manager Running Running 36 seconds ago
0aphe5lz4w3mrn9wx2rmdnykh \_ redis.3 redis:3.0.6 manager Shutdown Shutdown 47 seconds ago

$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
a02h3iatx9dfwnkcl5doqette redis.1 redis:3.0.7 worker1 Running Running about a minute ago
bq9xwhwbryx7i180fx1zw6pb2 \_ redis.1 redis:3.0.6 worker2 Shutdown Shutdown about a minute ago
5tn67yo2r8rdt9sx4tbmk6h3x redis.2 redis:3.0.7 worker2 Running Running about a minute ago
86mgm09e7vb8hzp7aki87fxcd \_ redis.2 redis:3.0.6 worker1 Shutdown Shutdown 2 minutes ago
1kdq4xygokkeeycdhgw1f9zpc redis.3 redis:3.0.7 manager Running Running 2 minutes ago
0aphe5lz4w3mrn9wx2rmdnykh \_ redis.3 redis:3.0.6 manager Shutdown Shutdown 2 minutes ago

終了後に再び状態確認しておきます。Updateがcompletedになっていることが分かります。

$ docker service inspect redis --pretty

ID: 6ue7ncgimxwsnarvvdgw7431d
Name: redis
Mode: Replicated
Replicas: 3
Update status:
State: completed
Started: 2 minutes ago
Completed: about a minute ago
Message: update completed
Placement:
UpdateConfig:
Parallelism: 1
Delay: 10s
On failure: pause
ContainerSpec:
Image: redis:3.0.7
Resources:

サービスを削除しておきます。

$ docker service rm redis

redis
$ docker service ps redis
Error: No such service: redis

次にDrainを試します。ノードの状態をDrainにするとそのノードではコンテナが作られなくなります。

既に作られているコンテナは別のノードに移動します。

$ docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6

6w08p3j5ew7pg4nurc3ywdq2l

$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
d4z5lw1sn8uiz21m0s2btgvc5 redis.1 redis:3.0.6 manager Running Running 8 seconds ago
ad3nqvbu357xjcao1wwdow2kf redis.2 redis:3.0.6 worker2 Running Running 7 seconds ago
0yndsykpbfsu4iegpxfuu900q redis.3 redis:3.0.6 worker1 Running Running 8 seconds ago

worker1をDrainにします。

$ docker node update --availability drain worker1

worker1

ノードの状態を確認するとDrainになっているのが分かります。

$ docker node ls

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
as3dl417gpz9795aedxa970th worker2 Ready Active
asqs3rls6pc32izn74zkkiysd worker1 Ready Drain
djvtufr82caej8ebysdbsj0ov * manager Ready Active Leader

serviceの状態を確認するとworker1で動いていたコンテナはmanagerに移動しているのが分かります。

$ docker service ps redis

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
d4z5lw1sn8uiz21m0s2btgvc5 redis.1 redis:3.0.6 manager Running Running about a minute ago
ad3nqvbu357xjcao1wwdow2kf redis.2 redis:3.0.6 worker2 Running Running about a minute ago
d8aehr5dad3u61d77iiun8gyj redis.3 redis:3.0.6 manager Running Running 50 seconds ago
0yndsykpbfsu4iegpxfuu900q \_ redis.3 redis:3.0.6 worker1 Shutdown Shutdown 50 seconds ago

worker1をactiveに戻しておきます。

$ docker node update --availability active worker1

worker1

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
as3dl417gpz9795aedxa970th worker2 Ready Active
asqs3rls6pc32izn74zkkiysd worker1 Ready Active
djvtufr82caej8ebysdbsj0ov * manager Ready Active Leader

移動したコンテナは戻りませんが、次に作成する際等はworker1にも割り当てられます。

Drainは色々使い方があるようで、例えば、メンテナンスするときなどには当然活用できるでしょう。

また、managerにはコンテナを作りたくないといった場合は、managerをDrainにすれば実現できます(もちろんlabel等を使っても同じことはできますが)。

とりあえず一旦全ノード削除しておきます。

docker-machine rm manager

docker-machine rm worker1
docker-machine rm worker2


managerのフェールオーバ

次にmanagerのフェールオーバを試してみます。

コンセンサスにはRaftが使われているので、奇数のmanagerが推奨されています。

ということで、managerとworkerを3台ずつ作ってみます。下記は出力結果を省略しています。

# docker-machineでmanagerとworkerを3台ずつ作成

docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} manager1
docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} manager2
docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} manager3
docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker1
docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker2
docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker3

# manager1でswarmモードを初期化
eval $(docker-machine env manager1)
docker swarm init --advertise-addr 104.236.176.63

# manager2,3を既存のswarmにmanagerとして追加
eval $(docker-machine env manager2)
docker swarm join \
--token SWMTKN-1-3pxkaylj5uubcwiu3a3d7e3zuwqabdbl2y7tf26c1wbbw4xnvy-9ed3sgq2agihmq7aewbvoim4e \
104.236.176.63:2377
eval $(docker-machine env manager3)
docker swarm join \
--token SWMTKN-1-3pxkaylj5uubcwiu3a3d7e3zuwqabdbl2y7tf26c1wbbw4xnvy-9ed3sgq2agihmq7aewbvoim4e \
104.236.176.63:2377

# worker1,2,3を既存のswarmにworkerとして追加
eval $(docker-machine env worker1)
docker swarm join \
--token SWMTKN-1-3pxkaylj5uubcwiu3a3d7e3zuwqabdbl2y7tf26c1wbbw4xnvy-619h8ucg44larxtqszj9080gx \
104.236.176.63:2377
eval $(docker-machine env worker2)
docker swarm join \
--token SWMTKN-1-3pxkaylj5uubcwiu3a3d7e3zuwqabdbl2y7tf26c1wbbw4xnvy-619h8ucg44larxtqszj9080gx \
104.236.176.63:2377
eval $(docker-machine env worker3)
docker swarm join \
--token SWMTKN-1-3pxkaylj5uubcwiu3a3d7e3zuwqabdbl2y7tf26c1wbbw4xnvy-619h8ucg44larxtqszj9080gx \
104.236.176.63:2377

結果を確認しておきます。

$ eval $(docker-machine env manager1)

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
0eapj2cat7ih6973k9ysapwz2 worker2 Ready Active
0inl859a5zuul7peoyjfjx9x8 worker3 Ready Active
6hfv3zrwrd5doma7s6tc7hs61 * manager1 Ready Active Leader
6snxc51snhhjzsin7qg0egobx manager2 Ready Active Reachable
7xj8a2ufn63k38j9aynfzbyl8 manager3 Ready Active Reachable
918ny04ls768sl33rl5n02qal worker1 Ready Active

おもむろにLeaderのmanagerを落としてみます。

docker-machine rm manager1

リーダーが変わったことを確認します。

$ eval $(docker-machine env manager2)

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
0eapj2cat7ih6973k9ysapwz2 worker2 Ready Active
0inl859a5zuul7peoyjfjx9x8 worker3 Ready Active
6hfv3zrwrd5doma7s6tc7hs61 manager1 Down Active Unreachable
6snxc51snhhjzsin7qg0egobx * manager2 Ready Active Reachable
7xj8a2ufn63k38j9aynfzbyl8 manager3 Down Active Leader
918ny04ls768sl33rl5n02qal worker1 Down Active

managerは奇数推奨なのでこのような場合は一台追加するべきです。

managerの追加は先述のdocker swarm joinコマンドでもできますが、docker node promoteというコマンドを使うことでworkerをmanagerにpromoteすることができるようなので、こちらを試してみます。

$ docker node promote worker1

結果を確認しておきます。

$ docker node ls

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
0eapj2cat7ih6973k9ysapwz2 worker2 Ready Active
0inl859a5zuul7peoyjfjx9x8 worker3 Ready Active
6hfv3zrwrd5doma7s6tc7hs61 manager1 Down Active Unreachable
6snxc51snhhjzsin7qg0egobx * manager2 Ready Active Reachable
7xj8a2ufn63k38j9aynfzbyl8 manager3 Ready Active Leader
918ny04ls768sl33rl5n02qal worker1 Ready Active Reachable

逆にdemoteコマンドを使うとmanagerをworkerにdemoteすることもできます。

$ docker node demote manager3

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
0eapj2cat7ih6973k9ysapwz2 worker2 Ready Active
0inl859a5zuul7peoyjfjx9x8 worker3 Ready Active
6hfv3zrwrd5doma7s6tc7hs61 manager1 Down Active Unreachable
6snxc51snhhjzsin7qg0egobx * manager2 Ready Active Leader
7xj8a2ufn63k38j9aynfzbyl8 manager3 Ready Active
918ny04ls768sl33rl5n02qal worker1 Ready Active Reachable

ちなみにSTATUSの変化は1分くらいかけて、Unknown、Downと変わってからReadyに変わりました。

次のデモのために再び全滅させておきます。

docker-machine rm manager1

docker-machine rm manager2
docker-machine rm manager3
docker-machine rm worker1
docker-machine rm worker2
docker-machine rm worker3


Routing meshを試す

Routing meshはserviceを作った場合に、リクエストを受けたノード上で該当のサービスを実行するコンテナが動いていなくても、コンテナが動いているノードにrerouteしてくれるというものです。

今度は再びmanager1台、worker3台構成で試してみます。

実験用に--engine-labelでラベルを指定し、worker1と2がenv=production、3がenv-developmentとなるようにしています。

# docker-machineでノードを作成

docker-machine create -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} manager
docker-machine create --engine-label env=production -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker1
docker-machine create --engine-label env=production -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker2
docker-machine create --engine-label env=development -d digitalocean --digitalocean-image "ubuntu-16-04-x64" --digitalocean-region "sfo1" --digitalocean-size "512mb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} worker3

# swarmの初期化とworkderの追加
eval $(docker-machine env manager)
docker swarm init --advertise-addr 162.243.146.81
eval $(docker-machine env worker1)
docker swarm join \
--token SWMTKN-1-3vh5e65rcvv5vbx10o456ikl6mmab7v5pgpebrilpejictw1kh-c5ewusty0safq5764gvgvknwl \
162.243.146.81:2377
eval $(docker-machine env worker2)
docker swarm join \
--token SWMTKN-1-3vh5e65rcvv5vbx10o456ikl6mmab7v5pgpebrilpejictw1kh-c5ewusty0safq5764gvgvknwl \
162.243.146.81:2377
eval $(docker-machine env worker3)
docker swarm join \
--token SWMTKN-1-3vh5e65rcvv5vbx10o456ikl6mmab7v5pgpebrilpejictw1kh-c5ewusty0safq5764gvgvknwl \
162.243.146.81:2377

Redisのサービスをコンテナがmanagerで起動するように作成します。

docker service create \

--replicas 1 \
--name redis \
--update-delay 10s \
--publish 6379:6379 \
--constraint node.hostname==manager \
redis:latest

worker上でアプリを動かします。

使うアプリは以前書いた記事で使ったウンコードウンコテナを使います。

中身はREDISからアクセスするたびに変化するカウンターの値を取得するだけです。

docker service create \

--replicas 2 \
--name app \
--update-delay 10s \
--publish 8000:8000 \
--env REDIS_HOST=162.243.146.81 \
--constraint engine.labels.env==production \
daikikohara/app01:v6

しばらく時間がかかるので、docker service ps appで起動状態になるまでまちます。

# これだとPrepareだからまだ

$ docker service ps app
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7t31od5tkcey8cri9mbhp7elt app.1 daikikohara/app01:v6 worker2 Running Preparing 53 seconds ago
2s74twgjjxlrxlgz3v5zxy498 app.2 daikikohara/app01:v6 worker1 Running Preparing 53 seconds ago

# こうなればOK
$ docker service ps app
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7t31od5tkcey8cri9mbhp7elt app.1 daikikohara/app01:v6 worker2 Running Running 3 minutes ago
2s74twgjjxlrxlgz3v5zxy498 app.2 daikikohara/app01:v6 worker1 Running Running 3 minutes ago

なお、上記結果の通り、labelでenvをproductionにしたworkerでのみコンテナが動いていることが分かります。

各workerノードにcurlでアクセスしてカウンターの値が取れるか確認しておきます。

各ノードのIPは以下の通りです。

$ docker-machine ls

NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
manager * digitalocean Running tcp://162.243.146.81:2376 v1.12.0
worker1 - digitalocean Running tcp://107.170.250.177:2376 v1.12.0
worker2 - digitalocean Running tcp://107.170.233.85:2376 v1.12.0
worker3 - digitalocean Running tcp://104.131.132.105:2376 v1.12.0

コンテナが起動しているworker1,2にリクエストすれば当然値が取れます。

$ curl http://107.170.250.177:8000

You have visited this page 1 times!

$ curl http://107.170.233.85:8000
You have visited this page 2 times!

routing meshにより、コンテナが起動していないworker3でも値が取れます。

$ curl http://104.131.132.105:8000

You have visited this page 3 times!

ってか、worker3はdevelopmentというlabelを指定してたので取れないことを想定していたんですが、swarmクラスタ上のノードだと全てrouting meshが有効になっているようです。

これってlabelで指定したサービス以外だと取れないことを設定できた方が便利な気がするので、今後に期待したいと思います。(もしかして既に設定できるかな?)

ということで、ホントはproductionの1ノードのみにscaleさせて逆側のproductionのworkerでも取れることを確認したかったのですが、そもそも既に動作確認できてしまったので、これで終わりますw


HEALTHCHECK

DockerfileにHEALTHCECKという命令が追加されました。HEALTHCHECKを使うと独自のロジックでコンテナのヘルスチェックをできるようになります。

上のapp01というコンテナを以下のような内容のDockerfileに置き換えてv7タグでpublishしています。

FROM golang:1.6.3

ADD app /app
HEALTHCHECK --interval=10s --timeout=5s --retries=3 CMD curl http://localhost:8000 | grep "You have visited"
CMD /app

上記の場合CMDに指定したコマンドを10秒間隔で実行し、5秒以内に正常に結果が得られなかったケースが3回連続したらコンテナはunhealthyと見なされます。

ということで、まずはredisのコンテナを起動します。

docker service create \

--replicas 1 \
--name redis \
--update-delay 10s \
--publish 6379:6379 \
--constraint node.hostname==manager \
redis:latest

続いてappを起動します。

docker service create \

--replicas 2 \
--name app \
--update-delay 10s \
--publish 8000:8000 \
--env REDIS_HOST=162.243.146.81 \
--constraint engine.labels.env==production \
daikikohara/app01:v7

redisサービスを終了させます。

docker service rm redis

上記のHEALTHCHECKが失敗するので、しばらくしてから確認すると以下のように何度もコンテナを再起動しようとして失敗しているのが分かります。

$ docker service ps app

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7u1xdmznc4n1qmxn5m8noeu84 app.1 daikikohara/app01:v7 worker1 Ready Ready 3 seconds ago
82g81zthfgm0o4b8ylbegsvfr \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 4 seconds ago "task: non-zero exit (2)"
9wlenwhsht77zcavdpw39ju7m \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 10 seconds ago "task: non-zero exit (2)"
51zxip69n196202i0cqelurf5 \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 16 seconds ago "task: non-zero exit (2)"
as4vhy7zxh78wj30k3w2b0cdp \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 22 seconds ago "task: non-zero exit (2)"
2v1tmjx0qmh0x46pfvklns542 app.2 daikikohara/app01:v7 worker2 Running Starting less than a second ago
eqqdrefs7w63v239tr1gjy85g \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 5 seconds ago "task: non-zero exit (2)"
2r17smeo78j1lppbu9n1z5z9h \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 11 seconds ago "task: non-zero exit (2)"
5zkes80bq2wtp8h4b3d2qpora \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 16 seconds ago "task: non-zero exit (2)"
e4s1lrwc1ainf5jfzfq1iqmg4 \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 22 seconds ago "task: non-zero exit (2)"

redisを立ち上げ直してしばらくしてから確認すると2コンテナともRunning状態を維持できるようになります。

$ docker service ps app

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
d39j1zw2fs2d1bc4o5tzc5q7n app.1 daikikohara/app01:v7 worker1 Running Running 2 minutes ago
9u8nmhwwmkczxqg9pjpcug214 \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"
4yau7s92c0917penlazl5uuq0 \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"
581y6jezbpr6cxwyynnqqvw97 \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"
7u1xdmznc4n1qmxn5m8noeu84 \_ app.1 daikikohara/app01:v7 worker1 Shutdown Failed 3 minutes ago "task: non-zero exit (2)"
at0qqu7xhjz90ujmnmgminn00 app.2 daikikohara/app01:v7 worker2 Running Running 2 minutes ago
f0cq0x7ccq9d88dpspolx78db \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"
4qpmgm93g899xu9rgr8rrqq30 \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"
1ce8fu69ua6hnqnomho52vb1t \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"
a5r6fkpme7elaj0qw3kln5zo3 \_ app.2 daikikohara/app01:v7 worker2 Shutdown Failed 2 minutes ago "task: non-zero exit (2)"


globalモード

ここまではreplicated serviceという各ノード上に適宜分散配置されるコンテナを使ったサービスになりますが、globalモードを使うと必ず各ノードで1コンテナずつ動くサービスが作れます。

公式ドキュメント等ではノードのモニタリングやウイルススキャン等、必ず各ノードで1つ動いておくべきものを動かすことを想定しているようです。

docker service create \

--name redis \
--mode global \
--publish 6379:6379 \
redis:latest

$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
1fitx5g74ujssl9bjbhyz5nv3 redis redis:latest worker3 Running Preparing 7 seconds ago
1quo2c3c9fz3wll6cl57dao4b \_ redis redis:latest worker2 Running Preparing 7 seconds ago
5paactsnolafblrz0y6j8rhfs \_ redis redis:latest worker1 Running Preparing 7 seconds ago
coh5zcahl5jedozkqzgcx06g4 \_ redis redis:latest manager Running Running 6 seconds ago

ということで、各ノードで1コンテナずつ動いていることが確認できました。


その他気になった点


  • ノード間の通信がデフォルトでTLSになったらしいです。(参考)


  • pluginコマンドとかも気になるんですが、まだexperimentalな上にドキュメントがよく分からなかったので試してません。。。

以上、またなにかあれば追記・修正します。