fbpx

CL LAB

HOME > CL LAB > Docker Swarmマネージャの障害復旧 #mirantis #docker #swarm

Docker Swarmマネージャの障害復旧 #mirantis #docker #swarm

 ★ 2

本稿ではDocker Swarmマネージャの障害復旧について、

  • 定足数(Quorum; クォーラム)を満たした状態での復旧
  • 定足数を満たさない状態からの復旧
  • マネージャをすべて喪失した状態からの復旧

の3パターンについて見ていきます。

前提条件

  • VirtualBox/Vagrantで環境を準備。
  • CentOS 7
  • Docker CE 20.10.10
  • Swarmマネージャ3台のHA構成とSwarmワーカー2台の、計5台のクラスタ。

Swarmクラスタの準備

次のVagrantfileでゲストOSを準備します。IPアドレスやメモリは必要に応じて変更してください。

nodes = {
  'manager01' => '192.168.123.101',
  'manager02' => '192.168.123.102',
  'manager03' => '192.168.123.103',
  'worker01'  => '192.168.123.201',
  'worker02'  => '192.168.123.202',
}
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.box_check_update = false
  nodes.each do |node_name, ipaddr|
    config.vm.define node_name do |cf|
      cf.vm.hostname = node_name
      cf.vm.network "private_network", ip: ipaddr
      cf.vm.provision "docker"
      cf.vm.provider "virtualbox" do |vb|
        vb.memory = 3072
      end
    end
  end
end

manager01, manager02, manager03をSwarmマネージャ、worker01, worker02をSwarmワーカーとしてクラスタを構築します。

まず manager01 でSwarm初期化を実行します。

[vagrant@manager01 ~]$ docker swarm init --availability=drain --advertise-addr 192.168.123.101
Swarm initialized: current node (i2cylwqkd2jtppmickcz38wr1) is now a manager.
 
To add a worker to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-8emzlfehglbpjcrfzw706ys4g 192.168.123.101:2377
 
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

初期化オプションとして--availability=drainを付与して、ワークロードコンテナをマネージャ上に起動しないようにしています。

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
i2cylwqkd2jtppmickcz38wr1 *   manager01   Ready     Drain          Leader           20.10.10

マネージャ参加トークンを払い出します。

[vagrant@manager01 ~]$ docker swarm join-token manager
To add a manager to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.101:2377

manager02 と manager03 でこれを実行し、マネージャとしてクラスタに参加させます。またこの際もオプションとして--availability=drainを付与して、ワークロードコンテナを起動しないようにします。

[vagrant@manager02 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.101:2377
This node joined a swarm as a manager.

[vagrant@manager03 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.101:2377
This node joined a swarm as a manager.

これで3台によるHA構成のSwarmマネージャが構築できました。これにより、3台のうち1台までのクラッシュや停止が許されます。詳細は Add manager nodes for fault tolerance をご覧ください。

次に worker01 と worker02 で、Swarm初期化時に表示されたワーカー参加コマンドを実行します。

[vagrant@worker01 ~]$ docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-8emzlfehglbpjcrfzw706ys4g 192.168.123.101:2377
This node joined a swarm as a worker.

[vagrant@worker02 ~]$ docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-8emzlfehglbpjcrfzw706ys4g 192.168.123.101:2377
This node joined a swarm as a worker.

これでHA構成のSwarmマネージャ3台とSwarmワーカー2台の計5台のクラスタが構築できました。

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
i2cylwqkd2jtppmickcz38wr1 *   manager01   Ready     Drain          Leader           20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Ready     Drain          Reachable        20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

簡単な図にすると次のようになります。

これにMirantis社公認Dockerトレーニングで用いられているサンプルアプリDockerCoinsをデプロイしてみましょう。ただしこのままだと各サービスのコンテナが1つずつしか起動しないので、少し手を加えて多くのコンテナが起動するようにします。

[vagrant@manager01 ~]$ curl -LO https://raw.githubusercontent.com/docker-training/orchestration-workshop/ee3.0/dockercoins/docker-compose.yml
[vagrant@manager01 ~]$ cp -a docker-compose.yml docker-compose.yml.orig
[vagrant@manager01 ~]$ vi docker-compose.yml

[vagrant@manager01 ~]$ diff -u docker-compose.yml.orig docker-compose.yml
--- docker-compose.yml.orig 2021-11-17 02:17:18.923986228 +0000
+++ docker-compose.yml  2021-11-17 02:18:49.958987464 +0000
@@ -7,6 +7,8 @@
     - dockercoins
     ports:
     - "8001:80"
+    deploy:
+      mode: global
 
   hasher:
     image: training/dockercoins-hasher:1.0
@@ -31,6 +33,9 @@
     image: training/dockercoins-worker:1.0
     networks:
     - dockercoins
+    deploy:
+      mode: replicated
+      replicas: 4
 
 networks:
     dockercoins:

デプロイします。

[vagrant@manager01 ~]$ docker stack deploy -c docker-compose.yml dc
Creating network dc_dockercoins
Creating service dc_hasher
Creating service dc_webui
Creating service dc_redis
Creating service dc_worker
Creating service dc_rng

次のようになりました。先にSwarmマネージャではワークロードコンテナを起動しないようにしたため、worker01 と worker02 のみでコンテナが起動しています。

[vagrant@manager01 ~]$ docker service ls
ID             NAME        MODE         REPLICAS   IMAGE                             PORTS
i2hbj25s8k3l   dc_hasher   replicated   1/1        training/dockercoins-hasher:1.0   *:8002->80/tcp
mghdfsmtcc9l   dc_redis    replicated   1/1        redis:latest
pvfzzcjy61kd   dc_rng      global       2/2        training/dockercoins-rng:1.0      *:8001->80/tcp
quxlyqf9kjem   dc_webui    replicated   1/1        training/dockercoins-webui:1.0    *:8000->80/tcp
rid41xkrfzzl   dc_worker   replicated   4/4        training/dockercoins-worker:1.0
[vagrant@manager01 ~]$ docker service ps $(docker service ls -q)
ID             NAME                               IMAGE                             NODE       DESIRED STATE   CURRENT STATE                ERROR     PORTS
zuudxvy4ncuw   dc_hasher.1                        training/dockercoins-hasher:1.0   worker01   Running         Running about a minute ago
mpb2anujjlsj   dc_redis.1                         redis:latest                      worker02   Running         Running about a minute ago
fo059jo0q6nb   dc_rng.uwhi7yqd7ir3oqy6r32bkz513   training/dockercoins-rng:1.0      worker01   Running         Running about a minute ago
h05fo90aracw   dc_rng.ykhntr9vgpdkibgacbjapj8xz   training/dockercoins-rng:1.0      worker02   Running         Running about a minute ago
jh6v6pu7tzcc   dc_webui.1                         training/dockercoins-webui:1.0    worker02   Running         Running about a minute ago
dei0olkvs9dx   dc_worker.1                        training/dockercoins-worker:1.0   worker02   Running         Running about a minute ago
uhwoak1etcsh   dc_worker.2                        training/dockercoins-worker:1.0   worker01   Running         Running about a minute ago
9oxd0nnr3ekq   dc_worker.3                        training/dockercoins-worker:1.0   worker02   Running         Running about a minute ago
q3sv0jh1t3ep   dc_worker.4                        training/dockercoins-worker:1.0   worker01   Running         Running about a minute ago

ブラウザで http://192.168.123.101:8000/ http://192.168.123.102:8000/ http://192.168.123.103:8000/ http://192.168.123.201:8000/ http://192.168.123.202:8000/ にアクセスし、次のDockerCoinsのWebUIが表示されれば正常に動作しています。

これで準備ができました。

Swarmマネージャが1台クラッシュ

突然 manager01 がクラッシュしてしまいました!

% vagrant destroy manager01
    manager01: Are you sure you want to destroy the 'manager01' VM? [y/N] y
==> manager01: Forcing shutdown of VM...
==> manager01: Destroying VM and associated drives...

バックアップも何も取っていない状態で、マネージャのリーダーだった manager01 が消滅してしまいました…。

しかし、心配しないでください。前述の通り、マネージャ3台のHA構成なので、マネージャ1台までのクラッシュは許容されます。

manager02 で状態を確認してみましょう。

[vagrant@manager02 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
i2cylwqkd2jtppmickcz38wr1     manager01   Down      Drain          Unreachable      20.10.10
3vlwv4nymq4gism039a1xhwxm *   manager02   Ready     Drain          Leader           20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

自動的にリーダーが manager02 に移っているので、Swarmマネージャとしての機能は損なわれていません。

[vagrant@manager02 ~]$ docker service ls
ID             NAME        MODE         REPLICAS   IMAGE                             PORTS
i2hbj25s8k3l   dc_hasher   replicated   1/1        training/dockercoins-hasher:1.0   *:8002->80/tcp
mghdfsmtcc9l   dc_redis    replicated   1/1        redis:latest
pvfzzcjy61kd   dc_rng      global       2/2        training/dockercoins-rng:1.0      *:8001->80/tcp
quxlyqf9kjem   dc_webui    replicated   1/1        training/dockercoins-webui:1.0    *:8000->80/tcp
rid41xkrfzzl   dc_worker   replicated   4/4        training/dockercoins-worker:1.0
[vagrant@manager02 ~]$ docker service ps $(docker service ls -q)
ID             NAME                               IMAGE                             NODE       DESIRED STATE   CURRENT STATE            ERROR     PORTS
zuudxvy4ncuw   dc_hasher.1                        training/dockercoins-hasher:1.0   worker01   Running         Running 21 minutes ago
mpb2anujjlsj   dc_redis.1                         redis:latest                      worker02   Running         Running 21 minutes ago
fo059jo0q6nb   dc_rng.uwhi7yqd7ir3oqy6r32bkz513   training/dockercoins-rng:1.0      worker01   Running         Running 21 minutes ago
h05fo90aracw   dc_rng.ykhntr9vgpdkibgacbjapj8xz   training/dockercoins-rng:1.0      worker02   Running         Running 21 minutes ago
jh6v6pu7tzcc   dc_webui.1                         training/dockercoins-webui:1.0    worker02   Running         Running 21 minutes ago
dei0olkvs9dx   dc_worker.1                        training/dockercoins-worker:1.0   worker02   Running         Running 21 minutes ago
uhwoak1etcsh   dc_worker.2                        training/dockercoins-worker:1.0   worker01   Running         Running 21 minutes ago
9oxd0nnr3ekq   dc_worker.3                        training/dockercoins-worker:1.0   worker02   Running         Running 21 minutes ago
q3sv0jh1t3ep   dc_worker.4                        training/dockercoins-worker:1.0   worker01   Running         Running 21 minutes ago

アプリも正常に動作しています。ブラウザでも確認してみてください。

繰り返しとなりますが、3台のHA構成であれば1台のクラッシュまでは許容されます。しかし、この状態でさらに1台、計2台がクラッシュすると大変なので、manager01 を急いで復旧させましょう。バックアップも取っていないのに、どうすればよいのでしょうか? 実は簡単です。新しく用意した manager01 をSwarmマネージャに再参加させるだけでよいのです。

% vagrant up manager01
(省略)
% vagrant ssh manager01
[vagrant@manager01 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.102:2377
This node joined a swarm as a manager.

以前使ったマネージャ参加コマンドで、参加先を起動中のSwarmマネージャのもの、ここでは manager02 のIPアドレスに変更して実行するだけでOKです。

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
i2cylwqkd2jtppmickcz38wr1     manager01   Down      Drain          Reachable        20.10.10
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Reachable        20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Ready     Drain          Leader           20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

このように manager01 がSwarmマネージャとして復帰しました。バックアップを取らずとも、マネージャに参加した際にクラスタのデータが自動的に同期されるので特に作業は必要ありません。強いて言えば、まぎらわしいのでクラッシュした古い manager01 を削除しておくくらいです。

[vagrant@manager01 ~]$ docker node demote i2cylwqkd2jtppmickcz38wr1
Manager i2cylwqkd2jtppmickcz38wr1 demoted in the swarm.
[vagrant@manager01 ~]$ docker node rm i2cylwqkd2jtppmickcz38wr1
i2cylwqkd2jtppmickcz38wr1
[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Reachable        20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Ready     Drain          Leader           20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

Swarmマネージャのバックアップ

先ほどはマネージャ1台のクラッシュだったので比較的復旧が簡単に済みましたが、安心・安全のために Backup Swarmの手順に従い、マネージャのバックアップを取っておきましょう。本稿では使っていませんが、Swarmのautolockを使っている場合はキーを別途バックアップしてください。

まずは、現時点でマネージャリーダーではない manager01 からバックアップを始めます。バックアップ対象は /var/lib/docker/swarm ディレクトリです。バックアップを取る前に、クラスタデータに変動が起きないように manager01 の docker を停止します。

[vagrant@manager01 ~]$ ENGINE=$(docker version -f '{{.Server.Version}}')
[vagrant@manager01 ~]$ sudo systemctl stop docker.service docker.socket
[vagrant@manager01 ~]$ ps auxwwwf | grep '[ d]ocker'
[vagrant@manager01 ~]$

クラッシュ時と同様、マネージャもアプリも正常に動作を続けているので心配しないでください。ただし、この状態で manager02 と manager03 のどちらかクラッシュするとマネージャが止まってしまうため、クリティカルな本番環境では2台までの停止が許容される5台のHA構成が良いでしょう。

ではバックアップを行います。

[vagrant@manager01 ~]$ sudo tar cvzf "/tmp/swarm-${ENGINE}-$(hostname -s)-$(date +%s%z).tgz" /var/lib/docker/swarm/
tar: Removing leading `/' from member names
/var/lib/docker/swarm/
/var/lib/docker/swarm/state.json
/var/lib/docker/swarm/docker-state.json
/var/lib/docker/swarm/certificates/
/var/lib/docker/swarm/certificates/swarm-root-ca.crt
/var/lib/docker/swarm/certificates/swarm-node.key
/var/lib/docker/swarm/certificates/swarm-node.crt
/var/lib/docker/swarm/worker/
/var/lib/docker/swarm/worker/tasks.db
/var/lib/docker/swarm/raft/
/var/lib/docker/swarm/raft/snap-v3-encrypted/
/var/lib/docker/swarm/raft/wal-v3-encrypted/
/var/lib/docker/swarm/raft/wal-v3-encrypted/0000000000000000-0000000000000000.wal

バックアップが取れていることを確認し、問題なければこのファイルを manager01 外の安全な場所に退避しておきましょう。

[vagrant@manager01 ~]$ tar tvfz /tmp/swarm-20.10.10-manager01-1637120105+0000.tgz
drwx------ root/root         0 2021-11-17 03:22 var/lib/docker/swarm/
-rw------- root/root       211 2021-11-17 03:22 var/lib/docker/swarm/state.json
-rw------- root/root       198 2021-11-17 03:07 var/lib/docker/swarm/docker-state.json
drwxr-xr-x root/root         0 2021-11-17 03:07 var/lib/docker/swarm/certificates/
-rw-r--r-- root/root       554 2021-11-17 03:07 var/lib/docker/swarm/certificates/swarm-root-ca.crt
-rw------- root/root       317 2021-11-17 03:07 var/lib/docker/swarm/certificates/swarm-node.key
-rw-r--r-- root/root       826 2021-11-17 03:07 var/lib/docker/swarm/certificates/swarm-node.crt
drwxr-xr-x root/root         0 2021-11-17 03:07 var/lib/docker/swarm/worker/
-rw-r--r-- root/root     32768 2021-11-17 03:31 var/lib/docker/swarm/worker/tasks.db
drwx------ root/root         0 2021-11-17 03:07 var/lib/docker/swarm/raft/
drwx------ root/root         0 2021-11-17 03:07 var/lib/docker/swarm/raft/snap-v3-encrypted/
drwx------ root/root         0 2021-11-17 03:31 var/lib/docker/swarm/raft/wal-v3-encrypted/
-rw------- root/root  64000000 2021-11-17 03:31 var/lib/docker/swarm/raft/wal-v3-encrypted/0000000000000000-0000000000000000.wal

バックアップが取れたら、dockerを起動します。

[vagrant@manager01 ~]$ sudo systemctl start docker
[vagrant@manager01 ~]$ ps auxwwwf | grep '[ d]ocker'
root      2833  3.0  2.6 1153808 78536 ?       Ssl  03:38   0:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Reachable        20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Ready     Drain          Leader           20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

同様の手順で、リーダーではない manager03 でバックアップを取得します。作業ログは省略します。

最後に、リーダーである manager02 でバックアップを取得します。まず docker を停止します。

[vagrant@manager02 ~]$ ENGINE=$(docker version -f '{{.Server.Version}}')
[vagrant@manager02 ~]$ sudo systemctl stop docker.service docker.socket
[vagrant@manager02 ~]$ ps auxwwwf | grep '[ d]ocker'
[vagrant@manager02 ~]$ 

リーダーの docker を停止してしまいましたが大丈夫でしょうか? 他のマネージャ、ここでは manager01 で確認してみましょう。

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Leader           20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Down      Drain          Unreachable      20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

自動的にリーダーが manager01 に移っているため、マネージャもアプリも正常に動作を続けています。安心して manager02 のバックアップ作業を行いましょう。詳細な作業ログは省略します。

すべてのマネージャのバックアップが取れました。これで2台以上のクラッシュが発生してもひとまずは安心です。

swarm-20.10.10-manager01-1637120105+0000.tgz
swarm-20.10.10-manager02-1637120862+0000.tgz
swarm-20.10.10-manager03-1637120446+0000.tgz

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Leader           20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Ready     Drain          Reachable        20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

Swarmマネージャが2台クラッシュ

今度は manager01 と manager02 が同時にクラッシュしてしまいました!

% vagrant destroy manager01 manager02
    manager02: Are you sure you want to destroy the 'manager02' VM? [y/N] y
==> manager02: Forcing shutdown of VM...
==> manager02: Destroying VM and associated drives...
    manager01: Are you sure you want to destroy the 'manager01' VM? [y/N] y
==> manager01: Forcing shutdown of VM...
==> manager01: Destroying VM and associated drives...

リーダーだった manager01 を含め、マネージャが2台も消滅してしまいました…。

生き残ったマネージャである manager03 でSwarm管理コマンドを実行しても、定足数を満たしていないために受け付けられない状態となってしまっています。

[vagrant@manager03 ~]$ docker node ls
Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.

ただ、ワーカーで起動済みのアプリは正常に動作し続けています。ブラウザでも確認してみてください。

[vagrant@worker01 ~]$ docker ps
CONTAINER ID   IMAGE                             COMMAND              CREATED       STATUS       PORTS     NAMES
42c2372fb05d   training/dockercoins-worker:1.0   "python worker.py"   2 hours ago   Up 2 hours             dc_worker.2.uhwoak1etcshf7augszho198z
2c023c5d0f30   training/dockercoins-worker:1.0   "python worker.py"   2 hours ago   Up 2 hours             dc_worker.4.q3sv0jh1t3ep68wgx6gbpqopx
2f3cda11b088   training/dockercoins-rng:1.0      "python rng.py"      2 hours ago   Up 2 hours   80/tcp    dc_rng.uwhi7yqd7ir3oqy6r32bkz513.fo059jo0q6nbc6j39av0chk3c
783bf01fa525   training/dockercoins-hasher:1.0   "ruby hasher.rb"     2 hours ago   Up 2 hours   80/tcp    dc_hasher.1.zuudxvy4ncuw73fmkhq08lwi0

[vagrant@worker02 ~]$ docker ps
CONTAINER ID   IMAGE                             COMMAND                  CREATED       STATUS       PORTS      NAMES
fb30066aa37c   training/dockercoins-webui:1.0    "node webui.js"          2 hours ago   Up 2 hours   80/tcp     dc_webui.1.jh6v6pu7tzccxq5raou01gsi4
f80358a4c8ef   redis:latest                      "docker-entrypoint.s…"   2 hours ago   Up 2 hours   6379/tcp   dc_redis.1.mpb2anujjlsjzstjncp4tevix
7dcf9f26e740   training/dockercoins-worker:1.0   "python worker.py"       2 hours ago   Up 2 hours              dc_worker.1.dei0olkvs9dx7e57qtfhot1yz
f3853a139326   training/dockercoins-worker:1.0   "python worker.py"       2 hours ago   Up 2 hours              dc_worker.3.9oxd0nnr3ekq75l824urcqta9
bfdec753d424   training/dockercoins-rng:1.0      "python rng.py"          2 hours ago   Up 2 hours   80/tcp     dc_rng.ykhntr9vgpdkibgacbjapj8xz.h05fo90aracwf12zm23yy1u9x

起動済みのアプリは動作し続けていますが、管理コマンドを受け付けないため、アプリに問題が発生しても復旧作業が行えません。急いでマネージャを復旧させる必要があります。

Recover from losing the quorum の手順に従い、生き残った manager03 をリーダーとしてクラスタを作り直し、manager01 と manager02 を置き換えます。

manager03 にて、manager03 にある既存のクラスタデータを用いて、manager03 を唯一のマネージャとする --force-new-cluster オプションを付与してクラスタの初期化を行います。

[vagrant@manager03 ~]$ docker swarm init --availability=drain --force-new-cluster --advertise-addr 192.168.123.103
Swarm initialized: current node (ufxoq2m2bewz4aujbdqzm5w27) is now a manager.
 
To add a worker to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-8emzlfehglbpjcrfzw706ys4g 192.168.123.103:2377
 
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

ひとまずクラスタ管理コマンドを受け付けるようになりました。

[vagrant@manager03 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012     manager01   Down      Drain                           20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Down      Drain                           20.10.10
ufxoq2m2bewz4aujbdqzm5w27 *   manager03   Ready     Drain          Leader           20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10
[vagrant@manager03 ~]$ docker service ls
ID             NAME        MODE         REPLICAS   IMAGE                             PORTS
i2hbj25s8k3l   dc_hasher   replicated   1/1        training/dockercoins-hasher:1.0   *:8002->80/tcp
mghdfsmtcc9l   dc_redis    replicated   1/1        redis:latest
pvfzzcjy61kd   dc_rng      global       2/2        training/dockercoins-rng:1.0      *:8001->80/tcp
quxlyqf9kjem   dc_webui    replicated   1/1        training/dockercoins-webui:1.0    *:8000->80/tcp
rid41xkrfzzl   dc_worker   replicated   4/4        training/dockercoins-worker:1.0

新しく manager01 と manager02 を用意します。

% vagrant up manager01 manager02

manager03 でクラスタ参加トークンを払い出します。

[vagrant@manager03 ~]$ docker swarm join-token manager
To add a manager to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.103:2377

これにワークロードコンテナをマネージャ上で起動しないよう--availability=drainを付与して、manager01 と manager02 で実行します。

[vagrant@manager01 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.103:2377
This node joined a swarm as a manager.

[vagrant@manager02 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.103:2377
This node joined a swarm as a manager.

これで無事マネージャが復旧しました。

[vagrant@manager03 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012     manager01   Down      Drain                           20.10.10
s6nh1jx2rls2ryfvfvkdhrc45     manager01   Ready     Drain          Reachable        20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Down      Drain                           20.10.10
woftntblwmor5i7o36px8hyat     manager02   Ready     Drain          Reachable        20.10.10
ufxoq2m2bewz4aujbdqzm5w27 *   manager03   Ready     Drain          Leader           20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

古い manager01 と manager02 を削除しておきましょう。

[vagrant@manager03 ~]$ docker node rm s4bm4um4k88nzqc6avq55e012 3vlwv4nymq4gism039a1xhwxm
s4bm4um4k88nzqc6avq55e012
3vlwv4nymq4gism039a1xhwxm
[vagrant@manager03 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s6nh1jx2rls2ryfvfvkdhrc45     manager01   Ready     Drain          Reachable        20.10.10
woftntblwmor5i7o36px8hyat     manager02   Ready     Drain          Reachable        20.10.10
ufxoq2m2bewz4aujbdqzm5w27 *   manager03   Ready     Drain          Leader           20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

この間、既存のアプリは動作中のままでした。

Swarmマネージャが3台クラッシュ

今度はマネージャが全滅してしまいました…。最悪のパターンです。

% vagrant destroy manager01 manager02 manager03
    manager03: Are you sure you want to destroy the 'manager03' VM? [y/N] y
==> manager03: Forcing shutdown of VM...
==> manager03: Destroying VM and associated drives...
    manager02: Are you sure you want to destroy the 'manager02' VM? [y/N] y
==> manager02: Forcing shutdown of VM...
==> manager02: Destroying VM and associated drives...
    manager01: Are you sure you want to destroy the 'manager01' VM? [y/N] y
==> manager01: Forcing shutdown of VM...
==> manager01: Destroying VM and associated drives...

依然としてアプリは動作し続けていますが、当然ながら管理コマンドなどを受け付ける先がありません。

[vagrant@worker01 ~]$ docker ps
CONTAINER ID   IMAGE                             COMMAND              CREATED       STATUS       PORTS     NAMES
42c2372fb05d   training/dockercoins-worker:1.0   "python worker.py"   3 hours ago   Up 3 hours             dc_worker.2.uhwoak1etcshf7augszho198z
2c023c5d0f30   training/dockercoins-worker:1.0   "python worker.py"   3 hours ago   Up 3 hours             dc_worker.4.q3sv0jh1t3ep68wgx6gbpqopx
2f3cda11b088   training/dockercoins-rng:1.0      "python rng.py"      3 hours ago   Up 3 hours   80/tcp    dc_rng.uwhi7yqd7ir3oqy6r32bkz513.fo059jo0q6nbc6j39av0chk3c
783bf01fa525   training/dockercoins-hasher:1.0   "ruby hasher.rb"     3 hours ago   Up 3 hours   80/tcp    dc_hasher.1.zuudxvy4ncuw73fmkhq08lwi0

[vagrant@worker02 ~]$ docker ps
CONTAINER ID   IMAGE                             COMMAND                  CREATED       STATUS       PORTS      NAMES
fb30066aa37c   training/dockercoins-webui:1.0    "node webui.js"          3 hours ago   Up 3 hours   80/tcp     dc_webui.1.jh6v6pu7tzccxq5raou01gsi4
f80358a4c8ef   redis:latest                      "docker-entrypoint.s…"   3 hours ago   Up 3 hours   6379/tcp   dc_redis.1.mpb2anujjlsjzstjncp4tevix
7dcf9f26e740   training/dockercoins-worker:1.0   "python worker.py"       3 hours ago   Up 3 hours              dc_worker.1.dei0olkvs9dx7e57qtfhot1yz
f3853a139326   training/dockercoins-worker:1.0   "python worker.py"       3 hours ago   Up 3 hours              dc_worker.3.9oxd0nnr3ekq75l824urcqta9
bfdec753d424   training/dockercoins-rng:1.0      "python rng.py"          3 hours ago   Up 3 hours   80/tcp     dc_rng.ykhntr9vgpdkibgacbjapj8xz.h05fo90aracwf12zm23yy1u9x

Restore Swarmの手順に従い、マネージャを復旧しましょう。幸い、先にバックアップを取得しているのでそれからリストアします。

manager01, manager02, manager03 を用意します。この際、以前の manager01, manager02, manager03 と同じIPアドレスであるようにします。

% vagrant up manager01 manager02 manager03

manager01 から復旧しましょう。manager01 にバックアップファイル swarm-20.10.10-manager01-1637120105+0000.tgz を設置します。

[vagrant@manager01 ~]$ ls swarm-20.10.10-manager01-1637120105+0000.tgz 
swarm-20.10.10-manager01-1637120105+0000.tgz

docker を停止します。

[vagrant@manager01 ~]$ sudo systemctl stop docker.service docker.socket
[vagrant@manager01 ~]$ ps auxwwwwf | grep '[ d]ocker'
[vagrant@manager01 ~]$ 

バックアップデータをリストアします。

[vagrant@manager01 ~]$ sudo tar xvf swarm-20.10.10-manager01-1637120105+0000.tgz -C /
var/lib/docker/swarm/
var/lib/docker/swarm/state.json
var/lib/docker/swarm/docker-state.json
var/lib/docker/swarm/certificates/
var/lib/docker/swarm/certificates/swarm-root-ca.crt
var/lib/docker/swarm/certificates/swarm-node.key
var/lib/docker/swarm/certificates/swarm-node.crt
var/lib/docker/swarm/worker/
var/lib/docker/swarm/worker/tasks.db
var/lib/docker/swarm/raft/
var/lib/docker/swarm/raft/snap-v3-encrypted/
var/lib/docker/swarm/raft/wal-v3-encrypted/
var/lib/docker/swarm/raft/wal-v3-encrypted/0000000000000000-0000000000000000.wal

docker を起動します。

[vagrant@manager01 ~]$ sudo systemctl start docker
[vagrant@manager01 ~]$ ps auxwwwwf | grep '[ d]ocker'
root      2056  1.3  2.2 1088016 64196 ?       Ssl  05:49   0:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

クラスタデータは戻ったようですが、管理コマンドは依然として受け付けられません。

[vagrant@manager01 ~]$ docker system info --format '{{json .Swarm}}' | jq . -
{
  "NodeID": "s4bm4um4k88nzqc6avq55e012",
  "NodeAddr": "192.168.123.101",
  "LocalNodeState": "pending",
  "ControlAvailable": true,
  "Error": "rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.",
  "RemoteManagers": [
    {
      "NodeID": "ufxoq2m2bewz4aujbdqzm5w27",
      "Addr": "192.168.123.103:2377"
    },
    {
      "NodeID": "3vlwv4nymq4gism039a1xhwxm",
      "Addr": "192.168.123.102:2377"
    },
    {
      "NodeID": "s4bm4um4k88nzqc6avq55e012",
      "Addr": "192.168.123.101:2377"
    }
  ],
  "Cluster": {
    "ID": "",
    "Version": {},
    "CreatedAt": "0001-01-01T00:00:00Z",
    "UpdatedAt": "0001-01-01T00:00:00Z",
    "Spec": {
      "Labels": null,
      "Orchestration": {},
      "Raft": {
        "ElectionTick": 0,
        "HeartbeatTick": 0
      },
      "Dispatcher": {},
      "CAConfig": {},
      "TaskDefaults": {},
      "EncryptionConfig": {
        "AutoLockManagers": false
      }
    },
    "TLSInfo": {},
    "RootRotationInProgress": false,
    "DefaultAddrPool": null,
    "SubnetSize": 0,
    "DataPathPort": 0
  }
}
[vagrant@manager01 ~]$ docker node ls
Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.
[vagrant@manager01 ~]$ docker service ls
Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It's possible that too few managers are online. Make sure more than half of the managers are online.

マネージャが2台クラッシュしたときと同様に、この既存のクラスタデータを用いて、manager01 を唯一のマネージャとする --force-new-cluster オプションを付与してクラスタの初期化を行います。

[vagrant@manager01 ~]$ docker swarm init --availability=drain --force-new-cluster --advertise-addr 192.168.123.101
Swarm initialized: current node (s4bm4um4k88nzqc6avq55e012) is now a manager.
 
To add a worker to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-8emzlfehglbpjcrfzw706ys4g 192.168.123.101:2377
 
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
[vagrant@manager01 ~]$ docker swarm join-token manager
To add a manager to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.101:2377

管理コマンドを受け付けるようになりました。

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Leader           20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Down      Drain                           20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Unknown   Drain                           20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10
[vagrant@manager01 ~]$ docker service ls
ID             NAME        MODE         REPLICAS   IMAGE                             PORTS
i2hbj25s8k3l   dc_hasher   replicated   1/1        training/dockercoins-hasher:1.0   *:8002->80/tcp
mghdfsmtcc9l   dc_redis    replicated   1/1        redis:latest
pvfzzcjy61kd   dc_rng      global       2/2        training/dockercoins-rng:1.0      *:8001->80/tcp
quxlyqf9kjem   dc_webui    replicated   1/1        training/dockercoins-webui:1.0    *:8000->80/tcp
rid41xkrfzzl   dc_worker   replicated   4/4        training/dockercoins-worker:1.0

manager02 と manager03 をマネージャとしてクラスタに再参加させましょう。

[vagrant@manager02 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.101:2377
This node joined a swarm as a manager.

[vagrant@manager03 ~]$ docker swarm join --availability=drain --token SWMTKN-1-3y5wa7xcsxavdyfibx58qr0g5ln2joui3fjxmjtet7sp67o04b-763hohmtxmxrr9zhu67y05pyj 192.168.123.101:2377
This node joined a swarm as a manager.

無事、3台のマネージャによるHA構成が復旧しました。

[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Leader           20.10.10
3vlwv4nymq4gism039a1xhwxm     manager02   Down      Drain                           20.10.10
frvz22bn7rd0uyxdawe9vn6cv     manager02   Ready     Drain          Reachable        20.10.10
nf4yl2jsatypawskypd77kgqt     manager03   Ready     Drain          Reachable        20.10.10
ufxoq2m2bewz4aujbdqzm5w27     manager03   Down      Drain                           20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10

古い manager02 と manager03 を削除しておきましょう。

[vagrant@manager01 ~]$ docker node rm 3vlwv4nymq4gism039a1xhwxm ufxoq2m2bewz4aujbdqzm5w27
3vlwv4nymq4gism039a1xhwxm
ufxoq2m2bewz4aujbdqzm5w27
[vagrant@manager01 ~]$ docker node ls
ID                            HOSTNAME    STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
s4bm4um4k88nzqc6avq55e012 *   manager01   Ready     Drain          Leader           20.10.10
frvz22bn7rd0uyxdawe9vn6cv     manager02   Ready     Drain          Reachable        20.10.10
nf4yl2jsatypawskypd77kgqt     manager03   Ready     Drain          Reachable        20.10.10
uwhi7yqd7ir3oqy6r32bkz513     worker01    Ready     Active                          20.10.10
ykhntr9vgpdkibgacbjapj8xz     worker02    Ready     Active                          20.10.10
[vagrant@manager01 ~]$ 

まとめ

本稿ではDocker Swarmマネージャ3台のHA構成で、

  • マネージャ1台の喪失 = 定足数(Quorum; クォーラム)を満たした状態
  • マネージャ2台の喪失 = 定足数を満たさない状態
  • マネージャ3台の喪失 = 全滅状態

の3パターンの障害からの復旧方法を見てきました。

Swarmマネージャは障害に対して堅牢かつ比較的容易に復旧できるようになっており、さらにSwarmワーカーで既に起動しているワークロードには極力影響を与えないようになっています。

しかしそれは十分な定足数を持つHA構成を取っていること、定期的にバックアップを取っていること、そしてリストアの予行演習などの準備ができていることといった、非常時への備えが平常時からできていることが大前提です。Swarmクラスタの設定・状態や、動作中のアプリによっては本稿で記載した通りに復旧が行えない可能性もありえます。是非皆様のクラスタの場合において、万が一の障害に備えた準備を日頃から行っておくようにしてください。本稿がその一助となれば幸いです。

CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post

[無料ウェビナー] GitLab_CI/CDハンズオン_2023111