【Docker入門】公式Docsの「Get Started」を日本語で要約しながらやってみる（Part4）

Docker公式の「Get Started」を日本語で要約しながら進めて見ているシリーズの第４弾です。

前回はこちら。
[【Docker入門】公式Docsの「Get Started」を日本語で要約しながらやってみる（Part3）](https://qiita.com/jnaiFy04EJ0cP2L/items/6bab57d4bf254101e9c9)


## イントロダクション

Part4では、これまで作ってきたアプリケーションをクラスターに乗せ、複数マシンで稼働させる。

複数コンテナ＆複数マシンで動くアプリケーションは、`swarm`というものをマシンにつなぐことで可能となる。

`swarm`はDocker化(Dockerized)されたクラスターのこと。


## Swarmクラスターを理解する

Swarmはマシンの集合でできており、Dockerを動かしている。Swarmはクラスターに繋がれている。

Swarmがクラスタに繋がれると、これまで通り実行したdockerコマンドも、クラスター内の`swarm manager`によって実行されることになる。

swarm内のマシンは、物理マシンでも仮想マシンでもありうる。swarmに繋がれると、これらのマシンはノード（nodes）と呼ばれる。

`swarm manager`は、swarm内のマシンにすぎないが、コマンドを実行したり、他のマシンが`workers`としてクラスターに加わる権限を与えたりできる。

`Workers`はキャパシティを提供するが、swarm managerのように、他マシンの権限を管理することはできない。

ここまで、自分のローカル上で、シングルホストモードとしてDockerを使ってきたが、Dockerは`swarm mode`に切り替えることもできる。

このモードに切り替えることで、swarmを使うことができるようになる。

現在のマシンがswarm managerへと切り替わり、dockerコマンドはswarm上から実行されるようになる。


## Swarmを立ち上げる

Swarmモードを立ち上げるには、`docker swarm init`コマンドを実行すればいい。

そして、`docker swarm join`コマンドを実行し、他のマシンをworkersとしてswarmに接続する。


## クラスターを作成する

仮想マシン（VMs)を作るためのハイパーバイザーが必要なので、Oracle VirtualBoxをインストールする。

https://www.virtualbox.org/wiki/Downloads

インストールを終えたら、`docker-machine`コマンドで仮想マシンを作る。

```
docker-machine create --driver virtualbox myvm1
docker-machine create --driver virtualbox myvm2
```


## VMとそのIPアドレスを確認

```
docker-machine ls
```


## Swarmを立ち上げ、ノードを追加する

`docker-machine ssh`で、仮想マシンにコマンドを送ることが可能。

myvm1にswarm managerになるように指示してみる。

```
docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"

Swarm initialized: current node (<node ID>) is now a manager.

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

    docker swarm join --token <token> <IP>:2377

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

<myvm1 ip>の部分には、`docker-machine ls`で確認できるIPアドレスを入れる。

この時のポート番号に注意！！

ポート番号は2377（swarm managerの番号）にするか、何も入れずにデフォルトに任せる。

`docker-machine ls`を使うと、ポート番号が2376のIPアドレスが返ってくるが、このポート番号を使うとエラーが起こるので使わない。

`docker swarm init`のレスポンスとして、他のノードを足すコマンドが表示される。

その部分をコピペして、myvm2をworkerとして追加してみる。

```
docker-machine ssh myvm2 "docker swarm join --token <token> <IP>:2377"
```

これでswarmの作成は完了！！

`docker node ls`で確認してみる。

```
docker-machine ssh myvm1 "docker node ls"
```

swarmからnodeを除外したい時は、`docker swarm leave`を使えばいける。


## アプリケーションをSwarmクラスター上にデプロイする

あとは、Part3でやった手順を繰り返すだけでいける。


## docker-machineシェルをswarm managerに設定する

その前にもう一つ必要な設定がある。

ここまで、`docker-machine ssh`コマンドを使って、仮想マシンを操作してきた。

もう一つのやり方として、`docker-machine env <machine>`を使って、シェルから扱えるように設定する方法がある。

こちらの方を使うと、ローカルにある`docker-compose.yml`を使って、デプロイできるので便利。

```
docker-machine env myvm1
```

このコマンドの出力の最終行に、シェルが`myvm1`（swarm manager）に指示できるように設定するコマンドが表記されているので、それをコピペ。

```
eval $(docker-machine env myvm1)
```

`docker-machine ls`で`myvm1`がアクティブになっていることを確認しよう。

```
docker-machine ls

NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
myvm1   *        virtualbox   Running   tcp://192.168.99.100:2376           v17.06.2-ce
myvm2   -        virtualbox   Running   tcp://192.168.99.101:2376           v17.06.2-ce
```


## swarm managerにアプリケーションをデプロイする

これで、Part3と同じように、`docker stack deploy`を使ってデプロイができる。

先ほどの設定のおかげで、myvm1に繋がりながら、自分のローカルにあるファイルにもアクセスできる状態にある。

`docker-compose.yml`があるディレクトリ上にいることを確認してから、以下のコマンドでデプロイを完了させる。

```
docker stack deploy -c docker-compose.yml getstartedlab
```

Part3で使ったコマンドも使えるようになっている。

ただし、今回は`myvm1`と`myvm2`にデプロイされている。

```
docker stack ps getstartedlab

ID                  NAME                  IMAGE                            NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
vk4tv701ql0x        getstartedlab_web.1   username/get-started:part2   myvm1               Running             Running 25 seconds ago                       
wjvvoe7yxw94        getstartedlab_web.2   username/get-started:part2   myvm2               Running             Running 5 minutes ago                        
716pyry3wcs5        getstartedlab_web.3   username/get-started:part2   myvm2               Running             Running 5 minutes ago                        
f4zb451o061v        getstartedlab_web.4   username/get-started:part2   myvm1               Running             Running 25 seconds ago                       
3rnecs0915at        getstartedlab_web.5   username/get-started:part2   myvm2               Running             Running 5 minutes ago 
```


## クラスターにアクセスする

`docker-machine ls`でIPアドレスを確認して、アクセスしてみる。

この時、`<IPアドレス>:ポート番号`の形でアクセスする。ポート番号を忘れずに。（筆者はポート番号を忘れて小一時間ハマって時間を無駄にしました…）

今回は`<IPアドレス>:4000`でアクセスすることになります。

おなじみのこの画面が表示されればオッケー。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/158916/c0a94503-4d43-37bd-6d90-dc4ddaf8ec80.png)


ここでも負荷分散はちゃんと動いていて、myvm1とmyvm2のコンテナからランダムでどれかが出てくる仕組み。

リロードをしてみると、HostnameのところのIDが変化しているのが分かると思います。

myvm1とmyvm2のIPアドレスは違うのに、なぜ負荷分散がちゃんと動くのでしょうか？

それは、swarm内のノードがイングレスネットワークのルーティングメッシュに加わっているから。

公式Docsの図をみると分かりやすい。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/158916/44a80a32-d4d9-582a-cb9e-3921c3669277.png)
（　https://docs.docker.com/get-started/part4/　)

3つのうち、どのIPアドレスからアクセスされても、`my-web1`か`my-web2`にルーティングされていることが分かる。


## アプリケーションをイテレート、スケールさせる

ここまで設定できると、Part2, 3で学んだことが実行できる。

`docker-compose.yml`を変更してスケールさせることができる。

コードを書き換え、再度ビルドし、プッシュすることで、アプリケーションの挙動を変更することができる。

そして、`docker stack deploy`コマンドを実行するだけで、変更点をデプロイすることができる。

`docker swarm join`コマンドを使えば、新たにマシンをworkersとして追加し、リソースを足すことができる。

この時も、`docker stack deploy`で変更を反映させることができる。


## docker-machineように設定したシェルの設定を解除する

`eval $(docker-machine env myvm1)`コマンドを実行して、docker-machineに指示を送る設定を行った。

これを解除するには、以下のコマンドを実行すればいい。

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


## docker-machineの停止・再起動

停止はこのstopコマンドを使う。

```
docker-machine stop myvm1
docker-machine stop myvm2
```

再起動にはstartコマンド。

```
docker-machine start myvm1
docker-machine start myvm2
```

以上でPart4はおしまい。