kubernetes構築ツール(kubespray, k0sctl, k3s)を比較してみた！

こんにちは！
ネットワークコンテンツ研究会 Nekko Cloud Teamのいるまるです。

現在、Nekko Cloud TeamではプライベートKubernetes基盤の開発に取り組んでいます。Kubernetesクラスターを構築するにあたり、様々な方法が存在し、その選択に悩みました。そこで今回は「高可用なKubernetesクラスターの構築」に焦点を当て、いくつかの構築ツールを比較したいと思います。

今回は以下のツールを比較します。
- kubespray
- k0sctl
- k3s

:::note info
間違いや、アップデートによる仕様変更等ありましたら、コメントにて教えて頂けるとありがたいです。
:::

# 実験する構成について

今回は、高可用なKubernetesクラスター自体の構築ツールについて比較します。
そのため、CNIや**kube-apiserverのロードバランサーなどKubernetes自体以外の部分は高可用構成となっていなかったり**、詳しく説明されていなかったりします。

# クラスターに使用するVMをセットアップ

今回の検証では以下のVMを3台作成しました。
- OS: ubuntu server 22.04 cloudimg
- CPU: 8Core
- RAM: 8GiB
- ROM: 32GiB
- 構築場所: ProxmoxVE(弊サークルのプライベートクラウド基盤を使用)

VMでは以下の設定を行いました。
- ssh鍵の設定
    本記事で公開鍵として`k8s_test`の表記があるものは、すべてここで設定したものです。
- Firewallの無効化

### クラスターのIPアドレス

| 図のVM名 | VMのホスト名 | VMのIPv4アドレス | VMのIPv6アドレス          |
| -------- | ------------ | ---------------- | ------------------------- |
| haproxy  | k8s-test-lb  | 192.168.16.193   | fd12::be24:11ff:fe9d:af10 |
| VM-1     | k8s-test-1   | 192.168.16.189   | fd12::be24:11ff:fe56:cf79 |
| VM-2     | k8s-test-2   | 192.168.16.190   | fd12::be24:11ff:fe63:5121 |
| VM-3     | k8s-test-3   | 192.168.16.191   | fd12::be24:11ff:fe14:e491 |

# kubespray

### 概要

> Kubesprayは、汎用的なOSやKubernetesクラスターの構成管理タスクのためのAnsibleプレイブック、インベントリー、プロビジョニングツール、ドメインナレッジをまとめたものです。
> https://kubernetes.io/ja/docs/setup/production-environment/tools/kubespray/

kubesprayはkubernetes-sigsによりメンテナンスされている、AnsibleをベースとしたKubernetes clusterの構築ツールです。

kubesprayは、クラスター構成を設定ファイルに記述して、これを元にクラスターをデプロイします。

### 実験環境

![kubespray.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613660/0aa3d9e9-3806-8c8c-318f-2981b8171f1b.png)


### kubesprayのセットアップ

PC-2で実行
```
git clone https://github.com/kubernetes-sigs/kubespray.git
cd kubespray
git branch -a
git switch remotes/origin/release-2.21 --detach
pip install -r requirements.txt
```

`git switch`で実行したいkubesprayのバージョンを選択します。
`pip`を使用するため、長期的に安定動作させたい場合や環境を汚したくない場合は、devcontainerを使用すると便利です。

### cluster設定をする

PC-2で実行

1. `inventory/sample`を`inventory/test-cluster`にコピーする
1. VM-1～VM-3のSSH鍵を`inventory/test-cluster/k8s-test`へコピーする
1. `inventory/test-cluster/inventory.ini`を以下のように編集する
    ```inventory.ini
    [all]
    node1 ansible_host=192.168.16.189 ansible_user=ncadmin ip=192.168.16.189 etcd_member_name=etcd1
    node2 ansible_host=192.168.16.190 ansible_user=ncadmin ip=192.168.16.190 etcd_member_name=etcd2
    node3 ansible_host=192.168.16.191 ansible_user=ncadmin ip=192.168.16.191 etcd_member_name=etcd3

    [kube_control_plane]
    node1
    node2
    node3

    [etcd]
    node1
    node2
    node3

    [kube_node]
    node1
    node2
    node3

    [calico_rr]

    [k8s_cluster:children]
    kube_control_plane
    kube_node
    calico_rr
    ```
1. `inventory/test-cluster/group_vars/k8s_cluster/k8s-cluster.yml`の以下の項目をtrueに編集する
    `inventory/test-cluster/artifacts`でkubeconfigを取得するために必要です
    ```
    # Make a copy of kubeconfig on the host that runs Ansible in {{ inventory_dir }}/artifacts
    kubeconfig_localhost: true
    # Use ansible_host as external api ip when copying over kubeconfig.
    kubeconfig_localhost_ansible_host: true
    # Download kubectl onto the host that runs Ansible in {{ bin_dir }}
    kubectl_localhost: true
    ```

### クラスターをセットアップする

```
ansible-playbook -i inventory/test-cluster/inventory.ini --private-key inventory/test-cluster/k8s-test --become --become-user=root cluster.yml
```

処理が終われば、クラスターのセットアップは完了です。

### クラスターをアップグレードする

`inventory/test-cluster/group_vars/k8s_cluster/k8s-cluster.yml`の`.kube_version`をアップグレード後のバージョンへ変更します。

アップグレードをPC-2で実行
```
ansible-playbook -i inventory/test-cluster/inventory.ini --private-key inventory/test-cluster/nc-k8s-test --become --become-user=root upgrade-cluster.yml
```

処理が終われば、クラスターのアップグレードは完了です。

### 実行時間

- セットアップ時間(1.29.7): 14分30秒
- アップグレード時間(1.29.7 -> 1.30.4): 25分17秒

### 注意事項

cluster再作成時は、kubesprayを一度削除し再作成する必要がありました。
kubesprayをそのまま使用した場合、artifactsがキャッシュされている？のか、なぜかkubeconfigが古いクラスターのまま更新されませんでした。

# k0sctl

### 概要

>Deploy and run Kubernetes workloads at any scale on any infrastructure.
>All batteries included. 100% open source & free.
> https://k0sproject.io/

k0sは単一のバイナリとして提供され、コントロールプレーンやノード上でKubernetesクラスターのセットアップやアップグレードに使用されます。各ノードに対してk0sを手動で1つずつセットアップすることも可能ですが、k0sctlを利用することで、1台の端末から複数のコントロールプレーンやノードを含むKubernetesクラスターを一括でセットアップできます。

k0sおよびk0sctlはMirantisによってメンテナンスされています。

k0sctlは、kubesprayと同様に設定ファイルを用いてクラスターの構成を定義し、これに基づいてクラスターをデプロイします。

### 実験環境

![k0sctl.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613660/2ef03441-d7ea-3c20-653c-7b91a071f7a3.png)


### k0sctlのセットアップ

PC-2で実行
```
brew install k0sproject/k0sctl
```

### クラスターのセットアップ

PC-2で以下の設定ファイルを作成
```k0sctl.yaml
apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: k0s-cluster
spec:
  hosts:
  - role: controller+worker
    ssh:
      address: 192.168.16.189
      user: ncadmin
      keyPath: ../k8s-test
  - role: controller+worker
    ssh:
      address: 192.168.16.190
      user: ncadmin
      keyPath: ../k8s-test
  - role: controller+worker
    ssh:
      address: 192.168.16.191
      user: ncadmin
      keyPath: ../k8s-test
  k0s:
    version: 1.31.1+k0s.0
    dynamicConfig: false
    config:
      spec:
        network:
          provider: "calico"
          calico:
            mode: "bird"
          podCIDR: "172.18.0.0/16"
          serviceCIDR: "172.19.0.0/16"
          dualStack:
            enabled: true
            IPv6podCIDR: "fd3b:15a9:3b12:2002::/108"
            IPv6serviceCIDR: "fd3b:15a9:3b12:2003::/108"
        api:
          externalAddress: 192.168.16.193
          sans:
          - 192.168.16.189
          - 192.168.16.190
          - 192.168.16.191
```

PC-2で実行
```
k0sctl apply --config k0sctl.yaml
```

処理が終われば、クラスターのセットアップは完了です。

### kubeconfigの取得

PC-2で実行
```
k0sctl kubeconfig --config k0sctl.yaml > config
```

### アップグレード方法

`k0sctl.yaml`の`.spec.k0s.version`を変更します。

インストール時と同じコマンドをPC-2で実行
```
k0sctl apply --config k0sctl.yaml
```

処理が終われば、クラスターのアップグレードは完了です。

### 実行時間

- セットアップ時間(v1.30.5): 1分24秒
- アップグレード時間(v1.30.5 -> v1.31.1): 2分12秒

# k3s

### 概要

> The certified Kubernetes distribution built for IoT & Edge computing
> https://k3s.io/

リソースが限られた環境向けに構築された、非常に軽量なKubernetesディストリビューションです。

k3sはRancherによって開発され、現在はCNCFのサンドボックスプロジェクトとして運営されています。

k3sでは、最初のノードのセットアップ時にクラスターが作成され、同時にトークンが生成されます。2台目以降のノードは、このトークンを使用してクラスターに参加する形式を採用しています。

### 実験環境

![k3s.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613660/b8d02958-f8f7-8ecd-640d-7752910ca602.png)


### 1台目のセットアップ

VM-1で実行
```
// 1台目のセットアップ
curl -sfL https://get.k3s.io | K3S_TOKEN=SECRET INSTALL_K3S_VERSION=v1.29.9+k3s1 sh -s - server \
	--node-taint CriticalAddonsOnly=true:NoExecute \
    --cluster-init \
    --tls-san=fd12::be24:11ff:fe9d:af10

// tokenの取得
sudo cat /var/lib/rancher/k3s/server/node-token
// 結果
K1006aefec7cc45005796b2bbdf9ad8e751f9a5befd065c78727fb27e8d380ff4d3::server:SECRET
```

### 2台目以降のセットアップ

VM-2とVM-3で実行
※K3S_TOKEN=の値をVM-1で取得したtokenに書き換え
```
curl -sfL https://get.k3s.io | K3S_TOKEN=K1006aefec7cc45005796b2bbdf9ad8e751f9a5befd065c78727fb27e8d380ff4d3::server:SECRET INSTALL_K3S_VERSION=v1.29.9+k3s1 sh -s - server \
	--node-taint CriticalAddonsOnly=true:NoExecute \
    --server https://[fd12::be24:11ff:fe9d:af10]:6443
```

### アップグレード方法

インストール時に使用したコマンドに、`INSTALL_K3S_VERSION`オプションを追加する形でアップグレードします。

VM-1で実行
```
curl -sfL https://get.k3s.io | K3S_TOKEN=SECRET INSTALL_K3S_VERSION=v1.30.5+k3s1 sh -s - server \
	--node-taint CriticalAddonsOnly=true:NoExecute \
    --cluster-init \
    --tls-san=fd12::be24:11ff:fe9d:af10
```

VM-2とVM-3で実行
```
curl -sfL https://get.k3s.io | K3S_TOKEN=K1006aefec7cc45005796b2bbdf9ad8e751f9a5befd065c78727fb27e8d380ff4d3::server:SECRET INSTALL_K3S_VERSION=v1.30.5+k3s1 sh -s - server \
	--node-taint CriticalAddonsOnly=true:NoExecute \
    --server https://[fd12::be24:11ff:fe9d:af10]:6443
```

### 実行時間

セットアップとアップグレード両方とも数秒程度で完了しました。

# Podのデプロイに関して

**k0sctlとk3sは、初期状態ではコントロールプレーンが設定されたノードにPodがデプロイできません。**
そのため、Nodeに設定されたTaintを削除する必要があります。

### Taintの削除方法

Taintの確認
```
kubectl describe nodes | grep Taints
```

Taintの削除
```
kubectl taint nodes k8s-test-1 CriticalAddonsOnly=true:NoExecute-
```

# まとめ

### 実行時間

実行時間は以下のようになりました。

|           | セットアップ実行時間 | アップグレード実行時間 |
| --------- | -------------------- | ---------------------- |
| kubespray | 14分30秒             | 25分17秒               |
| k0sctl    | 1分24秒              | 2分12秒                |
| k3s       | 数秒程度             | 数秒程度               |

### セットアップ・アップグレード

k3sでは、クラスター内の各VMに対して直接コマンドを実行する必要がありますが、クラスター外の端末を使用しなくて済むというメリットがあります。
一方で、k0sctlとkubesprayは、どちらもクラスター外の端末から設定ファイルを元にSSHを用いて、遠隔でデプロイを行います。
そのため、デプロイ時の冪等性を重視する場合は、k0sctlやkubesprayの方が便利でしょう。

### 結論

結論として、弊サークルのKubernetesクラスター構築ツールは、現時点（調査時点）ではkubesprayを採用する予定です。

その理由は以下の通りです。
- クラスター構成をテスト環境と一致させる冪等性を考慮すると、k0sctlまたはkubesprayが適している
- k0sctlはエラー発生時のログが、kubesprayよりも読みづらかった

なお、これらのツールを使用して構築するクラスターは同じKubernetesであるものの、利用できる機能や構成に差異があります。そのため、構築ツールの選定にあたっては、利便性以外の要素も考慮する必要があります。

例えば、以下の要素が挙げられます。
- リソースの限られたクラスターを構築する場合はk3sが選択肢に入る
- 自動アップグレードが必要な場合はk3sが有力な候補となる
- 使用したいCNIがサポートされている構築ツールの確認が必要
- 複雑な構成のクラスターを構築する際、テストしやすいツールの選定が重要

# おまけ

ProxmoxVEで今回のような検証をする場合、スナップショットを活用すると、以下のようなときに便利です。
- クラスター構築に失敗して、OSインストール直後の状態に戻したい
- 現在の状態を残して、別の検証がしたい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613660/f5eaeec4-f42e-6ff0-0262-9c8a2b608130.png)

# 参考文献

https://kubespray.io/#/
https://docs.k0sproject.io/head
https://docs.k3s.io/ja/
https://www.the38.page/posts/high-availability-k3s-cluster-setup/