Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

概要

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

さらに詳しく

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away