Kubespray での Kubernetes Cluster 構築 (v2.20.0 containerd)

## はじめに
[過去に Kubespray で Kubernetes クラスタを構築している](https://qiita.com/suzuyui/items/ed6534dd4181bc2c93a1)が、[kubespray は docker から containerd への移行は正式にサポートされていない(ただし移行方法例の記載はある)](https://github.com/kubernetes-sigs/kubespray/blob/master/docs/upgrades/migrate_docker2containerd.md)

既存クラスタを削除して Containerd のクラスタを再作成したので実施したメモを記載する
([kubespray v2.18.0 でデフォルトが containerd になった](https://github.com/kubernetes-sigs/kubespray/releases/tag/v2.18.0)ので最新バージョン(v2.20.0)であればデフォルトで入れ直せばcontainerdになる)

設定内容は[過去の構築](https://qiita.com/suzuyui/items/ed6534dd4181bc2c93a1)や[MetalLB実践](https://qiita.com/suzuyui/items/c83554dd055ef0f4253a)と同じなので説明や重複箇所はそちらも参照

## 実行環境

- ESXi
    - Version: 7.0u2a
    - license: Free
- Network (Server Gateway Router)
    - Edgerouter-X (ER-X)
    - Version: v2.0.9-hotfix.2
- kubespray サーバ
    - OS : Rocky Linux release 9.0 (Blue Onyx)
- Kubernetes ノード
    - OS : Ubuntus Ubuntu 22.04.1 LTS
    - インストールのみ完了した状態
    - 準備方法は 20.04 LTS 時に実施した内容とほぼ同じなので省略 ([参照先](https://qiita.com/suzuyui/items/ed6534dd4181bc2c93a1#vm-%E6%A7%8B%E7%AF%89))

### 設定 version

- Kubernetes Version
    - v1.25.4 (kubespray [v2.20.0](https://github.com/kubernetes-sigs/kubespray/releases/tag/v2.20.0) default)
- コンテナランタイム
    - containerd v1.6.10 (kubespray [v2.20.0](https://github.com/kubernetes-sigs/kubespray/releases/tag/v2.20.0) default)
- MetalLB
    - L3 mode BGP ([過去実践記事](https://qiita.com/suzuyui/items/c83554dd055ef0f4253a))

## 構築

### kubespray 実行準備

kubespray (ansible) 実行サーバの環境準備を実施する (Rocky9入れたばかりのサーバを想定)

```sh
sudo dnf install git python3 python3-pip sshpass -y
```

下記 kubespray をダウンロードして必要なモジュール (ansible etc.) を pip3 でインストールする

```sh
cd ~
git clone https://github.com/kubernetes-sigs/kubespray.git
cd kubespray
git checkout v2.20.0
pip3 install -r requirements.txt
```

クラスタ情報 hosts.yaml を作成する ([過去記事参照](https://qiita.com/suzuyui/items/e5794e23045c9ae82a1c#1-hostsyaml-%E3%81%AE%E6%BA%96%E5%82%99))

```sh
cp -rfp inventory/sample inventory/mycluster
vi ~/kubespray/inventory/mycluster/hosts.yaml
```

下記hosts.yaml例

```~/kubespray/inventory/mycluster/hosts.yaml
all:
  hosts:
    k8smaster01:
      ansible_host: 192.168.129.25
      ip: 192.168.129.25
      access_ip: 192.168.129.25
    k8smaster02:
      ansible_host: 192.168.129.35
      ip: 192.168.129.35
      access_ip: 192.168.129.35
    k8smaster03:
      ansible_host: 192.168.129.26
      ip: 192.168.129.26
      access_ip: 192.168.129.26
    k8sworker01:
      ansible_host: 192.168.129.27
      ip: 192.168.129.27
      access_ip: 192.168.129.27
    k8sworker02:
      ansible_host: 192.168.129.36
      ip: 192.168.129.36
      access_ip: 192.168.129.36
    k8sworker03:
      ansible_host: 192.168.129.37
      ip: 192.168.129.37
      access_ip: 192.168.129.37
    k8scalicorr01:
      ansible_host: 192.168.129.28
      ip: 192.168.129.28
      access_ip: 192.168.129.28
    k8scalicorr02:
      ansible_host: 192.168.129.38
      ip: 192.168.129.38
      access_ip: 192.168.129.38
  children:
    kube-master:
      hosts:
        k8smaster01:
        k8smaster02:
        k8smaster03:
    kube-node:
      hosts:
        k8sworker01:
        k8sworker02:
        k8sworker03:
    etcd:
      hosts:
        k8smaster01:
        k8smaster02:
        k8smaster03:
    k8s-cluster:
      children:
        kube-master:
        kube-node:
        calico-rr:
    calico-rr:
      hosts:
        k8scalicorr01:
        k8scalicorr02:
    rack0:
      hosts:
        k8scalicorr01:
        k8scalicorr02:
        k8smaster01:
        k8smaster02:
        k8smaster03:
        k8sworker01:
        k8sworker02:
        k8sworker03:
      vars:
        cluster_id: "1.0.0.1"
```

各ノードの `ufw の停止`や`ssh key 設定`などの[事前準備設定](https://qiita.com/suzuyui/items/ed6534dd4181bc2c93a1#kubespray-%E4%BA%8B%E5%89%8D%E8%A8%AD%E5%AE%9A)を実施する (詳細は[過去記事に記載](https://qiita.com/suzuyui/items/ed6534dd4181bc2c93a1#kubespray-%E4%BA%8B%E5%89%8D%E8%A8%AD%E5%AE%9A)のまま)


### MetalLB 設定

MetalLB は addon で入れられる
設定例は下記の通り ([MetalLBについてはこちらの記事を参照](https://qiita.com/suzuyui/items/c83554dd055ef0f4253a))

```sh
cd ~/kubespray/inventory/mycluster/group_vars/k8s_cluster/
cp -p k8s-cluster.yml k8s-cluster.yml.org
vi k8s-cluster.yml
```

```diff:k8s-cluster.yml
# configure arp_ignore and arp_announce to avoid answering ARP queries from kube-ipvs0 interface
# must be set to true for MetalLB to work
- kube_proxy_strict_arp: false
+ kube_proxy_strict_arp: true
```


```sh
cp -p addons.yml addons.yml.org
vi addons.yml
```

#### L3mode

```diff:addons.yml
- metallb_enabled: false
+ metallb_enabled: true
+ metallb_ip_range:
+   - 192.168.131.0/24
+ metallb_protocol: bgp
+ metallb_peers:
+   - peer_address: 192.168.129.254
+     peer_asn: 65001
+     my_asn: 65002
+ metallb_avoid_buggy_ips: true
+ metallb_speaker_tolerations:
+   - key: "node-role.kubernetes.io/control-plane"
+     operator: "Equal"
+     value: ""
+     effect: "NoSchedule"
+ metallb_controller_tolerations:
+   - key: "node-role.kubernetes.io/control-plane"
+     operator: "Equal"
+     value: ""
+     effect: "NoSchedule"
```

#### L2mode

```diff:addons.yml
- metallb_enabled: false
+ metallb_enabled: true
+ metallb_speaker_enabled: true
+ metallb_avoid_buggy_ips: true
+ metallb_ip_range:
+   - "192.168.129.100-192.168.129.199"
+ metallb_protocol: "layer2"
+ metallb_speaker_tolerations:
+   - key: "node-role.kubernetes.io/control-plane"
+     operator: "Equal"
+     value: ""
+     effect: "NoSchedule"
+ metallb_controller_tolerations:
+   - key: "node-role.kubernetes.io/control-plane"
+     operator: "Equal"
+     value: ""
+     effect: "NoSchedule"
```

### kubespray 実行

必要な設定記載やノード側下準備が完了したので、`cluster.yml`を実行してインストールを実施する

```sh
cd ~/kubespray
ansible-playbook -i inventory/mycluster/hosts.yaml -K --become --become-user=root cluster.yml
```

[.kube/config 設定の過去記事を参照](https://qiita.com/suzuyui/items/ed6534dd4181bc2c93a1#kubeconfig-%E8%A8%AD%E5%AE%9A)してローカルサーバに認証情報取得など実施する (今回、k8**s**maser01など入れ替えのため `s` を追加しているので`hostvars`指定箇所はそこだけ修正が必要)


実行サーバから kubectl でアクセスできるようになったことを確認する (kubectl がなければ[インストール](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-using-native-package-management)して実施)

```sh
$ kubectl get node
NAME            STATUS   ROLES           AGE   VERSION
k8scalicorr01   Ready    <none>          58m   v1.24.6
k8scalicorr02   Ready    <none>          58m   v1.24.6
k8smaster01     Ready    control-plane   61m   v1.24.6
k8smaster02     Ready    control-plane   60m   v1.24.6
k8smaster03     Ready    control-plane   60m   v1.24.6
k8sworker01     Ready    <none>          58m   v1.24.6
k8sworker02     Ready    <none>          58m   v1.24.6
k8sworker03     Ready    <none>          58m   v1.24.6
```

上記で構築完了

### その他
設定後に MetalLB の設定を変更したい場合は下記タグで対応する

```sh
cd ~/kubespray/
ansible-playbook -i inventory/mycluster/hosts.yaml -K --become --become-user=root cluster.yml --tags metallb
```

## まとめ
containerd 対応のため kubespray v2.20.0 でクラスタ再作成を実施した

addon で `argocd` や `ingress`, ストレージ系などもサポートされているのでそちらも試したい

また、ここで書いた hosts.yaml の記載方法が [legacy](https://github.com/kubernetes-sigs/kubespray/blob/c49dd50ef352752ad4d8bfec1013c469d44a1901/legacy_groups.yml) になっているので、修正を次のタイミングでしたい


## 追記
このクラスタで LoadbalancerIP へのアクセスがアサイン IP によってうまくいかない事象が発生した
MetalLB を L3/L2 両方で試したが直らず原因も不明だが、
CNI を`calico` -> `cilium` へ変更, `calicorr` ノードを含めない構成に変更したら問題が解消された

```diff_yaml:diff_k8s-cluster.yml_k8s-cluster.yml.org
- kube_network_plugin: calico
+ kube_network_plugin: cilium
- kube_proxy_strict_arp: false
+ kube_proxy_strict_arp: true
```