誰?
- @zembutsu a.k.a Masahito Zembutsu
- さくらインターネット株式会社 技術本部 (@zembutsu_works 仕事用)
- Docker Authorized Trainer
- HashiCorp や Docker のドキュメント翻訳や技術検証
- https://pocketstudio.net
- http://docs.docker.jp
- 過去の発表スライド
- http://www.slideshare.net/zembutsu
Topics
- ハンズオン概要
- swarm モードの基本的概念
- 手順
概要と目的
Docker 1.12 から組み込まれた swarm モードを試します。
- 3台のノードでクラスタを構築します
- クラスタ上で、Nginx サービス(コンテナ)を起動
- スケールアップ・ダウンや、ルーティング・メッシュ、ローリング・アップデート、自動復旧までの流れをコマンドを実行しながら理解
swarm mode
ハンズオン
注意事項
Docker Engine 1.12 (GA) 現在の情報に基づいています。バージョンが変わった場合、コマンド体系や挙動が変わる場合がありますので、ご注意願います。
1. 環境構築編
1.1 概要
1.1.1 準備する環境と役割
3台のノード(インスタンス/仮想サーバ)を準備します。それぞれ異なる役割があります。
manager (マネージャ)はクラスタのサービスの受け入れと、タスクの割り振りを行います。 worker (ワーカ)はマネージャからの命令を受け取り、タスク(としてのコンテナ)を実行します。
名前 | 役割 |
---|---|
node1 |
manager, worker |
node2 |
worker |
node3 |
worker |
便宜上、それぞれ node1
node2
node3
と呼びます。
今回は manager が 1 台です。また、 3 台ともコンテナを実行する worker の役割です。設定により、3 台とも manager と worker を兼ねられますし、どれかをmanager 専用にすることも可能です。
1.1.2 ハンズオン環境
- t2.nano のインスタンス x 3
- 東京リージョン
- ubuntu 16.04 イメージ
- 各インスタンスにパブリック IP を割り当て
セキュリティグループで、次の接続を許可する必要があります。
-
SSH 22(TCP)
SSH ログイン用 -
HTTP80(TCP)
動作確認用 -
2377(TCP)
クラスタ管理の通信用 -
7496(TCP,UDP)
ノード間の通信用 -
4789(TCP,UDP)
オーバレイ・ネットワークの通信
1.2. 環境の準備
1.2.1. インスタンスの準備
- ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20160721 (ami-23b54e42) をクリック
- ステップ2:
t2.nano
を選択 - ステップ3:インスタンス数の詳細
- インスタンス数
3
- 自動割り当てパブリック IP
有効化
- インスタンス数
- ステップ6:セキュリティグループの設定
- セキュリティグループの割り当て:
新しいセキュリティグループを作成する
docker-swarm
- SSH TCP 22
マイIP
- HTTP TCP 80
任意の場所
- カスタム TCP ルール
2377
- カスタム TCP/UDP ルール
4789
- カスタム TCP/UDP ルール
7946
- 作成
1.2.3. ログイン
各サーバに ubuntu
ユーザでログインします。
ssh ubuntu@<ip>
or
ssh -l ubuntu <ip>
1.3. Docker 1.12 のインストール
以下のコマンドを実行すると、ディストリビューションに対応したリポジトリとパッケージをセットアップします。
curl -sSL https://get.docker.com/ | sh
sudo usermod -aG docker ubuntu
sudo docker
を実行しなくても、 docker
コマンドを有効にする設定をしました。ログアウト再ログインすると有効になります。
1.4 動作確認
docker ps
と docker version
コマンドを実行し、どちらもエラーが出ないことを確認します。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker version
Client:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 22:11:10 2016
OS/Arch: linux/amd64
Server:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 22:11:10 2016
OS/Arch: linux/amd64
正常であれば、サーバの情報も表示します。
2. クラスタ構築編
Docker の swarm (クラスタ)を構築し、nginx サービスを起動します。ここでは zembutsu/docker-sample-nginx イメージを使います(Dockerfile, source repo)。
-
nginx:latest
イメージがベース - コンテナ ID を表示する index.html
- SSI を有効化する Nginx 設定ファイル(default.conf)
準備
これまでクラスタ構築用の環境を準備してきました。コンソール画面(ターミナル)を4つ開き、各サーバにログインします。node1(manager)
は2つログインしておきます。
2.1. swarm クラスタの構築
node1(manager)
で、次のコマンドを実行します。ハンズオン中は起動したままにします。
watch -n 1 'echo "$ docker node ls"; docker node ls; echo; echo "$ docker service ls"; docker service ls; echo ; echo "$ docker service ps mynginx"; docker service ps mynginx'
これは watch
コマンドで、以下のコマンドを毎秒実行します。
-
docker node ls
… swarm クラスタ上のノード一覧と、状態を表示 -
docker service ls
… クラスタ上のサービス一覧を表示 -
docker service ps mynginx
…mynginx
サービスのタスク(コンテナ)一覧を表示
実行時はまだ swarm を構成していないため、次のようにエラーメッセージが画面に表示されます。
$ docker node ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swa
rm join" to connect this node to swarm and try again.
$ docker service ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swa
rm join" to connect this node to swarm and try again.
$ docker service ps mynginx
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swa
rm join" to connect this node to swarm and try again.
2.1.1. クラスタの初期化
node1(manager)
でコマンド docker swarm init --listen-addr <プライベートIP>:2377
を実行します。しばらく待つと、次のような画面が表示されますので、 To add a worker to ....
の docker swarm join
コマンドをエディタ等にコピーします。
docker swarm init --listen-addr 10.0.0.11:2377
Swarm initialized: current node (931rg7ls3uqvj4kzzp7tdjmp9) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-5rhptp943t9khjc4mvuez2pq7n3q39fny5r7ambgxgnzr36v4o-7pl78zmpe7uue8fnyt3sqdywo \
10.0.0.11:2377
To add a manager to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-5rhptp943t9khjc4mvuez2pq7n3q39fny5r7ambgxgnzr36v4o-3hcqutifxpnv5wr15p0ychv5g \
10.0.0.11:2377
正常に認識されると、ノード一覧は次のような画面になります。1台のノードが MANAGER
として Active
(有効)になっているのが分かります。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
931rg7ls3uqvj4kzzp7tdjmp9 * ip-10-0-0-11 Ready Active Leader
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
$ docker service ps mynginx
Error: No such service: mynginx
docker info
コマンドでもクラスタの情報を確認できます。
$ docker info
(省略)
Swarm: active
NodeID: 931rg7ls3uqvj4kzzp7tdjmp9
IsManager: Yes
Managers: 1
Nodes: 1
ここでは node1
自身がマネージャ( IsManager: Yes )であり、現時点ではマネージャが1つ、ノードが1つと分かります。特に指定しなければ、
次に、 node2
node3
をクラスタに追加します。
2.1.2. ノードの追加①
node2(worker)
をクラスタに追加します。 node2
上で直前に控えた swarm join
コマンドを実行します。※皆さんの環境によってトークンが異なるため、このまま貼り付けても実行できません。
docker swarm join \
--token SWMTKN-1-5rhptp943t9khjc4mvuez2pq7n3q39fny5r7ambgxgnzr36v4o-7pl78zmpe7uue8fnyt3sqdywo \
10.0.0.11:2377
正常に認識されると、ノード一覧は次のような画面になります。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
931rg7ls3uqvj4kzzp7tdjmp9 * ip-10-0-0-11 Ready Active Leader
cjofpj3ga0n32elf99gxs16ha ip-10-0-0-13 Ready Active
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
$ docker service ps mynginx
Error: No such service: mynginx
2.1.3. ノードの追加②
node3(worker)
をクラスタに追加します。 node3
で控えておいた swarm join
コマンドを実行します。
docker swarm join \
--token SWMTKN-1-5rhptp943t9khjc4mvuez2pq7n3q39fny5r7ambgxgnzr36v4o-7pl78zmpe7uue8fnyt3sqdywo \
10.0.0.11:2377
正常に認識されると、ノード一覧に3つのノードが表示されます。
これで今回の環境が整いました。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
39h0ngc66hwydtviaietjmapc ip-10-0-0-12 Ready Active
931rg7ls3uqvj4kzzp7tdjmp9 * ip-10-0-0-11 Ready Active Leader
cjofpj3ga0n32elf99gxs16ha ip-10-0-0-13 Ready Active
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
$ docker service ps mynginx
Error: No such service: mynginx
2.2. サービスの作成と変更
2.2.1. サービスの作成
swarm モード上でコンテナを実行するには docker service create
コマンドを使います。このコマンドを実行できるのはマネージャ・ノードの node1
上のみです。
$ docker service create --replicas <タスク数> \
--name <サービス名> \
-p <公開ポート>:<コンテナのポート> \
<イメージ名>:<タグ>
ここでは Nginx コンテナでコンテナ ID を表示する zembutsu/docker-sample-nginx:1.0 イメージを使います。
Nginx イメージを起動するため node1(manager)
で次の docker service create
コマンドを実行します。
docker service create --replicas 1 --name mynginx -p 80:80 zembutsu/docker-sample-nginx:1.0
- サービスを作成する
docker service create
はマネージャ上でのみ実行可能 -
--replicas 1
は、起動するタスクの期待状態(desired state)を1
に指定 -
--name mynginx
はサービス名の定義 -
-p 80:80
はパブリック・ネットワークのポート80
をコンテナの80
にマッピング -
zembutsu/docker-sample-nginx:1.0
は起動するイメージとタグ
次のようにサービスが追加され、タスクとしてのコンテナが実行されるのが分かります。
ID NAME REPLICAS IMAGE COMMAND
d4832nzhk6ht mynginx 1/1 zembutsu/docker-sample-nginx:1.0
$ docker service ps mynginx
ID NAME IMAGE NODE DESIRED STATE
CURRENT STATE ERROR
eo0nxwwje5nx5jynfv9vssv1f mynginx.1 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-11 Running
Running 2 minutes ago
タスクはコンテナの実行単位であり、注目すべきは CURRENT STATE
(現在の状態)と DESIRED STATE
(期待状態)です。コマンド時刻時、 --replicas 1
を指定したのは、このサービスは指定したイメージを常時1つ実行するという意味があります。しかし、実際にはイメージのダウンロードや起動に時間がかかるため、今どのような状況にあるかが CURRENT STATE
に表示されます( Preparing
-> Starting
--> Running
と遷移)。
また、 docker servie ls
の REPLICAS
も同様です。タスク数が 0/1
(現在の数/期待数)から 1/1
に変わります。
2.2.2. コンテナの確認
この例ではホスト ip-10-0-0-11
(node1
) でタスク(コンテナ)を実行しています。node1
で docker ps
を実行すると、コンテナが実行中なのが分かります。
ubuntu@ip-10-0-0-11:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e9c2ab0f4782 zembutsu/docker-sample-nginx:1.0 "nginx -g 'daemon off" 8 minutes ago Up 8 minutes 80/tcp, 443/tcp mynginx.1.eo0nxwwje5nx5jynfv9vssv1f
2.2.3. ルーティング・メッシュの確認
この状態で、ブラウザあるいはから node1 (manager)
の **パブリック IP ** にアクセスします。正常に応答があれば、次のようにコンテナ ID の情報が確認できます。
ubuntu@ip-10-0-0-11:~$ curl http://54.199.232.181
<html>
<body>
<h1>Host: e9c2ab0f4782</h1>
</body>
</html>
同様に
-
node2 (worker)
のパブリック IP -
node3 (worker)
のパブリック IP
でもアクセスを試み、同じコンテナ ID の情報が表示されることを確認します。
sawrm クラスタ上のどのパブリック IP にアクセスしても、ルーティング・メッシュにより、自動的にタスク(コンテナ)を実行しているノード(この例では node1
)に通信が経路付けされます。
2.2.4. サービスの変更
サービスの状態を変更するには docker service update
コマンドを使います。
実行中の nginx コンテナの数を 3
に増やし、サービスを分散します。 サービスの状態を更新するには docker service update --replicas 3 mynginx
を実行します。
$ docker service update --replicas 3 mynginx
mynginx
コマンドを実行してしばらくすると、タスクが3つに増えるのが確認できます。
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
d4832nzhk6ht mynginx 3/3 zembutsu/docker-sample-nginx:1.0
$ docker service ps mynginx
ID NAME IMAGE NODE DESIRED STATE
CURRENT STATE ERROR
eo0nxwwje5nx5jynfv9vssv1f mynginx.1 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-11 Running
Running 16 minutes ago
2v1scy4uojwnn3qd6tmtdkpp1 mynginx.2 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-12 Running
Running 22 seconds ago
8kxqhzytt54pn2c3uktt6jmrx mynginx.3 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-13 Running
Running 2 seconds ago
この例では Preparing
(準備中)に時間がかかりますが、各ノード上に Docker イメージをダウンロードしているからです。イメージのダウンロード後は迅速にコンテナを開始できるようになるため、開始までのタイムラグを短縮したい場合は、あらかじめ各ノード上にイメージをダウンロード( docker pull
)しておくのがおすすめです。
また、swarm モードはデフォルトで spread(スプレッド;拡散の意味)ストラテジが適用されるため、各コンテナは全てのノードで均等に起動しようと(実行中コンテナの数が釣り合うように)します。
2.2.5. 負荷分散(ingress loadbalancing)の再確認
この状態で、再びサーバ側のホストに curl
またはブラウザでアクセスすると、コンテナIDが毎回切り替わります。各ノード上のコンテナは ingress という名前のオーバレイ・ネットワークでつながっています。そして、サービスに対するアクセスは、各タスク(コンテナ)に対して自動的に負荷分散します。
curl やブラウザの接続先を node1
だけでなく、 node2
や node-03
で実行しても、負荷分散されるのを確認します。
$ curl http://54.238.132.234
<html>
<body>
<h1>Host: 76998bac246c</h1>
</body>
</html>
$ curl http://54.238.132.234
<html>
<body>
<h1>Host: bba7788e2a0e</h1>
</body>
</html>
$ curl http://54.238.132.234
<html>
<body>
<h1>Host: e9c2ab0f4782</h1>
</body>
</html>
2.3. ローリング・アップデート
docker service update
はタスク数の変更だけでなく、実行中のイメージの差し替えも可能です。具体的には起動中のコンテナを停止し、新しいイメージのダウンロードと起動を自動的に行います。
先ほどの mynginx
サービスが使うイメージのタグを 1.0
から latest
に切り替えます。
$ docker service update \
--update-delay 5s \
--update-parallelism 1 \
--image zembutsu/docker-sample-nginx:latest \
mynginx
-
--update-delay
ノードごとの更新タイミングの遅延指定 -
--update-arallelism
並列に処理するノード数
暫く待つと、順番にタグ 1.0
のコンテナが停止し、自動的にタグ latest
のイメージに切り替わります。
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
d4832nzhk6ht mynginx 3/3 zembutsu/docker-sample-nginx:latest
$ docker service ps mynginx
ID NAME IMAGE NODE DESIRED
STATE CURRENT STATE ERROR
6x7my3c1q7w3msgq7u67bv6kx mynginx.1 zembutsu/docker-sample-nginx:latest ip-10-0-0-12 Running
Running 27 seconds ago
eo0nxwwje5nx5jynfv9vssv1f \_ mynginx.1 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-11 Shutdow
n Shutdown 29 seconds ago
29sccuc76n5lxos9wek8vqcpj mynginx.2 zembutsu/docker-sample-nginx:latest ip-10-0-0-13 Running
Running 44 seconds ago
2v1scy4uojwnn3qd6tmtdkpp1 \_ mynginx.2 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-12 Shutdow
n Shutdown 47 seconds ago
0avnz6ghafe34uae2zwwoesgo mynginx.3 zembutsu/docker-sample-nginx:latest ip-10-0-0-12 Running
Running 36 seconds ago
8kxqhzytt54pn2c3uktt6jmrx \_ mynginx.3 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-13 Shutdow
n Shutdown 38 seconds ago
curl
やブラウザで確認すると、表示結果には新しく Version: 1.1
の文字列が入っているのが分かります。
2.4. 障害自動復旧
swarm モードのサービスは、常に期待状態(desire state)を維持し続けます。そのため、あるノードで障害が起これば、自動的に別ノードで追加タスクを実行しなおす仕組みが働きます。
ここでは node3
上の Docker Engine を停止します。
ubuntu@ip-10-0-0-13:~$ sudo systemctl stop docker
```
----
しばらく待つと、自動的に ``node3`` の状態が停止 ``Down`` となります。
```
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
39h0ngc66hwydtviaietjmapc ip-10-0-0-12 Ready Active
931rg7ls3uqvj4kzzp7tdjmp9 * ip-10-0-0-11 Ready Active Leader
cjofpj3ga0n32elf99gxs16ha ip-10-0-0-13 Down Active
```
----
``REPLICAS`` が一時的に ``2/3`` になりますが、自動的に別ノードでタスク(コンテナ)が実行されるため、最終的には ``3/3`` に戻ります。
```
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
d4832nzhk6ht mynginx 3/3 zembutsu/docker-sample-nginx:latest
$ docker service ps mynginx
ID NAME IMAGE NODE DESIRED
STATE CURRENT STATE ERROR
6x7my3c1q7w3msgq7u67bv6kx mynginx.1 zembutsu/docker-sample-nginx:latest ip-10-0-0-12 Running
Running 3 minutes ago
eo0nxwwje5nx5jynfv9vssv1f \_ mynginx.1 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-11 Shutdow
n Shutdown 3 minutes ago
9rs1pjqmeru0s84f0nsdy1ha1 mynginx.2 zembutsu/docker-sample-nginx:latest ip-10-0-0-11 Running
Running about a minute ago
29sccuc76n5lxos9wek8vqcpj \_ mynginx.2 zembutsu/docker-sample-nginx:latest ip-10-0-0-13 Shutdow
n Running 3 minutes ago
2v1scy4uojwnn3qd6tmtdkpp1 \_ mynginx.2 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-12 Shutdow
n Shutdown 3 minutes ago
0avnz6ghafe34uae2zwwoesgo mynginx.3 zembutsu/docker-sample-nginx:latest ip-10-0-0-12 Running
Running 3 minutes ago
8kxqhzytt54pn2c3uktt6jmrx \_ mynginx.3 zembutsu/docker-sample-nginx:1.0 ip-10-0-0-13 Shutdow
n Shutdown 3 minutes ago
```
----
ノードに復旧させるには ``sudo systemctl start docker`` を実行します。
----
## 2.5. サービスの削除
サービスを削除するには ``docker service rm <サービス名>`` を実行します。ここでは ``mynginx`` サービスを削除します。
```
ubuntu@ip-10-0-0-11:~$ docker service rm mynginx
mynginx
```
----
サービス一覧からも、消えているのが分かります。
```
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
$ docker service ps mynginx
Error: No such service: mynginx
```
----
# 3. クラスタの離脱と削除
## 3.1. クラスタから離脱
クラスタからノードを自動削除するには、ノード上で ``docker swarm leave`` コマンドを実行します。 ワーカの ``node2`` と ``node3`` 上でコマンドを実行します。
```bash
$ docker swarm leave
Node left the swarm.
```
これで ``node2`` と ``node3`` 上の Docker エンジンは swarm モードではなくなりました
----
マネージャの ``node1`` には次のノード情報が残っています。
```
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
39h0ngc66hwydtviaietjmapc ip-10-0-0-12 Down Active
931rg7ls3uqvj4kzzp7tdjmp9 * ip-10-0-0-11 Ready Active Leader
cjofpj3ga0n32elf99gxs16ha ip-10-0-0-13 Down Active
```
----
この状態では管理情報が ``manager`` 上に残っています。最終的に情報を削除するには、 ``manager`` 上で ``docker node rm <ノードID>`` コマンドを実行します。
```
ubuntu@ip-10-0-0-11:~$ docker node rm 39h0ngc66hwydtviaietjmapc
39h0ngc66hwydtviaietjmapc
ubuntu@ip-10-0-0-11:~$ docker node rm cjofpj3ga0n32elf99gxs16ha
cjofpj3ga0n32elf99gxs16ha
```
----
## 3.2. クラスタの削除
最後に残った ``node1`` のマネージャ情報を削除するには ``docker swarm leave --force`` コマンドを実行します。
```
$ docker swarm leave --force
Node left the swarm.
```
----
これですべてのクラスタが解放されました。
```
$ docker node ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swa
rm join" to connect this node to swarm and try again.
```
----
# 4. 最後に
* インスタンス環境の削除をお願いいたします。
おつかれさまでした^^
----
## さらに詳しく
* 【参考訳】Docker 1.12 が一般利用版(GA)に · Pocketstudio Technology Log
* https://pocketstudio.net/2016/07/30/docker-1-12-goes-ga-translate/
* Swarm モード概要 — Docker-docs-ja 1.12.RC ドキュメント
* http://docs.docker.jp/engine/swarm/index.html
* Docker 1.12: swarm モードと Ingress Load Balancing 概要 · Pocketstudio Technology Log
* https://pocketstudio.net/2016/06/23/docker-1-12-swarm-mode-and-ingress-load-balancing/
* Docker 1.12 & Swarm Mode Introduction ~ Docker の新しい技術と swarm モードの紹介
* http://www.slideshare.net/zembutsu/docker-112-rc-introduction-to-swarm-mode