Docker machineを使ってSwarmクラスタを組む

#はじめに

docker-machineはインストール済みであるものとします。
nginxのコンテナを3つ起動して、SWARMクラスタを組んでみます。

#環境

- MacBookPro
- DockerforMac
- Catalina
- VirtualBox

#docker machineを3台用意する

ノードの名前は適当に下記の通り

1. mgr
1. wkr1
1. wkr2

```
% docker-machine create mgr
Running pre-create checks...

...略

% docker-machine create wkr1
Running pre-create checks...
Creating machine...

...略

% docker-machine create wkr2
Running pre-create checks...
Creating machine...

...略
```

#docker-machineが作成されたことを確認

```
% docker-machine ls
NAME   ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER      ERRORS
mgr    -        virtualbox   Running   tcp://192.168.99.102:2376           v19.03.12   
wkr1   -        virtualbox   Running   tcp://192.168.99.103:2376           v19.03.12   
wkr2   -        virtualbox   Running   tcp://192.168.99.104:2376           v19.03.12   
```

#mgrに接続する

docker-machine env で表示される環境変数をevalでまとめて設定することで、指定のマシンの操作が出来ます。

```
% docker-machine env mgr
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.102:2376"
export DOCKER_CERT_PATH="/Users/hogehoge/.docker/machine/machines/mgr"
export DOCKER_MACHINE_NAME="mgr"
# Run this command to configure your shell: 
# eval $(docker-machine env mgr)

% eval $(docker-machine env mgr)
```

#docker info でSWARMのステータスを確認

Swarm: inactive となっています。
これはまだDocker EngineがSWARMモードで動作していないことを表しています。

```
% docker info    
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
  scan: Docker Scan (Docker Inc., v0.5.0)

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.12
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 4.19.130-boot2docker
 Operating System: Boot2Docker 19.03.12 (TCL 10.1)
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 985.4MiB
 Name: mgr
 ID: MWAH:X47G:L6A3:7MDH:PX5H:QHVD:2AXC:Q5QQ:RKBO:O7SX:ZXD5:AOOA
 Docker Root Dir: /mnt/sda1/var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
  provider=virtualbox
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine
```

#mgrのipアドレスを確認

```
% docker-machine ip mgr
192.168.99.102
```

このマネージャーノードのIPアドレスは、他のノードと通信ができる必要があります。
また、SWARMでは下記のポートが他のノード向けに公開されている必要があります。

1. クラスタを管理する通信用：2377/tcp
1. ノード間の通信用：7946/tcp&udp
1. オーバーレイNW用：4789/udp

**※今回のように、ローカル環境のコンテナ間はBridgeネットワークに繋がっているため、設定不要で疎通が取れますが、クラウド環境で動かす場合は、通常設定が必要になります。**

#SWARMの初期化

docker initを実行するとSWARMに組み込むためのコマンドが表示されます。
docker initを実行したノードはマネージャー扱いになります。

--advertise-addr は他のノードと通信可能なIPアドレスを指定します。
実行結果にある docker swarm join --token 〜 をワーカーノードで実行するとSWARMクラスタにワーカーとして組み込む事が出来ます。
※このコマンドは後で再確認出来ます。

```
% docker swarm init --advertise-addr 192.168.99.102
Swarm initialized: current node (87ww9en27g72r8l7p56h0qyiu) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0jy1ja0jmkd8lmlc1huiq945lfapvc18eaq5hn5b51dd5z5tt0-362kwpyykdyzh85cfy0blc5xd 192.168.99.102:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
```

docker info を見てみると Swarm: active となりました。
Docker Engine がSWARMモードになりました。

```
% docker info 
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Build with BuildKit (Docker Inc., v0.5.1-docker)
  scan: Docker Scan (Docker Inc., v0.5.0)

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.12
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: active
  NodeID: 87ww9en27g72r8l7p56h0qyiu
  Is Manager: true
  ClusterID: o8jtts7o9gueglwch8f9f0t02
  Managers: 1
  Nodes: 1
  Default Address Pool: 10.0.0.0/8  
  SubnetSize: 24
  Data Path Port: 4789
  Orchestration:
   Task History Retention Limit: 5
  Raft:
   Snapshot Interval: 10000
   Number of Old Snapshots to Retain: 0
   Heartbeat Tick: 1
   Election Tick: 10
  Dispatcher:
   Heartbeat Period: 5 seconds
  CA Configuration:
   Expiry Duration: 3 months
   Force Rotate: 0
  Autolock Managers: false
  Root Rotation In Progress: false
  Node Address: 192.168.99.102
  Manager Addresses:
   192.168.99.102:2377
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 4.19.130-boot2docker
 Operating System: Boot2Docker 19.03.12 (TCL 10.1)
 OSType: linux
 Architecture: x86_64
 CPUs: 1
 Total Memory: 985.4MiB
 Name: mgr
 ID: MWAH:X47G:L6A3:7MDH:PX5H:QHVD:2AXC:Q5QQ:RKBO:O7SX:ZXD5:AOOA
 Docker Root Dir: /mnt/sda1/var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
  provider=virtualbox
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine
```

#マネージャーノードの確認

docker node ls コマンドを実行すると MANAGER STATUS が表示されます。
Leaderと記載されたノードがマネージャーノードです。

AVAILABILITYがACTIVEなのは、コンテナの実行が可能であることを示します。
マネージャーノードはワーカーも兼任しています。

このコマンドは管理用ノードであるマネージャーノードでのみ実行出来ます。

```
% docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
87ww9en27g72r8l7p56h0qyiu *   mgr        Ready     Active         Leader           19.03.12
```

#SWARMクラスタにworkerを追加する為のコマンド

先程docker swarm initを実行した際にも表示されていましたが、docker swarm join-token 〜 を実行する事でSWARMクラスタにノードを追加することが出来ます。

実行するコマンドを再確認する場合は、下記のコマンドを実行します。

```
% docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0jy1ja0jmkd8lmlc1huiq945lfapvc18eaq5hn5b51dd5z5tt0-362kwpyykdyzh85cfy0blc5xd 192.168.99.102:2377

```

ちなみにManagerを追加する為のコマンドの確認方法は下記のとおりです。

```
% docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0jy1ja0jmkd8lmlc1huiq945lfapvc18eaq5hn5b51dd5z5tt0-dxcqpz6t2izo0its451p8jmyz 192.168.99.102:2377

```

#mgrノードの接続を解除

```
% docker-machine env -u    
unset DOCKER_TLS_VERIFY
unset DOCKER_HOST
unset DOCKER_CERT_PATH
unset DOCKER_MACHINE_NAME
# Run this command to configure your shell: 
# eval $(docker-machine env -u)
% eval $(docker-machine env -u)
```

#wkr1ノードに接続を切り替える

```
% docker-machine env wkr1      
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.103:2376"
export DOCKER_CERT_PATH="/Users/hogehoge/.docker/machine/machines/wkr1"
export DOCKER_MACHINE_NAME="wkr1"
# Run this command to configure your shell: 
# eval $(docker-machine env wkr1)
```

#workerを追加する為のコマンドを実行する

```
% docker swarm join --token SWMTKN-1-0jy1ja0jmkd8lmlc1huiq945lfapvc18eaq5hn5b51dd5z5tt0-362kwpyykdyzh85cfy0blc5xd 192.168.99.102:2377
This node joined a swarm as a worker.
```

#wkr2ノードに接続を切り替える

```
% eval $(docker-machine env -u)  
% eval $(docker-machine env wkr2)
```

#workerを追加する為のコマンドを実行する

```
% docker swarm join --token SWMTKN-1-0jy1ja0jmkd8lmlc1huiq945lfapvc18eaq5hn5b51dd5z5tt0-362kwpyykdyzh85cfy0blc5xd 192.168.99.102:2377
This node joined a swarm as a worker.
```

#mgrに接続を切り替える

```
% eval $(docker-machine env -u)  
% eval $(docker-machine env mgr)

```

#workerノードが追加されたことを確認する

```
% docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
87ww9en27g72r8l7p56h0qyiu *   mgr        Ready     Active         Leader           19.03.12
tpr985lvu13s2fe7qe61iq2vi     wkr1       Ready     Active                          19.03.12
ubjoxhyu42s3aztaiuf8hs2vj     wkr2       Ready     Active                          19.03.12
```

#VisualizerでSWARMクラスタの状態をGUIで確認する

docker.sockとはDockerのソケットのパスです。

>標準では、unis:///var/run/docker.sock をリッスンし、ローカルの root ユーザのみ接続できます。これを 0.0.0.0:2375 や特定のホスト IP を指定することで、誰でもアクセス可能にできましたが、推奨されていません。理由は、デーモンが稼働しているホスト上の root アクセスを誰もが簡単に得られるためです。

出典： https://docs.docker.jp/engine/userguide/basics.html

```
% docker run -d --name=viz --publish=8080:8080/tcp \
--mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
dockersamples/visualizer
Unable to find image 'dockersamples/visualizer:latest' locally
latest: Pulling from dockersamples/visualizer
cd784148e348: Pull complete 
f6268ae5d1d7: Pull complete 
97eb9028b14b: Pull complete 
9975a7a2a3d1: Pull complete 
ba903e5e6801: Pull complete 
7f034edb1086: Pull complete 
cd5dbf77b483: Pull complete 
5e7311667ddb: Pull complete 
687c1072bfcb: Pull complete 
aa18e5d3472c: Pull complete 
a3da1957bd6b: Pull complete 
e42dbf1c67c4: Pull complete 
5a18b01011d2: Pull complete 
Digest: sha256:54d65cbcbff52ee7d789cd285fbe68f07a46e3419c8fcded437af4c616915c85
Status: Downloaded newer image for dockersamples/visualizer:latest
550b7657788c48807ed1e85a2f58c4a92bd339ad6f7a885cabeb14454fffd525
```

#IPアドレスの再確認

```
% docker-machine ip mgr
192.168.99.102
```

#ブラウザで確認する

mgtノードのIPでポートを8080に指定しブラウザで表示すると下図のような表示になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391107/b09bc298-9bb2-878d-e9e5-90eb06a655c0.png)


#クラスタにタスクを追加する

docker service コマンドでは、どのイメージからいくつコンテナを作成するか定義します。
-replicas で指定した数のタスクが作成されます。

作成されたタスクはマネージャーノードによって割り振られ、各ノードによってコンテナが実行されます。
今回はnginxのタスクを3つ指定します。

※マネージャーからタスクの割当を行う機能のことをスケジューリングサービスという
※通常1つのタスクにつき1つのコンテナが起動される

```
% docker service create -d --name nginx --replicas 3 --publish 8000:80 nginx
6xi76akiz8mvyave5b2ckc38z
```

#各ノードの状態を確認する

3つのコンテナが実行されていることが確認出来ます。
DESIRED STATEはわかりにくいですが、こうなると望ましいステータスという意味のようです。

```
% docker service ps nginx                                                   
ID             NAME      IMAGE          NODE      DESIRED STATE   CURRENT STATE            ERROR     PORTS
izptgb043w68   nginx.1   nginx:latest   wkr1      Running         Running 12 seconds ago             
fo0tq8betk8d   nginx.2   nginx:latest   wkr2      Running         Running 12 seconds ago             
z5enotrna7fd   nginx.3   nginx:latest   mgr       Running         Running 5 seconds ago
```

#SWARMクラスタ内のサービスの一覧を確認する

docker service ls を実行するとnginxのタスクが3つ実行されているのがわかります。

```
% docker service ls
ID             NAME      MODE         REPLICAS   IMAGE          PORTS
6xi76akiz8mv   nginx     replicated   3/3        nginx:latest   *:8000->80/tcp
```

#VisualizerでSWARMの状態を確認する

3つのノードでnginxが起動している事が確認出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391107/1a385098-f895-3687-05cf-ea62d17a7d85.png)


#それぞれのIPでnginxのデフォルト画面が表示されることを確認する

```
% docker-machine ls
NAME   ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER      ERRORS
mgr    *        virtualbox   Running   tcp://192.168.99.102:2376           v19.03.12   
wkr1   -        virtualbox   Running   tcp://192.168.99.103:2376           v19.03.12   
wkr2   -        virtualbox   Running   tcp://192.168.99.104:2376           v19.03.12  
```

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391107/933fcb9e-ad98-f673-2dc1-9bf40f689547.png)

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391107/4f1e59de-e3d3-5a2c-8e9f-e36a122ed8b8.png)

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391107/de2e01ea-fa7b-d118-db07-a33341cb24ba.png)