tech.guitarrapc.cóm

Technical updates

EKS CapabilityでArgoCDを展開する

2025/11/30、EKS Capabilityが発表されました。 Capabilityで実行するコントローラーは、EKS AutoModeの拡張のような形でAWSの保持するEKSが管理する実行環境で実行されるため、ユーザー管理のEKSクラスターではPodが実行されません。 感覚的には、Configurationが乏しいが完全AWS ManagedなEKS Addonのようなイメージです。

今回は、EKS Capabilityで実行するArgoCDはどのような感じなのか見てみましょう。私はOSS版のArgoCDを使っているので違いや制約がとても気になります。

短くまとめ

EKS CapabilityでArgoCDは動きます、しかも悪くない感じです。本番で使うにしても割とありより判断です。気になるところとして、ドキュメントにある制約が、書いてあるより引っかかりやすいです。忘れてはいけないのは、OSS版ArgoCDを見るとわかる通り、ArgoCD自体が多くのコンポーネントを必要として、Podも5台以上必要になることが多いです。Capability版はこれをAWSが管理してくれるので、運用負荷はかなり下がります。

OSS版でPod 0台にしてコストを下げる荒業は、EKS Capability版ではできずコンスタントに常時課金分がかかります。規模が小さいほど、たびたび思い出したように、えーって感じにはなりそう。しょうがない。

〇 よいところ

  • EKS CapabilityにセットしたIAM RoleでAWSサービス連携が容易なのは悪くない感じ
  • リモートクラスターをEKS Access Entryで登録するのもシンプルな感じでよい
  • ArgoCDはコンポーネントが複数あるしアップデートも割と大変なので任せられるのはあり

△ 気になるところ

  • インクラスターを登録するのにAmazonEKSClusterAdminPolicyをEKS Access Entryで紐づけるのは権限が気になる、バグ?
  • ArgoCD Notificationが使えない (Slack通知で困る)
  • 認証バックエンドがIdentity Centerに固定されている (Cognitoなど他IdPを使えない)
  • コストがちょっとかかる。Pod分が不要と思えばありな気もしなくはない。(ArgoCDはPod結構必要なので)

気にならない制約

  • Namespace supportは別になくても平気なのでよさそう。(ArgoCDのApplicationを複数のnamespaceにデプロイする機能。argocdnamespaceに集約すればいいので運用上は必須じゃない)
  • ArgoCD Image Updaterが使えない

EKS Capabilityを展開する

先日リリースされたばかりなので、TerraformやPulumiのようなIaCツールはまだAPIをサポートしていません。ドキュメントに沿って、AWS CLIかコンソールで操作できます。今回は、EKS AutoModeで展開したEKSクラスターに、AWSコンソールからArgoCDを展開します。

ArgoCD Capabilityを展開するには次の手順で進めます。

  • EKS CapabilityのためにIAM Roleを用意する
  • ArgoCD Capabilityを作成する

EKS CapabilityのためにIAM Roleを用意する

EKS Capabilityは、ユーザー管理EKSクラスターに対して操作するためIAM Roleを必要としているようです。 目新しいのがAsuumeRoleのcapabilities.eks.amazonaws.comです。また、権限にAWSSecretsManagerClientReadOnlyAccessを付けておくと、ArgoCDのリポジトリ参照時にSecrets Managerを参照できます。

apiVersion: v1
kind: Secret
metadata:
  name: private-repo
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: https://github.com/org/repo
  secretArn: arn:aws:secretsmanager:ap-northeast-1:012345689:secret:argocd/github-token # AWSSecretsManagerClientReadOnlyAccessをIAM Roleにつけておくと、この参照ができる

IAM Roleを作成する模擬的なPulumi C#のコードは次のようになります。

var argoCDCapabilityRole = new IamRoleComponent($"{name}-capability-argocd", opt, new()
{
    RequireInstanceProfile = false,
    AssumeRolePolicy = IamPolicy.GetAssumeRolePolicyJson("capabilities.eks.amazonaws.com", ["sts.AssumeRole", "sts:TagSession"]),
    IamPolicyArg = new IamPolicyArg
    {
        PolicyArns = IamPolicy.GetAwsManagedPolicyArns(
        [
            "arn:aws:iam::aws:policy/AWSSecretsManagerClientReadOnlyAccess",
        ]),
    },
    RoleName = $"{name}-capability-argocd",
});

ArgoCD Capabilityを作成する

IAM Roleが用意できたらEKS Capabilityを作成します。ドキュメントにはAWS CLIでの手順が載っていますが、Identity Centerとの連携が必要なので正直コンソールでやる方が楽です。IaCサポートもまだないので、今回は雰囲気をつかむことも狙ってコンソールでやってみましょう。

まずはCapabilityのタブから、Create capabilityをクリックします。

alt text

Argo CDを選択します。

alt text

ArgoCD Capabilityの設定画面が表示されます。今回はクラスター名をautomode-clusterにしていることを踏まえてスクショと見比べてましょう。各項目は次の通りです。

  • Capability Name: デフォルトでクラスター名-argocd
  • Capability Role: 先ほど作成したIAM Roleを指定。AssumeRoleの信頼関係にcapabilities.eks.amazonaws.comが設定されていれば、ドロップダウンに表示される
  • ArgoCD endpoint access: PublicかPrivateを選択。今回はPublicを選択1
  • Authentication access: AWS Identity Center(IdC)のユーザー/グループとArgoCDのロールマッピング設定。管理を簡単・単純化するためにも、IdCはグループを使ってマッピングするのがよいでしょう。今回はAdminグループ:AdminロールViewOnlyグループ:Viewerロールでマッピング

Additional configuration and defaultsで、ArgoCDが管理するnamespaceを指定できますが、そのままがいいです。OSS版ArgoCDでもインストール先のnamespaceは一般的にargocdにするはずなので。AWS Capability版のArgoCDは、Applicationsの展開先Namespaceは1か所固定です。

alt text

確認画面が出るので、問題なければ作成しましょう。

作成後、Capabilitiesタブに戻り、作成したCapabilityのステータスがACTIVEになっていることを確認します。

alt text

また、クラスターでCRDを見るとArgoCDのカスタムリソースが取得できるはずです。(大事)

$ kubectl api-resources | grep argoproj.io
applications                        app,apps           argoproj.io/v1alpha1              true         Application
applicationsets                     appset,appsets     argoproj.io/v1alpha1              true         ApplicationSet
appprojects                         appproj,appprojs   argoproj.io/v1alpha1              true         AppProject

CapabilityのArgoCDにアクセスする

EKSコンソールからCapabilityタブでArgoCDを選択して、詳細を表示します。Argo API endpointにあるURLから、ArgoCDのWeb UIにアクセスできます。

alt text

いつものArgoCDのSSOログイン画面が表示されるので、LOGIN VIA SSOをクリックしてIdentity Centerの認証でログインします。どうやらArgoCD内部の独自OIDC実装ではなくDexを使っているようで、OIDCのリフレッシュトークンを見ないバグはないようです。

alt text

Identity Centerでログインしているなら、スムーズにArgoCDのダッシュボードが表示されます。ログインしていない場合は、Identity Centerのログイン画面が表示されます。

alt text

動作しているArgoCDバージョンは、EKS Consoleの表示と同様に3.1.8+eks-1のようです。OSS版の3.1.8は2025/10/1リリースされているので、1か月遅れくらいでCapability版に反映されている感じですね。

クラスターの追加

やっていて罠がクラスター追加でした。

OSS版のArgoCDはインクラスターのKubernetesクラスターをデフォルトで追加します。しかし、CapabilityのArgoCDはクラスターが空っぽです。クラスター追加しましょう。

alt text

クラスターの追加は、argocd cliSecretsドキュメントで紹介されていますが、いざ追加しようとしてもどっちもスムーズにいきません。

ということで順番に見ていきましょう。

argocd cliでクラスターを追加する

argocd cliは、通常argocd loginでArgoCDのエンドポイントにログインします。しかし、CapabilityのArgoCDはargocd loginをサポートしていません。代わりの接続セットアップはドキュメントで次のようになっています。環境変数を使った暗黙の認証ですね。

# 暗黙の認証を設定する
CLUSTER_NAME=my-cluster
CAPABILITY_NAME="$CLUSTER_NAME-argocd"
MYPROFILE="foobar"
export ARGOCD_SERVER=$(aws eks describe-capability --cluster-name $CLUSTER_NAME --capability-name $CAPABILITY_NAME --query 'capability.configuration.argoCd.serverUrl' --output text --profile $MYPROFILE)
export ARGOCD_AUTH_TOKEN="ArgoCD Web UIからAPIトークンを発行する"
export ARGOCD_OPTS="--grpc-web"

# 後段で使うEKSクラスターのARNを取得する
CLUSTER_ARN=$(aws eks describe-cluster --name $CLUSTER_NAME --query 'cluster.arn' --output text --profile $MYPROFILE)

問題はこれでクラスターを追加しようとしても、うまくいきません。

$ argocd cluster add $CLUSTER_ARN --aws-cluster-name $CLUSTER_ARN --name in-cluster --project default
{"level":"fatal","msg":"rpc error: code = Unknown desc = Post \"https://https//dummy01234567890.eks-capabilities.ap-northeast-1.amazonaws.com/cluster.ClusterService/Create\": dial tcp: lookup https on 10.255.255.254:53: read udp 10.255.255.254:45086-\u003e10.255.255.254:53: i/o timeout","time":"2025-12-03T18:47:21+09:00"}

$ argocd cluster add $CLUSTER_ARN --aws-cluster-name $CLUSTER_ARN --name in-cluster --project default --insecure
{"level":"fatal","msg":"rpc error: code = Unknown desc = Post \"https://https//dummy01234567890.eks-capabilities.ap-northeast-1.amazonaws.com/cluster.ClusterService/Create\": dial tcp: lookup https on 10.255.255.254:53: read udp 10.255.255.254:45086-\u003e10.255.255.254:53: i/o timeout","time":"2025-12-03T18:47:21+09:00"}

対処として、ARGOCD_SERVERは通常https://を省くので、これを省くとうまくいきます。罠すぎる。

$ ARGOCD_SERVER=$(aws eks describe-capability --cluster-name $CLUSTER_NAME --capability-name $CAPABILITY_NAME --query 'capability.configuration.argoCd.serverUrl' --output text --profile $MYPROFILE | sed 's/^https:\/\///')
$ argocd cluster add $CLUSTER_ARN --aws-cluster-name $CLUSTER_ARN --name in-cluster --project default
Cluster 'https://dummy01234567890.gr7.ap-northeast-1.eks.amazonaws.com' added

alt text

alt text

Secretsでクラスターを追加する

Secretsで追加する場合、次のようなSecretをargocd namespaceに作成します。これはドキュメント通りです。今回はプロジェクトを追加しないので、project: defaultにしています。もし、初めてArgoCDを触るなら、まずはおとなしくdefaultプロジェクトに追加するのがよいでしょう。

$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: in-cluster
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: cluster
stringData:
  name: in-cluster
  server: arn:aws:eks:ap-northeast-1:0123456789:cluster/my-cluster
  project: default
EOF

ちなみにOSS版ArgoCDのように、https://kubernetes.default.svcのようなインクラスターのKubernetes APIエンドポイントを指定してもクラスターが追加されません。EKS Capability版では、EKSクラスターのARNを指定する必要があるようです。2

# 機能しない
apiVersion: v1
kind: Secret
metadata:
  name: in-cluster
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: cluster
stringData:
  name: in-cluster
  server: https://kubernetes.default.svc
  project: default

EKS Access Entryの権限を調整する

このままいざアプリケーションを追加するとすると、次のようなAPIアクセスエラーが発生します。エラーになるKubernetes APIは、その時々で変わるのですが基本的に何にもアクセスできない感じです。

Failed to load live state: failed to get cluster info for "arn:aws:eks:ap-northeast-1:0123456789:cluster/my-cluster": error synchronizing cache state : failed to sync cluster https://dummy01234567890.ap-northeast-1.prod.ccs.eks.aws.dev: failed to load initial state of resource CSINode.storage.k8s.io: failed to list resources: csinodes.storage.k8s.io is forbidden: User "arn:aws:sts::0123456789:assumed-role/my-eks-capability-argocd/aws-go-sdk-1764755848957927621" cannot list resource "csinodes" in API group "storage.k8s.io" at the cluster scope

原因は、EKS Access Entryに紐づけたAccess Policyの権限が不足しているためです。ドキュメントには、リモートクラスターの時だけAmazonEKSClusterAdminPolicyを紐づけるように書かれていますが、インクラスターでも必要なようです。恐らくCapabilityのバグ(あるいは何かおかしい)と予想していますが、いったん追加しましょう。

EKS ConsoleのAccess Entriesタブに移動します。ArgoCD Capabilityを追加すると、自動的にarn:aws:iam::0123456789:role/mycluster-eks-capability-argocdというEKS Access Entryが作成されています。これを見ると、AmazonEKSArgoCDClusterPolicy, AmazonEKSArgoCDPolicyの2ポリシーが紐づいています。

alt text

Attach policiesボタンをクリックして、AmazonEKSClusterAdminPolicyを追加しましょう。3

alt text

aws cliで調整してもいいでしょう。

aws eks associate-access-policy \
  --cluster-name my-cluster \
  --principal-arn arn:aws:iam::0123456789:role/mycluster-eks-capability-argocd \
  --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy \
  --access-scope type=cluster

before

alt text

after

alt text

アプリケーションを追加する

お待ちかねのアプリケーション追加です。今回は、簡単のためパブリックなGitHubリポジトリにあるサンプルアプリケーションを追加することで、ArgoCDのリポジトリ登録を省略します。試しに私のリポジトリguitarrapc/argocd-labにあるアプリケーションを追加します。

$ kubectl apply -f - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argocd-lab
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/guitarrapc/argocd-lab.git
    targetRevision: main
    path: k8s/api
  destination:
    name: in-cluster # Rename to actual cluster name if needed
    namespace: argocd-lab
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
EOF

ここでもしAPIエラーが発生したら、EKS Access Entryの権限を見直しましょう。

問題なくアプリケーションが追加できれば、次のように表示されます。

alt text

$ kubectl get all -n argocd-lab
NAME                            READY   STATUS    RESTARTS   AGE
pod/api-csharp-5c77f5d6-wwttt   1/1     Running   0          4m20s
pod/api-go-6dc5c4c5ff-4tmdk     1/1     Running   0          4m20s

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/api-csharp-svc   ClusterIP   172.20.44.169   <none>        80/TCP    4m20s
service/api-go-svc       ClusterIP   172.20.207.24   <none>        80/TCP    4m20s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/api-csharp   1/1     1            1           4m20s
deployment.apps/api-go       1/1     1            1           4m20s

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/api-csharp-5c77f5d6   1         1         1       4m20s
replicaset.apps/api-go-6dc5c4c5ff     1         1         1       4m20s

仮に、Kubernets上からGoのAPIサーバーDeploymentを削除しても、ArgoCDが自動的に復元してくれます。

$ kubectl delete deployment api-go -n argocd-lab
deployment.apps "api-go" deleted

alt text

3秒ほどで復元されました。

$ kubectl get deploy -n argocd-lab
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
api-csharp   1/1     1            1           5m15s
api-go       1/1     1            1           34s

alt text

ポートフォワードでアクセスしてみましょう。

$ kubectl port-forward -n argocd-lab svc/api-csharp-svc 8080:80
$ curl http://localhost:8080/
{"machineName":"api-csharp-56f8866dcd-qkkhw","osDescription":"Ubuntu 24.04.3 LTS","processorCount":1,"usedMemoryInMB":5}

$ kubectl port-forward -n argocd-lab svc/api-go-svc 8081:80
$ curl http://localhost:8081/
{"machineName":"api-go-64665c8c5f-2brsk","osDescription":"linux amd64","processorCount":2,"usedMemoryInMB":0}

削除もいつも通りです。アプリケーションを消してもいいですし、ArgoCD UIから削除してもOKです。

alt text

できないこと

OSS版ArgoCDを使っているため、ドキュメントで示されている「Capability版でできないこと」のいくつかが気になります。

ArgoCD Notificationsが使えない

ArgoCD Notificationsは、ArgoCDのイベントをSlackなどに通知する仕組みです。Capability版のArgoCDは、現状この機能をサポートしていません。

具体的には、ArgoCDはコントローラーの状態やNodeの状態によって、アプリケーションの同期状態が変わります。これをSlackなどに通知するときにArgoCD Notificationsを使います。Slack通知がないと見落としやすいため、使えないのはちょっと痛いです。

ArgoCD RBACはいじれない

OSS版ArgoCDは、ポリシーを定義することで自由にArgoCD内部RBACを設定できました。しかし、Capability版ではこの設定ができず、AdminEditorViewerの3ロールに固定されています。細かい権限設定ができないのはちょっと困ります。

たとえば、Syncでデプロイはできるけど、リソースの直接削除・編集はさせたくない。などは調整できない感じですね。

IdentityCenter以外のSSO認証がない

OSS版ArgoCDは任意のOIDC認証を設定できるので、CognitoやAuth0、Okta、Azure EntraID、Google Workspaceなど認証バックエンドを自由に選択できます。Capability版は、現状Identity Centerに固定されています。Identity Centerは悪くないのですが、他の認証バックエンドを使いたい場合は困ります。

個人的にうへーって感じなので、割と深刻に困る人はいるんじゃないですかね。Identity CenterをIdPとして利用するのって、これまであまりなかったような気がします。

ApplicationのNamespaceが一つ

OSS版ArgoCDは複数のNamespaceにApplicatcionをデプロイできましたが、Capability版では1Namespaceに固定されています。デフォルトならargocdNamespaceです。運用回避が可能な範囲ですが、アプリケーションと一緒のnamespaceにデプロイしたい時は困るでしょう。

現状は制約ですが、将来改善予定のようです。

Argo CD Image Updaterが使えない

Argo CD Image Updaterは、コンテナイメージのバージョン更新を検知して、GitHubなどのマニフェストリポジトリに更新PRを自動で作成する仕組みです。これを前提にできるならCIはマニフェストの展開を考える必要がなくなり、イメージプッシュまでが責務になるので便利。ですが、Capability版ではこの機能がサポートされていません。

しょうがない。

無理やりPodを消せない

割と力づくなのでめったにやらないのですが、OSS版ArgoCDでは特定のArgoCDコントローラーを強制に停止させることで、Podを0台にしてランニングコストを下げることができます。しかし、Capability版ではCapabilityが設定されているだけで時間課金されるため、コストを強制的に下げるみたいな荒業は使えません。一長一短ですね。

あと、CRDがかかわっているのでCapability版のArgoCDをアンインストールする前に、Applicationを忘れず削除する必要があるなどは忘れそうで注意です。

コスト

ArgoCD Capabilityのコストは次の通りです。料金は英語ページにしかまだ載ってないようです。

アプリケーションが多いほどお金かかるのはArgoCD的の負荷的にはそうなんですが、OSS版ArgoCDで考えるとアプリケーションが1,2つ増えてもPod負荷は変わらないので、フーンってお気持ちです。10とかあると変わるんですけどね。とはいえ、維持費が$26.98992/month、アプリケーション5つが常時稼働で$6.6708/month、合計$33.66072/monthです。まあ、ArgoCDのPodを5台以上立てることを考えると妥当な気もします。4

  • Argo CD base charge $0.037486 per Argo CD Capability hour (Capability自体の維持費)
  • Argo CD usage charge $0.001853 per Argo CD Application hour (Applicationあたりの維持費)

alt text

TIPS

コンテキスト名を変えてargocd cliを使いたい

Kubernetes ContextでEKS Clusterの接続名を変えると、クラスター追加時のargocdコマンドが変わります。TIPSとしておいておきます。

例えば、コンテキスト名をarn形式arn:aws:eks....からクラスター名my-clusterにしたとしましょう。すると、argocd cliでクラスター追加時にコンテキスト名が一致せず失敗します。

$ kubectx ${CLUSTER_NAME}=arn:aws:eks:${REGION}:${ACCOUNT_ID}:cluster/${CLUSTER_NAME}
$ argocd cluster add $CLUSTER_ARN --aws-cluster-name $CLUSTER_ARN --name in-cluster --project default
{"level":"fatal","msg":"context arn:aws:eks:ap-northeast-1:012345689:cluster/my-cluster does not exist in kubeconfig","time":"2025-12-03T19:30:14+09:00"}

この場合、$CLUSTER_ARNの代わりに、コンテキストの名前${CLUSTER_NAME}を指定します。

$ argocd cluster add $CLUSTER_NAME --aws-cluster-name $CLUSTER_ARN --name in-cluster --project default
Cluster 'https://dummy01234567890.gr7.ap-northeast-1.eks.amazonaws.com' added

まとめ

EKS CapabilityでArgoCDを展開してみました。現状でも十分に使えそうですが、いくつか気になる点もあります。特にEKS Access Entryの権限周りは、もう少し改善してほしいところです。

IaC側のサポートがないので、今のままだとCapabilityを追加しても、クラスターを消すときに連動しないので厄介です。Terraformは実装中で、Pulumi.Awsはこれが入ったら自動変換で入る想定なので、少し待ちましょう。

参考


  1. これかなり微妙です。PublicだとPublicにログイン画面へ到達できるので、正直Privateがよいです。いくらIdentity Centerで認証してもPublicにログイン画面が出てしまうのは、想定外の状況で攻撃ベクターを不要に与えることになります。Privateにして、VPC Endpoint経由でアクセスするのがよいですが、正直IP制限かZero TrustなネットワークをAWSが提供してほしい。
  2. AWS側のコントローラーでarnフォーマットかチェックしてそう。
  3. これ、権限強すぎるし、原理的にもおかしいので、バグっぽいですがどうなんでしょう
  4. EKS、こういう時に地味にお金かかるって感じあるんですよね。常時動かなくても、Serverless的な感じで時々フックされて動いてくれればいいのに、と運用してて感じることがあります。ありませんか?