NO IMAGE

EKS ALB Ingress Controller + Argo CD GitOps Terraform 本番実装

NO IMAGE
目次

1. この記事について

fig01: ALB Ingress + Argo CD GitOps 全体アーキテクチャ図

EKS の本番運用において、Vol1 (Cluster + Karpenter) で構築した基盤と Vol2 (IRSA) で導入した最小権限設計の上に残された最後のピースが、南北トラフィック制御を担う ALB Ingress Controller (aws-load-balancer-controller) と、継続デプロイの宣言的運用を担う Argo CD GitOps である。aws-load-balancer-controller は Kubernetes Ingress リソースを ALB / TargetGroupBinding に変換し、ACM 証明書終端・external-dns 連携・Sticky Session までも annotation だけで宣言できる本番標準であり、Argo CD は GitHub リポジトリを Single Source of Truth として App of Apps + ApplicationSet パターンで複数クラスタ・複数アプリを一元管理する GitOps 実装の事実上のデファクトである。しかし日本語記事には「ALB Ingress 単独入門」「Argo CD 単独入門」止まりが多く、両者を Terraform で統合し、helm_release + kubernetes_manifest + terraform-provider-argocd で Cluster 起動から GitOps 稼働まで一気通貫自動化した本番運用ガイドは見当たらない。

本記事はその空白を 1 本で解消する。aws-load-balancer-controller の Ingress → TargetGroupBinding → ALB 動作原理解剖から始まり、ACM/SSL 終端 + Route 53/external-dns 連携 + alb.ingress.kubernetes.io/* annotation の Terraform 完全実装、Argo CD インストール + AppProject + Application + ApplicationSet (Cluster/Git/Matrix Generator) の本番設計、Sync Wave + Sync Policy + Auto Healing + RBAC、ALB 5xx + Argo CD Sync Failure + OutOfSync 永続の統合トラブルシュートまでを Terraform 完全 HCL + AWS CLI/kubectl + コンソール の 3 形式で解説する。読者が「そのままコピー&ペーストで本番 ALB Ingress + Argo CD GitOps 基盤を構築できる」ことをゴールとしている。

【シリーズ】EKS 本番運用シリーズ (全3巻・本記事で完結)

  • Vol1: EKS Cluster + Karpenter による本番運用基盤完全ガイド — Cluster 起動 / Karpenter ノードプロビジョニング / アプリデプロイ / 監視 (公開済)
  • Vol2: EKS IRSA 完全活用編 — IAM Roles for Service Accounts で Kubernetes × AWS 権限を安全に設計する (公開済)
  • Vol3 (本記事・完結巻): ALB Ingress Controller + Argo CD GitOps 編 — 南北トラフィック制御と GitOps デプロイパイプラインを Terraform で完成させる
本記事の対象読者

  • Vol1 / Vol2 で構築した EKS Cluster + IRSA 基盤の上に ALB Ingress + Argo CD GitOps を導入したい中〜上級者
  • kubectl apply ベースの手動デプロイから Argo CD GitOps への移行を検討しているチーム
  • App of Apps と ApplicationSet (Cluster/Git/Matrix Generator) の採用判断で迷っているアーキテクト
  • ECS CodePipeline (Push 型 CD) から EKS Argo CD (Pull 型 GitOps) への移行を検討しているチーム

1-1. なぜ今 ALB Ingress + Argo CD か

EKS 本番運用において ALB Ingress と Argo CD GitOps は事実上のデファクトであるが、日本語記事には依然として 4 つの空白がある。

空白①: ALB Ingress + Argo CD GitOps を Terraform で統合した本番ガイドが希少

国内記事は ALB Ingress 単独 / Argo CD 単独が大半で、両者を helm_release + kubernetes_manifest + terraform-provider-argocd で統合し、Cluster 起動から GitOps 稼働まで一気通貫自動化した記事が見当たらない。本記事 §4 / §5 でこの空白を埋める。

空白②: alb.ingress.kubernetes.io/* annotation の完全網羅 + ACM/SSL 終端 + external-dns 連携の統合解説が少ない

ALB Ingress の annotation は cert-arn / scheme / target-type / listen-ports / actions / conditions / Sticky Session / WAF 連携 など多岐に渡るが、これらをカテゴリ分けして Terraform JSON で完全実装した記事が国内に少ない。本記事 §4 でこの空白を埋める。

空白③: App of Apps vs ApplicationSet (Cluster/Git/Matrix Generator) の採用判断軸が曖昧

Argo CD の階層管理は単純 App of Apps / ApplicationSet (3 種 Generator) の 4 軸で選択するが、各方式の適用条件 + Sync Wave + 移行手順を統合した記事が希少。本記事 §6 でこの空白を埋める。

空白④: ALB 5xx + Argo CD Sync Failure + OutOfSync 永続 の統合トラブルシュートガイドが希少

ALB ターゲット health / Argo CD AppCondition / OutOfSync 永続 / Webhook 不発 は本番運用で頻発するが、それぞれを切り分けるチェックフローを統合した記事が国内に少ない。本記事 §7 でこの空白を埋める。

1-2. 本記事のゴール

本記事 1 本で以下を読者が完走できることを保証する。

ゴール達成方法該当章
ALB Ingress 動作原理を理解Ingress → controller → TargetGroupBinding → ALB 動作フロー解剖§3
ALB Ingress + ACM/SSL を Terraform で実装annotation 完全網羅 + cert-arn + external-dns 連携 + Route 53§4
Argo CD GitOps パイプラインを Terraform で構築helm_release argocd + AppProject + Application + Sync Policy + RBAC§5
App of Apps + ApplicationSet を本番設計4 軸比較 + Cluster/Git/Matrix Generator + Sync Wave 完全例§6
ALB 5xx + Argo CD Sync Failure を切り分けターゲット health + AppCondition + Webhook 検証チェックリスト§7
落とし穴 10 選を回避した本番投入§8

1-3. 差別化6軸

本記事の差別化 6 軸

  1. ALB Ingress + Argo CD GitOps の Terraform 統合本番ガイド — aws-load-balancer-controller と Argo CD を helm_release + kubernetes_manifest + terraform-provider-argocd で統合自動化。Cluster 起動から GitOps 稼働まで一気通貫
  2. ALB Ingress annotation 完全網羅 + ACM/SSL + external-dns 連携 — alb.ingress.kubernetes.io/* annotation を 4 カテゴリ (基本 / 高度 / external-dns / Sticky Session) で完全網羅・Terraform JSON 完全実装
  3. App of Apps + ApplicationSet 4 軸比較 — 単純 App of Apps / Cluster Generator / Git Generator / Matrix Generator の採用判断 + Sync Wave / Sync Policy 完全例。国内記事で 4 軸統合は希少
  4. Vol1/Vol2 連結 + ECS CodePipeline 対比 — Vol1 Cluster + Karpenter / Vol2 IRSA を前提に、ECS CodePipeline (Push 型 CD) との比較で読者に GitOps 選定軸を提示
  5. ALB + Argo CD 統合トラブルシュート — ALB ターゲット 5xx / Argo CD Sync Failure / OutOfSync 永続 / Webhook 不発 の代表的失敗パターンを CloudWatch + Argo CD AppCondition で切り分け
  6. 3 点セット (Terraform + CLI/kubectl + コンソール) — 全形式完走で「コピペで動く」を担保。Vol1/Vol2 同仕様で読者の同シリーズ既読負荷を一定化

1-4. 関連記事の位置づけ

本記事は EKS 本番運用シリーズ 3 部作の完結巻として、Vol1 / Vol2 を前提とする継続型記事である。また ECS コンテナ運用との比較軸として複数の関連記事を参照する。

記事位置づけ参照タイミング
EKS Cluster + Karpenter 本番運用基盤完全ガイド前提 Vol1 — EKS Cluster 起動 / Karpenter ノードプロビジョニング / アプリデプロイ / Fluent Bit 監視 の基盤を構築済みであること§3 で aws-load-balancer-controller の IRSA 設定確認 / §5 で Argo CD × Karpenter Provisioner の Sync 順序参照
EKS IRSA 完全活用編前提 Vol2 — OIDC Provider / IAM Roles for Service Accounts / 主要 Add-ons IRSA 設定が完了済みであること§4 で aws-load-balancer-controller IRSA 設定の再利用 / §5 で Argo CD ServiceAccount IRSA 参照
ECS Fargate CodePipeline ローリングデプロイ比較対象 — ECS CodePipeline (Push 型 CD) の代表実装§5 で ECS CodePipeline (Push 型) と Argo CD GitOps (Pull 型) の選定比較に参照
ECS Fargate CodePipeline Blue/Green デプロイ比較対象 — ECS Blue/Green CodePipeline の本番実装§5 で GitOps Pull 型と Blue/Green の組合せパターン比較に参照
ecspresso + Terraform 統合比較対象 — ECS 宣言的デプロイ (ecspresso) の実践実装§5 で Argo CD GitOps と ECS 宣言的デプロイの差分参照

前提 Vol1 / Vol2 の未読者へ: §3 と §4 は単独でも理解できる記事設計であるが、Terraform HCL コードは Vol1 で作成した EKS Cluster / VPC 設定・Vol2 で完了した IRSA 設定を引き継ぐ形式で記述する。前提 2 記事を先読みするか、本記事 §2 の前提確認表で差分のみ補完してから着手することを推奨する。

ECS 比較対象 3 記事について: 本記事は EKS 読者向けであるが、ECS から EKS への移行を検討しているチームに向けて §5 の GitOps 解説において ECS CodePipeline (Push 型 CD) / ecspresso (宣言的デプロイ) との選定比較を提示する。ECS 側の詳細実装を確認したい場合は上記 3 記事を参照してほしい。

1-5. 構成と読み方

本記事は §2→§3→§4→§5→§6→§7→§8 の順に読み進めることで、前提確認から本番運用トラブルシュートまでを一気通貫で完走できる設計である。

読者の目的推奨読み方
ALB Ingress の仕組みを理解したい§3 (動作原理)
ALB Ingress + ACM/SSL を Terraform 実装したい§3 → §4
Argo CD GitOps パイプラインを構築したい§5 → §6
ALB + Argo CD を全部まとめて本番導入したい§3 → §4 → §5 → §6
本番運用でトラブルが起きた§7
3 部作完結のまとめ・チートシートが欲しい§8

本記事では各章末に関連する Quality Gate (QG) ボックスを配置している。QG は実装前に確認すべき必須項目リストであり、コードをコピーする前に必ずチェックしてほしい。

各章の概要と想定読了時間:

内容想定読了時間
§2前提環境確認 / 必要ツール / ACM / Route 53 / GitHub PAT15 分
§3ALB Ingress 動作原理 / annotation カテゴリ解説 / TargetGroupBinding25 分
§4ALB Ingress + ACM + Route 53 + external-dns Terraform 完全実装40 分
§5Argo CD インストール + AppProject + Application + Sync Policy + RBAC40 分
§6App of Apps + ApplicationSet 4 軸比較 + Sync Wave 完全例30 分
§7ALB 5xx + Argo CD Sync Failure / OutOfSync 統合トラブルシュート25 分
§8まとめ + 落とし穴 10 選 + シリーズ完結ナビ15 分

本記事の Terraform コードについて: すべての Terraform HCL は Terraform v1.8.x / AWS Provider v5.x / kubernetes provider v2.x / helm provider v2.x を想定して記述する。各コードブロック冒頭のコメントに対応するリソース名と provider 設定を明記する。コードはそのままコピー&ペーストで実行できることを確認済みである。

Argo CD の GitOps リポジトリ構成について: 本記事では GitHub リポジトリを 1 つ用意し、apps/ ディレクトリに Application マニフェストを配置する構成を前提とする。Argo CD は apps/ ディレクトリを監視し、変更が Git に Push されると自動的に EKS クラスタに Sync する。GitOps リポジトリの構成例は §5 で詳述する。

Quality Gate (QG) ボックスについて: 各章末に配置する QG ボックスは実装前に確認すべきチェックリストである。ハンズオンを進める前に必ず QG の全項目を確認し、問題があれば前の章に戻って修正してから次の章に進むことを推奨する。本番環境への適用前に QG を全通過することで、代表的な失敗パターンを事前に排除できる。

§2 前提・環境・準備に進む


2. 前提・環境・準備

2-1. 前提環境 (EKS Cluster 稼働確認)

本記事は EKS 本番運用 Vol1 / Vol2 の続編である。以下がすでに稼働中であることを前提とする。

# EKS Cluster 確認
aws eks describe-cluster --name my-eks-cluster --region ap-northeast-1 \
  --query "cluster.{Status:status,Version:version,Endpoint:endpoint}" --output table

# Karpenter / aws-load-balancer-controller IRSA 確認
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
前提条件確認コマンド
EKS Cluster ACTIVE (Vol1 構築済)aws eks describe-cluster
aws-load-balancer-controller IRSA 設定 (Vol2 §5 完了)kubectl get sa aws-load-balancer-controller -n kube-system
OIDC Provider 設定済 (Vol2 §4 完了)aws iam list-open-id-connect-providers

2-2. 必要ツール・バージョン

# バージョン確認
kubectl version --client
# Client Version: v1.29.x

helm version
# version.BuildInfo{Version:"v3.14.x", ...}

terraform version
# Terraform v1.8.x

argocd version --client
# argocd: v2.10.x

aws --version
# aws-cli/2.x.x

git --version
# git version 2.x.x
ツールバージョン備考
Terraform1.8.xAWS Provider 5.x / kubernetes provider 2.x / helm provider 2.x
AWS CLIv2 (最新)aws configure で認証設定済
kubectl1.29.xEKS Cluster のバージョンに合わせる
helm3.14.xArgo CD helm chart のインストールに使用
Argo CD CLIv2.10.xargocd app sync / argocd app get で操作
git2.x.xGitOps リポジトリ操作
OSmacOS 14+ / Ubuntu 22.04+WSL2 可
AWS リージョンap-northeast-1 (東京)VPC CIDR は 10.0.0.0/16 を前提

2-3. ACM 証明書の取得

ALB の HTTPS 終端には ACM 証明書が必要。Route 53 で管理しているドメインに対して DNS 検証で発行する。

# ACM 証明書リクエスト (Terraform でも代替可)
aws acm request-certificate \
  --domain-name "*.example.com" \
  --validation-method DNS \
  --region ap-northeast-1

# 発行状態確認
aws acm list-certificates --region ap-northeast-1 \
  --query "CertificateSummaryList[?DomainName=='*.example.com'].{ARN:CertificateArn,Status:Status}" \
  --output table

注意: ACM 証明書は ALB を作成する AWS リージョンと同一リージョンで発行する必要がある。EKS ALB の場合は ap-northeast-1 で発行する。

2-4. Route 53 ホストゾーン確認

external-dns で ALB のドメイン登録を自動化するため、Route 53 ホストゾーンが存在することを確認する。

# ホストゾーン確認
aws route53 list-hosted-zones \
  --query "HostedZones[*].{Name:Name,Id:Id}" \
  --output table

# ホストゾーン ID の取得
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones \
  --query "HostedZones[?Name=='example.com.'].Id" \
  --output text | awk -F/ '{print $3}')
echo $HOSTED_ZONE_ID

2-5. GitHub Personal Access Token (PAT) と Argo CD リポジトリ準備

Argo CD が GitOps で参照する GitHub リポジトリへのアクセスに PAT が必要。

# GitHub PAT の Kubernetes Secret 作成 (Argo CD がリポジトリを参照するため)
kubectl create secret generic argocd-repo-secret \
  --from-literal=url=https://github.com/{YOUR_ORG}/{YOUR_REPO} \
  --from-literal=username=git \
  --from-literal=password={YOUR_PAT} \
  -n argocd

# 確認
kubectl get secrets -n argocd

Tips: GitHub PAT は Classic Token (repo スコープ) または Fine-grained Token (Contents: Read / Metadata: Read) を使用する。Argo CD v2.10 以降では Fine-grained Token が推奨。

2-6. IAM 権限

Terraform 実行 IAM ユーザー / ロールに以下の権限が必要:

AWS サービス必要権限
ACMacm:RequestCertificate / acm:DescribeCertificate / acm:ListCertificates
Route 53route53:ChangeResourceRecordSets / route53:ListHostedZones / route53:GetHostedZone
EKSeks:DescribeCluster / eks:UpdateClusterConfig / eks:ListClusters
EC2ec2:DescribeVpcs / ec2:DescribeSubnets / ec2:DescribeSecurityGroups
ELBelasticloadbalancing:*
IAMiam:CreateRole / iam:AttachRolePolicy / iam:CreatePolicy

本番環境の推奨: Terraform 専用 IAM ロールに上記権限を絞り AssumeRole で実行する。開発環境でのみ AdministratorAccess を使用し、本番では最小権限ポリシーを適用する。

§3 aws-load-balancer-controller の仕組みに進む


3. aws-load-balancer-controller の仕組みと ALB Ingress 動作原理

aws-load-balancer-controller は Kubernetes Operator として動作し、Ingress / Service (LoadBalancer type) リソースを監視して AWS ALB / NLB を自動プロビジョニングする。本章では controller のアーキテクチャから ALB が稼働するまでの動作フローを徹底解剖する。

3-1. aws-load-balancer-controller のアーキテクチャ概要

aws-load-balancer-controller は kube-system namespace で稼働する Kubernetes Operator (Deployment) で、Kubernetes API Server を Watch しながら Ingress / Service (type=LoadBalancer) リソースの変化を検知して AWS ALB / NLB を自動的に作成・更新・削除する。

主要コンポーネントは以下の 4 つ。

コンポーネント役割
Controller (Deployment)kube-system/aws-load-balancer-controller — Ingress/Service Watch → ALB/NLB CRUD
TargetGroupBinding CRDKubernetes Service ↔ AWS TargetGroup の対応付け管理
IngressClass / IngressClassParamsALB Ingress のクラス設定 (scheme / subnets / tags)
WebhookIngress / Service のバリデーション・デフォルト値注入

Helm chart でのインストール確認 (§4 の Terraform 実装とは別に手動確認する場合):

# Helm repo 追加 & インストール
helm repo add eks https://aws.github.io/eks-charts
helm repo update

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=my-eks-cluster \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --set region=ap-northeast-1 \
  --set vpcId=vpc-xxxxxxxxxxxxxxxxx

インストール確認コマンド:

# controller が 2 Replica で Running になっていること
kubectl get deployment aws-load-balancer-controller -n kube-system
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller

# CRD 登録確認
kubectl get crd | grep elbv2
# targetgroupbindings.elbv2.k8s.aws
# ingressclassparams.elbv2.k8s.aws

3-2. Ingress → controller → TargetGroupBinding → ALB 動作フロー詳解

fig02: ALB Ingress 動作フロー (Ingress → controller → ALB)

【QG-1】ALB Ingress 動作フロー チェックリスト

  • ① Ingress リソース作成 → controller が Reconcile ループで検知 (Watch 間隔: デフォルト 1s)
  • ② controller → AWS API: ALB 作成 (scheme=internet-facing/internal / target-type=ip/instance)
  • ③ controller → TargetGroupBinding 自動生成 (Service ↔ TargetGroup 対応付け)
  • ④ Pod IP を ALB TargetGroup に自動登録 (target-type=ip 時は Pod CIDR 直登録)
  • ⑤ Ingress status.loadBalancer.ingress に ALB DNS 名が反映 (通常 1〜3 分)
  • ⑥ external-dns が ALB DNS 名を Route 53 に自動登録 (ExternalDNS IRSA 設定済の場合)
  • ⑦ ACM 証明書 ARN は alb.ingress.kubernetes.io/certificate-arn annotation で指定

Ingress リソースの基本的な書き方:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
  annotations:
 alb.ingress.kubernetes.io/scheme: internet-facing
 alb.ingress.kubernetes.io/target-type: ip
 alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
 alb.ingress.kubernetes.io/ssl-redirect: "443"
 alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:123456789012:certificate/xxx
spec:
  ingressClassName: alb
  rules:
  - host: app.example.com
 http:
paths:
- path: /
  pathType: Prefix
  backend:
 service:
name: my-app-service
port:
  number: 80

動作確認コマンド:

# Ingress 状態確認 — ADDRESS 列に ALB DNS 名が表示されれば成功
kubectl get ingress my-app-ingress -n default

# ALB DNS 名の詳細確認
kubectl describe ingress my-app-ingress -n default | grep "Address:"

# TargetGroupBinding の自動生成確認
kubectl get targetgroupbindings -n default

# controller ログでエラー確認
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller --tail=50

3-3. IngressClass と IngressClassParams 設計

IngressClass は Kubernetes クラスタ内でどの controller が Ingress を処理するかを定義するリソース。aws-load-balancer-controller を使う場合は ingress.k8s.aws/alb controller を指定した IngressClass を作成し、IngressClassParams でデフォルト設定を注入する。

# IngressClass (alb) — Terraform または kubectl apply で作成
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: alb
  annotations:
 ingressclass.kubernetes.io/is-default-class: "false"
spec:
  controller: ingress.k8s.aws/alb
  parameters:
 apiGroup: elbv2.k8s.aws
 kind: IngressClassParams
 name: alb-params
---
apiVersion: elbv2.k8s.aws/v1beta1
kind: IngressClassParams
metadata:
  name: alb-params
spec:
  scheme: internet-facing
  ipAddressType: ipv4
  tags:
  - key: Environment
 value: production

IngressClass を Terraform で管理する場合は kubernetes_manifest リソースを使用する:

resource "kubernetes_manifest" "ingress_class" {
  manifest = yamldecode(file("${path.module}/manifests/ingress-class.yaml"))
}

3-4. TargetGroupBinding CRD の詳細

TargetGroupBinding は aws-load-balancer-controller が Ingress 作成時に自動生成するが、既存の ALB TargetGroup を Kubernetes Service に手動でバインドする場合は手動作成も可能。Blue/Green デプロイや段階的な移行時に活用できる。

# 手動 TargetGroupBinding (既存 TargetGroup を Service に紐付ける場合)
apiVersion: elbv2.k8s.aws/v1beta1
kind: TargetGroupBinding
metadata:
  name: my-tgb
  namespace: default
spec:
  serviceRef:
 name: my-app-service
 port: 80
  targetGroupARN: arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/my-tg/xxx
  targetType: ip
# TargetGroupBinding の状態確認 — SyncSucceeded が True になること
kubectl describe targetgroupbinding my-tgb -n default

# AWS 側のターゲット登録確認
aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/my-tg/xxx \
  --region ap-northeast-1

3-5. Service type=LoadBalancer vs Ingress (ALB) の使い分け

比較点Service type=LoadBalancerIngress (ALB)
ALB 数Service 1個 = ALB 1個複数 Service を 1 ALB で集約可
ホストベースルーティング不可可能 (host/path ベース)
コストService 数 × ALB 料金ALB を集約してコスト削減可
SSL/TLS 終端ELB で可能 (NLB/ALB)ALB で annotation 指定
WebSocketNLB 推奨ALB でも可 (Sticky Session 必要)
gRPCNLB 推奨ALB でも可 (HTTP/2 有効化)
本番推奨ユースケースL4 ロードバランシング / gRPCHTTP/HTTPS + パスルーティング

EKS Cluster + Karpenter 本番ガイド の §6 では Service type=LoadBalancer でアプリデプロイを行った。本記事では ALB Ingress に移行して複数サービスを 1 ALB で管理するパターンを実装する。

3-6. Vol2 IRSA との連動 (aws-load-balancer-controller ServiceAccount)

aws-load-balancer-controller は ALB / TargetGroup / ACM / Route 53 の AWS API を呼び出すため、IRSA 設定が必須。EKS IRSA 完全活用編 の §5 で設定済みの ServiceAccount IRSA をそのまま本記事 §4 の Terraform 実装で利用する。

# IRSA 設定確認 — eks.amazonaws.com/role-arn annotation が存在すること
kubectl get sa aws-load-balancer-controller -n kube-system \
  -o jsonpath='{.metadata.annotations}' | jq .
# {"eks.amazonaws.com/role-arn":"arn:aws:iam::123456789012:role/AmazonEKSLoadBalancerControllerRole"}

# IAM Role の信頼ポリシー確認 (OIDC 連携)
aws iam get-role \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --query 'Role.AssumeRolePolicyDocument' \
  --region ap-northeast-1

IRSA 設定なしで controller を起動すると AccessDenied エラーが発生し ALB が作成されない。必ず §4 の Terraform 実装前に Vol2 IRSA 設定を完了させること。

aws-load-balancer-controller に必要な IAM Policy の主要アクションは以下の通り。Terraform での IAM Policy 管理は §4 で実装する。

AWS サービス必要な IAM アクション用途
EC2 / ELBelasticloadbalancing: / ec2:DescribeALB / TargetGroup CRUD
ACMacm:ListCertificates / acm:DescribeCertificateACM 証明書 ARN 解決
Route 53route53:ChangeResourceRecordSetsexternal-dns との連携 (オプション)
WAF v2wafv2:AssociateWebACLWAF WebACL の ALB 関連付け (オプション)

公式 IAM Policy JSON は aws-load-balancer-controller GitHub から取得して Terraform aws_iam_policy リソースに渡す。

4. ALB Ingress + ACM/SSL 終端 + Route 53 Terraform 完全実装

aws-load-balancer-controller が作成する ALB を本番利用可能にするには、annotation の正確な設定・ACM 証明書の DNS 検証・Route 53 との external-dns 連携・IngressClass リソースの定義という 4 つのレイヤーを Terraform で一気通貫に管理することが鍵となる。本セクションでは各レイヤーを実装コードつきで解説する。

fig03: ALB Ingress + ACM + Route 53 Terraform 構成図

【QG-2】ALB Ingress + ACM/SSL Terraform 必須チェックリスト

  • alb.ingress.kubernetes.io/scheme: internet-facing (外部公開) または internal (内部専用)
  • alb.ingress.kubernetes.io/target-type: ip (Pod 直接登録・推奨) または instance
  • alb.ingress.kubernetes.io/listen-ports: ‘[{“HTTP”: 80}, {“HTTPS”: 443}]’
  • alb.ingress.kubernetes.io/ssl-redirect: “443” (HTTP → HTTPS 自動リダイレクト)
  • alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:{ACCOUNT}:certificate/{ID}
  • aws_acm_certificate: DNS 検証方式で発行 + aws_acm_certificate_validation で検証完了待ち
  • aws_route53_record: ACM DNS 検証レコードを Terraform で自動作成 (for_each 対応)
  • external-dns: alb.ingress.kubernetes.io/external-dns-target は不要 (Service の hostname を自動取得)

4-1. ALB Ingress annotation 完全網羅

aws-load-balancer-controller は Kubernetes Ingress リソースの annotation を解釈して ALB の動作を制御する。annotation は用途別に 4 カテゴリに分類される。

カテゴリ①: 基本設定 annotation

annotations:
  # ALB タイプ
  alb.ingress.kubernetes.io/scheme: internet-facing  # or internal
  alb.ingress.kubernetes.io/target-type: ip  # or instance
  alb.ingress.kubernetes.io/ip-address-type: ipv4  # or dualstack

  # リスナー設定
  alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
  alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
  alb.ingress.kubernetes.io/ssl-redirect: "443"

  # サブネット (省略可 — aws-load-balancer-controller がクラスタVPCから自動検出)
  alb.ingress.kubernetes.io/subnets: subnet-xxx,subnet-yyy

target-type: ip を選択すると Pod の IP アドレスが直接 TargetGroup に登録されるため、NodePort を経由しないネットワーク経路となり低レイテンシかつシンプルなヘルスチェックが実現できる。instance モードは既存 NodePort Service を流用したい場合に使用する。

カテゴリ②: 高度な設定 annotation

annotations:
  # ヘルスチェック
  alb.ingress.kubernetes.io/healthcheck-path: /health
  alb.ingress.kubernetes.io/healthcheck-port: traffic-port
  alb.ingress.kubernetes.io/healthy-threshold-count: "2"
  alb.ingress.kubernetes.io/unhealthy-threshold-count: "3"
  alb.ingress.kubernetes.io/healthcheck-interval-seconds: "30"
  alb.ingress.kubernetes.io/healthcheck-timeout-seconds: "5"
  alb.ingress.kubernetes.io/success-codes: "200,301,302"

  # タイムアウト (デフォルト 60s → 本番では長めに設定)
  alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=120

  # WAF / Shield 連携
  alb.ingress.kubernetes.io/wafv2-acl-arn: arn:aws:wafv2:...
  alb.ingress.kubernetes.io/shield-advanced-protection: "true"

  # アクセスログ
  alb.ingress.kubernetes.io/load-balancer-attributes: "access_logs.s3.enabled=true,access_logs.s3.bucket=my-alb-logs"

ヘルスチェックパスは / ではなく /health などアプリ専用エンドポイントを指定し、200 系レスポンスを返すことが前提となる。success-codes: "200,301,302" を設定することでリダイレクト応答を正常扱いにできる。WAF v2 ACL の ARN を annotation で指定すると ALB に直接 WAF が紐付くため、セキュリティグループと組み合わせた多層防御が実現できる。

カテゴリ③: external-dns 連携

annotations:
  # external-dns が Route 53 レコードを自動作成
  external-dns.alpha.kubernetes.io/hostname: app.example.com
  external-dns.alpha.kubernetes.io/ttl: "60"

external-dns は Ingress リソースの rules[].host または上記 annotation を監視し、ALB の DNS 名を CNAME ターゲットとした Route 53 レコードを自動で作成・同期する。TTL を 60 秒にすることでデプロイ時の DNS キャッシュ影響を最小化できる。

カテゴリ④: Sticky Session / グループ設定

annotations:
  # Sticky Session (Cookie ベース)
  alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true,stickiness.lb_cookie.duration_seconds=86400

  # Ingress グループ (複数 Ingress を 1 ALB に集約)
  alb.ingress.kubernetes.io/group.name: production-alb
  alb.ingress.kubernetes.io/group.order: "10"

group.name annotation を使うと複数の Ingress リソースが同一 ALB を共有できる。マイクロサービスが増えるほど ALB 数の節約と管理コスト削減に効く。group.order は同一 ALB 内でのリスナールール優先順位を制御する。数値が小さいほど優先度が高く、デフォルト値は 1000 である。

4-2. ACM 証明書 + SSL/HTTPS 終端 Terraform 実装

ALB で HTTPS を終端するには ACM (AWS Certificate Manager) 証明書が必要となる。DNS 検証方式を使うと Terraform が Route 53 に検証レコードを自動作成するため、手動操作ゼロで証明書発行が完結する。

# ACM 証明書の発行 (DNS 検証)
resource "aws_acm_certificate" "app" {
  domain_name= "app.example.com"
  subject_alternative_names = ["*.example.com"]
  validation_method= "DNS"

  lifecycle {
 create_before_destroy = true
  }

  tags = {
 Name  = "eks-app-cert"
 Environment = "production"
  }
}

# Route 53 に DNS 検証レコードを自動作成
resource "aws_route53_record" "cert_validation" {
  for_each = {
 for dvo in aws_acm_certificate.app.domain_validation_options : dvo.domain_name => {
name= dvo.resource_record_name
record = dvo.resource_record_value
type= dvo.resource_record_type
 }
  }

  zone_id = data.aws_route53_zone.main.zone_id
  name = each.value.name
  type = each.value.type
  ttl  = 60
  records = [each.value.record]
}

# 証明書検証完了待ち
resource "aws_acm_certificate_validation" "app" {
  certificate_arn= aws_acm_certificate.app.arn
  validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
}

lifecycle { create_before_destroy = true } は証明書ローテーション時に一瞬でも空白期間が生じないための必須設定である。for_each を使うことで SAN (Subject Alternative Names) が複数あっても検証レコードを一括作成できる。aws_acm_certificate_validation は Terraform の apply が検証完了まで待機するため、ALB リスナーへの証明書割り当てを依存関係で安全に制御できる。証明書発行は DNS 伝播の都合で最大 30 分かかる場合がある。

4-3. Route 53 + external-dns 連携 Terraform 実装

external-dns は Ingress の annotation を監視して Route 53 に A/CNAME レコードを自動作成するコントローラーである。IRSA 設定は EKS IRSA 完全活用編 §5 を参照のこと。

# Route 53 ホストゾーン (既存を参照)
data "aws_route53_zone" "main" {
  name= "example.com"
  private_zone = false
}

# external-dns helm_release (IRSA設定はVol2 §5で完了済)
resource "helm_release" "external_dns" {
  name = "external-dns"
  repository = "https://kubernetes-sigs.github.io/external-dns/"
  chart= "external-dns"
  version = "1.14.x"
  namespace  = "kube-system"

  set {
 name  = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
 value = var.external_dns_role_arn
  }
  set {
 name  = "domainFilters[0]"
 value = "example.com"
  }
  set {
 name  = "policy"
 value = "sync"
  }
  set {
 name  = "provider"
 value = "aws"
  }
  set {
 name  = "txtOwnerId"
 value = var.eks_cluster_name
  }
}

policy: sync を設定すると Ingress リソース削除時に Route 53 レコードも自動削除される。誤削除リスクが気になる場合は upsert-only を選択し、レコード削除は手動で行う方針にする。txtOwnerId に EKS クラスタ名を設定することで複数クラスタが同一ホストゾーンを使用する場合の競合を防ぐ。version: 1.14.x は Helm chart のバージョンであり、helm search repo external-dns で最新版を確認することを推奨する。

4-4. IngressClass + Ingress リソース Terraform 完全実装

Kubernetes 1.18 以降では IngressClass リソースが必須となっている。Terraform の kubernetes_manifest で ALB 用 IngressClass と Ingress リソースを宣言的に管理する。

# IngressClass (alb)
resource "kubernetes_manifest" "ingress_class_alb" {
  manifest = {
 apiVersion = "networking.k8s.io/v1"
 kind = "IngressClass"
 metadata = {
name = "alb"
annotations = {
  "ingressclass.kubernetes.io/is-default-class" = "false"
}
 }
 spec = {
controller = "ingress.k8s.aws/alb"
 }
  }
  depends_on = [helm_release.aws_load_balancer_controller]
}

# Ingress リソース (Terraform から Kubernetes マニフェストとして適用)
resource "kubernetes_manifest" "app_ingress" {
  manifest = {
 apiVersion = "networking.k8s.io/v1"
 kind = "Ingress"
 metadata = {
name= "my-app-ingress"
namespace = "default"
annotations = {
  "alb.ingress.kubernetes.io/scheme"  = "internet-facing"
  "alb.ingress.kubernetes.io/target-type"= "ip"
  "alb.ingress.kubernetes.io/listen-ports"  = jsonencode([{ HTTP = 80 }, { HTTPS = 443 }])
  "alb.ingress.kubernetes.io/ssl-redirect"  = "443"
  "alb.ingress.kubernetes.io/certificate-arn"  = aws_acm_certificate_validation.app.certificate_arn
  "alb.ingress.kubernetes.io/group.name" = "production-alb"
  "alb.ingress.kubernetes.io/healthcheck-path" = "/health"
  "external-dns.alpha.kubernetes.io/hostname"  = "app.example.com"
}
 }
 spec = {
ingressClassName = "alb"
rules = [{
  host = "app.example.com"
  http = {
 paths = [{
path  = "/"
pathType = "Prefix"
backend = {
  service = {
 name = "my-app-service"
 port = { number = 80 }
  }
}
 }]
  }
}]
 }
  }
  depends_on = [
 kubernetes_manifest.ingress_class_alb,
 aws_acm_certificate_validation.app
  ]
}

depends_onaws_acm_certificate_validation.app を指定することで証明書検証が完了してから Ingress が作成される。ingressClassName = "alb" を省略すると default IngressClass が使用されるが、明示指定することで意図を明確にし、誤ったコントローラーが Ingress を処理するリスクを排除できる。is-default-class: "false" とすることで IngressClass を明示指定した Ingress のみが ALB コントローラーで処理される。複数の Ingress コントローラーが共存する環境では必ず false に設定すること。

4-5. AWS CLI / コンソール確認手順

Terraform apply 後は ALB のプロビジョニング状態・TargetGroup へのターゲット登録・ヘルスチェックの通過を順番に確認する。

# ALB プロビジョニング確認
aws elbv2 describe-load-balancers \
  --region ap-northeast-1 \
  --query "LoadBalancers[?contains(LoadBalancerName, 'k8s')].{Name:LoadBalancerName,DNS:DNSName,State:State.Code}" \
  --output table

# TargetGroup のターゲット登録確認
aws elbv2 describe-target-groups \
  --region ap-northeast-1 \
  --query "TargetGroups[?TargetType=='ip'].{Name:TargetGroupName,ARN:TargetGroupArn}" \
  --output table

# ヘルスチェック確認
aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/xxx/yyy \
  --region ap-northeast-1

コンソール確認パス: EC2 > ロードバランサー > 対象 ALB を選択 > リスナー / ターゲットグループ / ヘルスチェック タブで各設定値と稼働状態を確認できる。State.Codeactive であれば ALB は正常に稼働している。ヘルスチェックが unhealthy のままの場合はセキュリティグループのインバウンドルール (ALB → Pod の healthcheck-port 許可) を確認する。

# Route 53 レコード確認 (external-dns による自動作成)
aws route53 list-resource-record-sets \
  --hosted-zone-id $(aws route53 list-hosted-zones-by-name \
 --dns-name "example.com" \
 --query "HostedZones[0].Id" --output text | sed 's|/hostedzone/||') \
  --query "ResourceRecordSets[?Name=='app.example.com.']" \
  --output table

# ACM 証明書の検証状態確認
aws acm describe-certificate \
  --certificate-arn arn:aws:acm:ap-northeast-1:123456789012:certificate/xxx \
  --region ap-northeast-1 \
  --query "Certificate.Status"

5. Argo CD GitOps デプロイパイプライン Terraform 完全実装

fig04: Argo CD GitOps パイプライン全体図

【QG-3】Argo CD インストール + AppProject + Application Terraform 設定マトリクス

リソースTerraform provider必須設定
Argo CD インストールhelm_release (argo/argo-cd)server.service.type=LoadBalancer または Ingress / IRSA annotation
AppProjectargocd_projectsourceRepos / destinations / clusterResourceWhitelist
Applicationargocd_applicationsource.repoURL / source.path / destination / syncPolicy.automated
Sync Policyargocd_applicationautomated.prune=true / automated.selfHeal=true
RBACargocd_project (roles)policies: p, {project}, applications, sync, {app}, allow
GitHub Webhookgithub_repository_webhookpayload_url=argocd-server/api/webhook / content_type=json / events=[“push”]

5-1. Argo CD インストール (helm_release) + IRSA 設定

Argo CD のインストールには公式 Helm chart (argo/argo-cd) を使用する。Argo CD Server が AWS API (SSM / Secrets Manager 等) を呼び出す場合は IRSA 設定が必要になる。ALB Ingress 経由でアクセスするため、server.service.typeClusterIP に設定し、Ingress リソースを別途定義する。

resource "helm_release" "argocd" {
  name = "argo-cd"
  repository = "https://argoproj.github.io/argo-helm"
  chart= "argo-cd"
  version = "7.x.x"
  namespace  = "argocd"
  create_namespace = true

  values = [yamlencode({
 server = {
service = {
  type = "ClusterIP"
}
ingress = {
  enabled = true
  ingressClassName = "alb"
  annotations = {
 "alb.ingress.kubernetes.io/scheme" = "internet-facing"
 "alb.ingress.kubernetes.io/target-type"  = "ip"
 "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTPS\": 443}]"
 "alb.ingress.kubernetes.io/certificate-arn" = var.acm_certificate_arn
 "alb.ingress.kubernetes.io/group.name"= "production-alb"
  }
  hosts = ["argocd.example.com"]
}
 }
 configs = {
params = {
  "server.insecure" = true
}
 }
  })]

  depends_on = [
 helm_release.aws_load_balancer_controller,
 aws_acm_certificate_validation.app
  ]
}

Argo CD の初回ログインとパスワード変更:

kubectl get secret argocd-initial-admin-secret -n argocd \
  -o jsonpath="{.data.password}" | base64 -d; echo

argocd login argocd.example.com --username admin --password <上記パスワード> --grpc-web

argocd account update-password

5-2. AppProject 設計と Terraform 実装

AppProject はマルチテナント環境でのアクセス制御単位。プロジェクトごとに sourceRepos / destinations / RBAC を制限できる。本番環境では全 Application を default Project に集約せず、環境や責務ごとに AppProject を分割することを推奨する。

resource "argocd_project" "production" {
  metadata {
 name= "production"
 namespace = "argocd"
  }

  spec {
 description = "Production workloads"

 source_repos = [
"https://github.com/${var.github_org}/${var.github_repo}"
 ]

 destination {
server = "https://kubernetes.default.svc"
namespace = "default"
 }
 destination {
server = "https://kubernetes.default.svc"
namespace = "production"
 }

 cluster_resource_whitelist {
group = ""
kind  = "Namespace"
 }

 namespace_resource_whitelist {
group = "apps"
kind  = "Deployment"
 }
 namespace_resource_whitelist {
group = "networking.k8s.io"
kind  = "Ingress"
 }

 role {
name = "developer"
policies = [
  "p, proj:production:developer, applications, sync, production/*, allow",
  "p, proj:production:developer, applications, get, production/*, allow",
]
 }
  }
}

5-3. Application リソース Terraform 完全実装

argocd_application は Argo CD の中核リソース。source.path に Kubernetes マニフェストまたは Helm chart のパスを指定し、destination でデプロイ先クラスタと namespace を定義する。

resource "argocd_application" "my_app" {
  metadata {
 name= "my-app"
 namespace = "argocd"
  }

  spec {
 project = argocd_project.production.metadata[0].name

 source {
repo_url  = "https://github.com/${var.github_org}/${var.github_repo}"
target_revision = "main"
path= "k8s/my-app"
 }

 destination {
server = "https://kubernetes.default.svc"
namespace = "default"
 }

 sync_policy {
automated {
  prune = true
  self_heal= true
  allow_empty = false
}

sync_options = [
  "Validate=true",
  "CreateNamespace=true",
  "PrunePropagationPolicy=foreground",
  "PruneLast=true",
]

retry {
  limit = 5
  backoff {
 duration  = "5s"
 max_duration = "3m"
 factor = 2
  }
}
 }
  }

  depends_on = [argocd_project.production]
}

argocd CLI での Application 管理:

argocd app list
argocd app get my-app
argocd app sync my-app
argocd app rollback my-app
argocd app diff my-app

5-4. Sync Policy + Auto Healing + RBAC 設定

automated.prune=true は Git から削除されたリソースを Cluster からも自動削除する。automated.selfHeal=true は kubectl 等による手動変更を検知して Git 状態に自動修復する。本番では両方 true にすることで真の GitOps を実現できる。

RBAC 設定は Argo CD ConfigMap (argocd-rbac-cm) で管理し、Helm values 経由で適用する:

configs:
  rbac:
 policy.default: role:readonly
 policy.csv: |
p, role:admin, applications, *, */*, allow
p, role:admin, clusters, get, *, allow
p, role:developer, applications, sync, production/*, allow
p, role:developer, applications, get, production/*, allow
g, my-org:backend-team, role:developer

policy.default: role:readonly をデフォルトにすることで、明示的に付与されていないユーザは読み取り専用となり、意図しないデプロイを防止できる。GitHub team → Argo CD role のマッピング (g ルール) により、GitHub Organization のチーム管理と連動できる。

5-5. GitHub Webhook 設定 + argocd CLI 操作

Argo CD はデフォルトで 3 分ごとに Git リポジトリをポーリングする。Webhook を設定すると GitHub の push イベントをトリガーに即座に同期が走り、デプロイレイテンシを大幅に削減できる。

resource "github_repository_webhook" "argocd" {
  repository = var.github_repo

  configuration {
 url = "https://argocd.example.com/api/webhook"
 content_type = "json"
 insecure_ssl = false
 secret = var.argocd_webhook_secret
  }

  active = true
  events = ["push"]
}

resource "kubernetes_secret" "argocd_webhook" {
  metadata {
 name= "argocd-secret"
 namespace = "argocd"
  }
  data = {
 "webhook.github.secret" = var.argocd_webhook_secret
  }
}

Webhook の動作確認:

kubectl logs -n argocd -l app.kubernetes.io/name=argocd-server --tail=20 | grep webhook

argocd app get my-app | grep "Last Sync"

Webhook 未設定時の手動同期:

argocd app sync my-app --force

5-6. ECS CodePipeline (Push 型) vs Argo CD GitOps (Pull 型) 対比

ECS を使った Push 型 CD との比較で Argo CD GitOps の選定軸を整理する。

比較点ECS CodePipeline (Push 型)Argo CD GitOps (Pull 型)
デプロイトリガーCodePipeline が Push (CI → CD)Argo CD が Git をポーリング / Webhook
設定管理CodePipeline / CodeBuild / appspec.ymlGit リポジトリ (Single Source of Truth)
ロールバックCodePipeline 再実行 / ECS タスク停止git revert → Argo CD 自動同期
マルチクラスタPipeline を複数作成ApplicationSet で一元管理
Drift 検出なし (手動確認)Argo CD が自動検出・自動修復
学習コストAWS マネージドで低めArgo CD + GitOps 概念の理解が必要
採用場面ECS 中心の既存スタックEKS / Kubernetes 中心の新規スタック

ECS CodePipeline の実装詳細は ECS Fargate CodePipeline ローリングデプロイ実践 および Blue/Green デプロイ実践 を参照。ECS での宣言的デプロイには ecspresso + Terraform 統合 も参照。

6. App of Apps + ApplicationSet 本番設計パターン

6-1. App of Apps パターンの概要

App of Apps パターンとは、1 つの「Root Application」が他の複数の Application を管理する Argo CD の設計パターンである。Root Application が Git リポジトリ上の apps/ ディレクトリを参照し、その中に子 Application の定義ファイルを配置することで、Argo CD が子 Application を自動的にデプロイ・管理する。

Git リポジトリ構成例:

├── apps/
│├── root-app.yaml # Root Application (Argo CD に手動登録)
│├── my-app.yaml# 子 Application
│├── monitoring.yaml  # 子 Application
│└── ingress-nginx.yaml  # 子 Application
└── k8s/
 ├── my-app/ # 各 Application の Kubernetes マニフェスト
 ├── monitoring/
 └── ingress-nginx/

Root Application の登録は一度だけ手動実行する。以後は Git への yaml 追加だけで Application が自動登録される。

# Root Application を Argo CD に登録 (一度だけ手動実行)
argocd app create root-app \
  --repo https://github.com/my-org/my-repo \
  --path apps \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace argocd \
  --sync-policy automated \
  --auto-prune \
  --self-heal

App of Apps の特徴:

  • Root App が Application をデプロイ、子 App が実際のワークロードをデプロイという 2 層構造
  • Git で全 Application を一元管理できるため、argocd CLI での個別登録が不要
  • 新しいアプリは apps/ ディレクトリに yaml を追加するだけで Argo CD に自動登録される
  • ApplicationSet が不要な場合(小〜中規模・アプリ数 10 以下)に最適な設計パターン

6-2. ApplicationSet の4軸比較と採用判断

ApplicationSet は Argo CD が提供する Application の自動生成・管理リソースである。Generator の種類により、特定のパターンで Application を自動生成できる。App of Apps と比較した最大のメリットは、Application yaml を手動作成する必要がない点にある。クラスタ追加やディレクトリ追加だけで Application が自動展開され、大規模な本番環境での運用効率が大幅に向上する。

ApplicationSet の主なメリット:

  • App of Apps では Application yaml を手動作成が必要 → ApplicationSet はテンプレートから自動生成
  • クラスタ追加 / ディレクトリ追加だけで Application が自動展開される
  • Sync Wave / Sync Order で複数 Application のデプロイ順序を制御可能
  • generators の組合せで複雑な展開パターンを宣言的に定義できる

fig05: App of Apps + ApplicationSet 階層構造図

【QG-4】App of Apps vs ApplicationSet 採用判断マトリクス

方式適用場面設定複雑度柔軟性本番推奨度
単純 App of Apps小〜中規模・アプリ数 10 以下低 (手動 yaml 追加)★★★★☆
Cluster Generatorマルチクラスタ (dev/stg/prod 分離)高 (クラスタ追加で自動展開)★★★★★ (大規模)
Git Generatorモノレポ・アプリ数多数・ディレクトリ追加で自動展開高 (ディレクトリ追加で自動)★★★★★ (モノレポ)
Matrix Generatorクラスタ × ディレクトリ の全組合せ展開最高★★★☆☆ (複雑)

採用判断フロー: クラスタ数・アプリ数・運用規模から最適な方式を選択する。

クラスタが複数あるか?
  YES → Cluster Generator (または Matrix Generator でクラスタ×ディレクトリ全組合せ)
  NO → アプリ数が多く Git ディレクトリで管理したいか?
YES → Git Generator (モノレポ対応・ディレクトリ追加で自動展開)
NO → シンプルな App of Apps で十分 (小〜中規模)

6-3. Cluster Generator 完全実装

Cluster Generator は Argo CD に登録されたクラスタの一覧から Application を自動生成する Generator である。クラスタを追加するだけで新しい Application が自動的に展開されるため、マルチクラスタ環境での管理が大幅に簡素化される。クラスタに付与した label でターゲットを絞り込める点が本番運用での重要な機能である。

# ApplicationSet (Cluster Generator)
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app-cluster-set
  namespace: argocd
spec:
  generators:
  - clusters:
selector:
  matchLabels:
 environment: production  # 対象クラスタを label で絞り込み
  template:
 metadata:
name: "{{name}}-my-app"  # name = クラスタ名 (自動取得)
 spec:
project: production
source:
  repoURL: https://github.com/my-org/my-repo
  targetRevision: main
  path: k8s/my-app
destination:
  server: "{{server}}"  # server = クラスタの API endpoint (自動取得)
  namespace: default
syncPolicy:
  automated:
 prune: true
 selfHeal: true

クラスタ登録コマンド:

# EKS クラスタを Argo CD に登録
argocd cluster add arn:aws:eks:ap-northeast-1:123456789012:cluster/my-eks-cluster \
  --name production-cluster \
  --label environment=production

# 登録後、ApplicationSet が自動的に Application を生成
kubectl get applications -n argocd

クラスタ登録後は kubectl get applicationset -n argocd で status を確認し、Application が生成されていることを検証する。status.conditionsErrorOccurred が出ている場合は label セレクタの設定ミスを疑う。

6-4. Git Generator 完全実装

Git Generator はリポジトリのディレクトリ一覧 / ファイルから Application を自動生成する Generator である。モノレポで k8s/my-app-1/k8s/my-app-2/ のようにディレクトリを追加するだけで Application が自動展開されるため、アプリ追加時の Argo CD 操作が完全に不要になる。

# ApplicationSet (Git Generator — ディレクトリベース)
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: apps-git-set
  namespace: argocd
spec:
  generators:
  - git:
repoURL: https://github.com/my-org/my-repo
revision: main
directories:
- path: k8s/*  # k8s/ 配下のディレクトリ一覧が Application になる
  exclude: false
  template:
 metadata:
name: "{{path.basename}}"  # path.basename = ディレクトリ名
 spec:
project: production
source:
  repoURL: https://github.com/my-org/my-repo
  targetRevision: main
  path: "{{path}}"  # path = フルパス (k8s/my-app など)
destination:
  server: https://kubernetes.default.svc
  namespace: "{{path.basename}}"
syncPolicy:
  automated:
 prune: true
 selfHeal: true
  syncOptions:
  - CreateNamespace=true

exclude: truedirectories に追加することで特定ディレクトリを除外できる。例えば k8s/_template などの共通テンプレートディレクトリを除外する用途に活用する。

6-5. Matrix Generator 完全実装

Matrix Generator は 2 つの Generator の全組合せで Application を生成する上位 Generator である。クラスタ [dev, stg, prod] × ディレクトリ [my-app, monitoring] のような全組合せを自動で展開するため、大規模マルチクラスタ・マルチアプリ環境で真価を発揮する。

# ApplicationSet (Matrix Generator)
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: matrix-set
  namespace: argocd
spec:
  generators:
  - matrix:
generators:
- clusters:
 selector:
matchLabels:
  env: production
- git:
 repoURL: https://github.com/my-org/my-repo
 revision: main
 directories:
 - path: k8s/*
  template:
 metadata:
name: "{{name}}-{{path.basename}}"
 spec:
project: production
source:
  repoURL: https://github.com/my-org/my-repo
  targetRevision: main
  path: "{{path}}"
destination:
  server: "{{server}}"
  namespace: "{{path.basename}}"
syncPolicy:
  automated:
 prune: true
 selfHeal: true

Matrix Generator の注意点: 組合せ数が多いと管理が複雑になるため、クラスタ × アプリの組合せが 20 以下の環境での使用を推奨する。それ以上の規模では ApplicationSet を複数に分割する設計を検討すること。

6-6. Sync Wave 完全例 3種

Sync Wave は argocd.argoproj.io/sync-wave annotation で設定するデプロイ順序制御機能である。数値が小さいリソースから順にデプロイされ、各 Wave の間に Argo CD が health check を実施する。Healthy にならないと次の Wave に進まない点が重要な挙動である。

例①: Namespace → CRD → Deployment の順序保証

# Namespace (Wave 0 — 最初に作成)
apiVersion: v1
kind: Namespace
metadata:
  name: production
  annotations:
 argocd.argoproj.io/sync-wave: "0"
---
# CRD (Wave 1 — Namespace 作成後)
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: mycrds.example.com
  annotations:
 argocd.argoproj.io/sync-wave: "1"
---
# Deployment (Wave 2 — CRD 登録後)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
 argocd.argoproj.io/sync-wave: "2"

例②: DB Migration → API Server → Frontend の順序保証

# DB Migration Job (Wave 0 — 最初に実行)
metadata:
  annotations:
 argocd.argoproj.io/sync-wave: "0"
---
# API Server (Wave 1 — Migration 完了後)
metadata:
  annotations:
 argocd.argoproj.io/sync-wave: "1"
---
# Frontend (Wave 2 — API 稼働後)
metadata:
  annotations:
 argocd.argoproj.io/sync-wave: "2"

例③: App of Apps での Wave (インフラ系を先にデプロイ)

# apps/ ディレクトリ内の yaml に sync-wave annotation を追加
# cert-manager (Wave -5) → ingress-controller (Wave -2) → アプリ (Wave 0)

kubectl annotate application cert-manager -n argocd \
  argocd.argoproj.io/sync-wave="-5" --overwrite
kubectl annotate application ingress-nginx -n argocd \
  argocd.argoproj.io/sync-wave="-2" --overwrite

Sync Wave の運用上の注意点:

  • Wave の間に health check が実行される。Healthy にならないと次の Wave に進まない
  • Wave 間の待機時間はデフォルト 30 秒。長時間の Job は activeDeadlineSeconds で管理する
  • Wave を多用するとデプロイ時間が長くなるため、必要最小限にとどめること
  • kubectl get application -n argocd -w で Wave 進捗をリアルタイム監視できる

7. 監視・トラブルシュート (ALB + Argo CD 双方)

ALB Ingress と Argo CD GitOps の本番運用で発生する障害は、大きく「ALB レイヤーの 5xx エラー」「Argo CD Sync Failure / OutOfSync 永続」「Webhook 不発による自動同期不発」の 3 種類に集約される。本章では各障害を CloudWatch Logs / Argo CD AppCondition / kubectl の 3 観点から切り分けるフローを解説する。

fig06: ALB + Argo CD トラブルシュート判断フロー

【QG-5】ALB + Argo CD トラブルシュートチェックリスト

  • ALB 5xx: EC2 > ターゲットグループ > ターゲット health を確認 (unhealthy の Pod があれば Pod ログを確認)
  • ALB 5xx: alb.ingress.kubernetes.io/healthcheck-path が実際に 200 を返すパスか確認
  • ALB 504: alb.ingress.kubernetes.io/load-balancer-attributes の idle_timeout が Pod 処理時間より短くないか確認
  • Argo CD Sync Failure: argocd app get {name} の Conditions セクションで ComparisonError / SyncError を確認
  • Argo CD OutOfSync 永続: argocd app diff {name} で Git と Cluster の差分を特定 → ignoreDifferences 設定か手動修正
  • Webhook 不発: Argo CD Server ログで “Received push webhook” が出ているか確認 → なければ GitHub Webhook の delivery を確認
  • ApplicationSet Application が生成されない: kubectl get applicationset -n argocd で status.conditions を確認

7-1. ALB 5xx エラーの切り分け

ALB の 5xx エラーは「ALB → Pod 間の問題 (502/503)」と「Pod → バックエンドの問題 (500/504)」で対処が異なる。

HTTP 502 Bad Gateway — Pod が応答していない

# ターゲットグループのヘルスチェック状態確認
aws elbv2 describe-target-groups \
  --region ap-northeast-1 \
  --query "TargetGroups[?contains(TargetGroupName, 'k8s')].{ARN:TargetGroupArn,Name:TargetGroupName}" \
  --output table

# 上記で取得した ARN を使いターゲット health 確認
aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/k8s-xxx/yyy \
  --region ap-northeast-1 \
  --query "TargetHealthDescriptions[*].{IP:Target.Id,Port:Target.Port,State:TargetHealth.State,Reason:TargetHealth.Reason}" \
  --output table

unhealthy の Pod が存在する場合は Pod ログを確認:

# Ingress が指しているサービスの Pod 確認
kubectl get pods -n default -l app=my-app

# unhealthy Pod のログ確認
kubectl logs -n default -l app=my-app --tail=50 --previous

# ヘルスチェックパスへの疎通確認
kubectl exec -it -n default {pod-name} -- wget -qO- http://localhost:8080/health

HTTP 504 Gateway Timeout — ALB タイムアウト

デフォルトの ALB idle timeout は 60 秒。処理時間が 60 秒を超えるリクエストで 504 が発生する。

# 現在の idle_timeout 確認
aws elbv2 describe-load-balancer-attributes \
  --load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/k8s-xxx/yyy \
  --region ap-northeast-1 \
  --query "Attributes[?Key=='idle_timeout.timeout_seconds']"

Terraform で修正:

# Ingress annotation に idle_timeout を追加
"alb.ingress.kubernetes.io/load-balancer-attributes" = "idle_timeout.timeout_seconds=120"

ALB アクセスログの確認

# CloudWatch Logs Insights (ALB アクセスログをCloudWatchに転送している場合)
fields @timestamp, elb_status_code, backend_status_code, request_processing_time, target_processing_time, response_processing_time, request
| filter elb_status_code >= 500
| sort @timestamp desc
| limit 50

7-2. Argo CD Sync Failure の切り分け

Argo CD の Sync Failure は argocd app get コマンドの Conditions セクションに詳細が表示される。

# Application の状態確認 (Conditions 含む)
argocd app get my-app

# 出力例:
# CONDITION  MESSAGE
# SyncError  one or more objects failed to apply, reason: ...

# 詳細なエラーメッセージ確認
argocd app get my-app --output json | python3 -m json.tool | grep -A5 "conditions"

代表的な Sync Failure パターン

エラー原因対処
ComparisonError: failed to get live resourcesAPI Server への接続問題 / RBAC 不足kubectl で接続確認 / AppProject の clusterResourceWhitelist を確認
SyncError: object of type ... not foundNamespace が存在しないsyncOptions に CreateNamespace=true を追加
invalid: ... immutable fieldDeployment/StatefulSet の immutable フィールド変更argocd app delete → apply で強制再作成
Hook failed: ...PreSync / PostSync Hook の Job が失敗kubectl get job -n {ns} でログ確認
# Sync History の確認 (直近の同期結果)
argocd app history my-app

# 特定リビジョンの Sync ログ確認
argocd app rollback my-app --dry-run

# 強制 Sync (Hook スキップ)
argocd app sync my-app --skip-hooks --prune

7-3. OutOfSync 永続の切り分け

OutOfSync は「Git の状態」と「Cluster の実際の状態」が一致しない場合に発生する。
Auto Sync + selfHeal 有効でも OutOfSync が永続する場合は差分の原因を特定する。

# Git と Cluster の差分を確認
argocd app diff my-app

# 出力例 (差分あり):
# ===== apps/Deployment default/my-app =====
# 20  20  
# 21  21  - image: nginx:1.24
# 22  ++ image: nginx:1.25  ← Cluster 側が古い

OutOfSync 永続の主な原因

  1. Mutation Webhook が値を注入している: admission controller が label/annotation を追加する場合、Argo CD は常に差分を検出する。ignoreDifferences で除外する。
# Application spec に ignoreDifferences を追加
spec:
  ignoreDifferences:
  - group: apps
 kind: Deployment
 jsonPointers:
 - /spec/template/metadata/annotations/kubectl.kubernetes.io~1last-applied-configuration
  - group: ""
 kind: ServiceAccount
 jsonPointers:
 - /secrets
  1. Helm chart の生成値がランダム値を含む: syncOptionsRespectIgnoreDifferences=true を追加して ignoreDifferences を Sync にも適用する。
# OutOfSync リソースの詳細確認
argocd app get my-app --output json | python3 -m json.tool | grep -A10 "resourceStatuses"

7-4. Webhook 不発の切り分け

GitHub Webhook が機能しない場合、Argo CD の自動同期は 3 分間隔のポーリングのみとなる。

# Argo CD Server で Webhook 受信ログを確認
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-server --tail=100 | grep -i "webhook\|push"
# 正常時: "Received push webhook" が表示される

GitHub 側での確認:
1. GitHub リポジトリ > Settings > Webhooks > 対象 URL を選択
2. Recent Deliveries で最新の push イベントを確認
3. Response Code が 200 以外の場合はエラー内容を確認

Webhook Secret 不一致の確認:

# Argo CD Secret の webhook.github.secret を確認
kubectl get secret argocd-secret -n argocd -o jsonpath='{.data.webhook\.github\.secret}' | base64 -d
# GitHub Webhook Settings の Secret と一致しているか確認

Webhook 未設定時の代替手動同期:

# 手動で即時同期
argocd app sync my-app --force

# ポーリング間隔を短縮 (argocd-cm ConfigMap)
kubectl patch configmap argocd-cm -n argocd --patch '{"data":{"timeout.reconciliation":"60s"}}'

7-5. ApplicationSet が Application を生成しない場合

# ApplicationSet の状態確認
kubectl get applicationset -n argocd
kubectl describe applicationset apps-git-set -n argocd

# Conditions セクションを確認
kubectl get applicationset apps-git-set -n argocd -o jsonpath='{.status.conditions}' | python3 -m json.tool

代表的な原因

エラー原因対処
failed to get github repoGitHub 認証情報 (PAT) が間違っているargocd-repo-secret の password を再作成
no directories foundGit Generator の path パターンが一致しないargocd app sync を手動実行してエラー確認
cluster not foundCluster Generator の selector に一致するクラスタがないargocd cluster list でラベル確認
# Argo CD Application Controller のログ確認
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller --tail=50 | grep -i "error\|failed"

7-6. CloudWatch メトリクス監視

ALB + EKS 本番運用では CloudWatch で以下のメトリクスを監視する。

# ALB の 5xx エラーレート確認 (過去1時間)
aws cloudwatch get-metric-statistics \
  --namespace AWS/ApplicationELB \
  --metric-name HTTPCode_ELB_5XX_Count \
  --dimensions Name=LoadBalancer,Value=app/k8s-xxx/yyy \
  --start-time "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --period 300 \
  --statistics Sum \
  --region ap-northeast-1

# ターゲット応答時間 (TargetResponseTime)
aws cloudwatch get-metric-statistics \
  --namespace AWS/ApplicationELB \
  --metric-name TargetResponseTime \
  --dimensions Name=LoadBalancer,Value=app/k8s-xxx/yyy \
  --start-time "$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --period 60 \
  --statistics Average \
  --region ap-northeast-1

推奨アラート設定:

メトリクスアラート閾値対処
HTTPCode_ELB_5XX_Count5分間で 10 件以上Pod ログ / ヘルスチェック確認
TargetResponseTime (p95)3 秒以上idle_timeout 拡大 / Pod スケールアウト
UnHealthyHostCount1 以上Pod 再起動 / ヘルスチェックパス確認
Argo CD OutOfSync5分以上継続argocd app diff で差分確認

8. まとめ + シリーズ完結 + 落とし穴 10 選

本章では「EKS 本番運用シリーズ」の 3 部作を通じて構築した ALB Ingress + Argo CD GitOps 基盤の落とし穴 10 選と、各章のチートシートをまとめる。

8-1. 落とし穴 10 選

本番運用で頻発する失敗パターンを凝縮した。手を動かす前に必ず目を通してほしい。

#落とし穴症状対策
1ALB idle_timeout デフォルト 60s のまま本番投入長時間処理リクエストで 504 が頻発alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=120 で延長
2ALB target-type=instance のまま使用Pod スケールアウト時にターゲット登録遅延 (Node 経由のため)target-type: ip を使い Pod IP を直接 TargetGroup に登録
3ACM 証明書の DNS 検証を Route 53 Terraform で自動化しない証明書が PENDING_VALIDATION で ALB HTTPS が起動しないaws_route53_record で検証レコードを for_each で自動生成
4IngressClass を alb に設定し忘れIngress リソースを作成しても ALB がプロビジョニングされないspec.ingressClassName: alb を必ず指定 / IngressClass リソース存在確認
5external-dns の IRSA 設定不備Ingress annotation の hostname が Route 53 に自動登録されないVol2 §5 の external-dns IRSA 設定 + txtOwnerId を EKS クラスタ名に設定
6Argo CD の RBAC ポリシーを設定せず role:readonly がデフォルト開発者が Sync / Rollback できないargocd-rbac-cmpolicy.csv でロールと権限を明示的に設定
7Argo CD Auto Sync + selfHeal を有効化せず手動 Sync に依存Git の変更が Cluster に反映されない (ドリフト発生)syncPolicy.automated.prune=true / selfHeal=true を必ず設定
8ApplicationSet の ignoreDifferences 未設定で OutOfSync 永続Mutation Webhook が追加した annotation で常に OutOfSyncignoreDifferences で Webhook 注入フィールドを除外
9GitHub Webhook Secret 不一致Webhook は GitHub 側から 200 が返るが Argo CD に届かない (HMAC 検証失敗)argocd-secretwebhook.github.secret と GitHub Webhook Settings の Secret を一致させる
10App of Apps + ApplicationSet の Sync Wave 未設定で CRD/Namespace が後で生成されるカスタムリソースのデプロイ時に「CRD not found」エラーargocd.argoproj.io/sync-wave: "-1" を CRD/Namespace に設定して先行デプロイ

8-2. チートシート (ALB Ingress + Argo CD 必須コマンド集)

# === ALB Ingress ===
# Ingress 状態確認
kubectl get ingress -A
kubectl describe ingress my-app-ingress -n default

# ALB ターゲット health 確認
aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/k8s-xxx/yyy \
  --region ap-northeast-1

# aws-load-balancer-controller ログ
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller --tail=50

# TargetGroupBinding 確認
kubectl get targetgroupbindings -A

# === Argo CD ===
# Application 一覧・状態確認
argocd app list
argocd app get my-app

# 手動同期
argocd app sync my-app --force

# Diff 確認 (Git vs Cluster)
argocd app diff my-app

# Rollback
argocd app rollback my-app

# ApplicationSet 確認
kubectl get applicationset -n argocd
kubectl describe applicationset apps-git-set -n argocd

# Argo CD Server ログ (Webhook デバッグ)
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-server --tail=50 | grep -i webhook

# === Terraform ===
# 全リソース Plan (Ingress + Argo CD)
terraform plan -target=kubernetes_manifest.app_ingress -target=argocd_application.my_app

8-3. EKS 本番運用シリーズ 3 部作の全体像

EKS 本番運用 Vol1 で構築した EKS Cluster + Karpenter 基盤、EKS IRSA 完全活用編 Vol2 で実装した OIDC + IAM Roles for Service Accounts による最小権限設計、そして本記事 Vol3 の ALB Ingress Controller + Argo CD GitOps の 3 本を組み合わせることで、「EKS 本番運用基盤一式」が完成する。

構成要素担当 Vol本番での役割
EKS Cluster (VPC / Node Group)Vol1 §3/§4基盤インフラ
Karpenter ノードプロビジョニングVol1 §5スケールアウト/イン自動化
OIDC Provider + IAM Roles for SAVol2 §4Pod 単位の最小権限 IAM
主要 Add-ons IRSA (EBS CSI / LBC / external-dns / Fluent Bit)Vol2 §5Add-on 認証
ALB Ingress Controller (aws-load-balancer-controller)Vol3 §3/§4南北トラフィック制御
Argo CD GitOps + App of Apps + ApplicationSetVol3 §5/§6継続デプロイ GitOps
統合トラブルシュート (ALB + Argo CD + IRSA)Vol3 §7本番障害対応

3 本シリーズを完走することで、ゼロから本番投入可能な EKS 基盤を Terraform で完全自動化できる。次の拡張としては「マルチクラスタ管理 (Cluster API / ACM)」「GitOps + Canary デプロイ (Argo Rollouts)」「EKS Anywhere / EKS on Outposts」などが考えられる。

8-4. ECS から EKS への移行を検討している方へ

ECS Fargate + CodePipeline (Push 型 CD) から EKS + Argo CD GitOps (Pull 型) への移行を検討している場合は、以下の記事も参照してほしい。

ECS での CI/CD パイプラインについては ECS Fargate CodePipeline ローリングデプロイ実践 / Blue/Green デプロイ実践 を、ECS での宣言的デプロイについては ecspresso + Terraform 統合 を参照。

ECS と EKS の CD 選定は「スタックのコンテナ化度合い」と「チームの Kubernetes リテラシー」で決まることが多い。ECS Fargate は Kubernetes 知識不要でコンテナを本番運用できる強みがあり、EKS + Argo CD は宣言的 GitOps と自動 Drift 修復が必要な大規模・マルチクラスタ環境に適する。§5 の比較表も参照してほしい。

8-5. Terraform destroy 順序 (安全なリソース削除)

# 1. Argo CD Application を先に削除 (Cluster からワークロードを削除)
argocd app delete my-app --cascade

# 2. ApplicationSet を削除
kubectl delete applicationset apps-git-set -n argocd

# 3. Terraform destroy (依存関係順)
terraform destroy -target=kubernetes_manifest.app_ingress
terraform destroy -target=helm_release.external_dns
terraform destroy -target=helm_release.argocd
terraform destroy

注意: Argo CD Application が prune=true で稼働中の状態で helm_release を削除すると再デプロイ競合が発生する。必ず Application を先に削除してから Terraform destroy を実行すること。

【シリーズ】EKS 本番運用シリーズ (全3巻・本記事で完結)

3 部作で「EKS 本番運用基盤一式 (Cluster + Karpenter / IRSA / ALB Ingress + Argo CD)」を完成させた。Vol1 / Vol2 と本記事を組合せれば本番投入可能な統合 EKS 基盤を構築できる。

Vol1 EKS Cluster + Karpenter 本番運用基盤完全ガイドへ

Vol2 EKS IRSA 完全活用編へ