はじめに
こんにちは。Sreake事業部にて長期インターンをしている髙橋です。普段は、ネットワークの運用などを講義で学びながら、同時にSREを目指して独学で勉強をしています。
本記事では、Kubernetes(以下K8sと呼称します)のCRDとしてK8sクラスタを管理するCluster APIおよびCluster API Provider AWSと、ArgoCDを使用したEKSクラスタの構築・管理についての検証結果について、そのメリット・デメリットや実際の使用感などをまとめます。
用語定義
Cluster APIとは
Cluster API(以下、CAPIと呼称します)は、K8sのCRDを使用して、K8sクラスタのライフサイクル管理を行うための、SIG Cluster Lifecycleが主導しているプロジェクトです。
CAPIは、K8sクラスタ及びその構成要素を以下のようなK8sのリソースとして定義し、コントローラーがこれらのリソースを監視して、クラスタの作成、更新、削除などの操作を自動化します。
記事執筆中の2026年6月現在、CAPIのAPIバージョンはv1beta2となっており、現在も活発に開発が続けられています。
Introduction – The Cluster API Book
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: hoge
namespace: default
spec:
clusterNetwork:
pods:
cidrBlocks:
- 192.168.0.0/16
controlPlaneRef:
apiVersion: controlplane.cluster.x-k8s.io/v1beta2
kind: AWSManagedControlPlane
name: hoge-control-plane
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
kind: AWSManagedCluster
name: hoge
---
apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineDeployment
metadata:
name: hoge-md-0
namespace: default
spec:
clusterName: hoge
replicas: 2
selector:
matchLabels: null
template:
spec:
bootstrap:
configRef:
apiVersion: bootstrap.cluster.x-k8s.io/v1beta2
kind: EKSConfigTemplate
name: hoge-md-0
clusterName: hoge
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1beta2
kind: AWSMachineTemplate
name: hoge-md-0
version: v1.30.0
⚠️ 上記マニフェストで
Cluster/MachineDeploymentがv1beta1、参照先がv1beta2と混在しているのは誤記ではなく、clusterctl generate cluster --infrastructure awsが使用するCAPA提供のクラスタテンプレートが、記事執筆時点でコアリソースのapiVersionをv1beta1のままハードコードしているためです(cluster.x-k8s.ioとCAPAのAPIグループはバージョンが独立しています)。
CAPI v1.11以降はコアリソースのstorage versionがv1beta2となっており、v1beta1で投入したマニフェストはconversion webhookによって変換されて保存されます。そのためこのまま適用しても動作します。
Cluster API Provider AWSとは
Cluster API Provider AWS(以下、CAPAと呼称します)は、CAPIのAWS向けの実装で、AWS上のK8sクラスタの管理を行うためのプロジェクトです。
CAPAは、AWSのリソースをK8sのCRDとして定義し、CAPAのコントローラーがこれらのリソースを監視して、AWS上のクラスタの作成、更新、削除などの操作を自動化します。
Introduction – Kubernetes Cluster API Provider AWS
検証概要
CAPIのように、K8sクラスタをIaCで管理する有名な方法として、Terraformなどがあります。既存のそのような方法と比べ、CAPIにどのようなメリット・デメリットがあるのかを検証します。
また近年、K8sをただのコンテナオーケストレーションツールとしてだけでなく、GitOpsの実行エンジンとして活用するケースが増えてきました。このような時代の流れの中で、GitOpsの一実装として、CAPI+ArgoCDがどのようなメリット・デメリットがあるのかを確認するため、実際にArgoCDを用いてCAPIマニフェストを管理し、クラスタのGitOpsを実現する検証を行いました。
使用環境
今回は、以下の環境で検証を行いました。
クラウドプロバイダ
| 項目 | 用途 |
|---|---|
| AWS EKS | CAPIの管理先クラスタ CAPIのコントローラーが動作するクラスタ |
| AWS EC2 | CAPAに必要なKeypairの管理など |
| AWS IAM | CAPAが使用するIAM Roleの管理など |
| Kind | 初期セットアップ用のローカルK8sクラスタ |
コマンドラインツール他
| 項目 | 用途 | 執筆時点でのバージョン | インストール方法 | 備考 |
|---|---|---|---|---|
| kubectl | K8sクラスタの管理 | v1.36.1 | 公式ドキュメントの手順に従ってインストール | Kube APIサーバーとのマイナーバージョンの差を±1に収めなければならないことに注意してください |
| clusterctl | CAPIの管理 | v1.13.0 | 公式ドキュメントの手順に従ってインストール | Arch系列ならAURにも存在します yay -Si clusterctl |
| clusterawsadm | CAPAの管理 | v2.11.1 | Releaseから入手 あるいは brew install clusterawsadm | |
| ArgoCD CLI | ArgoCDの管理 | v3.4.2 | 公式ドキュメントの手順に従ってインストール | |
| AWS CLI | AWSの管理 | v2.34.32 | 公式ドキュメントの手順に従ってインストール | AWS CLI v2が必須であることに注意してください |
| docker等 | Kindの管理 | v5.8.2 *1 | 公式ドキュメントの手順に従ってインストール | *1 筆者の環境ではPodmanを使用しています |
| kind | ローカルK8sクラスタの管理 | v0.31.0 | 公式ドキュメントの手順に従ってインストール |
目標構成
最終的に構築する構成と、各コンポーネントの相互作用を以下に示します。
ArgoCDがGitリポジトリをSSoT(単一の信頼源)として、Management Cluster自身の構成(CAPIマニフェストを含む)とWorkload Cluster上のApp群を継続的にreconcileします。また、CAPAがWorkload ClusterをAWS上に展開します。
なお、クラスタ定義マニフェストの移管プロセスであるPivot / Reverse Pivot はクラスタの管理権限を移譲する一度きりのライフサイクルイベントであり、継続的な相互作用(実線)とは区別して点線で示しています。

最終的なArgoCDのApp構成は以下のようになります

構築フロー
上記の構成を、以下の順序で構築していきます。 より詳細な構築フローは、CAPI/CAPAのドキュメントや、ArgoCDのドキュメントを参照してください。
⚠️ 以下のコマンド例は、サブコマンドやオプション及び一部手順を大幅に削ったサンプルです
多くのコマンドがそのままでは動かない事に注意してください 実際に使用する際には、CAPI及び各種プロバイダの公式リファレンスを確認するようにしてください。
1. kind で bootstrap cluster を作成し、CRDとコントローラーを投入する
# kindクラスタ作成
$ kind create cluster --name capi-bootstrap
# クラスタにCRD及びコントローラーを投入する
$ clusterctl init --infrastructure aws
2. kind にクラスタを定義するマニフェストを投入し、管理用EKSクラスタを展開
# マニフェストを作成するためのコマンド オプションが多数必要なためこのままでは動かない
$ clusterctl generate cluster mgmt > cluster.yaml
# 適用
$ kubectl apply -f cluster.yaml
3. kind から EKSに、CAPI リソースを委譲(Pivot)
# CAPIリソースを委譲する
$ clusterctl move --to-kubeconfig ./dest-cluster-kubeconfig
# 要らなくなったkindクラスタを削除
$ kind delete clusters --name capi-bootstrap
4. EKS上にArgoCDを導入
# Helmでインストール
$ helm repo add argo https://argoproj.github.io/argo-helm
$ helm install argocd argo/argo-cd
5. CAPIリソースをArgoCD管理下に配置する
- argocdにAppを作成
- フェーズ2で使用したcluster.yamlを配置 で基本的には問題ないです。
6. App展開用のEKSクラスタを定義したマニフェストをArgoCDで展開
# 新しいクラスタマニフェストを用意する
$ clusterctl generate cluster workload > workload.yaml
作成したマニフェストを、フェーズ5と同じ要領で管理下に置きます
7. 新EKSクラスタにAppを展開
# workloadクラスタのコンテキストをargocdに登録する
$ argocd cluster add workload-context
登録したクラスタをターゲットに、Appを作成します
検証結果
メリット
Terraformに比べプレーンな状態での管理能力に優れる
CAPIは、Terraformとは異なり、K8sのCRDを使用してクラスタを管理します。そのため、
- 継続的なReconcileのため、Stateの信頼性が高い
- 特別な下準備なくAuto Healingの仕組みが準備されている 等の利点を感じました。Terraformでも同じようなことは実現可能ですが、別途エンジン等を入れなければ実現不可能である点を考えると、CAPIの方が基盤の維持管理の側面では分があるように感じました。
Self-Manageするための仕組みが組み込まれている
clusterctl move --to-kubeconfig <TO_KUBECONFIG> とすることで、ある管理用クラスタの管理下にあるCAPI リソースを別の管理用クラスタに移動(Pivot)させることが出来ます。
この機能は、自分自身のCRを自分に載せることも可能であり、この仕組みによってSelf-Managedなクラスタを作成することが可能です。
自分自身を削除しないように気をつける必要はありますが、循環参照するクラスタ郡やCAPI管理外に存在するクラスタを作成することなく、管理用クラスタのGitOpsも実現可能である点は非常に優れていると言えるでしょう。
kubectl delete -f CLUSTER.yaml するだけで、リソースの依存順に削除してくれる
Terraform等でも同様のことが言えますが、リソースの削除でデッドロック等を起こさないよう、リソースの削除時はその依存順に削除してくれます。
K8sの一般的なOperator実装に近い実装なので、比較的認知負荷が低い
K8s管理者特有の視点ではありますが、CustomResourceを追加・監視する一般的なOperator実装に近い(というより、おそらくそのまま)実装であるため、Terraformに比べて認知負荷が低く感じました。
新しくアプリケーションのアーキテクチャやマークアップ言語を勉強する必要なく導入できるため、その点ではある程度楽ができます。
ただし、これはなんの勉強も必要ないということではなく、CAPAと各種Providerの責任範囲や各Providerの管理リソースなどは別途確認する必要がある点には注意が必要です。
デメリット
Providerが育ちきっていないケースがある
これは以下の大抵のデメリットの原因なのですが、今回使用したCAPAは十分に育ちきっていません。
APIの破壊的な変更が低頻度ながら存在したり、安定的な動作が見込めない機能が盛り込まれたりしています。
Cluster API Provider AWS のリポジトリ運用が安定していない
今回踏んだ最大の罠でした。
CAPAが提供しているbookは、githubに存在するリポジトリのmainブランチから生成されますが、mainブランチの更新がCAPAのRelease更新と同期していません。
そのため、bookには存在しているのに、実際には最新Releaseでも使用できない機能が存在したりします。
例として、EKSクラスタ上のCAPAをPod Identityで認可するためのオプションである、 clusterawsadm controller use-pod-identity の該当bookページには、その存在が明確に記載されているにもかかわらず、記事執筆時点での最新Releaseであるv2.11.1では存在しません。
[user@machine ~]$ clusterawsadm version
clusterawsadm version: &version.Info{Major:"2", Minor:"11", GitVersion:"2.11.1", GitCommit:"eaa4c99b64d76179cb37e465808f6f00360d0bcc", GitTreeState:"clean", BuildDate:"2026-04-23T13:40:49Z", GoVersion:"go1.24.13", AwsSdkVersion:"v1.41.1", Compiler:"gc", Platform:"linux/amd64"}
[user@machine ~]$ clusterawsadm controller use-pod-identity --cluster-name cluster1
Error: unknown flag: --cluster-name
Usage:
clusterawsadm controller [command] [flags]
clusterawsadm controller [command]
Available Commands:
print-credentials print credentials the controller is using
rollout-controller initiates rollout and restart on capa-controller-manager deployment
update-credentials update credentials the controller is using (i.e., update controller bootstrap secret)
zero-credentials zero credentials the controller is started with
Flags:
-h, --help help for controller
Global Flags:
-v, --v int Set the log level verbosity. (default 2)
Use "clusterawsadm controller [command] --help" for more information about a command.
BootstrapだけのためにIAM Access keyが欲しい
多くのケースで、Bootstrapは手元のマシンから実行することになると思いますが、aws login 等で作成されたstsは自動更新を前提とした短命トークンであり、これをclusterctl init 時にControllerに埋め込むと、時間が経つと動作できなくなる不完全なControllerが生成されてしまいます。
これを避けるためには、(筆者が確認できている手段は)IAM Access keyを使用して永続的なトークンを得るか、EC2上などにbootstrapクラスタを作成しIMDSで自動更新される権限を渡すかの二択になりますが、IAM Access keyは長期運用するとAttack-Surfaceになる懸念が、EC2 IMDSの使用はあまりにも大掛かりすぎる上に、他クラスタにPivotするとトークンが更新できなくなるという問題があります。
EKS上にCAPIリソースをPivotした後は、Pod-Identityを使用することでこの制約を免れることが出来ますが、この機能も現在の最新Releaseには載っていません。(mainブランチには存在するので、恐らく次のRelease時に使用可能になると考えられます。)
また、管理クラスタの解体時などは、自己破壊的な動作による不完全な解体を避けるため、必ず手元にCAPIリソースを移してから作業する必要が出てきますが、この際にもAccess keyが必要となってきます。
Bootstrapが手元から発火する
clusterctl や clusterawsadm 等のCAPI用コマンドラインツールは環境変数を参照して動作します。
そのため、一部の機密情報(例:AWSのクレデンシャル)が環境変数に載ることになり、やや危険です。
また、Init実行者の環境変数によって動作が変わるので、環境の再現性が損なわれます。
Remote clusterのContextを手動でArgoCDに載せる必要がある
CAPIでClusterを建てた後、そのクラスタにArgoCDでAppを展開したいとなったときは、手動でRemote clusterのContextをArgoCDに追加する必要があります。
ただし、CACO等の自動化ツールも存在し、これらの手法によって無視できる程度まで手動管理の煩雑さを減らすことは可能です。
運用上の知見/その他
CAPIが参照するリソースのArgoCDでの運用には注意
CAPIが参照するリソースが載ったAppを、prune=trueにしたり、allowEmpty=trueにしたりすると、間違ってマニフェストを削除した状態でpushしてしまった場合などにクラスタが完全に削除されてしまう恐れがあります。
特に、Self-Manage用のマニフェストなどは、上記のオプション付きで誤って削除すると、完全に削除しきれなかった孤児リソースが発生しかねません。
CAPI用AppはPrune, allowEmptyをfalseにする, Cluster毎にAppは分割する, Self-Manage用AppのAuto-syncはfalseにする等、その運用方法はいつも以上に敏感になる必要があります。
Controllerが、Reconcile時に一部フィールドを書き加える
CAPI/CAPAコントローラーは、Reconcile時に一部未定義値をDefaultingします。kubectl apply -f 等のみで運用する場合は特に問題ありませんが、ArgoCDで管理しようとすると、実際には変更点がないDiffが発生し、OutOfSyncとなる可能性があります。
これを回避するには、該当AppのignoreDifferencesを作成し、差分を無視させると良いでしょう。

一部リソースがDefaultingによってOutOfSyncステータスになっている

matchLabelsをnullに書き戻そうとしているが、書き戻してもすぐ上書きされるため、IgnoreDifferenceするのが良い
# Application.yaml
ignoreDifferences:
- group: cluster.x-k8s.io
kind: '*'
managedFieldsManagers: [manager]
- group: controlplane.cluster.x-k8s.io
kind: '*'
managedFieldsManagers: [manager]
- group: infrastructure.cluster.x-k8s.io
kind: '*'
managedFieldsManagers: [manager]
- group: bootstrap.cluster.x-k8s.io
kind: '*'
managedFieldsManagers: [manager]
まとめ
今回は、CAPI/CAPAとArgoCDを用いての、EKSクラスタ管理のGitOpsを検証してみました。
K8sのカスタムリソースとしてK8sクラスタを管理するという仕組みをArgoCDに載せるアーキテクチャは極めて有用である一方で、CAPIならではの注意点が多く見られる結果となりました。
また、今回使用したProviderであるCAPAはまだ発展途上である様子が強く見られ、現時点で実運用するのは難しいだろうという印象を受けました。 総じて、将来的な可能性を多く秘めた技術として、今後の動向を注視する価値のある技術でしょう。