
アプリケーションをDockerコンテナとして、本番環境で稼働させるにはオーケストレーションツールは無くてはならないものです。今回は、Docker Swarmを使って、Dockerコンテナをオーケストレーションする方法を紹介します。
はじめに
Dockerコンテナを開発環境や実証実験で使う機会は圧倒的に増えてきました。そのおかげでDocker自体やDocker Composeを使いこなすエンジニアは増えました。次のステップとして、Dockerコンテナを本番環境に導入することを考えると思いますが、その場合はDockerコンテナのオーケストレーションを考える必要が出てきます。現状のDockerオーケストレーションツールのデファクトスターンダードはGoogle社のKubernetesですが、今回はDocker社がDockerネイティブとしてサポートしているSwarmを使う方法をDockerオーケストレーションの入門として紹介します。
Docker Machineとは?
Docker Machineとは、任意のホストの仮想環境上にDockerエンジンの実行環境を構築するプロビジョニングツールです。
例えば、個人の開発環境を考えると、Mac上でDockerコンテナを稼働させる場合、Docker for MacをインストールすることでDockerエンジンをローカルで実行し、そのDockerエンジン上でDockerコンテナを稼働させることになると思います。しかし、本番環境などMac以外でDockerコンテナを稼働させることを考えた場合はどうすればよいでしょうか?その答えとして、Dockerコンテナの実行環境であるDockerエンジンを持ち運び可能にすることで、好きなホスト上でDockerコンテナを実行可能にする仕組みがDocker Machineです。この仕組みにより、ドライバー(仮想環境の種類)を指定することで、VirtualBox上でもAWS上でもAzura上でも、好きなホストの仮想環境上でDockerエンジンを動かし、Dockerコンテナンを稼働させることができます。
Docker Swarmとは?
Docker Swarmとは、Dockerコンテナのオーケストレーションツールです。新しく入れるツールというのではなく、Dockerにネイティブで組み込まれており、Swarmモードをアクティブにすることで利用可能になります。
今回のメイントピックなので、細かい説明は抜きにして、次の章から手を動かしてい理解していきましょう。
Docker Swarmを使ってみよう!
概要
今回は、Swarm用のマネージャーノード1台、ワーカーノード2台の構成でDocker Machineを作り、Swarmのノード上にNginxのサービスをいくつか立ち上げてみましょう。
事前に、Swarmのノードの構成が書かれた公式ドキュメントや、Swarmのサービスの構成が書かれた公式ドキュメントあたりに目を通しておくと理解が深まります。
前提
以下がインストールされている必要があります。
- Docker for Mac
- VirtualBox
細かいバージョンは「環境」を参照してください。
Swarm用のマネージャーノードを作る
まずは、Docker Machineで「swarm-manager」という名前のノードを作り、Swarmモードを有効にします。Docker MachineのデフォルトのドライバーはVirtualBoxなので、ノードはVirtualBox上に作成されます。
$ docker-machine create swarm-manager
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager - virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
$ eval $(docker-machine env swarm-manager)
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager * virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
$ docker-machine ip swarm-manager
192.168.99.100
$ docker swarm init --advertise-addr 192.168.99.100
$ docker info | grep Swarm
Swarm: active
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
jm20ptzjqptaqop9e9g1frv58 * swarm-manager Ready Active Leader 18.06.1-ce
「swarm-manager」ノードのSwarmがアクティブになり、Leaderになっていることが確認できます。これでマネージャーノードは完成です。
Swarm用のワーカーノードを作る
次に、ワーカーノードを2台(「swarm-wocker1」と「swarm-wocker2」)を作成し、Swarmのオーバーレイ・ネットワーク(ingressネットワーク)に追加します。追加したノードはSwarm内でルーティング・メッシュにより、自動的にロードバランスされます。
先に「swarm-manager」ノード上でワーカーノードを追加するためのトークンを取得します。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
jm20ptzjqptaqop9e9g1frv58 * swarm-manager Ready Active Leader 18.06.1-ce
$ docker swarm join-token worker
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-398kt7tj5z33es0ek580gtz4r0d1xgm6yqqktczzzus1bxm9gy-3o2etc9uhs7pb96h67fnzqw73 192.168.99.100:2377
それから、ワーカーノードを作っていきます。
$ docker-machine create swarm-worker1
$ docker-machine create swarm-worker2
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager * virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
swarm-worker1 - virtualbox Running tcp://192.168.99.101:2376 v18.06.1-ce
swarm-worker2 - virtualbox Running tcp://192.168.99.102:2376 v18.06.1-ce
$ eval $(docker-machine env swarm-worker1)
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager - virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
swarm-worker1 * virtualbox Running tcp://192.168.99.101:2376 v18.06.1-ce
swarm-worker2 - virtualbox Running tcp://192.168.99.102:2376 v18.06.1-ce
$ docker swarm join --token SWMTKN-1-398kt7tj5z33es0ek580gtz4r0d1xgm6yqqktczzzus1bxm9gy-3o2etc9uhs7pb96h67fnzqw73 192.168.99.100:2377
This node joined a swarm as a worker.
$ eval $(docker-machine env swarm-worker2)
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager - virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
swarm-worker1 - virtualbox Running tcp://192.168.99.101:2376 v18.06.1-ce
swarm-worker2 * virtualbox Running tcp://192.168.99.102:2376 v18.06.1-ce
$ docker swarm join --token SWMTKN-1-398kt7tj5z33es0ek580gtz4r0d1xgm6yqqktczzzus1bxm9gy-3o2etc9uhs7pb96h67fnzqw73 192.168.99.100:2377
This node joined a swarm as a worker.
$ eval $(docker-machine env swarm-manager)
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager * virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
swarm-worker1 - virtualbox Running tcp://192.168.99.101:2376 v18.06.1-ce
swarm-worker2 - virtualbox Running tcp://192.168.99.102:2376 v18.06.1-ce
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
vp63ef6ywgyqykiplzn24o9nq * swarm-manager Ready Active Leader 18.06.1-ce
kf8fsltttorlbqips470qnlvj swarm-worker1 Ready Active 18.06.1-ce
9vgc77yekm2fj72oq5x96f1ok swarm-worker2 Ready Active 18.06.1-ce
これで、「swarm-manager」というマネージャーノード1台、「swarm-worker1」と「swarm-worker2」のワーカーノード2台の構築が完了しました。
Swarmビジュアライザーを追加する
それでは、ノード上にサービスを、、、と行きたいところですが、その前にSwarmの構成を可視化するツールであるSwarmビジュアライザーを導入してみましょう。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager * virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
swarm-worker1 - virtualbox Running tcp://192.168.99.101:2376 v18.06.1-ce
swarm-worker2 - virtualbox Running tcp://192.168.99.102:2376 v18.06.1-ce
$ docker service create --name=viz --publish=8080:8080/tcp --constraint=node.role==manager --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock dockersamples/visualizer
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76d49f568d84 dockersamples/visualizer:latest "npm start" About a minute ago Up About a minute (healthy) 8080/tcp viz.1.nab0yu9vfz6312v9b85grwhej
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
m9c4l9ggdhes viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp
$ docker-machine ip swarm-manager
192.168.99.100
それでは、「192.168.99.100:8080」にアクセスしてみましょう。
構築したSwarmの3台のノードと、マネージャーノード上にSwarmビジュアライザーが「viz」という名前のサービスとして起動していることが可視化されています。
ちなみに、今回は「viz」というサービスとして起動しましたが、Swarmのサービスに含めたくない場合は、以下のように通常のコンテナとして起動することも可能です。
$ docker container run -d --name=viz --publish=8080:8080/tcp --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock dockersamples/visualizer
この場合はSwarmビジュアライザーにも表示されません。
Swarmのノード上でサービスを作成する
それでは、Nginxのサービスを5つ作成してみましょう。(厳密にはSwarmではノード上の1つのアプリケーションを「タスク」と呼び、それをグループ化したものを「サービス」と呼んでいますが、この記事では便宜上、1つのアプリケーションを一般的な意味でサービスと表現しています。)
$ docker service create -d --name web --publish 8000:80 --replicas 5 nginx
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
m9c4l9ggdhes viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp
dq4pntmf9eej web replicated 5/5 nginx:latest *:8000->80/tcp
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
e8p6ojsguah7 web.1 nginx:latest swarm-worker1 Running Running 1 minutes ago
y9honj8v0rzj web.2 nginx:latest swarm-worker2 Running Running 1 minutes ago
sr6e97b32pc2 web.3 nginx:latest swarm-manager Running Running 2 minutes ago
5vaipy05i88i web.4 nginx:latest swarm-worker1 Running Running 1 minutes ago
i7innmnribly web.5 nginx:latest swarm-worker2 Running Running 1 minutes ago
Swarmビジュアライザーで確認してみましょう。
5つの「web」というサービスが各ノードに割り振られて作成され、稼働しています。
各ノードのIPを確認して、Nginxが各ノード上で動いているかも確認してみましょう。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
swarm-manager * virtualbox Running tcp://192.168.99.100:2376 v18.06.1-ce
swarm-worker1 - virtualbox Running tcp://192.168.99.101:2376 v18.06.1-ce
swarm-worker2 - virtualbox Running tcp://192.168.99.102:2376 v18.06.1-ce
$ docker-machine ip swarm-manager
192.168.99.100
$ docker-machine ip swarm-worker1
192.168.99.101
$ docker-machine ip swarm-worker2
192.168.99.102
「192.168.99.100:8000」にアクセスしてみましょう。
「192.168.99.101:8000」にアクセスしてみましょう。
「192.168.99.102:8000」にアクセスしてみましょう。
全てのノード上でNginxのサービスが稼働していることが確認できました。
サービスのスケールを変更する
docker service scaleコマンドにより、サービスの数を自由に変更できます。今回は、5つある「web」のサービスを1つにしてみましょう。
$ docker service scale web=1
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
m9c4l9ggdhes viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp
dq4pntmf9eej web replicated 1/1 nginx:latest *:8000->80/tcp
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
e8p6ojsguah7 web.1 nginx:latest swarm-worker1 Running Running 29 minutes ago
Swarmビジュアライザーで見てみましょう。
サービスが1つに変更されていることが確認できました。
この状態で、ブラウザで「192.168.99.100:8000」、「192.168.99.101:8000」、「192.168.99.102:8000」にアクセスすると、全てが同じサービスにルーティングされ、Nginxの画面が表示されます。ルーティング・メッシュが作成去れているからですね。
サービスを削除する
最後に、サービスを削除してみましょう。
$ docker service rm web
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
m9c4l9ggdhes viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp
Swarmビジュアライザーで確認します。
「web」のサービスはきれいに削除されています。
この状態で、ブラウザで「192.168.99.100:8000」、「192.168.99.101:8000」、「192.168.99.102:8000」にアクセスすると、当然「このサイトにアクセスできません」と表示されます。
これでSwarmによるDockerオーケストレーションの基本は完了です。
おまけ(AWSのEC2上でSwarmを実行する方法)
ここまでは、ローカル環境で実施してきましたが、一歩進めてAWSのEC2上で同じことを実行してみましょう。
AWSのEC2上にSwarmのノードを構築する
基本は同じで、Docker MachineのドライバーにAmazon EC2を指定する(–driver amazonec2)だけでOKです。注意点としては、マネージャーノードは「2377」のポートを開放する必要があります。また、今回はSwarmビジュアライザー用に「8080」ポート、Webサーバ用に「8000」ポートを開放します。
$ aws configure
$ docker-machine create --driver amazonec2 --amazonec2-open-port 2377 --amazonec2-open-port 8080 --amazonec2-open-port 8000 --amazonec2-region us-east-1 aws-swarm-manager1
$ docker-machine create --driver amazonec2 --amazonec2-open-port 8000 --amazonec2-region us-east-1 aws-swarm-worker1
$ docker-machine create --driver amazonec2 --amazonec2-open-port 8000 --amazonec2-region us-east-1 aws-swarm-worker2
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
aws-swarm-manager1 - amazonec2 Running tcp://52.90.91.140:2376 v18.06.1-ce
aws-swarm-worker1 * amazonec2 Running tcp://54.227.204.32:2376 v18.06.1-ce
aws-swarm-worker2 - amazonec2 Running tcp://54.172.255.110:2376 v18.06.1-ce
$ eval $(docker-machine env aws-swarm-manager1)
$ docker-machine ip aws-swarm-manager1
52.90.91.140
$ docker swarm init --advertise-addr 52.90.91.140
Swarm initialized: current node (q7igg1nnai34e41qrcaao8thq) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-1vsrzboersaqygif1lo58n00390bp6d6wnkoukn1q7ff47gsm4-23utao937z0gmrz7hpher10lw 52.90.91.140:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
$ eval $(docker-machine env aws-swarm-worker1)
$ docker swarm join --token SWMTKN-1-1vsrzboersaqygif1lo58n00390bp6d6wnkoukn1q7ff47gsm4-23utao937z0gmrz7hpher10lw 52.90.91.140:2377
This node joined a swarm as a worker.
$ eval $(docker-machine env aws-swarm-worker2)
$ docker swarm join --token SWMTKN-1-1vsrzboersaqygif1lo58n00390bp6d6wnkoukn1q7ff47gsm4-23utao937z0gmrz7hpher10lw 52.90.91.140:2377
This node joined a swarm as a worker.
$ eval $(docker-machine env aws-swarm-manager1)
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
aws-swarm-manager1 * amazonec2 Running tcp://52.90.91.140:2376 v18.06.1-ce
aws-swarm-worker1 - amazonec2 Running tcp://54.227.204.32:2376 v18.06.1-ce
aws-swarm-worker2 - amazonec2 Running tcp://54.172.255.110:2376 v18.06.1-ce
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
q7igg1nnai34e41qrcaao8thq * aws-swarm-manager1 Ready Active Leader 18.06.1-ce
28m2usguvsbp5720ny9xee1r7 aws-swarm-worker1 Ready Active 18.06.1-ce
qrn9hes6jkg52n7n38xsu35sf aws-swarm-worker2 Ready Active 18.06.1-ce
AWSコンソールからEC2インスタンスの状態を確認してみましょう。
マネージャーノード1台、ワーカーノード2台がEC2インスタンスとして作成されていますね。
続いて、Security Groupも確認してみましょう。
想定通り、「2377」、「8080」、「8000」のポートが開放されています。「2376」ポートはDocker Machineがデフォルトで使っているポートです。
Swarmビジュアライザーを追加する
先ほどと同じくSwarmビジュアライザーをサービスとして追加します。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
q7igg1nnai34e41qrcaao8thq * aws-swarm-manager1 Ready Active Leader 18.06.1-ce
28m2usguvsbp5720ny9xee1r7 aws-swarm-worker1 Ready Active 18.06.1-ce
qrn9hes6jkg52n7n38xsu35sf aws-swarm-worker2 Ready Active 18.06.1-ce
$ docker service create --name=viz --publish=8080:8080/tcp --constraint=node.role==manager --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock dockersamples/visualizer
aqp0ge6qhwirizc0cb9221gwd
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
$ docker-machine ip aws-swarm-manager1
52.90.91.140
「52.90.91.140:8080」にアクセスしましょう。
Swarmビジュアライザーが稼働していることが確認できました。
サービスを作成する
先ほどと同じく、Nginxのサービスを5つ作成してみましょう。
$ docker service create -d --name web --publish 8000:80 --replicas 5 nginx
pkbfqjik6c8kfquwsmjckesla
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
aqp0ge6qhwir viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp
vzhv0xxfat15 web replicated 5/5 nginx:latest *:8000->80/tcp
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
i4bdnxib2e3b web.1 nginx:latest aws-swarm-worker2 Running Running 1 minutes ago
o00x9iigopac web.2 nginx:latest aws-swarm-manager1 Running Running 1 minutes ago
gc6wo6rxtgep web.3 nginx:latest aws-swarm-worker1 Running Running 1 minutes ago
opi12tbgytk6 web.4 nginx:latest aws-swarm-worker2 Running Running 1 minutes ago
he0qy7w5a5d7 web.5 nginx:latest aws-swarm-worker1 Running Running 1 minutes ago
$ docker-machine ip aws-swarm-manager1
52.90.91.140
「52.90.91.140:8080」にアクセスしましょう。
サービスが想定どおりに稼働している事がわかります。
ブラウザからサービスを表示してみましょう。
$ docker-machine ip aws-swarm-manager1
52.90.91.140
$ docker-machine ip aws-swarm-worker1
54.227.204.32
$ docker-machine ip aws-swarm-worker2
54.172.255.110
「52.90.91.140:8000」にアクセスしましょう。
「54.227.204.32:8000」にアクセスしましょう。
「54.172.255.110:8000」にアクセスしましょう。
問題なく動いていますね。
クリーンアップ
最後の最後にサービスとAWSのEC2上のDocker Machineをきれいに削除して終わりにしましょう。
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
aqp0ge6qhwir viz replicated 1/1 dockersamples/visualizer:latest *:8080->8080/tcp
vzhv0xxfat15 web replicated 5/5 nginx:latest *:8000->80/tcp
$ docker service rm viz web
viz
web
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
q7igg1nnai34e41qrcaao8thq * aws-swarm-manager1 Ready Active Leader 18.06.1-ce
28m2usguvsbp5720ny9xee1r7 aws-swarm-worker1 Ready Active 18.06.1-ce
qrn9hes6jkg52n7n38xsu35sf aws-swarm-worker2 Ready Active 18.06.1-ce
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
aws-swarm-manager1 * amazonec2 Running tcp://52.90.91.140:2376 v18.06.1-ce
aws-swarm-worker1 - amazonec2 Running tcp://54.227.204.32:2376 v18.06.1-ce
aws-swarm-worker2 - amazonec2 Running tcp://54.172.255.110:2376 v18.06.1-ce
$ docker-machine rm aws-swarm-manager1 aws-swarm-worker1 aws-swarm-worker2
About to remove aws-swarm-manager1, aws-swarm-worker1, aws-swarm-worker2
WARNING: This action will delete both local reference and remote instance.
Are you sure? (y/n): y
Successfully removed aws-swarm-manager1
Successfully removed aws-swarm-worker1
Successfully removed aws-swarm-worker2
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
これでAWSのEC2上のインスタンスもきれいに削除されました。自動で作成されていたKey PairsやNetwork Interfacesも一緒に削除されますが、docker-machineという名前のSecurity Groupは残るので気をつけましょう。
最後に
いかがでしたか?これでDocker Swarmを使って、Dockerコンテナをオーケストレーションできるようになったことでしょう。それでは。
環境
- PC: macOS High Sierra 10.13.6
- Docker: 18.06.1-ce, build e68fc7a
- Docker Machine: 0.15.0, build b48dc28d
- VirtualBox: 5.2.18r124319
- AWS CLI: aws-cli/1.16.20 Python/3.7.0 Darwin/17.7.0 botocore/1.12.10