ということで、タイトル通り、過去最大のupdateと言われているDocker1.12の気になる機能を試しました。
meetup等でDocker社の人の話を聞いた内容や公式ドキュメントベースで気になった箇所のみ試します。
ちなみに後方互換性は保たれているので、以下で出てくるswarm init等のコマンドを使わない限り今まで通り使えるそうです。
自分が気になったところを試しただけなので、網羅的な更新一覧および、内部の仕組みは公式ページなり、いつも訳して下さっている前佛さんの日本語訳を参考にしてください。
- GitHub上のリリース情報
- Docker Built-in Orchestration Ready for Production: Docker 1.12 Goes GA
- Docker 1.12: Now with Built-in Orchestration!
あとは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を使いたいと思います。
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コンテナずつ動いていることが確認できました。
その他気になった点
以上、またなにかあれば追記・修正します。