kubeadmでcontrol nodeをjoinさせるときに発生するetcd cluster is not healthyの対処法

# 前提
タイトルのerrorはkubeadmでk8sをHA構成で構築している時に一度削除したcontrol nodeをもう一度追加しようとした時のerrorです。

# TL;DR
errorを吐いているnodeのipは`192.168.110.12`
```
$ kubectl exec etcd-control-node0 -n kube-system -it -- sh
sh-5.2# etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    member list -w table
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
|        ID        | STATUS  |     NAME      |         PEER ADDRS          |        CLIENT ADDRS         | IS LEARNER |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
| 233150a5485a40d9 | started | control-node2 | https://192.168.110.12:2380 | https://192.168.110.12:2379 |      false |
| 52334327109b3fe3 | started | control-node0 | https://192.168.110.10:2380 | https://192.168.110.10:2379 |      false |
| a054738f4e5ba2c5 | started | control-node1 | https://192.168.110.11:2380 | https://192.168.110.11:2379 |      false |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
sh-5.2# etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    member remove 233150a5485a40d9
sh-5.2# etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    member list -w table
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
|        ID        | STATUS  |     NAME      |         PEER ADDRS          |        CLIENT ADDRS         | IS LEARNER |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
| 52334327109b3fe3 | started | control-node0 | https://192.168.110.10:2380 | https://192.168.110.10:2379 |      false |
| a054738f4e5ba2c5 | started | control-node1 | https://192.168.110.11:2380 | https://192.168.110.11:2379 |      false |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
```

# error発生時の状況
まず諸事情によりkubeadmのcontrol nodeを削除しました。
```
control-node1 $ sudo kubeadm reset
control-node0 $ sudo kubectl delete node control-node1
```

そして、control-node1をOS installから作り直しもう一度joinさせました。
`kubeadm-config.yaml`はjoinの時の設定が書かれたfileです。
```
control-node1 $ sudo kubeadm join --config kubeadm-config.yaml
```
しかし、下記のようなerrorが表示されました。
```
[check-etcd] Checking that the etcd cluster is healthy
error execution phase check-etcd: etcd cluster is not healthy: failed to dial endpoint https://192.168.110.12:2379 with maintenance client: context deadline exceeded
To see the stack trace of this error execute with --v=5 or higher
```

# 試行錯誤
私はalmalinuxを使っているので`firewalld`かと思ったのですが、portはしっかりと開いていました。
etcdには2379portが使われます。
```
$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp1s0
  sources:
  services: cockpit dhcpv6-client ssh
  ports: 6443/tcp 2379-2380/tcp 10250-10252/tcp
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
```
selinuxはもちろん無効化してあります。
```
$ getenforce
Disabled
```

そして次章のissueに辿り着きました。

# 対処

https://github.com/kubernetes/kubeadm/issues/1432

> If nodes terminated or shutdown, i use etcdctl to remove this etcd member. It could not use kubeadm. And if etcd cluster have two member, one of node goes away, the cluster not health, it maybe need human intervention. 

Thank you, Dear pytimer.

というわけで、`etcdctl`というやつでmemberを確認して削除してみましょう。
しかし、どのnodeにも`etcdctl`なんてcommandはありません。
当たり前です。
etcdはk8sのcontainer上で動作しているのですから。
なので、etcd container上で`etcdctl`を実行している記述を探していたら下記のyoutubeを見つけました。

https://www.youtube.com/watch?v=VZFEi64EB4k

~~まあ、先ほどのissueとyoutubeで本当は時系列が逆だったりするのですが、説明しやすいので、、、~~
というわけで、youtube上で実行されている下記のcommandをcontrol nodeで実行してみます。
```
$ kubectl exec etcd-control-node0 -n kube-system -it -- sh
sh-5.2# etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    member list -w table
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
|        ID        | STATUS  |     NAME      |         PEER ADDRS          |        CLIENT ADDRS         | IS LEARNER |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
| 233150a5485a40d9 | started | control-node2 | https://192.168.110.12:2380 | https://192.168.110.12:2379 |      false |
| 52334327109b3fe3 | started | control-node0 | https://192.168.110.10:2380 | https://192.168.110.10:2379 |      false |
| a054738f4e5ba2c5 | started | control-node1 | https://192.168.110.11:2380 | https://192.168.110.11:2379 |      false |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
```

~~なんかfalseになってるのは無視して~~control-node2がetcdに残っているのが確認できます。
issueが言っていたのはこのことだとわかったので、このetcd memberを削除します。

そのcommandは下記で見つけました。

http://r00t.dk/post/2023/09/04/kubernetes-remove-dead-etcd-node/

これを実行してみます。
```
sh-5.2# etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    member remove 233150a5485a40d9
sh-5.2# etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
    --cert /etc/kubernetes/pki/etcd/peer.crt \
    --key /etc/kubernetes/pki/etcd/peer.key \
    member list -w table
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
|        ID        | STATUS  |     NAME      |         PEER ADDRS          |        CLIENT ADDRS         | IS LEARNER |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
| 52334327109b3fe3 | started | control-node0 | https://192.168.110.10:2380 | https://192.168.110.10:2379 |      false |
| a054738f4e5ba2c5 | started | control-node1 | https://192.168.110.11:2380 | https://192.168.110.11:2379 |      false |
+------------------+---------+---------------+-----------------------------+-----------------------------+------------+
```

削除できたのが確認できました。
再度joinさせてみます。
```
$ sudo kubeadm join --config kubeadm-config.yaml
~~~~~~~~~
Run 'kubectl get nodes' to see this node join the cluster.
```
成功しました。

# 参考文献

https://github.com/kubernetes/kubeadm/issues/1432

https://www.youtube.com/watch?v=VZFEi64EB4k

http://r00t.dk/post/2023/09/04/kubernetes-remove-dead-etcd-node/