HelmチャートでKubernetesにCiliumをインストール

# はじめに

Kubernetesで使われるCNI(Container Network Interface)の一つであるCiliumを使って、Kubernetesの内部ネットワークを構築してみました。構築にはHelmとHelmfileを使います。

# 動作確認した環境の情報

### Kubernetesクラスター

kubeadmを使ってオンプレミスのマシンにKubernetesクラスターを下表のように構築しています。（``kubectl get nodes -owide``の出力結果をもとに表を作っています）

| 項目 | Control Plane | Worker |
| --- | --- | --- |
| NAME(ノード名) | control-plane | worker01 |
| VERSION | v1.29.3 | v1.29.3 |
| INTERNAL-IP | 100.x.x.x | 100.y.y.y |
| EXTERNAL-IP | \<none> | \<none> |
| OS-IMAGE | Debian GNU/Linux 12 (bookworm) | Ubuntu 20.04.6 LTS |
| KERNEL-VERSION | 6.1.0-18-amd64 | 5.4.0-172-generic |
| CONTAINER-RUNTIME | containerd://1.6.20 | containerd://1.6.28 |

#### 補足

* kubeadmによるK8sクラスターの構築は自作になりますが、以下のツールを利用
    * https://github.com/showchan33/k8s-setup/blob/main/README.ja.md
* INTERNAL-IPが100系になっているのは、ノードのネットワークをTailscaleというメッシュ型のVPNサービスを使っているため。以下は参考記事
    * [Kubernetesクラスターを「クラウド↔自宅ネットワーク」間で作る（Tailscale編）](https://qiita.com/showchan33/items/7500bcb73b10be437e49)

### HelmとHelmfileのバージョン

Control PlaneにHelmとHelmfileをインストールしておく必要があります。今回はそれぞれ以下のバージョンを使いました。

```
$ helm version --short
v3.14.3+gf03cc04
```

```
$ helmfile version -o=short
0.162.0
```

# Ciliumのインストール

Helmfileを使ってCiliumのインストールしていきます。
Helmでのインストール方法は以下のサイトに書かれており、これを参考にHelmfileを作っていきます。

https://docs.cilium.io/en/stable/installation/k8s-install-helm/

ちなみにHelmfileというのは、「KubernetesのHelmチャートを管理するためのツール」です。``helm``コマンドの場合、リポジトリの追加やチャートのインストールを一つ一つ実行していく必要がありますが、それらをYAMLファイルに宣言的に書くことで、Helmチャートが管理しやすくなります。（Dockerを使ったことがあれば、「HelmにおけるHelmfileは、Dockerに対するDocker Compose」と思っていただければわかりやすいでしょう）

## Helmfileを用意

さて、CiliumをHelmチャートからインストールする内容をHelmfileに書き下すと、以下のようになります。

```yaml:helmfile-cilium.yaml
repositories:
- name: cilium
  url: https://helm.cilium.io

releases:
- name: cilium
  namespace: kube-system
  chart: cilium/cilium
  version: 1.15.2
  # 以下は必須ではない
  values:
  - k8sServiceHost: "100.x.x.x" # Control Planeのホスト名またはIPアドレス
  - k8sServicePort: "6443"
  - hubble:
      relay:
        enabled: true
      ui:
        enabled: true
  # - ipam:
  #     operator:
  #       clusterPoolIPv4PodCIDRList: ["192.168.128.0/17"] # CIRDはあくまで一例
```

### valuesで設定している値について

上記のYAMLファイルで最後に記載しているvaluesの設定は必須ではないですが、今回設定した経緯について記載します。

#### k8sServiceHost, k8sServicePort
デフォルトだと``k8sServiceHost``は``10.96.0.1``で、``k8sServicePort``は``443``のようです。ここで``10.96.0.1``は、クラスターネットワークにおけるkube-apiserverのIPアドレスです。
筆者環境だと、Ciliumを最初に構築した際にworkerノードから``10.96.0.1``への通信ができないトラブルが発生しました。そこで、これらの設定値を「ホストOSからアクセスする際のkube-apiserverのIPアドレスとポート」に変更することで解決しました。

#### hubble配下

Hubble UIを有効にするための設定を書いています。以下の「Helm」のタブに書かれたコマンドを参考にKeyValueを指定しています。

https://docs.cilium.io/en/stable/gettingstarted/hubble/#enable-the-hubble-ui

Hubble UIについては[こちら](https://github.com/cilium/hubble-ui)にも書かれていますが、Web上でK8sの各サービスの依存関係を可視化することができます。私もHubble UIを使って、自分が作っているサービスを可視化できた時は結構感動しました！なので、この設定は有効にしておくことをお勧めします。

### clusterPoolIPv4PodCIDRListについて（24/06/16追記）

[ドキュメント](https://docs.cilium.io/en/stable/network/concepts/ipam/cluster-pool/#check-for-conflicting-node-cidrs)によると、CiliumのデフォルトのCIDRが``10.0.0.0/8``のようで、ノードのIPやサービスのCIDRがこの範囲に重なると正常起動しません。したがって重複する場合は、``ipam.operator.clusterPoolIPv4PodCIDRList``に重複しないCIDRを書いてあげる必要があります。

※よく考えると、**kube-apiserverのクラスター中のIPアドレス ``10.96.0.1``はCiliumのデフォルトのPod CIDRと重複している**ので、ここはいつも変更していた方が良さそうですね。

#### その他

今回設定した以外のvaluesについては、以下で確認できます。かなりの数の変数があるので、カスタマイズする際は該当箇所を地道に探していく必要がありそうです。

https://github.com/cilium/cilium/blob/main/install/kubernetes/cilium/values.yaml

## Helmfileを使ってCiliumをインストール

以下のコマンドを実行して、Ciliumをインストールします。

```
helmfile apply -f helmfile-cilium.yaml
```

以下のようにPodがデプロイされればインストール完了です。
```
$ kubectl get pod -A -l app.kubernetes.io/part-of=cilium
NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE
kube-system   cilium-bx8w5                       1/1     Running   0          112s
kube-system   cilium-operator-7cb9969fdf-lw5sd   1/1     Running   0          112s
kube-system   cilium-operator-7cb9969fdf-zb8pq   1/1     Running   0          112s
kube-system   cilium-tg5fj                       1/1     Running   0          112s
kube-system   hubble-relay-d8b6b55c9-z9bf8       1/1     Running   0          112s
kube-system   hubble-ui-6548d56557-vkhpl         2/2     Running   0          112s
```

## Cilium CLIのインストール

必須ではないですが、Ciliumの状況確認や操作を行うために、以下のCilium CLIを入れておくと良さそうです。

https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/#install-the-cilium-cli

インストールすると、次のように``cilium``のコマンドが使えるようになります。

```
$ cilium status
    /¯¯\
 /¯¯\__/¯¯\    Cilium:             OK
 \__/¯¯\__/    Operator:           OK
 /¯¯\__/¯¯\    Envoy DaemonSet:    disabled (using embedded mode)
 \__/¯¯\__/    Hubble Relay:       OK
    \__/       ClusterMesh:        disabled

(以後の出力は省略)
```

# Hubble UIを使ってみる

Hubble UIを使って、クラスター内でのネットワーク経路を可視化してみましょう。

``hubble-ui``というServiceリソースがこれに相当するため、K8sクラスター外のネットワークにポートフォワードするコマンドを実行します。

```
kubectl port-forward -n kube-system svc/hubble-ui 8080:80 --address='0.0.0.0'
```

``http://[kubectlを実行したホストのIP]:8080``にアクセスすると、以下のようなトップページが表示されるはずです。

![screenshot 246.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/dae6c0e5-de0b-6607-fb0a-7438e9a948a5.png)

試しにkube-systemのnamespaceを選択すると、次のようなサービスマップが出てきます。

![screenshot 247.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/583d79f0-69d2-5bd8-a8af-fd6f28ee74c5.png)

この図は、「``hubble-ui``のPodから、``hubble-relay``のPodに通信が行われている」ことを意味しています。実際に``kubectl``コマンドでそれを確認してみましょう。

**hubble-relayのServiceリソースが4245のポートのPodにロードバランシングしていることの確認**
```
$ kubectl describe svc -n kube-system hubble-relay | grep 4245
TargetPort:        4245/TCP
Endpoints:         10.0.0.127:4245
```

**hubble-relayのPodが4245のポートをlistenしていることの確認**
```
$ kubectl describe pod -n kube-system hubble-relay-d8b6b55c9-z9bf8 | grep 4245
    Port:          4245/TCP
```

上記は簡単な例ですが、ネットワークがより複雑になった場合でもHubble UIで可視化してくれるので非常に活用できそうです！

※Hubble UIの使い方は、以下のサイトも参考になります。
* https://github.com/cilium/hubble-ui
* https://docs.cilium.io/en/stable/gettingstarted/hubble/#open-the-hubble-ui

# おわりに

あまり皆さんにとっては重要な情報ではないですが、本記事掲載に至った背景を最後に書いておきます。

個人用にオンプレKubernetesを作って動かしているのですが、Control Planeを担っているマシンのOSをDebian 10から11にアップグレードするのに失敗し、OSをクリーンインストールせざるを得ない状況になってしまいました。そのためKubernetes環境も一から作り直す羽目に...。
だいぶショックでしたが、「せっかく作り直すんだったらCNIもこれまで使っていたCalicoからCiliumに変えてみよう！」と思い立ち、Ciliumのインストールを実現できました。
たまには今までやってきたことをリセットするのも必要だなと思いました。