Cluster API × ArgoCD による GitOps 駆動のクラスタライフサイクル管理

Sreake事業部

2026.7.14

はじめに

こんにちは。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/MachineDeploymentv1beta1、参照先が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 EKSCAPIの管理先クラスタ
CAPIのコントローラーが動作するクラスタ
AWS EC2CAPAに必要なKeypairの管理など
AWS IAMCAPAが使用するIAM Roleの管理など
Kind初期セットアップ用のローカルK8sクラスタ

コマンドラインツール他

項目用途執筆時点でのバージョンインストール方法備考
kubectlK8sクラスタの管理v1.36.1公式ドキュメントの手順に従ってインストールKube APIサーバーとのマイナーバージョンの差を±1に収めなければならないことに注意してください
clusterctlCAPIの管理v1.13.0公式ドキュメントの手順に従ってインストールArch系列ならAURにも存在します yay -Si clusterctl
clusterawsadmCAPAの管理v2.11.1Releaseから入手 あるいは brew install clusterawsadm
ArgoCD CLIArgoCDの管理v3.4.2公式ドキュメントの手順に従ってインストール
AWS CLIAWSの管理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管理下に配置する

  1. argocdにAppを作成
  2. フェーズ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が手元から発火する

clusterctlclusterawsadm 等の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を作成し、差分を無視させると良いでしょう。

Workloadクラスタ wl1の様子
一部リソースがDefaultingによってOutOfSyncステータスになっている
実際にArgoCD上で確認できたDiff
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はまだ発展途上である様子が強く見られ、現時点で実運用するのは難しいだろうという印象を受けました。 総じて、将来的な可能性を多く秘めた技術として、今後の動向を注視する価値のある技術でしょう。

ブログ一覧へ戻る

お気軽にお問い合わせください

SREの設計・技術支援から、
SRE運用で使用する
ツールの導入など、
SRE全般についてご支援しています。

資料請求・お問い合わせ