ArchLinux+kubeadm+cri-o+flannelでkubernetesクラスタ構築

# はじめに
本記事ではArchLinux上でkubernetesクラスタを構築していきます。基本的には[ArchWiki](https://wiki.archlinux.jp/index.php/Kubernetes#kubeadm_.E3.82.92.E4.BD.BF.E3.81.86)に従いますが、ハマりどころが数ヶ所あったので、そのあたりを中心に書いていきます。

# 構成
```bash
NAME         STATUS   ROLES           AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
takenoko-1   Ready    control-plane   90m   v1.28.2   192.168.220.21   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
takenoko-2   Ready    <none>          90m   v1.28.2   192.168.220.22   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
takenoko-3   Ready    <none>          80m   v1.28.2   192.168.220.23   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
takenoko-4   Ready    <none>          80m   v1.28.2   192.168.220.24   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
```
master1台、worker3台の計4台構成です。
コンテナランタイムはcri-o、CNIはflannelを使用しています。
ArchLinuxのインストールは完了し、ネットワークの設定が完了し名前解決可能であることを前提としています。

# 事前準備
対象マシン: 全マシン

まずスワップを無効にします
```bash
sudo swapoff -a
```
続いて/etc/fstabからスワップの設定を削除します

```bash:etc/fstab
# /dev/mapper/swap none swap defaults 0 0
```

# kubeadmのインストール
対象マシン: 全マシン

必要なパッケージをインストールします
```bash
yay -S kubeadm kubelet kubectl docker cri-o cni-plugins open-iscsi
```

# cri-oの設定
対象マシン: 全マシン

cri-oを起動します
```bash
sudo systemctl enable --now crio
sudo systemctl status crio
```

続いてcri-oの設定を行います
```bash
cat <<EOF | sudo tee /etc/modules-load.d/crio.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward = 1
net.ipv4.ip_nonlocal_bind = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system
```

Arch は cniplugins によって提供されるプラグインを `/usr/lib/cni` と `/opt/cni/bin` の両方にインストールしますが、他のほとんどのプラグイン（例えばクラスタ内デプロイメント、kubelet によって管理されるプラグインなど）はデフォルトでは2番目のディレクトリにしかインストールされません

CRI-O は最初のディレクトリにあるプラグインを探すようにしか設定されていないため、設定を変更しない限り、2 番目のディレクトリにあるプラグインは利用できません

この問題を解決するには、CRI-O の設定ファイルを編集して、プラグインのディレクトリを `/opt/cni/bin` に変更します

```bash:/etc/crio/crio.conf.d/00-plugin-dir.conf
[crio.network]
plugin_dirs = [
  "/opt/cni/bin/",
 ]
```

## kubeletの設定
対象マシン: 全マシン

kubeletを有効化します
```bash
sudo systemctl enable --now kubelet
```

## unqualified-search-domainsの追加
対象マシン: 全マシン

Archではunqualified-search-domainsが設定されていないので、imageの名前が咲楽された場合に名前解決できないエラーが発生することがあります

そのため、 `/etc/NetworkManager/NetworkManager.conf` にunqualified-search-domainsを追加します
```bash:/etc/NetworkManager/NetworkManager.conf
unqualified-search-registries = ["docker.io", "quay.io"]
```

# kube initの実行
対象マシン: master1台

準備が整ったので、kubeadm initを実行します
```bash
sudo kubeadm init --apiserver-advertise-address=192.168.220.21 --pod-network-cidr=10.244.0.0/16 --cri-socket=unix:///var/run/crio/crio.sock
```
`--apiserver-advertise-address=192.168.220.21` はmasterのIPアドレスを指定してください

```bash
Your Kubernetes control-plane has initialized successfully!
```
と表示されれば成功です

その下に表示されるコマンドを実行します
```bash
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

また、その下のworkerのjoinコマンドを控えておいてください
```bash
kubeadm join 192.168.220.25:6443 --token xxx \
        --discovery-token-ca-cert-hash sha256:yyy
```

# クラスタへの参加
対象マシン: worker3台

kubeadm initを実行した際に表示されたコマンドを実行します
```bash
sudo kubeadm join 192.168.220.25:6443 --token xxx \
        --discovery-token-ca-cert-hash sha256:yyy
```

# CNIの設定
対象マシン: master1台

CNIを設定します
```bash
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl apply -f kube-flannel.yml
```

# ノードの確認
対象マシン: master1台

ノードが正常に追加されているか確認します
```bash
kubectl get nodes
```
```bash
NAME         STATUS   ROLES           AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
takenoko-1   Ready    control-plane   90m   v1.28.2   192.168.220.21   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
takenoko-2   Ready    <none>          90m   v1.28.2   192.168.220.22   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
takenoko-3   Ready    <none>          80m   v1.28.2   192.168.220.23   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
takenoko-4   Ready    <none>          80m   v1.28.2   192.168.220.24   <none>        Arch Linux           6.5.7-arch1-1       cri-o://1.28.1
```
全てReadyになっていれば成功です

# トラブルシューティング
- nodeがNotReadyのままReadyにならない
    - まずは再起動してみてください
    - それでもダメな場合は、 `crio.conf` の設定が正しく行えているか確認してください

# あとがき
私の場合は`crio.conf` の設定を見落としており、nodeがNotReadyのままReadyにならないという状態になっていました。
クラスタを運用する上でArchLinux特有の問題はありますが、他のディストリビューションと比較しても手順が少ないことが気に入っています。
今後の運用していく中でより理解を深められたらと思います。

# 参考文献
- ArchWiki Kubernetes
    - https://wiki.archlinux.jp/index.php/Kubernetes#kubeadm_.E3.82.92.E4.BD.BF.E3.81.86
- ArchWiki CRI-O
    - https://wiki.archlinux.org/title/CRI-O#Plugin_Installation