kubeadmで作ったKubernetesをちゃんと作り直そう

# はじめに

kubeadmで作ったKubernetesクラスターを何らかの事情で作り直す際に、各ノードで``kubeadm reset``コマンドでクリーンアップした後に``kubeadm init``(または``kubeadm join``)を実行する必要があります。しかしながら、単に``kubeadm reset``をやっただけではiptablesのルールやCNIに関する設定が残ったままで、再作成が上手く行かないケースがあります。

Webで調べると、クラスターの再作成でつまずかないためには「``iptables -F``と``iptables -X``を実行する」とか「Kubernetesに関する設定ファイルを全部消す」とか「kubeletを停止する」とか色んな情報が出てきます。私自身これまであまり深く考えずそれらの情報をごった煮にして、次のようなコマンドをおまじないで実行してきました。

```
sudo systemctl stop kubelet
sudo kubeadm reset -f
sudo iptables -F
sudo iptables -t nat -F
sudo iptables -t mangle -F
sudo iptables -t raw -F
sudo iptables -X
sudo iptables -t nat -X
sudo iptables -t mangle -X
sudo iptables -t raw -X
sudo rm -rf /var/lib/etcd
sudo rm -rf /etc/kubernetes
sudo rm -rf /var/lib/cni
sudo rm -rf /etc/cni
rm -rf ~/.kube
```

ところがある時、いつものように上のコマンドを実行したら、同じノードでKubernetesとは独立して動いていたDockerが動かなくなってしまいました。

後になってわかったのですが、``iptables -F``や``iptables -X``を実行したことで、Dockerに関するiptablesのルールとチェインが消えてしまい、結果Dockerが動かなくなったのです。Kubernetes作り直しの度に私は毎回、iptablesのルールを全消ししていたわけですね。あな恐ろしや...

[Kubernetesの公式サイト](https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%89%8A%E9%99%A4)にも「iptablesをリセットしたい場合は``iptables -F``や``iptables -X``をやってねー」と軽い感じで書いてあるのですが、どうやらこのお二方は``rm -rf /``（通称バルス）の域にはいかないまでも、決して軽く扱ってはいけないお方のようです。

これを機に「何も理解せずにおまじないを続けてはいけないな、ちゃんと理解して必要なコマンドだけ実行しよう」と改心しました。

本記事はこのような背景を踏まえ、「kubeadmで作ったKubernetesを再作成する前に必要最低限やること」について記載しています。

# Kubernetesクラスターの削除手順

以下に2つのケースにおける削除手順を記載します。
**Controle Planeだけではなく、Workerノードでも実行する必要がある**ことを忘れないようご注意ください。

※ 動作を確認したKuberenetesのバージョンはv1.29.5です。

## ケース1：CNIを同じものを使う場合

クラスター再作成時に前と同じCNIを使う（例えばCilium→Cilium、Flannel→Flannel等）のであれば、以下のコマンドのみ実行すればOKです。

```
sudo kubeadm reset -f
```

``-f``オプションは必須ではないですが、これを入れておくとコマンド実行後に「本当に消していいか？」の対話型の入力をスキップすることができます。

``kubeadm reset``を実行後の出力を見ればわかりますが、kubernetesに関する以下のディレクトリやファイルはこのコマンドが勝手に消してくれるので、後で手動で削除コマンドを実行しなくても大丈夫です。

* /var/lib/etcd
* /etc/kubernetes/manifests
* /var/lib/kubelet
* /etc/kubernetes/pki
* /etc/kubernetes/admin.conf
* /etc/kubernetes/super-admin.conf
* /etc/kubernetes/kubelet.conf
* /etc/kubernetes/bootstrap-kubelet.conf
* /etc/kubernetes/controller-manager.conf
* /etc/kubernetes/scheduler.conf

## ケース2：異なるCNIを使う場合

クラスター再作成時に別のCNIを使いたい場合（例えばFlannel→Cilium等）は、以下の手順で前に使っていたCNIの各種設定を消す必要があります。

### (2-1) 以下のコマンドを順次実行

```
sudo kubeadm reset -f
sudo find /var/lib/cni -mindepth 1 -delete
sudo rm -rf /etc/cni/*
```

:::note info
上記の2番目のコマンドは、``/var/lib/cni``ディレクトリ内の全てのファイルを消すコマンドです。このディレクトリの権限が0600で、``sudo rm -rf /var/lib/cni/*``だとファイル消去できないために上のコマンドに変えています。
:::

### (2-2) CNIに関するネットワークインターフェースの削除

```
sudo ip link delete <インターフェース名>
```
CNIが作ったインターフェース名が何なのかについてですが、CNIがFlannelとCiliumの場合に現時点(24/06/09時点)で以下であることを確認できました。

* Flannel
    * flannel.1
    * cni0
    * 先頭がvethで始まるもの（ない場合もある？）
* Cilium
    * cilium_vxlan
    * cilium_net

これ以外のCNIを使っている場合は、各自でご確認いただければと思います。

### (2-3) CNIに関するiptablesのルールとチェインを削除

「CNIに関するルールとチェインのみを削除したい」場合は少々工夫が要ります。この後、特定のチェインに限定したルールを削除するシェルスクリプトをご紹介します。

時短優先で「iptablesのルール全消しで問題ないよ！」という方は以下のコマンドでもOKですが、<font color="red">**十分注意した上で自己責任で実行してください。**</font>

```
sudo iptables -F
sudo iptables -t nat -F
sudo iptables -t mangle -F
sudo iptables -t raw -F
sudo iptables -X
sudo iptables -t nat -X
sudo iptables -t mangle -X
sudo iptables -t raw -X
```

#### 特定のチェインと、そのルールを全て削除するスクリプト

以下のスクリプトにより、指定したiptablesのチェインに関するルールのみを削除でき、「iptablesのルール全消し」を回避できます。

```sh:clear-iptables-chain.sh
#!/bin/bash
CHAIN="$1"

if [ "$#" -ne 1 ]; then
    echo "Usage: $0 <chain_name>"
    exit 1
fi

declare -A TABLE_CHAINS
TABLE_CHAINS=(
    ["filter"]="INPUT OUTPUT FORWARD"
    ["nat"]="PREROUTING POSTROUTING OUTPUT"
    ["mangle"]="PREROUTING POSTROUTING INPUT OUTPUT FORWARD"
    ["raw"]="PREROUTING OUTPUT"
    # ["security"]="INPUT OUTPUT FORWARD" # 必要ならば追加
)

# テーブル毎のループ。 filter, nat, mangle, rawの4種類ある
for TABLE in "${!TABLE_CHAINS[@]}"; do

    # ビルトインチェインから該当チェインに送るルールを全て削除
    for BUILTIN_CHAIN in ${TABLE_CHAINS[$TABLE]}; do
        sudo iptables -t $TABLE -L $BUILTIN_CHAIN -n --line-numbers | grep $CHAIN | while read -r line; do
            RULE_NUM=$(echo $line | awk '{print $1}')
            sudo iptables -t $TABLE -D $BUILTIN_CHAIN $RULE_NUM
            echo "Deleted rule number $RULE_NUM in table $TABLE in chain $BUILTIN_CHAIN with target $CHAIN"
        done
    done

    if sudo iptables -t $TABLE -L $CHAIN &> /dev/null; then
        echo "Found chain $CHAIN in table $TABLE"
        # 指定したチェインに属するルールを削除
        sudo iptables -t $TABLE -F $CHAIN
        echo "Deleted all rules in chain $CHAIN"
        # 指定したチェインを削除
        sudo iptables -t $TABLE -X $CHAIN
        echo "Deleted chain $CHAIN"
    fi

done
```

利用例を以下に記載します。

##### Flannelの場合

```
./clear-iptables-chain.sh FLANNEL-FWD && \
./clear-iptables-chain.sh FLANNEL-POSTRTG
```

##### Ciliumの場合

```
./clear-iptables-chain.sh CILIUM_FORWARD && \
./clear-iptables-chain.sh CILIUM_INPUT && \
./clear-iptables-chain.sh CILIUM_OUTPUT && \
./clear-iptables-chain.sh CILIUM_OUTPUT_nat && \
./clear-iptables-chain.sh CILIUM_POST_nat && \
./clear-iptables-chain.sh CILIUM_PRE_nat && \
./clear-iptables-chain.sh CILIUM_OUTPUT_raw && \
./clear-iptables-chain.sh CILIUM_PRE_raw && \
./clear-iptables-chain.sh CILIUM_POST_mangle && \
./clear-iptables-chain.sh CILIUM_PRE_mangle
```

# おわりに

結構試行錯誤して、Kubernetesを作り直す一つの手法を曲がりなりにも導き出しましたが、各CNIでネットワークインターフェースやiptablesを削除するツールが提供されていると嬉しいなあと思いました。本当はあるけど単に自分が知らないだけかもしれませんが。