Docker Swarm 入門ハンズオン

# Docker Swarm について 
通常、Docker では、複数のホストにまたがってコンテナが存在する場合、docker コマンドを実行するたびに`-H` オプションを付加して接続先を切り替える必要が有りました。
結果として、複数のホスト上にコンテナが散財する場合、docker コマンドで透過的にコンテナを管理することが困難でした。

そういった問題はDocker Swarm を使うことで軽減することができます。
Docker Swarm は1 つ以上のDocker ホストを1 つのDocker ホスト(Docker Swarm manager) にpool することができるようになり、ユーザはそのDocker Swarm manager ホストに対してコマンドを発行することで、複数のDocker ノードをcluster として透過的に管理することができるようになります。
Docker Swarm は標準的なDocker API を提供しているので、Docker デーモンと既に通信しているツール類はSwarm を複数のホストに透過的に使用ために使うことができるようになります。

# Docker Swarm を使うための要件 
Docker Swarm はDocker のコンテナとして用意されているので、pull することですぐに使うことができます。
pull したあとはDocker Swarm manager の設定をし、Docker Swarm agent コンテナが起動している他のノードをDocker cluster の一員として追加し、Docker Swarm manager から一元的に操作することができるようになります。

# 今回の構成 


* 構成
<table><tbody>
  <tr>
    <th> OS</th>
    <th> IP アドレス</th>
    <th> ホスト名</th>
    <th> 備考</th>
  </tr>
  <tr>
    <td> Ubuntu 15.10</td>
    <td> 192.168.1.121</td>
    <td> swmgr01</td>
    <td> Swarm manager。また、Docker Swarm manager を操作するための管理端末としても使用</td>
  </tr>
  <tr>
    <td> Debian jessie</td>
    <td> 192.168.1.131</td>
    <td> swagt01</td>
    <td> Swarm agent 01</td>
  </tr>
  <tr>
    <td> Debian jessie</td>
    <td> 192.168.1.132</td>
    <td> swagt02</td>
    <td> Swarm agent 02</td>
  </tr>
  <tr>
    <td> Debian jessie</td>
    <td> 192.168.1.133</td>
    <td> swagt03</td>
    <td> Swarm agent 03</td>
  </tr>
</tbody></table>

![Docker_SwarmManager0000.png](https://qiita-image-store.s3.amazonaws.com/0/70152/4fcf2240-f13a-2ecc-bc80-eaa526d6325d.png)


# Docker Swarm のインストールと作成 
ここではUbuntu でDocker Swarm のインストールと作成方法について説明してきます。
Ubuntu のDocker Engine を使用してそれらの手順を見ていくことにします。
なお、ここではUbuntu にDocker Engine をインストールする手順については割愛します。

[Docker Engine をDocker リポジトリからインストールする(Ubuntu 15.04, 14.04 LTS)](http://qiita.com/TsutomuNakamura/items/4eb3ccf8393dcba25eff)

# discovery token の発行 
まずはDocker Swarm イメージを使用してdiscovery token を発行します。
そのために`docker run swarm create` コマンドを実行します。
これを実行することで、swarm コンテナ上で`swarm create` コマンドが実行され、discovery token が発行されます。


```text:DockerSwarmコンテナの作成とdoscoverytokenの発行(swmgr01)
$ docker run --rm swarm create
Unable to find image 'swarm:latest' locally
latest: Pulling from library/swarm
d681c900c6e3: Pull complete 
188de6f24f3f: Pull complete 
90b2ffb8d338: Pull complete 
237af4efea94: Pull complete 
3b3fc6f62107: Pull complete 
7e6c9135b308: Pull complete 
986340ab62f0: Pull complete 
a9975e2cc0a3: Pull complete 
Digest: sha256:c21fd414b0488637b1f05f13a59b032a3f9da5d818d31da1a4ca98a84c0c781b
Status: Downloaded newer image for swarm:latest
8f620653b5157592418a2da287dc722d
```


上記のコマンドの結果より、`8f620653b5157592418a2da287dc722d` のdiscovery token が発行されたました。
このdiscovery token はDocker Swarm エージェントを起動するときに使用するものとなるので、安全な場所に保管しておくようにしてください。

# swarm ノードの作成(swagt01-03) 
今回用意したDocker ノード(swagt01, swagt02, swagt03)をDocker Swarm agent として起動します。
Docker Swarm agent は、それぞれのモニタ情報を登録し、discovery token のバックエンドで更新をかけます。
本手順ではDocker Hub ベースのtoken ディスカバリサービスを使います。

Docker Swarm agent ノードにログインし、`/lib/systemd/system` ファイルの`ExecStart` の値を次のように変更し、daemon reload を実施してdocker daemon を起動します。

```text:/lib/systemd/system/docker.serviceatswagt01-03
ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
```



```text:Dockerdaemonの起動
$ systemctl daemon-reload
$ systemctl restart docker
```


## Docker Swarm agent をdiscovery サービスに加入させる(swagt01-03) 
各Docker Swarm agent をdiscovery サービスに加入させます。
それぞれのDocker Swarm agent のとSwarm Manager が接続可能な状態で、次のコマンドを実行し、discovery サービス上の`node_ip`と`cluster_id` を更新します。


```text:コマンド書式
$ docker run -d swarm join --addr=<node_ip>:2375 token://<cluster_id>
```


実際のコマンド例としては次のようになります。
ここではコンテナを作成すると同時に`--name` オプションも使用してコンテナ名を指定するようにしています。


```text:swagt01
$ docker run --name swagt01 -d swarm join --addr=192.168.1.131:2375 token://8f620653b5157592418a2da287dc722d
Unable to find image 'swarm:latest' locally
latest: Pulling from library/swarm
d681c900c6e3: Pull complete 
188de6f24f3f: Pull complete 
90b2ffb8d338: Pull complete 
237af4efea94: Pull complete 
3b3fc6f62107: Pull complete 
7e6c9135b308: Pull complete 
986340ab62f0: Pull complete 
a9975e2cc0a3: Pull complete 
Digest: sha256:c21fd414b0488637b1f05f13a59b032a3f9da5d818d31da1a4ca98a84c0c781b
Status: Downloaded newer image for swarm:latest
9b73b74bafda6703c0b5dc328f0501422a056079c923a37dbb7d36d89fbff77f
```



```text:swagt02
$ docker run --name swagt02 -d swarm join --addr=192.168.1.132:2375 token://8f620653b5157592418a2da287dc722d
......
996de4e921d8902720c8abf3e62da460698b1cda36c73d4c385ded2acb87375e
```



```text:swagt03
$ docker run --name swagt03 -d swarm join --addr=192.168.1.133:2375 token://8f620653b5157592418a2da287dc722d
......
bbf0a5bf6e097e5085118c07a4b5087d7808320b30e8a16f4517bf1b73200848
```


# Docker Swarm manager の設定 
Docker Swarm agent をコントロールするためのDocker Swarm manager の設定を行っていきます。

## Docker Swarm manager の起動 
Docker Swarm manager となるマシン上でDocker Swarm manager を起動します。


```text:SwarmManager起動コマンド書式
$ docker run -d -p <manager_port>:2375 swarm manage token://<cluster_id>
```



```text:swmgr01
$ docker run --name swmgr01 -d -p 2375:2375 swarm manage token://8f620653b5157592418a2da287dc722d
750562b8fc7fd12ba5e103add01bb12e1ee92a4073958b4f396c82e503492057
```


## Docker Swarm manager の設定確認 
Docker Swarm manager が起動したら`docker info` コマンドで設定を確認してみましょう。
コマンドを実行するときは`-H` オプションを指定して接続先マネージャのノードを指定します。


```text:dockerinfo書式
$ docker -H tcp://<manager_ip>:2375 info
```



```text:swmgr01
$ docker -H tcp://192.168.1.121:2375 info
Containers: 0
Images: 0
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 0
CPUs: 0
Total Memory: 0 B
Name: 750562b8fc7f
```


上記のようにDocker manager の情報が表示されれば成功です。


### DOCKER_TLS_VERIFY フラグについて 
もしTLS エラーが出力された場合は`DOCKER_TLS_VERIFY` 環境変数をunset します。


```text:DOCKER_TLS_VERIFYをunsetする
$ unset DOCKER_TLS_VERIFY
```


# docker コマンドを使用してクラスタへ接続する 
Docker Swarm cluster へ接続するには、通常のDocker へ接続する時と同様にdocker コマンドを指定することができます。
しかし、docker コマンドを実行するときの接続先`-H` はDocker Swarm manager のIP とport を指定する用にしてください。


```text:dockerコマンドでclusterの状態を確認する
$ docker -H tcp://<ip:port> info
$ docker -H tcp://<ip:port> run ...
$ docker -H tcp://<ip:port> ps
$ docker -H tcp://<ip:port> logs ...
```


# cluster に参加しているノードをリスト表示する 
`swarm list` コマンドを実行することでcluster に参加している起動ノードを一覧表示することができます。


```text:cluster上で起動しているノードを一覧表示する
$ docker run --rm swarm list token://<cluster_id>
```



```text:(anynode)
$ docker run --rm swarm list token://8f620653b5157592418a2da287dc722d
192.168.1.133:2375
192.168.1.132:2375
192.168.1.131:2375
```


以上でDocker cluster 環境の構築は完了です。次はDocker Swarm cluster 上にコンテナを作成していきます。

# Docker Swarm 上にコンテナを作成する 
Swarm クラスタが正常に構築されていることを確認するために、試しにDebian コンテナを起動してみましょう。
Swarm クラスタ上にコンテナを作成する場合は`-H` オプションでDocker Swarm manager のノードを指定します。
今回、Docker Swarm manager は`192.168.1.121:2375` になるので、コマンドは次のようになります。


```text:swmgt01
swmgt01~$ docker -H tcp://192.168.1.121:2375 run --name test_busybox -ti busybox /bin/sh

## ...暫く時間がかかります...

/ # id
uid#0(root) gid=0(root) groups10(wheel)
/ # hostname
19486390f2fe
/ #
/ # exit
```

上記のようにコンテナが作成されれば成功です。

## コンテナの所在の確認 
先ほど作成したコンテナがどのDocker Swarm ノードに作成されたか確認してみましょう。
こちらも先ほどと同様に`-H` オプションでDocker Swarm manager の`IP:port` を指定して`docker ps -a` コマンドを実行します。


```text:swmgr01
swmgt01~$ docker -H tcp://192.168.1.121:2375 ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
19486390f2fe        busybox             "/bin/sh"                4 minutes ago       Exited (0) 3 minutes ago                       swagt03/test_busybox
c4366b2190eb        swarm               "/swarm join --addr=1"   47 minutes ago      Up 47 minutes              2375/tcp            swagt03/swagt03
f3c3d542c908        swarm               "/swarm join --addr=1"   47 minutes ago      Up 47 minutes              2375/tcp            swagt02/swagt02
65b3c986da3b        swarm               "/swarm join --addr=1"   48 minutes ago      Up 48 minutes              2375/tcp            swagt01/swagt01
```


上記の出力結果を確認すると、swagt03 ノード上にbusybox コンテナが作成されたことがわかります。
このコンテナが本当に`swagt03` に作成されているか確認するために、`swagt03` ノードにログインし、`docker ps -a` コマンドを実行してみましょう。


```text:swagt03
swagt03~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
19486390f2fe        busybox             "/bin/sh"                11 minutes ago      Exited (0) 10 minutes ago                       test_busybox
c4366b2190eb        swarm               "/swarm join --addr=1"   54 minutes ago      Up 54 minutes               2375/tcp            swagt03
```


すると、上記のようにDocker Swarm manager で見た時と同じコンテナが`swagt03` 上に作成されていることが確認できると思います。

では、さらにコンテナを作成していくとどのようになっていくかを確認してみましょう。
新しくDocker Swarm cluster 上にdebian のコンテナを作成し、`docker -H tcp://IP:port ps -a` コマンドでどこのノードにコンテナが作成されるか確認してみましょう。


```text:swmgr01
swmgr01~$ docker -H tcp://192.168.1.121:2375 run --name test_debian -ti debian /bin/bash
root@0a232282bff7:/# 
root@0a232282bff7:/# exit
exit

swmgr01~$ docker -H tcp://192.168.1.121:2375 ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
0a232282bff7        debian              "/bin/bash"              53 seconds ago      Exited (0) 38 seconds ago                       swagt02/test_debian
19486390f2fe        busybox             "/bin/sh"                21 minutes ago      Exited (0) 20 minutes ago                       swagt03/test_busybox
c4366b2190eb        swarm               "/swarm join --addr=1"   About an hour ago   Up About an hour            2375/tcp            swagt03/swagt03
f3c3d542c908        swarm               "/swarm join --addr=1"   About an hour ago   Up About an hour            2375/tcp            swagt02/swagt02
65b3c986da3b        swarm               "/swarm join --addr=1"   About an hour ago   Up About an hour            2375/tcp            swagt01/swagt01
```


すると次は`swagt02` 上に新しくコンテナが作成されていることが確認できます。
このようにDocker Swarm cluster 上ではcluster に参加しているノードに対して、あたかも1 つのノード上のDocker daemon を操作しているかのような感覚で、透過的に複数ノードにまたがるコンテナを管理することができるようになります。

## Docker Swarm cluster 上のコンテナの開始、停止、削除 
Docker Swarm cluster 上のコンテナの開始、停止、削除については、コンテナ作成の時と同様にDocker Swarm manager 経由となるようにコマンドを実行して管理することができます。


```text:開始
$ docker -H tcp://<Swarm manager IP>:<port> start <Container>
```



```text:停止
$ docker -H tcp://<Swarm manager IP>:<port> stop <Container>
```



```text:削除
$ docker -H tcp://<Swarm manager IP>:<port> rm <Container>
```


また、その他のオプションについても通常のDocker コマンドと同じものが扱えるようになっています。
例えばコンテナのコマンド実行をする`docker exec`、イメージの削除を行う`docker rmi`、Docker コンテナの状態確認を行う`docker ps` 等も同様に`-H` オプションでDocker Swarm manager を指定して実行することができます。

# 参考 
<dl>
  <dt> Docker Swarm overview</dt>
  <dd> https://docs.docker.com/swarm/</dd>
</dl>

<dl>
  <dt> Install and Create a Docker Swarm</dt>
  <dd> https://docs.docker.com/swarm/install-w-machine/</dd>
</dl>

<dl>
  <dt> Docker Tutorial : Getting Started With Docker Swarm</dt>
  <dd> http://devopscube.com/docker-tutorial-getting-started-with-docker-swarm/</dd>
</dl>

<dl>
  <dt> Create a swarm for development</dt>
  <dd> https://docs.docker.com/swarm/install-manual/</dd>
</dl>

<dl>
  <dt> DOCKER SWARM WITH TLS AUTHENTICATION</dt>
  <dd> http://www.blackfinsecurity.com/docker-swarm-with-tls-authentication/</dd>
</dl>

<dl>
  <dt> Protect the Docker daemon socket</dt>
  <dd> https://docs.docker.com/engine/articles/https/</dd>
</dl>

<dl>
  <dt> Docker Swarmで複数Dockerホストからクラスタを作る</dt>
  <dd> http://blog.takanabe.tokyo/2015/11/23/1565/</dd>
</dl>