GCE上でDocker Swarm使ってクラスタ構築した Part2 (マルチマネージャノード)


- [GCE上でDocker Swarm使ってクラスタ構築した Part1 (Getting Startedレベル)](http://qiita.com/tora470/items/a7e044844dfee21d2648)

未だに公式の方にはDocker Swarmのドキュメントも残ってて、こっちはswarm modeとか書いててイマイチどっちで呼称するべきなのかがよくわかりません。(2016年8月16日現在)
Part2は複数のマネージャノードの話。

## ノード関連

### マネージャノード

軽くおさらい。Part1で書いてないことまで書いてますが。

- クラスターを管理するためのノード
- サービスのスケジューリングをするノード
- デフォルトだとこいつもワーカーノードになる得る
- AvailabilityをDrainに変更すれば管理だけするノードになる
	- Docker的にはマネージャノードは管理に集中させた方がいいからDrainにしといた方がいいっぽい。そりゃそうだな。
- Raftアルゴリズム実装して使ってる

#### マネージャノードが落ちたらどうするん？

Part1では、シングルマネージャノードで動かしてました。
公式の[How nodes work](https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/)でも書いてるとおり、シングルの場合はそのマネージャノードが落ちた場合サービス自体は動き続けるけど、クラスタを作り直す必要があります。
LBを外側に置いてれば、アプリケーションとしては動き続けられます。

インスタンス再起動なら、復帰時に勝手にクラスタの再構成はしてくれます。
ここの`failed`はもっとマネージャがクラスタから強制的に抜けるとかのぶっ壊しをしたらってことでしょう。

というわけで、Swarmの恩恵を預かるには、クラスタノードの数に合わせて以下のようにマネージャの数を決めるのがオススメだそうです。

- 3マネージャなら、1マネージャが落ちることまでは許容できる
- 5マネージャなら、2マネージャまでなら許容できる
- Nマネージャなら、`(N-1)/2`マネージャまでなら許容できる
- Dockerは7マネージャをオススメする
- これ以上増やしてもスケーラビリティ・パフォーマンスには繋がらない

### ワーカーノード

- コンテナ実行のためのノード
- スケジュールの決定には関わらない
- 言われたことだけやる人
- 自分からクラスタに参加する
- Drainのノードにはタスクは割り当てられない

#### ワーカーノードをマネージャノードに昇格

これでワーカーノードを格上げできます。

```
$ docker node promote <NODE_NAME>
$ docker node ls 
ID                           HOSTNAME              STATUS  AVAILABILITY  MANAGER STATUS
54dnxv70465ysj0nkf34oe2cy    my-swarm-worker-zujm  Ready   Active        Reachable
8x1ev7mve4znsgs9f4n7rqa5x *  my-swarm-manager      Ready   Drain         Leader
eniapt9t58gpi78vry2opgbp5    my-swarm-worker-k4r1  Ready   Active
```

MANAGER_STATUSがReachableになってます。
マネージャノードを複数用意しといてかつ必要な数のマネージャを用意しておけば、

#### マネージャノードをワーカーノードに降格

```
$ docker node demote my-swarm-worker-zujm 
Manager my-swarm-worker-zujm demoted in the swarm.
$ docker node ls 
ID                           HOSTNAME              STATUS  AVAILABILITY  MANAGER STATUS
54dnxv70465ysj0nkf34oe2cy    my-swarm-worker-zujm  Ready   Active        
8x1ev7mve4znsgs9f4n7rqa5x *  my-swarm-manager      Ready   Drain         Leader
eniapt9t58gpi78vry2opgbp5    my-swarm-worker-k4r1  Ready   Active
```

### クラスタに参加

マネージャとして参加する方法と、ワーカーとして参加する方法があります。
`docker swarm init`した時に参加時のコマンドを参照できますが、あとからでも確認できます。
以下のコマンドをマネージャノードで実行して下さい。

```
$ docker swarm join-token [worker|manager]
```

それぞれ参加するコマンドは同じですが、マネージャとワーカーでトークンの値が違います。

```
$ docker swarm join --token <TOKEN> <MANAGER_IP>:2377
```

ちなみに、このノードに参加する場合、マネージャノードが複数ある場合はどのマネージャノードを指定してもOKですが、
Joinコマンド自体のマネージャノードが固定されちゃってるとそのマネージャノードが落ちてたら困りますね。
なんか方法を考える必要がありますね。

### ノードの削除

ワーカーノード自ら離脱する場合と、マネージャノードが削除する場合の2パターンがあります。

自分で離脱する場合
ちなみに、マネージャノードは`--force`オプションを付けると離脱できますが、あんまりオススメはしません。
あと、マネージャノードが

```
$ docker swarm leave
```

マネージャが削除する場合

```
$ docker node rm <NODE_NAME>
```

## サービス関連

サービスはアプリケーションが動くための定義です。
公式の[How services work](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/)にサービスの図解がのってるので参考にするとよりイメージしやすいかと思います。

超わかりやすいサービスとタスクとコンテナの関係(公式より)
![zu1](https://docs.docker.com/engine/swarm/images/services-diagram.png)

2つのデプロイ方法

- Replicated Service
- Global Service

## バックアップ

ディザスタリカバリのためにマネージャノードの以下のディレクトリをバックアップしとくといいようです。

`/var/lib/docker/swarm/raft`

## 環境がぶっ壊れたら（ディザスタリカバリ）

クラスタ作り直しましょう。
アプリケーションもコンテナで動いているなら、仮にぶっ壊れてたとしてもアプリケーションそのものは復旧簡単ですよね。

```
$ docker swarm init --force-new-cluster --listen-addr <MANAGER_IP>:2377
```

## GCPで作るなら…

雑ですがこんな感じかな？

![ファイル 2016-08-17 15 12 23.jpeg](https://qiita-image-store.s3.amazonaws.com/0/8637/eb60b0a6-ac65-324f-dd38-c1138bdb8d20.jpeg "ファイル 2016-08-17 15 12 23.jpeg")

- マネージャノード
	- 最初にswarm init
	- トークンをメタデータに保存
	- リーダーが自分のIPをメタデータに保存
	- って、ここまで書いて気付いたけどマネージャノードの最初はインスタンスグループ外で一個作った方がいいですね。
	- Part1のDeploymentManagerでマネージャノード作ってるのでまずはこれでクラスタ作成して、  
	  以降のマネージャノードの増減はインスタンスグループ追加すればいいかな。
- ワーカーノード
	- メタデータからトークンとか必要な情報を持ってくる
	- SwarmにJoin

管理するのめんどくさいですねｗ

とりあえず今回はここまで。
Swarm modeについては大体書けることは書いた感があります。・