EKS ArgoCD Capability 構築 — CodeCommit プライベートリポジトリから GitOps デプロイする
目次
はじめに
前回・前々回の記事では、EKS ArgoCD Capability を構築し、GitHub の公開リポジトリ(guestbook サンプル)からデプロイした。しかし実プロジェクトでは、デプロイ対象のマニフェストはプライベートリポジトリに置かれる。
EKS ArgoCD Capability は CodeCommit との「直接統合」をサポートしている。ここでいう直接統合とは、ArgoCD に Repository Secret(リポジトリの認証情報を格納する Kubernetes Secret)を作成せずに、Application の repoURL に CodeCommit の URL を直接指定する方式だ。Capability Role に codecommit:GitPull を付与するだけで、認証は IAM が透過的に処理する。セルフホスト ArgoCD では Git 認証情報を Kubernetes Secret として管理する必要があったが、Capability 版では IAM に統合されている。
この記事では、CodeCommit 直接統合でプライベートリポジトリからの GitOps デプロイを構築し、設定ミス時のエラー挙動とデバッグ方法も検証する。公式ドキュメントは Configure repository access を参照。
前提条件:
- EKS クラスターに ArgoCD Capability が構築済み(シリーズ第1回参照)
- ターゲットクラスターが登録済み
- AWS CLI、kubectl、git が設定済み
- 検証リージョン: ap-northeast-1
検証 1: 直接統合でプライベートリポジトリからデプロイする
CodeCommit リポジトリの準備
CodeCommit にリポジトリを作成し、nginx の Deployment + Service マニフェストを push する。
CodeCommit リポジトリの作成手順
aws codecommit create-repository \
--repository-name argocd-demo \
--repository-description "Demo repository for ArgoCD Capability"ローカルにクローンして Git 認証ヘルパーを設定する。CodeCommit の HTTPS 接続にはこの設定が必要だ。
git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/argocd-demo
cd argocd-demo
git config credential.helper '!aws codecommit credential-helper $@'
git config credential.UseHttpPath truenginx の Deployment と Service を作成する。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80git add . && git commit -m "Initial commit: nginx deployment and service"
git push -u origin mainCapability Role に権限を追加
Capability Role に codecommit:GitPull のインラインポリシーを追加する。Resource の 111122223333 は自分の AWS アカウント ID に置き換える。
aws iam put-role-policy \
--role-name ArgoCDCapabilityRole \
--policy-name CodeCommitGitPull \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "codecommit:GitPull",
"Resource": "arn:aws:codecommit:ap-northeast-1:111122223333:argocd-demo"
}
]
}'ポイントは Resource をリポジトリ ARN にスコープしている点だ。* にすればアカウント内の全リポジトリにアクセスできるが、最小権限の原則に従い、必要なリポジトリだけに絞るべきだ。
Application の作成とデプロイ
Application を作成する。repoURL に CodeCommit の HTTPS URL を直接指定する。Repository Secret は作成しない。destination.name はターゲットクラスター登録時の名前(シリーズ第1回で local-cluster として登録済み)を指定する。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx-codecommit
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/argocd-demo
targetRevision: main
path: manifests
destination:
name: local-cluster
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=truekubectl apply -f nginx-codecommit.yamlfinalizers を設定しておくと、Application 削除時にデプロイ済みリソースもカスケード削除される(シリーズ第2回での教訓)。syncPolicy.automated は Git の変更を自動で同期する設定で、prune: true は Git から削除されたリソースをクラスターからも削除し、selfHeal: true はクラスター上で手動変更されたリソースを Git の状態に戻す。検証環境では便利だが、本番環境では意図しない削除を防ぐために prune の有効化は慎重に判断すべきだ。
約1分後、Application が Synced / Healthy になった。
kubectl get application nginx-codecommit -n argocd -o wideNAME SYNC STATUS HEALTH STATUS REVISION PROJECT
nginx-codecommit Synced Healthy d3bd890b2ce55b3092dc422147755b8a2417c462 defaultPod と Service も正常に起動している。
NAME READY STATUS RESTARTS AGE
nginx-fd956d49d-snhfv 1/1 Running 0 75s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.100.146.27 <none> 80/TCP 75sRepository Secret なしで、CodeCommit プライベートリポジトリからのデプロイが成功した。 Capability Role の IAM ポリシーだけで認証が透過的に処理されている。
マニフェスト変更の自動同期
GitOps の「push したら反映される」サイクルが CodeCommit 連携でも機能するか確認する。replicas を 1 → 2 に変更して push した。
# replicas: 1 → 2 に変更して push
git commit -am "Scale nginx to 2 replicas" && git pushArgoCD のデフォルトポーリング間隔は約3分だ。30秒ごとにステータスを監視した結果、push から約5分15秒後に新しいリビジョンが反映され、Pod が 2 つにスケールした。
# 30秒ごとにリビジョンと Pod 数を確認
while true; do
rev=$(kubectl get application nginx-codecommit -n argocd \
-o jsonpath='{.status.sync.revision}' 2>/dev/null)
pods=$(kubectl get pods -n default --no-headers 2>/dev/null | wc -l)
echo "$(date +%H:%M:%S) revision=${rev:0:8} pods=$pods"
sleep 30
done20:54:12 revision=d3bd890b pods=1
20:54:44 revision=d3bd890b pods=1
...(中略)...
20:58:25 revision=d3bd890b pods=1
20:58:56 revision=c03946cd pods=2 ← ここで同期ポーリング間隔(約3分)を考慮すると、5分程度は想定内だ。push のタイミングとポーリングサイクルのずれにより、反映までの時間は毎回異なる。より即時性が必要な場合は Webhook の設定 を検討するとよい。
検証 2: 設定ミス時のエラー挙動とデバッグ方法
直接統合では ArgoCD UI の Settings → Repositories にリポジトリが表示されない。ArgoCD の Repositories 画面は argocd.argoproj.io/secret-type: repository ラベルが付いた Kubernetes Secret を読み取って一覧を構成するため、Repository Secret を作成していない直接統合ではリポジトリが認識されない。接続テストも UI からは行えない。
では、設定ミスが起きたときにどこを見ればよいのか。読者が実際にやりがちな2つのミスを再現して確認した。
ケース 1: 権限を付与する前にデプロイした場合
codecommit:GitPull を付与せずに Application を作成すると、以下のエラーが Application の status.conditions に表示された。
kubectl get application nginx-codecommit -n argocd \
-o jsonpath='{.status.conditions[0].message}'Failed to load target state: failed to generate manifest for source 1 of 1:
rpc error: code = Unknown desc = failed to list refs: authorization failed:
<AccessDeniedException>
<Message>User: arn:aws:sts::111122223333:assumed-role/ArgoCDCapabilityRole/...
is not authorized to perform: codecommit:GitPull on resource:
arn:aws:codecommit:ap-northeast-1:111122223333:argocd-demo
because no identity-based policy allows the codecommit:GitPull action</Message>
</AccessDeniedException>エラーメッセージは非常に具体的だ。「どのロールが」「どのアクションを」「どのリソースに対して」拒否されたかが明確に示されている。IAM のエラーがそのまま ArgoCD の条件に伝播するため、デバッグに必要な情報は十分にある。
ただし、権限を付与した後に Application がすぐにはリカバリしない点に注意が必要だ。今回の検証では、IAM ポリシーを追加して約90秒待っても同じエラーが継続した。ArgoCD はエラー発生時にリトライ間隔をバックオフする仕組みがあるため、これが原因と考えられる。手動で hard refresh を実行すれば即座にリカバリできる。
kubectl annotate application nginx-codecommit -n argocd \
argocd.argoproj.io/refresh=hard --overwriteこの hard refresh 後、約15秒でデプロイが開始された。
ケース 2: リポジトリ URL を間違えた場合
存在しないリポジトリ名(argocd-demo-typo)を repoURL に指定した Application を作成し、エラーを確認した。ケース 1 と同じ AccessDeniedException が返り、エラーメッセージ内のリソース ARN だけが argocd-demo-typo に変わっている。
is not authorized to perform: codecommit:GitPull on resource:
arn:aws:codecommit:ap-northeast-1:111122223333:argocd-demo-typoURL typo でも権限不足でも、同じ AccessDeniedException が返る。 今回の検証では IAM ポリシーの Resource を特定のリポジトリ ARN にスコープしていたため、スコープ外のリポジトリ名は権限エラーとして処理された。「リポジトリが見つからない」というエラーにはならない。
これはデバッグ時に混乱を招く可能性がある。AccessDeniedException が出たら、まず IAM ポリシーの Resource ARN と Application の repoURL を突き合わせて、リポジトリ名が一致しているかを確認するのがよい。
補足: Repository Secret を使う方法
直接統合の代わりに、Repository Secret を作成して CodeCommit リポジトリを明示的に登録する方法もある。
apiVersion: v1
kind: Secret
metadata:
name: codecommit-repo
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
stringData:
type: git
url: https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/argocd-demo
project: defaultRepository Secret を作成すると、ArgoCD UI の Settings → Repositories にリポジトリが表示される。公式ドキュメントによると、UI から接続ステータスや認証エラーを確認できる。
どちらを選ぶか:
- 直接統合 — 設定が最小限。IAM ポリシー1つで完結する。リポジトリ数が少なく、チームが IAM に慣れている場合に適している
- Repository Secret — ArgoCD UI での可視性が高い。リポジトリ数が多い場合や、ArgoCD の管理画面で接続状態を一覧したい場合に適している
どちらの方法でも、認証は Capability Role の IAM ポリシーで行われる。Repository Secret はあくまで ArgoCD にリポジトリの存在を「教える」ためのものだ。
まとめ
- IAM ポリシー1つで CodeCommit 連携が完結する — Capability Role に
codecommit:GitPullを追加するだけで、Repository Secret なしにプライベートリポジトリからデプロイできる。セルフホスト ArgoCD で必要だった Git 認証情報の管理が不要になる - URL typo と権限不足が同じエラーになる — 今回の検証では IAM ポリシーの
Resourceをリポジトリ ARN にスコープしていたため、存在しないリポジトリへのアクセスもAccessDeniedExceptionとして返った。エラーが出たら、まず IAM ポリシーのResourceとrepoURLのリポジトリ名を突き合わせるのが最初のデバッグステップだ - 権限修正後は手動 refresh が推奨 — 今回の検証では IAM ポリシーを追加して約90秒待っても自動リカバリしなかった。
argocd.argoproj.io/refresh=hardアノテーションで即座にリトライできる
クリーンアップ
# Application の削除(finalizer 付きなのでリソースもカスケード削除される)
kubectl delete application nginx-codecommit -n argocd
# IAM ポリシーの削除
aws iam delete-role-policy \
--role-name ArgoCDCapabilityRole \
--policy-name CodeCommitGitPull
# CodeCommit リポジトリの削除
aws codecommit delete-repository \
--repository-name argocd-demo \
--region ap-northeast-1