Cluster APIのHelmChartProxyで複数クラスターにHelmチャートを一括配布しよう

今回はCluster APIの機能の1つであるHelmChartProxyを使って、複数のKubernetesクラスターに対して一括でHelmチャートを配布する方法を紹介します。

## はじめに

複数のKubernetesクラスターを運用していると、同じHelmチャートを複数のクラスターにデプロイする必要が出てきます。従来は各クラスターに対して個別にHelmコマンドを実行する必要がありましたが、Cluster APIのHelmChartProxyを使うと、一括デプロイが可能になります。

今回は以下のことを試していきます：

- 全クラスターへの一括デプロイ
- ラベルを使った特定クラスターへのデプロイ
- プライベートレジストリからのデプロイ

## お試し環境準備

### 必要なツール

- Docker (メモリ16GB以上推奨)
- kubectl
- kind
- clusterctl

### 1. 管理クラスターの作成

まずはkindを使って管理クラスターを作成します。以下の設定ファイルを用意します：

```yaml
# kind-cluster-with-extramounts.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  ipFamily: dual
nodes:
- role: control-plane
  extraMounts:
    - hostPath: /var/run/docker.sock
      containerPath: /var/run/docker.sock
```

設定ファイルを使ってクラスターを作成：

```bash
kind create cluster --config kind-cluster-with-extramounts.yaml
```

### 2. Cluster APIのセットアップ

管理クラスターにCluster APIをインストールします：

```bash
export CLUSTER_TOPOLOGY=true
clusterctl init --infrastructure docker --addon helm
```

全コンポーネントの準備が完了するまで待ちます：

```bash
kubectl wait --for=condition=Available --timeout=300s -n capi-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-bootstrap-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-control-plane-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n capd-system deployments --all && \
kubectl wait --for=condition=Available --timeout=300s -n caaph-system deployments --all
```

### 3. ワークロードクラスターの作成

今回は「muscat」と「delaware」という2つのクラスターを作成します：

```bash
# muscatクラスターのマニフェスト生成
clusterctl generate cluster muscat \
  --flavor development \
  --kubernetes-version v1.28.0 \
  --control-plane-machine-count=3 \
  --worker-machine-count=3 \
  > muscat.yaml

# delawareクラスターのマニフェスト生成
clusterctl generate cluster delaware \
  --flavor development \
  --kubernetes-version v1.28.0 \
  --control-plane-machine-count=3 \
  --worker-machine-count=3 \
  > delaware.yaml

# クラスターの作成
kubectl apply -f muscat.yaml
kubectl apply -f delaware.yaml
```

kubeconfigの取得：

```bash
clusterctl get kubeconfig muscat > muscat-kubeconfig.yaml
clusterctl get kubeconfig delaware > delaware-kubeconfig.yaml
```

### 4. CNIのセットアップ

両クラスターにCalicoをインストール：

```bash
# muscatにCalico導入
kubectl --kubeconfig=muscat-kubeconfig.yaml apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml

# delawareにCalico導入
kubectl --kubeconfig=delaware-kubeconfig.yaml apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
```

## HelmChartProxyを使ったデプロイ

### 全クラスターへのデプロイ

nginxを全クラスターにデプロイする例を見ていきましょう：

```yaml
# helm-chart-proxy-nginx.yaml
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: nginx
spec:
  clusterSelector: {} # 空のセレクターは「全クラスター選択」を意味します
  repoURL: oci://registry-1.docker.io/bitnamicharts
  chartName: nginx
  version: "18.2.5"
  releaseName: nginx
  namespace: nginx
  options:
    waitForJobs: true
    atomic: true
    wait: true
    timeout: 5m
    install:
      createNamespace: true
  valuesTemplate: |-
    service:
      type: NodePort
```

デプロイと確認：

```bash
# nginxのデプロイ
kubectl apply -f helm-chart-proxy-nginx.yaml

# HelmReleaseProxyの準備完了を待機
kubectl wait --for=condition=Ready --timeout=300s helmreleaseproxy --all

# muscatのPod確認
kubectl --kubeconfig=muscat-kubeconfig.yaml get pods -n nginx

# delawareのPod確認
kubectl --kubeconfig=delaware-kubeconfig.yaml get pods -n nginx
```

### 特定クラスターへのデプロイ

ラベルを使って特定のクラスターにだけデプロイすることもできます：

```yaml
# helm-chart-proxy-nginx.yaml
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: nginx
spec:
  clusterSelector:
    matchLabels:
      use-nginx: "true"  # このラベルを持つクラスターにのみデプロイ
  # ... (他の設定は同じ)
```

使い方：

```bash
# nginxのデプロイ
kubectl apply -f helm-chart-proxy-nginx.yaml

# muscatクラスターにラベル付け
kubectl label cluster muscat use-nginx=true

# デプロイの確認
kubectl get helmreleaseproxy -A

# muscatでnginxが動いているか確認
kubectl --kubeconfig=muscat-kubeconfig.yaml get pods -n nginx

# delawareでnginxが動いていないことを確認
kubectl --kubeconfig=delaware-kubeconfig.yaml get pods -n nginx
```

### プライベートレジストリからのデプロイ

GitHub Container Registryを例に見てみましょう：

1. GitHub Personal Access Tokenを作成（read:packages権限必要）

2. レジストリ認証情報の設定：

```bash
# base64エンコードした認証情報でconfig.jsonを作成
echo -n "YOUR_GITHUB_USERNAME:YOUR_GITHUB_TOKEN" | base64 > auth.txt

cat > config.json << EOF
{
  "auths": {
    "ghcr.io": {
      "auth": "$(cat auth.txt)"
    }
  }
}
EOF

# シークレットの作成
kubectl create secret generic github-creds \
  --from-file=config.json \
  -n caaph-system
```

3. プライベートチャート用のHelmChartProxy作成：

```yaml
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: private-chart
spec:
  clusterSelector: {}
  repoURL: oci://ghcr.io/YOUR_GITHUB_USERNAME
  chartName: YOUR_CHART_NAME
  version: "0.1.0"
  credentials:
    secret:
      name: github-creds
      namespace: caaph-system
    key: config.json
  # ... (他の設定)
```

## まとめ

HelmChartProxyを使うことで、複数クラスターへのHelmチャートの配布が格段に楽になりました。特に以下のメリットがあります：

- 一括デプロイによる運用工数の削減
- ラベルベースでの柔軟なデプロイ制御
- プライベートレジストリのサポート

もし複数のKubernetesクラスターを運用している場合は、ぜひHelmChartProxyの導入を検討してみてください。