Docker 1.12RC の swarm mode チュートリアル

  • 91
    Like
  • 0
    Comment

概要

Docker Engine 1.12 RC1 (リリース候補版)から Docker Swarm の機能が swarm モード として統合されました。このチュートリアルは3台のサーバを使い、swarm(クラスタ)の形成と、その上で Nginx サービスとタスク(コンテナ)を起動、スケールアップ、スケールダウン、削除を試します。

所要時間は15分程度です。

注意事項

Docker Engine 1.12 RC2 現在の情報に基づいています。将来的な仕様変更や、バグを含む可能性があります。そのため、用途は新しいモードの検証/体験用とお考えいただければと思います。

環境の準備

新しい3台のサーバを準備します。RC 版の Docker Engine は既存の環境と共存できません。そのため、既にお使いの環境ではなく、新しい検証用環境を作ることを強くお薦めします。

3台のサーバは、次の役割を持ちます。 manager (マネージャ)はクラスタのサービスの受け入れと、タスクの割り振りを行います。 worker (ワーカ)はマネージャからの命令を受け取り、タスク(としてのコンテナ)を実行します。

名前 役割
node-01 manager, worker
node-02 worker
node-03 worker

今回は manager が 1 台かつ 3 台ともコンテナを実行する worker です。設定により、3 台とも manager と worker を兼ねられますし、manager 専用にすることも可能です。

なお、環境は、ローカルの仮想化環境やリモートのどちらでも構いません。私は DigitalOcean 上の以下の環境で動作確認を行いました。

  • 512MB / 1 CPU / 20 GB SSD の最小環境を三台
  • Ubuntu 16.04 x64, CentOS 7.2 x64
  • Private Networking を有効化(クラスタ用通信のため)

ファイアウォールなど、パケットがフィルタされている環境では、次の接続を許可する必要があります。

  • 2377(TCP) クラスタ管理の通信用
  • 7496(TCP,UDP) ノード間の通信用
  • 4789(TCP,UDP) オーバレイ・ネットワークの通信

RC 版の Docker Engine のセットアップ

サーバにログイン後、以下のコマンドを実行すると、自動的に RC 版に対応したリポジトリとパッケージをセットアップします。

# curl -fsSL https://test.docker.com/ | sh

CentOS 7.2 では Docker が自動起動しないため、次のコマンドで起動します。

# systemctl enable docker
# systemctl start docker

動作確認は docker version を実行し、クライアントとサーバ両方の情報を表示するのを確認します。

root@node-01:~# docker version
Client:
 Version:      1.12.0-rc2
 API version:  1.24
 Go version:   go1.6.2
 Git commit:   906eacd-unsupported
 Built:        Fri Jun 17 21:21:56 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.0-rc2
 API version:  1.24
 Go version:   go1.6.2
 Git commit:   906eacd-unsupported
 Built:        Fri Jun 17 21:21:56 2016
 OS/Arch:      linux/amd64

swarm クラスタの初期化

Docker Engine の swarm mode を使うには、まず docker swarm init コマンドを使い、クラスタの初期化を行います。このコマンドを実行したサーバが manager となります。かつ、一番始めに実行したサーバが manager の Leader(リーダ)となります。

ここでは node-01 にログインし、次の watch コマンドを実行します。

watch -n 1 'echo "$ docker node ls"; docker node ls; echo; echo "$ docker service ls"; docker service ls; echo ; echo "$ docker service tasks mynginx"; docker service tasks mynginx'

これは、毎秒画面上に次の情報を表示します。

  • swarm クラスタのノード一覧( docker node ls
  • サービス一覧( docker service ls
  • mynginx サービスのタスク一覧( docker service tasks mynginx

こうすると、以降のチュートリアルでノードの状態やサービスの状態を、リアルタイムで把握できます。

次に、クラスタを初期化(managerの起動)します。

root@node-01:~# docker swarm init --listen-addr <node-01のIPアドレス>:2377
Swarm initialized: current node (3cmtfzqo9vqysc9htzm1adepf) is now a manager.

画面上の docker node ls は、次のように1台のノードがクラスタに存在しているのが分かります。

$ docker node ls
ID                           NAME     MEMBERSHIP  STATUS  AVAILABILITY  MANAGER STATUS
3cmtfzqo9vqysc9htzm1adepf *  node-01  Accepted    Ready   Active        Leader

また、 docker info コマンドからも、クラスタの情報を確認できます。

$ docker info
(省略)
Swarm: active
 NodeID: 3cmtfzqo9vqysc9htzm1adepf
 IsManager: Yes
 Managers: 1
 Nodes: 1

ここでは node-01 自身がマネージャ( IsManager: Yes )であり、現時点ではマネージャが1つ、ノードが1つと分かります。

次に、 node-02 node-03 をクラスタに追加します。

root@node-02:~# docker swarm join <node-01のIPアドレス>:2377
This node joined a Swarm as a worker.

root@node-03:~# docker swarm join <node-01のIPアドレス>:2377
This node joined a Swarm as a worker.

画面上にはワーカとして追加したと表示されます。 docker node ls の情報を見ると、次のように3つのノードが swarm クラスタに参加しているのが分かります。

$ docker node ls
ID                           NAME     MEMBERSHIP  STATUS  AVAILABILITY  MANAGER STATUS
3cmtfzqo9vqysc9htzm1adepf *  node-01  Accepted    Ready   Active        Leader
6xzla3yzemtnx0iotqxvad3qn    node-02  Accepted    Ready   Active
8tn1a8u5qeh2ohcq3l9uxo2y0    node-03  Accepted    Ready   Active

以上で swarm モードを使ってサービスを実行する準備が整いました。

サービスの作成

swarm モード上でコンテナを実行するには docker service create コマンドを使います。このコマンドを実行できるのはマネージャ・ノードの node-01 上でのみです。

$ docker service create --replicas <タスク数> \
    --name <サービス名> \
    -p <公開ポート>:<コンテナのポート> \
    <イメージ名>:<タグ>

ここでは Nginx コンテナでコンテナ ID を表示する zembutsu/docker-sample-nginx:1.0 イメージを使います。

$ docker service create --replicas 1 --name mynginx -p 80:80 zembutsu/docker-sample-nginx:1.0

次のようにサービスが追加され、タスクとしてのコンテナが実行されるのが分かります。

$ docker service ls
ID            NAME     REPLICAS  IMAGE                             COMMAND
dc52legcse3q  mynginx  1/1       zembutsu/docker-sample-nginx:1.0

$ docker service tasks mynginx
ID                         NAME       SERVICE  IMAGE                             LAST STATE
          DESIRED STATE  NODE
12kmzbiirvsq8rli1gqjhbgjz  mynginx.1  mynginx  zembutsu/docker-sample-nginx:1.0  Running 10
 seconds  Running        node-01

タスクはコンテナの実行単位であり、注目すべきは LAST STATE (現在の状態)と DESIRED STATE (期待状態)です。コマンド時刻時、 --replicas 1 を指定したのは、このサービスは指定したイメージを常時1つ実行するという意味があります。しかし、実際にはイメージのダウンロードや起動に時間がかかるため、今どのような状況にあるかが LAST STATE に表示されます( Preparing -> Starting --> Running と遷移)。

また、 docker servie lsREPLICAS も同様です。タスク数が 0/1 (現在の数/期待数)から 1/1 に変わります。

この例では node-01 でタスク(としてのコンテナ)を実行しました。このコンテナの情報は docker ps コマンドでも確認できます。

root@node-01:~# docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED              STATUS              PORTS               NAMES
6095b5af72ba        zembutsu/docker-sample-nginx:1.0   "nginx -g 'daemon off"   About a minute ago   Up About a minute   80/tcp, 443/tcp     mynginx.1.12kmzbiirvsq8rli1gqjhbgjz

あとは curl やブラウザでこのサーバにアクセスします。実行すると、画面上にコンテナ ID を表示します。

$ curl http://<host_ip>
<html>
<body>
        <h1>Host: 6095b5af72ba</h1>
</body>
</html>

サービスのスケールアップ・スケールダウン

サービスの状態を変更するには docker service update コマンドを使います。ここでは mynginx サービスの数を3つに増やします。

root@node-01:~# docker service update --replicas 3 mynginx

コマンドを実行して暫くすると、タスクが3つに増えるのが確認できます。

$ docker service ls
ID            NAME     REPLICAS  IMAGE                             COMMAND
dc52legcse3q  mynginx  3/3       zembutsu/docker-sample-nginx:1.0

$ docker service tasks mynginx
ID                         NAME       SERVICE  IMAGE                             LAST STATE
          DESIRED STATE  NODE
12kmzbiirvsq8rli1gqjhbgjz  mynginx.1  mynginx  zembutsu/docker-sample-nginx:1.0  Running 5
minutes   Running        node-01
3nyxsldx8wciwvu5r0o5nachl  mynginx.2  mynginx  zembutsu/docker-sample-nginx:1.0  Running 25
 seconds  Running        node-03
1miyrnvmg5i3czmq65sio6ped  mynginx.3  mynginx  zembutsu/docker-sample-nginx:1.0  Running 25
 seconds  Running        node-02

この例では Preparing (準備中)に時間がかかりますが、各ノード上に Docker イメージをダウンロードしているからです。イメージのダウンロード後は迅速にコンテナを開始できるようになるため、開始までのタイムラグを短縮したい場合は、あらかじめ各ノード上にイメージをダウンロード( docker pull )しておくのがおすすめです。

また、swarm モードはデフォルトで spread(スプレッド;拡散の意味)ストラテジが適用されるため、各コンテナは全てのノードで均等に起動しようと(実行中コンテナの数が釣り合うように)します。

この状態で、再びサーバ側のホストに curl でアクセスすると、コンテナIDが毎回切り替わります。各ノード上のコンテナは ingress という名前のオーバレイ・ネットワークでつながっています。そして、サービスに対するアクセスは、各タスク(コンテナ)に対して自動的に負荷分散します。

curl やブラウザの接続先を node-01 だけでなく、 node-02 node-03 で実行しても、負荷分散されるのを確認します。

自動復旧

swarm モードのサービスは、常に期待状態(desire state)を維持し続けます。そのため、あるノードで障害が起これば、自動的に別ノードで追加タスクを実行しなおす仕組みが働きます。

ここでは node-03 上の Docker Engine を停止します。

root@node-03:~# systemctl stop docker
Warning: Stopping docker.service, but it can still be activated by:
  docker.socket

暫く待つと、 docker node lsnode-03 の状態が Down になります。

$ docker node ls
ID                           NAME     MEMBERSHIP  STATUS  AVAILABILITY  MANAGER STATUS
3cmtfzqo9vqysc9htzm1adepf *  node-01  Accepted    Ready   Active        Leader
6xzla3yzemtnx0iotqxvad3qn    node-02  Accepted    Ready   Active
8tn1a8u5qeh2ohcq3l9uxo2y0    node-03  Accepted    Down    Active

そして、その瞬間、別のノードでタスクが再開されるのが分かります。

$ docker service tasks mynginx
ID                         NAME       SERVICE  IMAGE                             LAST STATE
          DESIRED STATE  NODE
12kmzbiirvsq8rli1gqjhbgjz  mynginx.1  mynginx  zembutsu/docker-sample-nginx:1.0  Running 6
minutes   Running        node-01
68vay29xunr8cawwyuhoza2lm  mynginx.2  mynginx  zembutsu/docker-sample-nginx:1.0  Accepted 4
 seconds  Accepted       node-02
1miyrnvmg5i3czmq65sio6ped  mynginx.3  mynginx  zembutsu/docker-sample-nginx:1.0  Running 2
minutes   Running        node-02

swarm クラスタのノードは常にマネージャが監視していますので、 node-03 の Docker Engine を再開したら、自動的にクラスタに復旧します。

root@node-03:~# systemctl start docker

コマンドを実行すると、再び node-03Active になります。

$ docker node ls
ID                           NAME     MEMBERSHIP  STATUS  AVAILABILITY  MANAGER STATUS
3cmtfzqo9vqysc9htzm1adepf *  node-01  Accepted    Ready   Active        Leader
6xzla3yzemtnx0iotqxvad3qn    node-02  Accepted    Ready   Active
8tn1a8u5qeh2ohcq3l9uxo2y0    node-03  Accepted    Ready   Active

ローリング・アップデート

docker service update はタスク数の変更だけでなく、実行中のイメージの差し替えも可能です。具体的には起動中のコンテナを停止し、新しいイメージのダウンロードと起動を自動的に行います。

先ほどの mynginx サービスが使うイメージのタグを latest に切り替えます。

$ docker service update \
    --update-delay 5s \
    --update-parallelism 1 \
    --image zembutsu/docker-sample-nginx:latest 
    mynginx
  • --update-delay ノードごとの更新タイミングの遅延指定
  • --update-arallelism 並列に処理するノード数

暫く待つと、自動的にタグが latest に切り替わります。

$ docker service ls
ID            NAME     REPLICAS  IMAGE                                COMMAND
3y37oegkuv4l  mynginx  3/3       zembutsu/docker-sample-nginx:latest

$ docker service tasks mynginx
ID                         NAME       SERVICE  IMAGE                                LAST STATE          DESIRED STATE  NODE
0803qlg3o9cxmu2h5tp1od51t  mynginx.1  mynginx  zembutsu/docker-sample-nginx:latest  Running 11 seconds  Running        node-03
3tsojfojtzngpip1qbct64q8b  mynginx.2  mynginx  zembutsu/docker-sample-nginx:latest  Running 29 seconds  Running        node-01
8f2ch2bbuegbakzjegi8fp1gy  mynginx.3  mynginx  zembutsu/docker-sample-nginx:latest  Running 20 seconds  Running        node-03

curl やブラウザで確認すると、新しく Version: 1.1 の文字列が入っているのが分かります。

$ curl http://139.59.243.63
<html>
<body>
        <h1>Host: 87f7fec795da</h1>
        Version: 1.1
</body>
</html>

サービスの削除

docker service rm コマンドでサービスを削除します。

root@node-01:~# docker service rm mynginx
mynginx

$ docker node ls
ID                           NAME     MEMBERSHIP  STATUS  AVAILABILITY  MANAGER STATUS
3cmtfzqo9vqysc9htzm1adepf *  node-01  Accepted    Ready   Active        Leader
6xzla3yzemtnx0iotqxvad3qn    node-02  Accepted    Ready   Active
8tn1a8u5qeh2ohcq3l9uxo2y0    node-03  Accepted    Ready   Active

$ docker service ls
ID  NAME  REPLICAS  IMAGE  COMMAND

$ docker service tasks mynginx
Error: No such service: mynginx

あとは、任意のイメージ実行などをお試しください。おつかれさまでした。

おまけ:global モード

デフォルトではタスクはノードに分散されますが、global モードを指定すると、全ノード上でコンテナを均等に起動できます。ただし、スケールアップやスケールダウンはできません。

実行するには、 service createservice update--mode オプションを使用します。

例:

docker service create --name mynginx -p 80:80 --mode global zembutsu/docker-sample-nginx
du6211e72ml4g3f744a389ui4

結果:

$ docker service ls
ID            NAME     REPLICAS  IMAGE                         COMMAND
du6211e72ml4  mynginx  global    zembutsu/docker-sample-nginx

$ docker service tasks mynginx
ID                         NAME     SERVICE  IMAGE                         LAST STATE         DESIRED STATE  NODE
a8lh89jjgf5icezfrgaduxwyk  mynginx  mynginx  zembutsu/docker-sample-nginx  Running 6 seconds  Running        node-03
3o29jqb02owmftfjb9hl4464n  mynginx  mynginx  zembutsu/docker-sample-nginx  Running 6 seconds  Running        node-02
9j3h6mx1mqa3j9v076aa7g4ip  mynginx  mynginx  zembutsu/docker-sample-nginx  Running 6 seconds  Running        node-01

さらに詳しく