はじめに — クラスタが 1 つだった時代は終わった
Kubernetes 導入初期、組織あたりのクラスタは 1 つ、多くても 2〜3 個でした。しかし今は状況がまったく違います。環境別の分離(dev/stage/prod)、リージョン別の分離、規制ドメイン別の分離(ネットワーク分離が求められる金融機関ならなおさら)、テナントごとの専用クラスタ、そして店舗・工場・車両に配備されるエッジクラスタまで。数十個は当たり前で、通信事業者やリテールエッジを運用する組織は数百から数千のクラスタを回しています。
クラスタが 10 個を超えた瞬間、次の問いが日常になります。
- 新しいクラスタを 1 つ作るのに何日かかるのか。その手順は文書化されているのか、それとも特定のエンジニアの頭の中にしかないのか。
- クラスタ 37 番の Kubernetes バージョンはいくつか。フリート全体のバージョン分布を 1 画面で見られるか。
- コントロールプレーンノードが死んだら、誰が、いつ、どうやって復旧するのか。
- フリート全体を v1.31 から v1.32 に上げるのに何週間かかるのか。
これらの問いに自信を持って答えられないなら、クラスタライフサイクル管理が組織のボトルネックになっているということです。本稿で扱う Cluster API(略して CAPI)は、この問題に対する Kubernetes コミュニティの公式な解答です。中核となるアイデアはシンプルかつ急進的です。**クラスタそのものを Kubernetes リソースとして宣言し、コントローラにその宣言を現実にさせる。**
既存の方式はなぜ限界にぶつかるのか
コンソールクリック(ClickOps)
クラウドコンソールでボタンを押してクラスタを作る方式は、1 個作るだけなら最速です。しかし再現性がありません。3 か月後に同じ構成のクラスタを作るにはスクリーンショットと記憶に頼るしかなく、監査証跡も残しにくい。クラスタ間の設定ドリフトは必然で、「このクラスタだけなぜ違うのか」の原因を誰も説明できなくなります。
Terraform / OpenTofu
Infrastructure as Code としての Terraform は優れたツールですが、クラスタライフサイクルには構造的な弱点があります。
- **実行時にしか動作しません。** terraform apply が終われば状態の監視も終わります。誰かがコンソールでノードグループを削除しても、次の apply まで誰も気づきません。継続的な reconcile が存在しないのです。
- **state ファイルが単一障害点です。** state のロック、バックエンド管理、破損した state の復旧は、それ自体が運用負担です。
- **ノードレベルのライフサイクル表現が弱い。**「このノードが 10 分間 NotReady なら交換せよ」のような宣言は Terraform の言語では表現しにくい。
- 数百クラスタ規模になると、ワークスペース/モジュール分割、plan の所要時間、ドリフト検知のすべてが苦痛になります。
kubeadm スクリプト
kubeadm はクラスタブートストラップの事実上の標準的な低レベルツールですが、あくまで「1 台のノードをクラスタに入れる」ためのツールです。VM のプロビジョニング、LB の構成、証明書の更新、ノードの交換、バージョンアップグレードの順序制御は、すべて利用者のシェルスクリプトに委ねられます。これらのスクリプトは時間とともに、誰も手を出せない秘伝の儀式と化します。
3 方式に共通する欠陥は 1 つです。**宣言と現実を継続的に一致させる主体が存在しない**こと。Kubernetes が Pod について解決したまさにその問題が、クラスタ自身については未解決のまま残っていたわけです。
Cluster API の核心哲学 — Kubernetes で Kubernetes を管理する
Cluster API は Kubernetes SIG Cluster Lifecycle が開発する公式サブプロジェクトです。その哲学は 3 文に要約できます。
1. **宣言的 API。** クラスタ、マシン、コントロールプレーンをすべて CRD(カスタムリソース)として定義します。「ワーカー 3 台、バージョン v1.32.2」と宣言すれば終わりです。
2. **コントローラの reconcile ループ。** Deployment コントローラが Pod 数を合わせるように、CAPI コントローラはマシン数とバージョンを合わせます。現実が宣言から逸脱すれば(ノード障害、手動削除)、自動的に収束させます。
3. **プロバイダ抽象化。** AWS でも vSphere でもベアメタルでも、インフラごとの差異はプロバイダプラグインの背後に隠します。ユーザー体験は同じ kubectl と YAML のままです。
たとえるならこうです。Pod に Deployment があるように、クラスタには Cluster API があります。ReplicaSet が Pod を量産するように MachineSet がマシン(ノード VM)を量産し、Deployment が Pod をローリング更新するように MachineDeployment がノードをローリング交換します。Kubernetes 運用者がすでに知っているメンタルモデルを、クラスタの次元に引き上げたものです。
もう 1 つ重要な原則が**イミュータブルインフラ(不変インフラ)**です。CAPI はマシンを「修理」しません。設定やバージョンが変われば、新しいマシンを作り、古いマシンを破棄します。稼働中のノードに SSH で入ってパッケージをアップグレードする行為は、モデルの外側の行為です。
アーキテクチャ解剖 — management cluster と workload cluster
CAPI の世界には 2 種類のクラスタがあります。
- **Management cluster(管理クラスタ)**: CAPI のコントローラと CRD がインストールされたクラスタ。他のクラスタの宣言(YAML)がここに保存され、reconcile されます。
- **Workload cluster(ワークロードクラスタ)**: 管理クラスタが作り出す対象クラスタ。実際のアプリケーションはここで動きます。ワークロードクラスタ自身は CAPI の存在を知りません。
+----------------------------------------------------------------------+
| Management Cluster |
| |
| +----------------+ +----------------+ +------------------------+ |
| | CAPI Core | | Bootstrap | | Control Plane | |
| | Controller | | Provider | | Provider | |
| | (Cluster, | | (CABPK: | | (KCP: KubeadmControl- | |
| | Machine, MS, | | KubeadmConfig)| | Plane controller) | |
| | MD, MHC) | +----------------+ +------------------------+ |
| +----------------+ |
| +-------------------------------+ |
| | Infrastructure Provider | etcd に保存された宣言: |
| | (CAPA/CAPZ/CAPV/CAPD/Metal3) | Cluster, MachineDeployment, |
| +-------------------------------+ KubeadmControlPlane ... |
+----------------------------------------------------------------------+
| | |
| プロビジョニング/reconcile| |
v v v
+----------------+ +----------------+ +----------------+
| Workload | | Workload | | Workload |
| Cluster A | | Cluster B | | Cluster C |
| (prod-seoul) | | (prod-tokyo) | | (edge-store-7) |
+----------------+ +----------------+ +----------------+
コア CRD の関係図
CAPI の CRD は役割ごとにきれいに分かれています。まず関係を図で見てみましょう。
+-----------+
| Cluster | クラスタ全体の傘リソース
+-----+-----+
|
+------------------+-------------------+
| controlPlaneRef | infrastructureRef
v v
+----------------------+ +---------------------------+
| KubeadmControlPlane | | (Infra)Cluster |
| (replicas, version) | | 例: DockerCluster, |
+----------+-----------+ | AWSCluster: VPC/LB等 |
| +---------------------------+
| 作成/管理
v
+---------+ 1:1 +------------------------+
| Machine |------------- | (Infra)Machine |
+---------+ | 例: DockerMachine, |
^ | AWSMachine: VM |
| +------------------------+
| 作成 ^ 1:1
+--------+-------+ |
| MachineSet | <-- テンプレート参照: (Infra)MachineTemplate
+--------+-------+ KubeadmConfigTemplate
^
| 作成/ローリング交換
+--------+----------------+ +---------------------+
| MachineDeployment | | MachineHealthCheck |
| (replicas, version, | | 異常マシンの検知 → |
| rolling strategy) | | remediation(交換) |
+-------------------------+ +---------------------+
各リソースの責務を整理すると次のとおりです。
| リソース | たとえ (Pod の世界) | 責務 |
| --- | --- | --- |
| Cluster | Namespace に近い傘 | クラスタネットワーク CIDR とコントロールプレーン/インフラ参照を束ねる最上位リソース |
| Machine | Pod | ノード 1 台の宣言。不変 — スペックが変われば交換 |
| MachineSet | ReplicaSet | 同一スペックのマシンのレプリカ数を維持 |
| MachineDeployment | Deployment | MachineSet のローリング更新をオーケストレーション |
| KubeadmControlPlane | StatefulSet に近い | コントロールプレーンのマシン群と etcd メンバーシップ、証明書、バージョン管理 |
| KubeadmConfig | cloud-init 生成器 | マシン起動時に実行する kubeadm init/join 設定の生成 |
| MachineHealthCheck | livenessProbe + 自動交換 | 異常ノードを検知して remediation をトリガー |
KubeadmControlPlane(KCP)はとりわけ重要です。コントロールプレーンは etcd のクォーラム(定足数)があるため、一般のワーカーのように気軽に入れ替えられません。KCP コントローラはアップグレード時に、新しいコントロールプレーンマシンを 1 台追加し、etcd メンバーとして合流させ、古いマシンを etcd から安全に除去してから破棄する手順を自動化します。手作業なら冷や汗ものの作業が、宣言 1 行で終わります。
プロバイダモデル — 抽象化の実体
CAPI 本体はインフラのことをまったく知りません。実際の VM 作成はインフラプロバイダが、ノード初期化スクリプトの生成はブートストラッププロバイダが、コントロールプレーンのオーケストレーションはコントロールプレーンプロバイダが担当します。
インフラプロバイダ
| プロバイダ | 対象インフラ | 成熟度/備考 |
| --- | --- | --- |
| CAPA | AWS (EC2, EKS) | 成熟。EKS managed control plane をサポート |
| CAPZ | Azure (VM, AKS) | 成熟。AKS managed topology をサポート |
| CAPG | GCP (GCE, GKE) | 安定しているが CAPA/CAPZ より機能の幅は狭い |
| CAPV | vSphere | オンプレミス仮想化の事実上の標準的選択肢 |
| CAPO | OpenStack | 通信事業者/プライベートクラウドで活発 |
| CAPD | Docker コンテナ | 開発/テスト/CI 専用。本番禁止 |
| Metal3 | ベアメタル (Ironic ベース) | BMC で物理サーバの電源/イメージを制御 |
| BYOH | 既存ホストの再利用 | OS 導入済みのホストをノードとして編入 |
ブートストラップ / コントロールプレーンプロバイダ
kubeadm がデフォルト(CABPK + KCP)ですが、エコシステムはより広がっています。
| プロバイダ | ディストリビューション | 特徴 |
| --- | --- | --- |
| kubeadm (デフォルト) | バニラ Kubernetes | 最も成熟、リファレンス実装 |
| k3s | k3s | 軽量エッジ環境向け。k3s-io コミュニティが維持 |
| RKE2 | RKE2 | Rancher 系、セキュリティ強化ディストリビューション |
| Talos | Talos Linux | SSH のない不変 OS、API のみで管理。Sidero Labs |
| マネージド CP | EKS/AKS/GKE | インフラプロバイダに内蔵された managed control plane リソース |
マネージド Kubernetes との関係は後段で別途扱いますが、要点だけ言えば、CAPA の AWSManagedControlPlane のようなリソースにより **EKS のコントロールプレーンでさえ CAPI 宣言の対象**になり得ます。
ハンズオン — CAPD でノート PC の上にクラスタ工場を回す
CAPD(Cluster API Provider Docker)は Docker コンテナを「マシン」として扱うため、クラウドアカウントなしにノート PC で全フローを体験できます。kind、Docker、clusterctl、kubectl が必要です。
ステップ 1 — management cluster の準備と clusterctl init
CAPD が Docker ソケットを使えるように kind クラスタを作成
cat > kind-mgmt.yaml <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: capi-mgmt
nodes:
- role: control-plane
extraMounts:
- hostPath: /var/run/docker.sock
containerPath: /var/run/docker.sock
EOF
kind create cluster --config kind-mgmt.yaml
ClusterClass 機能を有効化してから CAPI + CAPD をインストール
export CLUSTER_TOPOLOGY=true
clusterctl init --infrastructure docker
clusterctl init は cert-manager、CAPI コア、kubeadm ブートストラップ/コントロールプレーンプロバイダ、CAPD を management cluster にインストールします。インストールの確認:
kubectl get pods -A | grep -E "capi|capd|cert-manager"
capd-system / capi-kubeadm-bootstrap-system /
capi-kubeadm-control-plane-system / capi-system が Running なら正常
ステップ 2 — ワークロードクラスタ宣言 YAML の全文
clusterctl generate cluster でテンプレートを生成することもできますが、学習のためにコアリソースを直接見てみます。以下はコントロールプレーン 1 台 + ワーカー 2 台のクラスタの全文です。
dev-cluster-01.yaml — Cluster: 最上位の傘
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: dev-cluster-01
namespace: default
labels:
env: dev
region: local
spec:
clusterNetwork:
pods:
cidrBlocks: ["192.168.0.0/16"]
serviceDomain: cluster.local
controlPlaneRef:
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
name: dev-cluster-01-cp
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerCluster
name: dev-cluster-01
インフラクラスタ: CAPD では LB コンテナなどを表現
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerCluster
metadata:
name: dev-cluster-01
namespace: default
コントロールプレーンマシンのインフラテンプレート
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
metadata:
name: dev-cluster-01-cp
namespace: default
spec:
template:
spec:
extraMounts:
- containerPath: /var/run/docker.sock
hostPath: /var/run/docker.sock
KubeadmControlPlane: コントロールプレーンの宣言
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
name: dev-cluster-01-cp
namespace: default
spec:
replicas: 1
version: v1.31.4
machineTemplate:
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
name: dev-cluster-01-cp
kubeadmConfigSpec:
clusterConfiguration:
apiServer:
certSANs: [localhost, 127.0.0.1, 0.0.0.0, host.docker.internal]
initConfiguration:
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
joinConfiguration:
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
ワーカーマシンのインフラテンプレート
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
metadata:
name: dev-cluster-01-md-0
namespace: default
spec:
template:
spec: {}
ワーカーマシンのブートストラップ(join)設定テンプレート
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfigTemplate
metadata:
name: dev-cluster-01-md-0
namespace: default
spec:
template:
spec:
joinConfiguration:
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
MachineDeployment: ワーカープールの宣言
apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineDeployment
metadata:
name: dev-cluster-01-md-0
namespace: default
spec:
clusterName: dev-cluster-01
replicas: 2
selector:
matchLabels: null
template:
spec:
clusterName: dev-cluster-01
version: v1.31.4
bootstrap:
configRef:
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfigTemplate
name: dev-cluster-01-md-0
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
name: dev-cluster-01-md-0
なお、本稿の例は広く展開されている v1beta1 API を基準にしています。最新の CAPI リリースラインでは v1beta2 への移行が進んでいるため、適用前に使用中のリリースの API バージョンを確認してください。
kubectl apply -f dev-cluster-01.yaml
ステップ 3 — 収束プロセスの観察
ツリー形式で全体の状態を見る(最も有用なコマンド)
clusterctl describe cluster dev-cluster-01
個別リソースの追跡
kubectl get cluster,machinedeployment,machineset,machine
kubectl get kubeadmcontrolplane
docker ps # CAPD が作った「マシン」コンテナが見えます
Machine が Pending → Provisioning → Provisioned → Running と遷移していく様子は、Pod のライフサイクルとまったく同じ感覚です。
ステップ 4 — kubeconfig の取得と CNI のインストール
新しいクラスタのノードは CNI がないため NotReady 状態です。これは正常です。
clusterctl get kubeconfig dev-cluster-01 > dev-01.kubeconfig
kubectl --kubeconfig dev-01.kubeconfig get nodes
STATUS NotReady — CNI インストール前なので正常
Calico のインストール (Cilium、Flannel など何でも可)
kubectl --kubeconfig dev-01.kubeconfig apply -f \
https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/calico.yaml
kubectl --kubeconfig dev-01.kubeconfig get nodes
しばらくすると全ノード Ready
この時点で気づきが訪れます。たった今、クラスタを 1 つ **kubectl apply 一発**で作りました。100 個作るには? YAML を 100 セット apply すればいい。そしてその YAML は Git に入れられます。
運用の深掘り — アップグレード、スケーリング、自動復旧
ローリングアップグレードの原理 — ノードはパッチせず交換する
CAPI のアップグレードは OS パッチ型ではなく**マシン交換型**です。version フィールドを変えると、コントローラが新バージョンのマシンを作って合流させ、古いマシンを drain してから破棄します。
コントロールプレーンのアップグレード: KCP の version のみ変更
kubectl patch kubeadmcontrolplane dev-cluster-01-cp --type merge \
-p '{"spec":{"version":"v1.32.2"}}'
ワーカーのアップグレード: MachineDeployment の version を変更
kubectl patch machinedeployment dev-cluster-01-md-0 --type merge \
-p '{"spec":{"template":{"spec":{"version":"v1.32.2"}}}}'
内部の動作手順は次のとおりです。
KCP アップグレード (replicas=3 の場合)
1. 新しい v1.32 コントロールプレーンマシンを 1 台作成 (計 4 台)
2. kubeadm join --control-plane で合流、etcd メンバー 4
3. 古い v1.31 マシンを 1 台選択 → etcd member remove → drain → 削除 (計 3 台)
4. 古いマシンがなくなるまで 1〜3 を繰り返し
5. クォーラムは常に維持: 3 → 4 → 3 → 4 → 3
MachineDeployment アップグレード (RollingUpdate 戦略)
1. 新バージョンの MachineSet を作成
2. maxSurge/maxUnavailable に従って新マシンを追加、古いマシンを drain して削除
3. 古い MachineSet の replicas が 0 になるまで繰り返し
アップグレード順序のルールも Kubernetes のバージョンスキューポリシーそのままです。**コントロールプレーンが先、ワーカーは後**。kubelet は kube-apiserver より最大 3 マイナーバージョン低くてよいため、ワーカーのアップグレードは段階的に進める余裕があります。
スケーリング
ワーカー 2 台 → 5 台
kubectl scale machinedeployment dev-cluster-01-md-0 --replicas=5
コントロールプレーン 1 台 → 3 台 (HA への移行)
kubectl scale kubeadmcontrolplane dev-cluster-01-cp --replicas=3
オートスケーリングが必要なら、cluster-autoscaler が CAPI プロバイダモードをサポートしています。クラウドのノードグループの代わりに MachineDeployment をスケール対象とする方式です。
MachineHealthCheck — ノード障害の自動復旧
MachineHealthCheck(MHC)はノードの状態を監視し、異常状態が継続するとそのマシンを削除(=新しいマシンに交換)します。これが remediation です。
apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineHealthCheck
metadata:
name: dev-cluster-01-worker-mhc
namespace: default
spec:
clusterName: dev-cluster-01
一度に多くのマシンを交換しすぎないための安全弁
maxUnhealthy: 40%
起動後この時間内にノードとして合流できなければ異常
nodeStartupTimeout: 10m
selector:
matchLabels:
cluster.x-k8s.io/deployment-name: dev-cluster-01-md-0
unhealthyConditions:
- type: Ready
status: Unknown
timeout: 300s
- type: Ready
status: "False"
timeout: 300s
maxUnhealthy は極めて重要な安全装置です。たとえば CNI 障害で全ノードが NotReady になったとき、MHC が全マシンを入れ替えてしまう大惨事を防いでくれます。異常率がしきい値を超えると remediation を止めて人間を待ちます。
ClusterClass — クラスタのテンプレート化
クラスタ 1 つにつき YAML 7 本を管理するのは、10 個でも苦行です。ClusterClass はクラスタの「クラス(テンプレート)」を定義し、個々のクラスタは変数を埋めるだけの薄い宣言にします。
apiVersion: cluster.x-k8s.io/v1beta1
kind: ClusterClass
metadata:
name: standard-dev
namespace: default
spec:
controlPlane:
ref:
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlaneTemplate
name: standard-dev-cp
machineInfrastructure:
ref:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
name: standard-dev-cp-machine
infrastructure:
ref:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerClusterTemplate
name: standard-dev-infra
workers:
machineDeployments:
- class: default-worker
template:
bootstrap:
ref:
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
kind: KubeadmConfigTemplate
name: standard-dev-worker-bootstrap
infrastructure:
ref:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: DockerMachineTemplate
name: standard-dev-worker-machine
variables:
- name: workerReplicas
required: true
schema:
openAPIV3Schema:
type: integer
default: 2
これでクラスタ 1 つはここまで短くなります。topology フィールドが鍵です。
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: dev-cluster-02
namespace: default
spec:
clusterNetwork:
pods:
cidrBlocks: ["192.168.0.0/16"]
topology:
class: standard-dev
version: v1.31.4
controlPlane:
replicas: 1
workers:
machineDeployments:
- class: default-worker
name: md-0
replicas: 3
variables:
- name: workerReplicas
value: 3
managed topology の真価は**クラス変更の伝播**にあります。ClusterClass のマシンテンプレートを修正すると、そのクラスを使うすべてのクラスタが(ポリシーに従い)ローリング交換で追従します。数百クラスタの標準化はこのメカニズムの上で回ります。
マシンイメージ管理 — image-builder
本番では「kubeadm と kubelet が焼き込まれた」ゴールデンイメージを使います。Kubernetes SIG が管理する image-builder プロジェクトが、Packer + Ansible ベースで AWS AMI、Azure イメージ、vSphere OVA、Raw/QCOW2(ベアメタル)などをビルドしてくれます。
git clone https://github.com/kubernetes-sigs/image-builder.git
cd image-builder/images/capi
例: vSphere 向け Ubuntu 22.04 + K8s v1.31 の OVA をビルド
make build-node-ova-vsphere-ubuntu-2204
イメージのバージョン管理がそのままノードのバージョン管理です。「K8s バージョン + OS パッチレベル」をイメージタグに固定すれば、クラスタの全ノードがビット単位で同一になります。イミュータブルインフラの土台です。
GitOps との結合 — クラスタフリートを Git で統治する
CAPI リソースは結局のところ普通の Kubernetes YAML なので、Argo CD や Flux で管理クラスタに sync すれば**クラスタの GitOps**が完成します。
+-----------+ push +-----------+ sync +---------------------+
| Platform | ------------> | Git | ------------> | Management Cluster |
| Team | PR レビュー | fleet- | Argo CD / | CAPI コントローラが |
| | | repo | Flux | reconcile |
+-----------+ +-----------+ +----------+----------+
|
作成/アップグレード/復旧 v
+---------------------------+
| Workload Clusters (フリート)|
+---------------------------+
リポジトリ構成の例は次のとおりです。
fleet-repo/
├── clusterclasses/
│ ├── standard-prod.yaml
│ └── standard-edge.yaml
├── clusters/
│ ├── prod/
│ │ ├── prod-seoul-01.yaml # topology ベースの薄い宣言
│ │ └── prod-tokyo-01.yaml
│ ├── stage/
│ │ └── stage-seoul-01.yaml
│ └── edge/
│ ├── store-0001.yaml
│ └── store-0002.yaml
└── addons/
├── cni/ # 新規クラスタに入る基本アドオン
└── monitoring/
このパターンの運用効果は強力です。
- クラスタの作成/変更が **PR レビュー**を通過しなければなりません。監査証跡は Git の履歴そのものです。
- バージョンアップグレードが「YAML の version フィールドを変える PR」1 つに標準化されます。
- 新規クラスタに CNI・モニタリングなどのアドオンを自動展開するには、Argo CD ApplicationSet の cluster generator、または CAPI の ClusterResourceSet を使います。
フリート規模のネーミングとラベル戦略
数十〜数百クラスタでは、一貫したネーミングとラベルが自動化の取っ手になります。
ネーミング規則の例: <用途>-<リージョン>-<連番>
prod-seoul-01, stage-tokyo-01, edge-store-0042
推奨ラベル (Cluster リソースに付与):
env: prod | stage | dev
region: seoul | tokyo | ...
tier: core | edge
team: payments | search | ...
upgrade-wave: "1" | "2" | "3" # アップグレードの波を制御
upgrade-wave ラベルは特に有用です。第 1 波(社内向けクラスタ)に新バージョンを先に適用して数日間寝かせ、問題なければ第 2 波、第 3 波へ広げる運用を、ラベルセレクタベースの自動化で構築できます。
pivot、バックアップ/DR、バージョンスキュー — 管理クラスタ自体の運用
鶏と卵 — management cluster は誰が作るのか
よくあるブートストラップパターンはこうです。
1. ローカルに一時的な kind クラスタを作り clusterctl init
2. 一時クラスタから「本物の」management cluster(クラウド/オンプレ)をワークロードクラスタとして作成
3. **clusterctl move** ですべての CAPI リソースを新クラスタへ移行(pivot)
4. 以後、management cluster が自分自身を管理(self-hosted)
新クラスタにプロバイダをインストールしてからリソースを移行
clusterctl init --kubeconfig mgmt-real.kubeconfig --infrastructure aws
clusterctl move --to-kubeconfig mgmt-real.kubeconfig
clusterctl move は Cluster をはじめとする所有チェーンのオブジェクトとシークレット(kubeconfig、CA、etcd 証明書)を丸ごと移します。移行中は reconcile が一時停止(pause)されるため、ワークロードクラスタは影響を受けません。
management cluster が死んだらワークロードも死ぬのか
いいえ。これが CAPI 設計の重要な美徳です。**ワークロードクラスタは management cluster なしでも完全に独立して動作します。** 失うのはライフサイクル操作(作成/アップグレード/自動復旧)だけです。それでも DR 計画は必要です。
- CAPI リソースの原本が Git にあるなら(GitOps)、新しい management cluster を作って再 sync するのが第一の復旧経路です。ただしクラスタのシークレット(CA など)は Git にないため、バックアップが必須です。
- Velero などで management cluster の CAPI ネームスペース(リソース+シークレット)を定期バックアップします。
- 復旧リハーサルを必ず実施すべきです。「バックアップがある」と「復旧できる」は別の命題です。
バージョンスキューとアップグレード順序
管理体系そのもののバージョンも管理対象です。
アップグレード順序 (上から下へ)
1. management cluster の Kubernetes バージョン
(CAPI リリースがサポートする範囲を確認)
2. clusterctl バイナリ
3. CAPI コア + プロバイダ: clusterctl upgrade plan / apply
4. ワークロードクラスタ群の K8s バージョン (wave 単位でローリング)
- 各クラスタ内部: コントロールプレーン → ワーカー
- マイナーバージョンの飛び越え禁止 (1.30 → 1.32 は不可、1.31 経由)
CAPI の contract バージョン(インフラプロバイダとの互換契約)も併せて確認が必要です。コアだけ上げてプロバイダを放置すると、reconcile が止まる事故が起きます。clusterctl upgrade plan が互換マトリクスを計算してくれるので、必ず plan を先に見ます。
限界と現実 — 導入前に知っておくべきこと
学習コストと求められる運用成熟度
CAPI は抽象化レイヤが多い。問題が起きたら Cluster → KCP → Machine → InfraMachine → cloud-init ログまで降りていくデバッグチェーンを辿れなければなりません。Kubernetes のコントローラパターン(owner reference、condition、finalizer)に不慣れなチームには急な坂です。
プロバイダの成熟度のばらつき
CAPA/CAPZ/CAPV には大規模本番事例が多くありますが、一部のプロバイダは機能の幅もドキュメントも薄い。導入前に、当該プロバイダのリリース周期、Issue への応答速度、ClusterClass 対応の有無を必ず確認してください。
マネージド Kubernetes(EKS/AKS/GKE)との関係
「どうせ EKS を使うのに CAPI は必要か?」は正当な問いです。答えは組織の形によります。
- EKS クラスタが 3 つだけなら、Terraform や eksctl で十分な可能性が高い。
- しかし EKS + オンプレミス vSphere + エッジベアメタルが混在するフリートなら、CAPI は**単一の API で全体を覆える事実上唯一の選択肢**に近い。CAPA の AWSManagedControlPlane や CAPZ の AKS サポートのように、マネージドコントロールプレーンも CAPI リソースとして宣言できるからです。
Crossplane / Terraform との比較
| 観点 | Cluster API | Crossplane | Terraform |
| --- | --- | --- | --- |
| 主目的 | K8s クラスタライフサイクル専用 | 汎用クラウドリソースの組み立て | 汎用 IaC |
| 動作モデル | コントローラの常時 reconcile | コントローラの常時 reconcile | 実行時 apply |
| ノード/マシン抽象化 | 第一級概念 (Machine など) | なし (マネージド K8s 中心) | モジュールで間接表現 |
| コントロールプレーンのオーケストレーション | KCP が etcd まで自動化 | マネージド CP に委任 | 自前実装が必要 |
| 自動復旧 | MachineHealthCheck 内蔵 | リソースドリフト補正レベル | なし |
| クラスタ外リソース (DB など) | 対象外 | 強み | 強み |
| 状態ストア | etcd (K8s ネイティブ) | etcd | state ファイル |
3 者は敵ではなく分業関係であることが多い。実際に「VPC/IAM は Terraform、クラスタは CAPI、クラスタが使う DB は Crossplane」のようにレイヤを分ける組織がよくあります。
どんな組織に合うか — 意思決定ガイド
質問 1. 管理するクラスタが 5 個未満で増える計画もない
→ CAPI は過剰。マネージド K8s + IaC で十分。
質問 2. クラスタが 10 個以上、またはテナント/エッジで増える予定
→ CAPI の有力候補。特にクラスタ作成をセルフサービス化したいなら。
質問 3. オンプレミス (vSphere/ベアメタル) やマルチクラウドが混在
→ CAPI の最も強いユースケース。単一宣言モデルの価値が最大化。
質問 4. チームに K8s コントローラ/CRD の運用経験があるか
→ なければ、まず小さな規模 (CAPD 実習、dev クラスタ) で筋肉をつける。
質問 5. プラットフォームチームが存在するか
→ CAPI はプラットフォームチームの道具。専任のオーナーがいなければ放置されて腐ります。
トラブルシューティング — マシンが止まったとき見る順序
マシンが Provisioning で止まるのは CAPI 運用で最もよくある症状です。診断の順序を体に染み込ませておけば、大半は 20 分以内に原因へたどり着けます。
1. 全体像: どこで止まったかツリーで確認
clusterctl describe cluster dev-cluster-01 --show-conditions all
2. Machine の conditions とイベント
kubectl describe machine dev-cluster-01-md-0-xxxxx
kubectl get events --field-selector involvedObject.kind=Machine
3. インフラマシン (プロバイダ側) の状態 — VM は実際に起動したか
kubectl describe dockermachine dev-cluster-01-md-0-xxxxx
AWS なら: kubectl describe awsmachine ...
4. ブートストラップシークレットは作られたか (cloud-init データ)
kubectl get secret | grep dev-cluster-01-md-0
5. コントローラログ — レイヤごとに
kubectl logs -n capi-system deploy/capi-controller-manager
kubectl logs -n capi-kubeadm-bootstrap-system \
deploy/capi-kubeadm-bootstrap-controller-manager
kubectl logs -n capi-kubeadm-control-plane-system \
deploy/capi-kubeadm-control-plane-controller-manager
kubectl logs -n capd-system deploy/capd-controller-manager
6. マシン内の cloud-init ログ (インフラごとにアクセス方法が異なる)
CAPD: docker exec でコンテナに入って
cat /var/log/cloud-init-output.log (または journalctl -u kubelet)
よく遭遇する原因の一覧です。
| 症状 | よくある原因 |
| --- | --- |
| InfraMachine が作られない | プロバイダ未インストール、credential シークレットの誤り、クォータ超過 |
| VM は起動したが join しない | イメージに kubeadm/kubelet がない、CP エンドポイントへのネットワーク遮断 |
| 最初の CP マシンで停止 | LB/エンドポイント未作成、certSANs の不一致、etcd の起動失敗 |
| ノードが NotReady のまま | CNI 未インストール (正常な段階)、CNI 設定の誤り |
| アップグレード中に停止 | PDB により drain 不能、maxSurge のリソース不足 |
| 削除が終わらない | finalizer 待ち — インフラ削除の失敗をプロバイダログで確認 |
とりわけ **PDB(PodDisruptionBudget)による drain のデッドロック**はアップグレードの定番イシューです。minAvailable がレプリカ数と等しい PDB があると、drain は永遠に終わりません。nodeDrainTimeout を設定しておけば、一定時間後に強制的に先へ進められます。
導入チェックリスト
[ ] 管理対象クラスタ数/増加計画が CAPI 導入を正当化するか
[ ] インフラプロバイダ (CAPA/CAPV/Metal3 など) の成熟度を検証したか
[ ] CAPD ベースのローカル実習でチーム全員が全フローを体験したか
[ ] ゴールデンイメージのパイプライン (image-builder) を構築したか
[ ] ClusterClass で標準クラスタ形状をテンプレート化したか
[ ] MachineHealthCheck の maxUnhealthy 安全弁を設定したか
[ ] GitOps リポジトリ構成と PR レビューポリシーを定義したか
[ ] ネーミング/ラベル/アップグレード wave 戦略を文書化したか
[ ] management cluster のバックアップ (Velero など) と復旧リハーサルを完了したか
[ ] clusterctl upgrade plan に基づく定期アップグレードカレンダーがあるか
[ ] マシン停止のトラブルシューティング・ランブックを作成したか
[ ] PDB/nodeDrainTimeout ポリシーをワークロードチームと合意したか
おわりに
Cluster API の本質は「クラスタ作成ツール」ではなく、**クラスタに対する運用モデルの置き換え**です。コンソールクリックとスクリプトの世界では、クラスタは手で捏ねる工芸品でした。CAPI の世界では、クラスタは Deployment が量産する Pod のように、宣言で定義されコントローラが守る普通のリソースです。ノードが死ねば交換され、バージョンを上げればローリングで収束し、すべての変更が Git の履歴に残ります。
もちろんタダではありません。抽象化レイヤの学習コスト、プロバイダエコシステムを見極める目、そして management cluster という新しい運用対象が生まれます。クラスタ 5 個以下の組織には過剰な装備かもしれません。しかし、クラスタがまもなく数十個になる運命なら — そしてほとんどのプラットフォーム組織はその運命を避けられません — 早く学ぶほど利息のつく技術です。今日、ノート PC の上で kind と CAPD による 30 分の実習から始めてみてください。
参考資料
- Cluster API 公式ドキュメント (The Cluster API Book): https://cluster-api.sigs.k8s.io/
- Cluster API GitHub リポジトリ: https://github.com/kubernetes-sigs/cluster-api
- Quick Start (CAPD 実習): https://cluster-api.sigs.k8s.io/user/quick-start
- ClusterClass コンセプトドキュメント: https://cluster-api.sigs.k8s.io/tasks/experimental-features/cluster-class/
- clusterctl リファレンス: https://cluster-api.sigs.k8s.io/clusterctl/overview
- Cluster API Provider AWS (CAPA): https://cluster-api-aws.sigs.k8s.io/
- Cluster API Provider Azure (CAPZ): https://capz.sigs.k8s.io/
- Cluster API Provider GCP (CAPG): https://github.com/kubernetes-sigs/cluster-api-provider-gcp
- Cluster API Provider vSphere (CAPV): https://github.com/kubernetes-sigs/cluster-api-provider-vsphere
- Cluster API Provider OpenStack (CAPO): https://github.com/kubernetes-sigs/cluster-api-provider-openstack
- Metal3 (ベアメタルプロバイダ): https://metal3.io/
- Kubernetes image-builder: https://image-builder.sigs.k8s.io/
- kubeadm 公式ドキュメント: https://kubernetes.io/docs/reference/setup-tools/kubeadm/
- Kubernetes バージョンスキューポリシー: https://kubernetes.io/releases/version-skew-policy/
- kind 公式ドキュメント: https://kind.sigs.k8s.io/
- Argo CD 公式ドキュメント: https://argo-cd.readthedocs.io/
- Flux 公式ドキュメント: https://fluxcd.io/
- Crossplane 公式サイト: https://www.crossplane.io/
현재 단락 (1/498)
Kubernetes 導入初期、組織あたりのクラスタは 1 つ、多くても 2〜3 個でした。しかし今は状況がまったく違います。環境別の分離(dev/stage/prod)、リージョン別の分離、規制ドメ...