最初に
ホントはRaft Distributed Consensus Alrogithm/Protocolを使っているようなのでマネージャーが3台より多くあると障害にも強いクラスタになるようですが今回はそんなこと考えないです。
気になった方はetcd総選挙を眺めてみるを読むと良いかもしれないです。(すごい参考になりました)
この辺めっちゃ参考にしてます。
https://docs.docker.com/engine/swarm/
実行環境
node | 役割 |
---|---|
node-01 | worker兼マネージャー |
node-02 | worker |
ターミナル1はnode-01のコマンド実行用にする
$ docker-machine create -d virtualbox node-01
$ eval $(docker-machine env node-01)
ターミナル2はnode-02のコマンド実行用にする
$ docker-machine create -d virtualbox node-02
$ eval $(docker-machine env node-02)
初期化
まずはマネージャーの初期化
$ docker swarm init --advertise-addr $(docker-machine ip node-01)
Swarm initialized: current node (61p7kfvmw4m4nbfz3vodgc2y6) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-0ue65cw4x1k6j2hys2n6hgzpqy0ckv8du7v88e6drkoylh1snm-d7uhyzmofmli2mxa9n93jwepd \
192.168.99.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
上記を実行するとworkerを参加させるためのtoken付きのコマンドが発行される
このコマンドをworkerにしようと思っているnode-02で実行するとクラスタに参加できる
参加する前に現状のクラスタの状態を確認しておく
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
61p7kfvmw4m4nbfz3vodgc2y6 * node-01 Ready Active Leader
tokenの確認は下記のコマンドでもできる
$ docker swarm join-token worker
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-0ue65cw4x1k6j2hys2n6hgzpqy0ckv8du7v88e6drkoylh1snm-d7uhyzmofmli2mxa9n93jwepd \
192.168.99.100:2377
マネージャーとしてクラスタに参加させたい場合は docker swarm join-token manager
を実行するとマネージャーとして参加させるためのtokenが見れる
node-02をworkerとして参加させて見る
$ docker swarm join \
--token SWMTKN-1-0ue65cw4x1k6j2hys2n6hgzpqy0ckv8du7v88e6drkoylh1snm-d7uhyzmofmli2mxa9n93jwepd \
192.168.99.100:2377
This node joined a swarm as a worker.
クラスタの状態を確認する
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
61p7kfvmw4m4nbfz3vodgc2y6 * node-01 Ready Active Leader
cu9p6rego36d4hhtn2653bacj node-02 Ready Active
ちなみにworker側で状態の確認などはできない
$ docker node ls
Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.
サービスの作成
redisサービスを生成する
(TODO: redisのクラスタが生成できるかもしれないが調査できていないためreplicasは1にしている)
$docker service create --replicas 1 --name redis -p 6379:6379 redis:3.2.0-alpine
7vurzloshshm2wn5vezxuexku
サービスの確認を連打していたらREPLICASが1/1になるのが確認できる
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
ac3iz5deljd1 redis 0/1 redis:3.2.0-alpine
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
ac3iz5deljd1 redis 1/1 redis:3.2.0-alpine
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
25g7igyki966vlljtv9lktywx redis.1 redis:3.2.0-alpine node-01 Running Preparing 7 seconds ago
実際にどちらのnodeからでも接続できるか確認する
ついでにnode-01でfooにbarをセットしてnode-02で確認できるかも見ておく
$ redis-cli -h $(docker-machine ip node-01)
192.168.99.100:6379> set foo bar
OK
192.168.99.100:6379> get foo
"bar"
192.168.99.100:6379> exit
$ redis-cli -h $(docker-machine ip node-02)
192.168.99.101:6379> get foo
"bar"
192.168.99.101:6379> exit
サービスのスケールアップ・スケールダウン、そして自動復旧について
redisのコンテナ数を2つに増やすには下記のscaleコマンドを実行します
$ docker service scale redis=2
redis scaled to 2
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
25g7igyki966vlljtv9lktywx redis.1 redis:3.2.0-alpine node-01 Running Running 27 minutes ago
73f8jbhknsqu2xo4czq3ng7r0 redis.2 redis:3.2.0-alpine node-02 Running Running less than a second ago
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
ac3iz5deljd1 redis 2/2 redis:3.2.0-alpine
上記のようにかんたんにスケールアップできますが、自動的に負荷分散されるのでredis等の場合にはコンテナ側でクラスタ化しないと値のセットして参照したら見れないことになる可能性があるので1つに戻しておきます。
$ docker service scale redis=1
redis scaled to 1
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
25g7igyki966vlljtv9lktywx redis.1 redis:3.2.0-alpine node-01 Running Running 32 minutes ago
73f8jbhknsqu2xo4czq3ng7r0 redis.2 redis:3.2.0-alpine node-02 Shutdown Shutdown 3 seconds ago
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
ac3iz5deljd1 redis 1/1 redis:3.2.0-alpine
上のreplicasの数を減らした場合コンテナは削除されずただストップする形になるので何度も試してるとゴミが残ることになります。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a18235283c81 redis:3.2.0-alpine "docker-entrypoint.sh" 6 minutes ago Exited (0) About a minute ago redis.2.73f8jbhknsqu2xo4czq3ng7r0
そして消されるコンテナは古い順ではなくNAMEに書かれてる数値が大きいものから削除されるようです(要検証)
20ぐらいまで増やして1つに絞ってみたらredis.13が生き残ったったのでランダムっぽいです
dcjg438wipqsw6lsi0vw67f5a redis.11 redis:3.2.0-alpine node-01 Shutdown Shutdown about a minute ago
09a4j1fwxb91tkqioz4bti3sz redis.12 redis:3.2.0-alpine node-01 Shutdown Shutdown 3 seconds ago
064hpn2v6jwpy0p8kbpryzwn7 redis.13 redis:3.2.0-alpine node-01 Running Running 3 minutes ago
8lu1d4qwtyb1wz050fjccnbtm redis.14 redis:3.2.0-alpine node-01 Shutdown Shutdown about a minute ago
c9740i08ndi7dte16wsri9ev0 redis.15 redis:3.2.0-alpine node-01 Shutdown Shutdown about a minute ago
099mt2ha487pafhufc37hiutv redis.16 redis:3.2.0-alpine node-02 Shutdown Shutdown 3 seconds ago
docker stop
等によってコンテナが眠ってしまった場合自動的にreplicasの数になるように実行されます。
↑この機能を利用していい感じにコンテナの差し替えができるのでは無いかと思ったりもしている
ローリング・アップデート
下記の設定をするだけでローリングアップデートできます。
--update-delay
--update-parallelism
5秒待ち1コンテナずつ更新かける場合は下記のコマンドになる。
$ docker service update --update-delay 5s --update-parallelism 1 --image redis:3.2.5-alpine redis
redis
scaleをとりあえず20にして試した結果
840x553ujrfghnbqhqi9s0zx5 redis.7 redis:3.2.5-alpine node-02 Running Running 55 seconds ago
3qoj8jpmcfj1ji20aa2hgx1by \_ redis.7 redis:3.2.0-alpine node-01 Shutdown Shutdown 58 seconds ago
844vrpbzjs29q9kua2b3n9r3p \_ redis.7 redis:3.2.0-alpine node-01 Shutdown Shutdown 17 minutes ago
db6k0he84jv9xp0az3r8sqd4z redis.8 redis:3.2.0-alpine node-01 Running Running 3 minutes ago
31ict01zi3l0spo05a4gjixwi \_ redis.8 redis:3.2.0-alpine node-01 Shutdown Shutdown 16 minutes ago
bssq36i1fq20e5a2a629n83bz redis.9 redis:3.2.0-alpine node-01 Running Running 3 minutes ago
e7sea97hqpd5d1pjaugxb33pv \_ redis.9 redis:3.2.0-alpine node-02 Shutdown Shutdown 17 minutes ago
52e7l8s5ossbq6nndbwfrbxxq redis.10 redis:3.2.5-alpine node-02 Running Running 6 seconds ago
8jozd1yew7vou0g8x458t0t9e \_ redis.10 redis:3.2.0-alpine node-01 Shutdown Shutdown 9 seconds ago
21hlsx81oruek4p8de0ujztxb \_ redis.10 redis:3.2.0-alpine node-01 Shutdown Shutdown 16 minutes ago
03mtra8s2zw2tomwgqsqz4sxa redis.11 redis:3.2.5-alpine node-02 Running Running 25 seconds ago
サービス削除
すごいサービス消したら紐付いてたコンテナ全部消してくれる!
$ docker service rm nginx
nginx
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
まとめ
すげえ
まとめパート2
バックエンドにetcd等を用意しなくて良くなったswarmって感想。
ただファイルでnodeの管理ができないのでつらいかもしれないですが、一度構築したら必要ないので問題無い気がします。
Nginxとかscaleし易いやつで試せって話でした。試そうと思ったときに適当にdockerhubから選んだ僕があれでした。
# おまけ
REPLICASの話をつらつらと書きましたが実はgrobalモードがあります。(やる気が出たら記事に追記なりします)
気になった方は調べてみてください。