AWS Container本番運用Vol3|EKS Pod Identity×Karpenter編

目次

§1 なぜ Container Vol3 か — EKS最新ベストプラクティス全体像 + 三部作ナビ

EKS 本番運用の “第二の壁”

EKS クラスターを GitOps で安定稼働させると、次のような “第二の壁” に直面するケースが多い。

  • IRSA の権限管理が煩雑: OIDC Provider の登録・Trust Policy の ARN 管理・Service Account annotations の三重管理が認知負荷を高め続ける
  • Node コストが読めない: Cluster Autoscaler では Node 構成が固定的で過剰プロビジョニングが常態化し、コスト最適化の余地が大きい
  • Cross-AZ 通信コストが膨らむ: デフォルトの Service ルーティングは AZ をまたぐため、大規模クラスターでは月数万円規模のデータ転送コストが発生する
  • Service Discovery が場当たり的: ELB・CoreDNS・環境変数が混在し、Cross-cluster 通信が絡むと設定変更のたびにリスクが上がる

これらは EKS 自体の限界ではなく、最新のベストプラクティスを適用する好機を示している。AWS は 2023〜2024 年にかけて EKS のコアコンポーネントを刷新した。EKS Pod Identity (2024年 GA) / Karpenter v1 (2024年 GA) / Topology Aware Routing (Kubernetes 1.27 安定化) / EKS Service Connect が出揃い、EKS 本番運用は新しいフェーズに入っている。本記事はこの 4 軸を体系化した実装ガイドだ。

Vol1 → Vol2 → Vol3 の架橋

Container 本番運用シリーズは 3 巻の段階的な構成になっている。

主題対象者
Vol1ECS × Fargate × ECR × ECS Exec × Service Connect 基礎コンテナ初導入チーム
Vol2EKS × ArgoCD × Kustomize × Argo Rollouts GitOps 編Kubernetes 導入・GitOps パイプライン構築チーム
Vol3 (本記事)EKS 縦深化 — Pod Identity × Karpenter × Topology Aware × Service ConnectEKS 本番運用 SRE / プラットフォームエンジニア

Vol1 で ECS コンテナ基盤を構築し、Vol2 で EKS + GitOps パイプラインを整備した段階が本記事の出発点だ。Vol3 では「権限管理の刷新」「コスト最適化」「通信コスト削減」「Service Discovery 統一」の 4 軸で EKS 運用を縦深化する。

EKS の進化と本記事の位置付け

EKS は 2017 年の提供開始以来、大きく 3 つのフェーズを経てきた。

フェーズ期間主要トピック
初期採用期2018〜2020マネージド Node Group / EKS managed add-ons / Fargate Profile
運用成熟期2021〜2022EKS Anywhere / Bottlerocket AMI / EKS Blueprints / Karpenter v0
最適化期2023〜現在Pod Identity GA / Karpenter v1 GA / Topology Aware Routing 安定化 / EKS Auto Mode

2024 年の最大の変化は Pod Identity と Karpenter v1 の同時 GA だ。IRSA は「動くがスケールしない」権限管理方式として位置付けられ、Pod Identity が公式推奨の後継になった。Karpenter は v0 系での実績を踏まえて v1 API が安定化し、本番導入のハードルが大きく下がった。Topology Aware Routing は Kubernetes 1.27 で TopologyAwareHints feature gate がデフォルト有効になり、追加設定なしで利用できるようになった。

EKS Auto Mode (2024年 re:Invent 発表) はノード管理・スケーリング・ネットワークを AWS が完全管理するモードで、Karpenter を内包する。本記事では EKS Auto Mode 非採用のセルフマネージドな構成を対象とし、各コンポーネントの仕組みと設計判断を詳細に解説する。

既存クラスターに EKS Auto Mode を後から有効化すると既存 Node Group や Karpenter との共存設定が必要になる。新規クラスターの場合は Auto Mode の採用も選択肢だが、Karpenter を明示的に管理することで NodePool 設計や Disruption Budget の細かな制御が可能になる。本記事の内容は Auto Mode を使わない場合の標準的な実装ガイドとして活用してほしい。

本記事の前提環境とバージョン

コンポーネント推奨バージョン備考
EKS1.29 以降Pod Identity は 1.24 以降で対応
Karpenterv1.0 以降v1 API が 2024年 GA
Terraform AWS Provider5.xaws_eks_pod_identity_association リソースサポート
kubectl1.29 以降EKS クラスターバージョンと合わせる
eksctl0.175 以降Pod Identity Association サポート
helm3.xKarpenter のインストールに使用

EKS のバージョンは 2025 年時点で 1.29〜1.32 が主流だ。1.24 未満のクラスターは Pod Identity に対応しないため、アップグレードを先に実施すること。Karpenter v0.x 系を既存利用している場合は v1 への移行が必要であり、NodePool / NodeClass の API 名が変更されている点に注意する (v0 系: Provisioner / AWSNodeTemplate)。

Terraform AWS Provider 5.x 系では aws_eks_pod_identity_association リソースが 5.20 以降でサポートされている。aws_eks_addonaddon_version はアカウントの利用可能バージョンに依存するため、aws eks describe-addon-versions で最新バージョンを確認してから Terraform コードに記述すること。

Vol3 で解決する 4 軸

軸 1: EKS Pod Identity — IRSA 後継による権限管理の刷新

IRSA (IAM Roles for Service Accounts) は EKS クラスターに OIDC Provider を作成し、Service Account に eks.amazonaws.com/role-arn annotations を付与する方式だ。権限が必要なワークロードが増えるたびに OIDC Provider 側の Trust Policy と Service Account annotations を同期させる必要があり、管理対象が線形に増加する。

EKS Pod Identity は EKS コントロールプレーンと IAM を直接統合する。eks:CreatePodIdentityAssociation API で「クラスター + namespace + Service Account + IAM ロール」を Association リソースとして一元管理し、OIDC Provider が不要になる。Pod 起動時に EKS が自動的に一時認証情報を注入するため、Service Account annotations の付け忘れによるアクセス拒否も解消される。

軸 2: Karpenter — NodePool × Spot × Consolidation

Cluster Autoscaler は Node Group (ASG) 単位のスケーリングに留まり、インスタンスタイプの動的選択ができない。結果として「最大ワークロード向けの大きめインスタンスを常時起動」する保守的な設定が横行し、コストが最大化する。

Karpenter は NodePool / NodeClass の 2 層抽象化でこの問題を根本解決する。NodePool でワークロード要件 (CPU/メモリ/GPU/Spot 許可) を定義し、NodeClass で EC2 インスタンスファミリーと AMI を指定すると、Karpenter が Pod のスケジューリング要求に最適なインスタンスタイプをリアルタイムで選択する。Consolidation (WhenUnderutilized / WhenEmpty) で過剰プロビジョニングを自動解消し、Drift Detection で AMI 更新を無停止ロールアウトする。

軸 3: Topology Aware Routing — Cross-AZ コスト削減

EKS の標準 Service は kube-proxy が全 AZ の Ready な Pod にラウンドロビンでルーティングする。マルチ AZ クラスターでは AZ をまたぐ通信が常時発生し、AWS の AZ 間データ転送コストが積み上がる。Pod が 3 AZ × 複数 Deployment にわたる大規模クラスターでは月数万〜数十万円規模になることがある。

Topology Aware Routing は Service に 1 行 annotation を追加するだけで同一 AZ 内の Pod を優先的に選択する。Kubernetes が EndpointSlice の hints.forZones フィールドを自動設定し、kube-proxy または Cilium がゾーン内エンドポイントを優先する。Pod Topology Spread Constraints と組み合わせて AZ 間の Pod 分散を均等にすることで、機能が最大限発揮される。

軸 4: Service Connect — Service Discovery の統一

ECS と EKS が混在する環境では Service Discovery が分断しがちだ。ECS 側は AWS Cloud Map / Service Connect、EKS 側は CoreDNS / Ingress Controller / ELB と、サービス間通信の設定が 2 系統存在すると変更時のリスクが高まる。

EKS Service Connect は ECS Service Connect と共通のインターフェースで Service Discovery を提供し、ECS-EKS 混在クラスターでも統一した論理名でサービス間通信を記述できる。内蔵 TLS 終端・CloudWatch ServiceLens 統合による Observability・Cross-cluster Service Discovery が付属し、App Mesh の後継として本番採用が進んでいる。

本記事の対象読者

次のいずれかの課題を持つ SRE / プラットフォームエンジニアを対象とする。

  • IRSA の管理コストを削減したい、または Pod Identity への移行タイミングを判断したい
  • Karpenter を導入して Node コストを最適化したいが、NodePool 設計の全体像が把握できていない
  • Cross-AZ 通信コストが無視できない規模に達し、Topology Aware Routing の適用を検討している
  • ECS/EKS 混在環境の Service Discovery を Service Connect で統一したい
  • 上記 4 軸を Terraform で一括管理する実装パターンを入手したい

前提知識: Kubernetes 基本概念 (Pod / Deployment / Service / ServiceAccount / RBAC) / Terraform 基礎 / AWS IAM 基礎。Kubernetes の深掘り説明は最小限にし、実装コードとアーキテクチャ判断の根拠を中心に解説する。

4 軸で期待できるコスト削減の概算

各軸の導入効果を具体的なコスト観点で整理する。実際の削減幅はワークロードの特性によって変わるが、以下は本番導入実績をもとにした目安だ。

コスト削減観点目安削減率
Pod Identity直接的コスト削減なし (運用工数削減)IRSA 管理工数 30〜50% 削減
KarpenterSpot + Consolidation による Node コスト削減EC2 コスト 30〜60% 削減
Topology Aware RoutingAZ 間データ転送コスト削減転送コスト 30〜60% 削減
Service Connect直接的コスト削減なし (ELB 廃止で削減可能)ALB/NLB コスト 10〜20% 削減

月額 EC2 コストが 50 万円のクラスターで Karpenter + Topology Aware Routing を適用すると、合計で 20〜35 万円の削減が見込める。Pod Identity と Service Connect は運用コスト・可用性向上が主な効果で、金銭的なコスト削減は間接的だ。

Karpenter の Spot 活用は中断リスクを伴う。重要なワークロード (データベース / ステートフルサービス) は On-Demand NodePool に配置し、バッチ処理や水平スケールするステートレスワークロードに Spot NodePool を適用するのが現実的な設計だ。§3 ではこの NodePool 階層化設計を詳細に解説する。Topology Aware Routing も同様に、Zone 内の Pod 数が少ない場合は Fallback が発生して効果が減衰する。§4 で Pod Topology Spread Constraints との組み合わせを具体的に解説する。

クイックスタート — 課題別の推奨読み順

急ぎで特定の課題を解決したい場合は、以下の読み順を推奨する。

課題推奨読み順
IRSA 管理負荷を今すぐ下げたい§2 → §7 Q2 → §6 詰まり1〜2
Node コストを月内に削減したい§3 → §7 Q1/Q5 → §6 詰まり3〜4
Cross-AZ コストを削減したい§4 → §7 Q3 → §6 詰まり5
Service Discovery を統一したい§5 → §7 Q4 → §6 詰まり6〜7
全軸を体系的に理解したい§2 → §3 → §4 → §5 → §6 → §7 → §8 (通し読み)
📍 Container本番運用シリーズナビ — 三部作完結

Vol1: ECS × Fargate × ECR × ECS Exec × Service Connect 完全ガイド

Vol2: EKS × ArgoCD × Kustomize × Argo Rollouts GitOps 編

Vol3 (本記事): EKS 縦深化 — Pod Identity × Karpenter × Topology Aware Routing × Service Connect

読者想定: Vol1/Vol2 読了済みの SRE・プラットフォームエンジニア。IRSA 管理負荷・Node コスト・Cross-AZ 通信コスト・Service Discovery 複雑化のいずれかに直面しているチームに向けた実装ガイド。

本記事のロードマップ — §2〜§8 の構成

4 軸の縦深化を次の順序で解説する。各セクションは独立して参照できるよう設計しているため、課題に応じて該当セクションから読み始めてほしい。

§主題主要トピック
§2EKS Pod Identity 本番運用IRSA との比較・Association 管理・IRSA → Pod Identity 段階的移行
§3Karpenter 本番運用NodePool / NodeClass 設計・Spot 最適化・Consolidation・Drift Detection
§4Topology Aware Routing 本番運用Zone-aware ルーティング・Pod Spread Constraints・Cross-AZ コスト削減
§5Service Connect 詳細Service Discovery・TLS・CloudWatch ServiceLens・Cross-cluster
§6詰まりポイント 7 選4 軸の典型的な詰まりパターンを判断ツリーで体系化
§7アンチパターン → 正解パターン変換演習5 問の実装演習 (Terraform / kubectl / Helm)
§8まとめ + 三部作完成 + クロスリンクナビContainer 三部作総括・全軸クロスリンク表

次の §2 では EKS Pod Identity の仕組みと IRSA からの移行戦略を詳細に解説する。

4 軸は独立して適用できるが、組み合わせると相乗効果がある。Karpenter の Node 起動に Pod Identity の権限が必要になり、Topology Aware Routing の効果を最大化するには Karpenter で AZ 間の Pod 分散を均等にする必要がある。Service Connect の TLS 認証に用いる証明書ストアへのアクセスも Pod Identity で管理できる。全軸を順番に適用することで、EKS クラスター全体が「最小権限・最小コスト・最短レイテンシ・統一 Service Discovery」の状態に近づく。


§2 EKS Pod Identity 本番運用 — IRSA後継 × Association管理 × 移行戦略

EKS Pod Identity とは

IRSA の課題から理解する

EKS Pod Identity を理解するには IRSA (IAM Roles for Service Accounts) の課題を先に整理するのが近道だ。

IRSA の認証フロー:

  1. EKS クラスターに OIDC (OpenID Connect) Provider を作成し、IAM に登録する
  2. IAM ロールの Trust Policy に sts:AssumeRoleWithWebIdentity とクラスターの OIDC Issuer URL を記述する
  3. Kubernetes Service Account に eks.amazonaws.com/role-arn: <iam-role-arn> annotation を付与する
  4. Pod 起動時に IRSA Webhook が OIDC JWT Token を Volume Mount し、AWS SDK が一時認証情報を取得する

この方式の問題は三重管理にある。OIDC Provider の更新・Trust Policy の ARN 管理・Service Account annotations の同期がそれぞれ独立して行われるため、ワークロードが増えるにつれて管理コストが比例的に増大する。OIDC Issuer URL はクラスター単位で固定されるため、マルチクラスター環境では「クラスター数 × ワークロード数」分の Trust Policy を維持する必要がある。

EKS Pod Identity の仕組み

EKS Pod Identity は EKS コントロールプレーンと IAM を直接統合する新方式だ (2024年1月 GA、EKS 1.24 以降)。

認証フロー:

  1. eks:CreatePodIdentityAssociation API で「クラスター名 + namespace + Service Account 名 + IAM ロール ARN」を Association リソースとして登録する
  2. Pod 起動時に EKS Pod Identity Agent (DaemonSet、kube-system namespace) が EKS コントロールプレーンから一時認証情報を取得して Pod に注入する
  3. Pod は AWS_CONTAINER_CREDENTIALS_FULL_URI 環境変数経由でローカルの Pod Identity Agent から認証情報を取得する

OIDC Provider が不要になるため、クラスターを増減しても IAM の Trust Policy を変更する必要がない。Association リソースは namespace × serviceAccountName の組み合わせで一意に管理されるため、権限の棚卸しが容易になる。

IRSA vs EKS Pod Identity 比較

比較軸IRSAEKS Pod Identity
OIDC Providerクラスター毎に作成必要不要
Trust Policy 管理クラスター OIDC ARN を記述Service: pods.eks.amazonaws.com のみ
Service Account 設定eks.amazonaws.com/role-arn annotation 必須不要 (Association のみ)
マルチクラスター対応クラスター数分の Trust Policy 変更が必要Association の付け替えのみ
対応 EKS バージョン全バージョン1.24 以降
Lambda 対応対応非対応 (Lambda は IRSA 継続)
権限棚卸しの容易さService Account annotations を全 NS から grepaws eks list-pod-identity-associations 一覧で完結

Pod Identity Agent のセットアップ

Pod Identity Agent は EKS Add-on として提供されている。既存クラスターへの追加は Terraform または AWS CLI で数分で完了する。

Terraform で追加する場合:

resource "aws_eks_addon" "pod_identity_agent" {
  cluster_name  = aws_eks_cluster.main.name
  addon_name = "eks-pod-identity-agent"
  addon_version = "v1.3.2-eksbuild.2"

  resolve_conflicts_on_create = "OVERWRITE"
  resolve_conflicts_on_update = "OVERWRITE"

  depends_on = [aws_eks_cluster.main]
}

AWS CLI でバージョン確認と追加:

# 利用可能なバージョン確認
aws eks describe-addon-versions \
  --addon-name eks-pod-identity-agent \
  --query 'addons[0].addonVersions[*].addonVersion'

# Add-on 追加
aws eks create-addon \
  --cluster-name my-cluster \
  --addon-name eks-pod-identity-agent

# DaemonSet 稼働確認
kubectl get daemonset eks-pod-identity-agent -n kube-system

Agent が正常に展開されると、各 Node に Pod Identity Agent の Pod が 1 つずつ稼働する。Node 上で AWS_CONTAINER_CREDENTIALS_FULL_URI への HTTP リクエストを受け付けるローカルサーバーとして動作し、Pod は EKS コントロールプレーンとの通信を意識せずに認証情報を取得できる。

Association 管理 — Terraform × eksctl × AWS CLI

Terraform で Association を作成する

Pod Identity Association は IAM ロール側の Trust Policy 変更が最小限で済む。IAM ロールの assume_role_policy の Principal を pods.eks.amazonaws.com に変更し、aws_eks_pod_identity_association リソースを作成するだけだ。

# IAM ロール (Trust Policy を Pod Identity 向けに設定)
resource "aws_iam_role" "app_s3_reader" {
  name = "eks-app-s3-reader"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect = "Allow"
  Principal = {
 Service = "pods.eks.amazonaws.com"
  }
  Action = [
 "sts:AssumeRole",
 "sts:TagSession"
  ]
}
 ]
  })
}

resource "aws_iam_role_policy_attachment" "app_s3_reader" {
  role = aws_iam_role.app_s3_reader.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}

# Pod Identity Association
resource "aws_eks_pod_identity_association" "app_s3" {
  cluster_name = aws_eks_cluster.main.name
  namespace = "production"
  service_account = "app-service-account"
  role_arn  = aws_iam_role.app_s3_reader.arn
}

Trust Policy の Principal が pods.eks.amazonaws.com になる点が IRSA との最大の違いだ。クラスター ARN や OIDC Issuer URL を Trust Policy に埋め込む必要がないため、同じ IAM ロールを複数クラスターの Pod Identity Association に再利用できる。

eksctl で Association を管理する

# Association 作成
eksctl create podidentityassociation \
  --cluster my-cluster \
  --namespace production \
  --service-account-name app-service-account \
  --role-arn arn:aws:iam::123456789012:role/eks-app-s3-reader

# Association 一覧確認
eksctl get podidentityassociation --cluster my-cluster

# Association 削除
eksctl delete podidentityassociation \
  --cluster my-cluster \
  --namespace production \
  --service-account-name app-service-account

AWS CLI で Association を確認する

# namespace 毎の Association 一覧
aws eks list-pod-identity-associations \
  --cluster-name my-cluster \
  --namespace production

# 特定 Association の詳細
aws eks describe-pod-identity-association \
  --cluster-name my-cluster \
  --association-id a-xxxxxxxxxxxx

Service Account 紐付け — Deployment / StatefulSet への適用

Pod Identity では Service Account annotations が不要になる。既存の Service Account は annotations を削除するだけで Pod Identity に切り替えられる。

Service Account マニフェスト:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-service-account
  namespace: production
  # IRSA では必要だった annotations は不要
  # annotations:
  #eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/irsa-role

Deployment での Service Account 指定:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  namespace: production
spec:
  selector:
 matchLabels:
app: my-app
  template:
 metadata:
labels:
  app: my-app
 spec:
serviceAccountName: app-service-account
containers:
- name: app
  image: my-ecr-repo/app:latest
  env:
  - name: AWS_DEFAULT_REGION
 value: ap-northeast-1

Deployment の Pod が起動すると、EKS Pod Identity Agent が AWS_CONTAINER_CREDENTIALS_FULL_URI 環境変数を自動的に注入する。AWS SDK は Credential Provider Chain 内でこの環境変数を検出し、Agent から一時認証情報を取得する。アプリケーションコードの変更は不要だ。

StatefulSet も同様に spec.template.spec.serviceAccountName を指定するだけで Pod Identity が動作する。Job / CronJob など、あらゆる Pod ベースのリソースで同じ方式が使える。

動作確認:

# Pod 内から認証情報の取得元を確認
kubectl exec -n production deployment/app -- \
  aws sts get-caller-identity

# 期待出力: Association で指定した IAM ロールの ARN が表示される
# {
#"UserId": "AROA...:eks-app-s3-reader",
#"Account": "123456789012",
#"Arn": "arn:aws:iam::123456789012:assumed-role/eks-app-s3-reader/..."
# }

移行戦略 — IRSA から Pod Identity への段階的移行

IRSA と Pod Identity は同一クラスター内で共存できる。一括移行はリスクが高いため、ワークロード単位の段階的移行が推奨だ。

Phase 1: 新規ワークロードを Pod Identity で作成

既存の IRSA ワークロードは変更せず、新規ワークロードから Pod Identity を採用する。Pod Identity Agent のインストール後、すぐに新規 Association を作成できる。

# 新規 Association 作成 (既存 IRSA は影響なし)
aws eks create-pod-identity-association \
  --cluster-name my-cluster \
  --namespace new-service \
  --service-account new-service-sa \
  --role-arn arn:aws:iam::123456789012:role/new-service-role

Phase 2: 既存 IRSA ワークロードをワークロード単位で移行

1 ワークロードずつ移行し、動作確認を積み重ねる。

# Step 1: 移行対象の IAM ロールの Trust Policy を更新
# (sts:AssumeRoleWithWebIdentity → sts:AssumeRole + Principal: pods.eks.amazonaws.com)
aws iam update-assume-role-policy \
  --role-name existing-app-role \
  --policy-document file://pod-identity-trust-policy.json

# Step 2: Pod Identity Association 作成
aws eks create-pod-identity-association \
  --cluster-name my-cluster \
  --namespace production \
  --service-account existing-app-sa \
  --role-arn arn:aws:iam::123456789012:role/existing-app-role

# Step 3: Service Account の IRSA annotations を削除
kubectl annotate serviceaccount existing-app-sa \
  -n production \
  eks.amazonaws.com/role-arn-

# Step 4: Pod を再起動して Pod Identity を適用
kubectl rollout restart deployment existing-app -n production

# Step 5: 権限動作確認
kubectl exec -n production deployment/existing-app -- \
  aws sts get-caller-identity

pod-identity-trust-policy.json:

{
  "Version": "2012-10-17",
  "Statement": [
 {
"Effect": "Allow",
"Principal": {
  "Service": "pods.eks.amazonaws.com"
},
"Action": [
  "sts:AssumeRole",
  "sts:TagSession"
]
 }
  ]
}

Phase 3: OIDC Provider のクリーンアップ (全移行完了後)

全ワークロードの移行が完了したら OIDC Provider を削除してクリーンアップする。削除前に IRSA を使用しているリソースが残っていないか確認すること。

# IRSA を使用中の Service Account を検索
kubectl get serviceaccounts -A -o json | \
  jq '.items[] | select(.metadata.annotations["eks.amazonaws.com/role-arn"] != null) | 
  {namespace: .metadata.namespace, name: .metadata.name, role: .metadata.annotations["eks.amazonaws.com/role-arn"]}'

# (全移行完了後) OIDC Provider ARN 確認
aws iam list-open-id-connect-providers

# OIDC Provider 削除
aws iam delete-open-id-connect-provider \
  --open-id-connect-provider-arn \
  arn:aws:iam::123456789012:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/XXXX
EKS Pod Identity × IRSA 比較と移行フロー
図01: EKS Pod Identity Association × IRSA 認証経路比較 + 移行フロー
⚠️ Pod Identity でよくある罠 1 — Trust Policy の変更漏れで AccessDenied

IRSA から Pod Identity に切り替える際、Trust Policy の Principal を変更し忘れると AccessDenied が発生する。IRSA では Principal が federated: arn:aws:iam::ACCOUNT:oidc-provider/... だが、Pod Identity では Service: pods.eks.amazonaws.com に変更する必要がある。

Association を作成しただけで Trust Policy を変更していないと、Pod Identity Agent が一時認証情報を取得しようとしたときに sts:AssumeRole が拒否される。確認コマンド:

aws iam get-role --role-name <role-name> --query 'Role.AssumeRolePolicyDocument'

出力の Statement[].Principalpods.eks.amazonaws.com が含まれていることを確認すること。IRSA 時代の federated エントリが残っている場合は両方共存できるが、Pod Identity 用の sts:AssumeRole エントリが追加されていなければ認証は失敗する。

⚠️ Pod Identity でよくある罠 2 — Lambda 関数は Pod Identity 非対応

EKS Pod Identity は Lambda 関数には対応していない (2025年時点)。EKS Pod 上のワークロードと Lambda 関数が同じ IAM ロールを共有する構成では、Lambda 側は引き続き Lambda Execution Role で権限付与する必要がある。

移行計画を立てる前に IRSA ロールを使用している Lambda 関数を棚卸しすること:

aws lambda list-functions --query 'Functions[].{Name:FunctionName,Role:Role}'

EKS Pod と Lambda が同じロールを共有していた場合は、Pod 用と Lambda 用に IAM ロールを分割してから移行を開始すること。共有ロールのまま Trust Policy を Pod Identity 向けに変更すると、Lambda の権限が失われる。

§3 Karpenter へ

Pod Identity で権限管理を刷新したら、次のコスト最適化に取り組む。§3 では Karpenter v1 の NodePool / NodeClass 設計から Spot 最適化・Consolidation・Drift Detection まで、Node コスト削減の全体像を解説する。


§3 Karpenter 本番運用 — NodePool × NodeClass × Spot最適化 × Consolidation

EKS クラスターのノード管理は、従来の Managed Node Group (MNG) や Self-managed Node Group から Karpenter への移行が本番環境での標準解となった。MNG では Launch Template を事前定義し、Cluster Autoscaler がスケールアウトを判断するまでに数分かかる。Karpenter はスケジューリングできない Pod を直接検知し、必要最小限のインスタンスを数十秒でプロビジョニングする。コスト削減とスケール速度の両面で MNG を凌ぐ。

Karpenter v1 のコアオブジェクトは 3 つだ。NodePool (ノードの要件定義)、EC2NodeClass (AWS 固有のインフラ設定)、NodeClaim (Karpenter が内部生成するノード要求)。運用者が直接管理するのは NodePool と EC2NodeClass のみで、NodeClaim は Karpenter が自動管理する。

3-1: NodePool 設計 — 階層化が Karpenter 活用の核心

NodePool は「どんなインスタンスを起動できるか」の要件定義だ。1 NodePool にすべての Pod を収容するフラット構成は本番では避ける。Critical (on-demand 固定) / Standard (on-demand 優先) / Spot (Spot 最大活用) の 3 層階層化が鉄則だ。

# Critical NodePool: 基幹ワークロード専用 (on-demand 固定)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: critical
spec:
  template:
 metadata:
labels:
  node-tier: critical
 spec:
nodeClassRef:
  group: karpenter.k8s.aws
  kind: EC2NodeClass
  name: default
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["on-demand"]
  - key: kubernetes.io/arch
 operator: In
 values: ["amd64"]
  - key: karpenter.k8s.aws/instance-category
 operator: In
 values: ["m", "c"]
  - key: karpenter.k8s.aws/instance-generation
 operator: Gt
 values: ["5"]
taints:
  - key: node-tier
 value: critical
 effect: NoSchedule
  limits:
 cpu: "200"
 memory: "800Gi"
  disruption:
 consolidationPolicy: WhenEmpty
 consolidateAfter: 30s
 budgets:
- nodes: "0%"
  schedule: "0 9 * * 1-5"
  duration: 8h
- nodes: "10%"
# Spot NodePool: バッチ・非重要ワークロード専用
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: spot
spec:
  template:
 metadata:
labels:
  node-tier: spot
 spec:
nodeClassRef:
  group: karpenter.k8s.aws
  kind: EC2NodeClass
  name: default
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["spot", "on-demand"]
  - key: kubernetes.io/arch
 operator: In
 values: ["amd64"]
  - key: karpenter.k8s.aws/instance-category
 operator: In
 values: ["m", "c", "r"]
  - key: karpenter.k8s.aws/instance-generation
 operator: Gt
 values: ["5"]
  - key: karpenter.k8s.aws/instance-size
 operator: NotIn
 values: ["nano", "micro", "small"]
  limits:
 cpu: "500"
 memory: "2000Gi"
  disruption:
 consolidationPolicy: WhenUnderutilized
 consolidateAfter: 5m
 budgets:
- nodes: "20%"

requirementsinstance-categorym, c, r を指定し instance-size から小型を除外することで Spot Diversification を自動実現する。インスタンスタイプを 1 種類に固定すると Spot 容量が枯渇した際に on-demand fallback しか選択肢がなくなる。複数ファミリーを許可すれば Karpenter が最適なインスタンスを自動選択する。

spec.disruption.budgets は時間帯別の disruption 上限を設定する。Critical NodePool では月〜金の 9 時から 8 時間を nodes: "0%" にして業務時間帯の強制 Pod 移動を禁止し、夜間のみ最大 10% の consolidation を許可する。

3-2: EC2NodeClass 設計 — AMI × セキュリティグループ × サブネット

EC2NodeClass (旧 AWSNodeTemplate) は AWS 固有のインフラ設定を担う。AMI セレクター、VPC サブネット選択、セキュリティグループ選択の 3 点が核心だ。

apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  # AL2023 を EKS バージョンに自動追跡
  amiSelectorTerms:
 - alias: al2023@latest

  # IAM インスタンスプロファイル
  instanceProfile: "KarpenterNodeInstanceProfile"

  # サブネット: タグセレクター形式
  subnetSelectorTerms:
 - tags:
  karpenter.sh/discovery: "my-cluster"
  Tier: "private"

  # セキュリティグループ: タグセレクター形式
  securityGroupSelectorTerms:
 - tags:
  karpenter.sh/discovery: "my-cluster"

  # EBS ルートボリューム
  blockDeviceMappings:
 - deviceName: /dev/xvda
ebs:
  volumeType: gp3
  volumeSize: 50Gi
  encrypted: true

subnetSelectorTermssecurityGroupSelectorTerms はタグマッチングで動作する。Terraform で VPC・サブネット作成時に karpenter.sh/discovery = クラスター名 タグを付与しておけば NodeClass を変更せずに新規サブネット追加が自動反映される。alias: al2023@latest は EKS バージョン互換の最新 AL2023 AMI を Karpenter が自動解決するため AMI ID 管理が不要になる。

3-3: Terraform によるKarpenter インストール — Pod Identity 連携

Karpenter は Pod Identity と組み合わせてインストールする。

# Karpenter コントローラー用 Pod Identity Association
resource "aws_eks_pod_identity_association" "karpenter" {
  cluster_name = aws_eks_cluster.main.name
  namespace = "kube-system"
  service_account = "karpenter"
  role_arn  = aws_iam_role.karpenter_controller.arn
}

resource "aws_iam_role" "karpenter_controller" {
  name = "karpenter-controller"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "pods.eks.amazonaws.com" }
Action = ["sts:AssumeRole", "sts:TagSession"]
 }]
  })
}

# Karpenter を Helm でインストール
resource "helm_release" "karpenter" {
  namespace  = "kube-system"
  name = "karpenter"
  repository = "oci://public.ecr.aws/karpenter"
  chart= "karpenter"
  version = "1.0.0"
  create_namespace = false

  set {
 name  = "settings.clusterName"
 value = aws_eks_cluster.main.name
  }
  set {
 name  = "settings.interruptionQueue"
 value = aws_sqs_queue.karpenter_interruption.name
  }
}

# Spot Interruption 通知受信用 SQS キュー
resource "aws_sqs_queue" "karpenter_interruption" {
  name = "karpenter-interruption"
  message_retention_seconds = 300
}

# EventBridge から SQS へ: EC2 Spot 中断通知をルーティング
resource "aws_cloudwatch_event_rule" "spot_interruption" {
  name = "karpenter-spot-interruption"

  event_pattern = jsonencode({
 source= ["aws.ec2"]
 detail-type = ["EC2 Spot Instance Interruption Warning"]
  })
}

resource "aws_cloudwatch_event_target" "spot_interruption" {
  rule = aws_cloudwatch_event_rule.spot_interruption.name
  arn  = aws_sqs_queue.karpenter_interruption.arn
}

settings.interruptionQueue に SQS キューを設定することで Karpenter は EC2 Spot 中断通知 (2 分前) を受信し、対象 Node を事前に drain する。EventBridge のルールを設定しないと SQS キューへ通知が届かず、Spot 中断時に Pod が強制終了される。

Karpenter NodePool / Spot / Consolidation 全体アーキテクチャ
図02: Karpenter NodePool階層化 × Spot Diversification × Consolidation × Drift Detection 統合構成

3-4: Spot 最適化 — Diversification × Interruption Handler × Fallback 設計

Spot インスタンスで本番コストを最大 70% 削減できる一方、中断リスクへの設計が不可欠だ。

price-capacity-optimized 戦略: Karpenter v1 は NodePool の requirementscapacity-type: spot を指定するだけで内部的に price-capacity-optimized に相当するアロケーション戦略を自動選択する。単純に最安値を追う pure-price 戦略と異なり、容量が潤沢なプールを優先するため中断率を抑えつつコスト削減を実現する。

on-demand Fallback 設計: 重要度が中程度のワークロードは NodePool の requirements["spot", "on-demand"] を並記し、Spot 容量枯渇時に on-demand へ自動切替させる。厳密に Spot のみ使用したい場合は ["spot"] 固定にし、別途 on-demand NodePool で fallback Pod を受け付ける 2 NodePool 構成にする。

# Spot 専用ワークロードの Pod 設定例 (バッチジョブ)
spec:
  nodeSelector:
 karpenter.sh/capacity-type: spot
 node-tier: spot
  tolerations:
 - key: "node-tier"
value: "spot"
effect: "NoSchedule"
  terminationGracePeriodSeconds: 90

Spot を使う Pod の terminationGracePeriodSeconds は 90 秒以内に設定する。Spot 中断通知は 2 分前に届くが drain 処理に 10〜20 秒かかるため実質的な猶予は 90 秒程度だ。

3-5: Consolidation — WhenEmpty vs WhenUnderutilized の使い分け

Consolidation は稼働中のノードを自動削除・統合してコストを最適化する機能だ。2 つのポリシーを使い分ける。

Policy動作推奨用途
WhenEmptyPod が 0 になったノードのみ削除本番 on-demand (安全優先)
WhenUnderutilizedPod を他ノードへ移動して空きノードを削除Spot・バッチ (コスト優先)

WhenUnderutilized は積極的な Pod 移動を伴うため PDB (Pod Disruption Budget) の設定が必須だ。PDB なしで有効にすると Pod が強制移動されリクエスト断が発生する。

# PDB: 本番 Deployment に必ず設定する
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-server-pdb
  namespace: production
spec:
  minAvailable: 2
  selector:
 matchLabels:
app: api-server
---
# StatefulSet の場合: maxUnavailable 形式が安全
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: db-proxy-pdb
  namespace: production
spec:
  maxUnavailable: 1
  selector:
 matchLabels:
app: db-proxy

3-6: Drift Detection — NodePool 変更時の自動ロールアウト

Drift Detection は Karpenter v1 のデフォルト有効機能だ。EC2NodeClass や NodePool の設定が現在稼働中の Node と一致しない場合、その Node を「drift」状態と判断して順次置き換える。

典型的な Drift トリガー:

  • AMI 更新: alias: al2023@latest で新しい AL2023 AMI がリリースされると既存ノードが drift 判定
  • サブネット変更: subnetSelectorTerms のタグ変更により選択対象サブネットが変わった場合
  • インスタンスプロファイル変更: EC2NodeClass の instanceProfile 更新
  • NodePool requirements 変更: 許可インスタンスタイプの追加・削除

Drift による置き換えは spec.disruption.budgets の制限に従うため、PDB と組み合わせればゼロダウンタイムの Node ローリングアップデートが実現する。

# NodeClaim の Drift 状態を確認
kubectl get nodeclaims -o wide
# STATUS 列が "Drifted" の NodeClaim が置き換え対象

# Drift 済み NodeClaim の詳細確認
kubectl describe nodeclaim <name> | grep -A 5 "Conditions"

AMI を特定 ID に固定した場合はセキュリティパッチが自動適用されないため、月次の AMI ID 更新フローを CI/CD に組み込む必要がある。alias: al2023@latest と固定 ID の使い分けは自動追従 (利便性) vs 意図的な更新タイミング制御 (安全性) のトレードオフだ。

Karpenter 本番運用 3鉄則

NodePool 階層化必須: Critical (on-demand) / Standard / Spot の 3 層で分離する。全 Pod を 1 NodePool に集約すると Spot 中断が基幹サービスに波及する。各層に taintsnodeSelector を対応付けてワークロードを振り分けること。

Spot Diversification: instance-category を複数ファミリー (m/c/r) に分散し instance-generation: Gt "5" で世代を絞る。単一インスタンスタイプへの依存は Spot 容量枯渇で全 Pod スケジュール不能になるリスクを招く。

interruption-queue 必須: SQS キューが未設定では Spot 2 分前通知を受信できず中断時に Pod が強制終了される。Helm インストール時に settings.interruptionQueue を設定し、EventBridge → SQS ルーティングを合わせて構築すること。

Spot 中断時の対処 — PDB 設定なしは障害直結

Karpenter の Consolidation (WhenUnderutilized) や Drift Detection は Pod を他ノードへ移動する。この移動に耐えられるのは PodDisruptionBudget が設定された Pod だけだ。

必須チェックリスト:

・全本番 Deployment / StatefulSet に PDB を設定 (minAvailable または maxUnavailable を明示)
・Spot NodePool の consolidationPolicy: WhenUnderutilized は PDB 設定完了後にのみ有効化する
・SQS interruption queue を設定し Spot 中断 2 分前に Node を drain させる
spec.disruption.budgets で業務時間帯の同時 disruption 上限を設定 (例: nodes: "10%")
・StatefulSet の PDB は maxUnavailable: 1 形式を使い同時に複数 Pod が disrupted にならないよう制御する

PDB なしで Spot 中断が発生すると移動先 Node への再スケジュールが完了する前にリクエストが失われる。特に DB Proxy や Stateful なサービスは PDB の有無が本番障害の分水嶺になる。

§4 では EKS クラスター内の Cross-AZ 通信コストをコントロールする Topology Aware Routing を解説する。Karpenter で Spot を活用してコンピューティングコストを削減しても、Zone をまたぐ Pod 間通信が多いとデータ転送費用がコスト削減を相殺する。Topology Aware Routing と Karpenter を組み合わせることでコンピューティングコストと通信コストの双方を最適化できる。


§4 Topology Aware Routing 本番運用 — Service Topology Hints × Zone-aware × Cross-AZ コスト最適化

Kubernetes のサービス間通信は、デフォルトでは全 AZ の Pod に均等分散されます。3 AZ 構成のクラスタでは同一 AZ 内通信と Cross-AZ 通信が 1:2 の割合で発生し、AWS の Cross-AZ データ転送料金(片方向 0.01 USD/GB)が積み重なります。Topology Aware Routing(旧称: Topology Aware Hints)はこのコスト構造を根本的に解決し、同一 AZ 内の Pod へ優先ルーティングすることで Cross-AZ 転送量を 30〜60% 削減します。

Topology Aware Routing の仕組み — EndpointSlice と Hints

Topology Aware Routing の実体は EndpointSlice コントローラの Hints 自動付与機能です。

動作フロー:

  1. EndpointSlice コントローラが各 Pod の topology.kubernetes.io/zone label を読み取る
  2. AZ ごとの endpoint 比率を計算し、均等分散が保証できると判断した場合のみ Hints を生成
  3. 各 endpoint に hints.forZones[*].name フィールドを付与
  4. kube-proxy(または Cilium/eBPF datapath)が Hints を参照し、同一 AZ 内 endpoint を優先選択
  5. 同一 AZ 内に有効な endpoint が存在しない場合のみ、他 AZ の endpoint へフォールバック

この仕組みにより、アプリケーション側の変更なしに Zone-aware ルーティングが実現されます。

Zone-aware ルーティング設定

Service annotation 一行で有効化できます:

apiVersion: v1
kind: Service
metadata:
  name: payment-service
  namespace: production
  annotations:
 service.kubernetes.io/topology-mode: "Auto"
spec:
  selector:
 app: payment-service
  ports:
 - name: http
port: 80
targetPort: 8080
 - name: grpc
port: 9090
targetPort: 9090
  type: ClusterIP

topology-mode: Auto が現在推奨の設定値です。旧 annotation service.kubernetes.io/topology-aware-hints: auto も互換性のために動作しますが、Kubernetes 1.27 以降は topology-mode への移行が推奨されています。

既存の全 Service に一括適用するには kubectl patch を使用します:

# 全 ClusterIP Service への一括適用
for svc in $(kubectl get svc -n production \
  --field-selector spec.type=ClusterIP \
  -o jsonpath='{.items[*].metadata.name}'); do
  kubectl patch svc "$svc" -n production \
 -p '{"metadata":{"annotations":{"service.kubernetes.io/topology-mode":"Auto"}}}'
done

Hints 生成条件と確認手順

EndpointSlice コントローラが Hints を自動生成するには、以下の条件を全て満たす必要があります:

条件閾値・詳細確認コマンド
AZ 間の endpoint 数の偏り(max - min) / max < 0.2(20% 以内)kubectl get endpointslices -o yaml
Node の zone labeltopology.kubernetes.io/zone が全 Node に存在kubectl get nodes --show-labels
Service の endpoint 数3 以上(AZ 数 × 1 Pod 以上)kubectl get endpoints
ExternalTrafficPolicyCluster(デフォルト)のみ有効kubectl get svc -o yaml

Hints が正しく付与されているかを確認するには:

kubectl get endpointslices -n production -o yaml | grep -A5 "hints:"

Hints が付与された場合の出力例:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: payment-service-xk9mq
  namespace: production
addressType: IPv4
endpoints:
  - addresses:
- 10.0.1.42
 hints:
forZones:
  - name: ap-northeast-1a
 nodeName: ip-10-0-1-100.compute.internal
 topology:
topology.kubernetes.io/zone: ap-northeast-1a
 conditions:
ready: true
  - addresses:
- 10.0.2.55
 hints:
forZones:
  - name: ap-northeast-1c
 nodeName: ip-10-0-2-200.compute.internal
 topology:
topology.kubernetes.io/zone: ap-northeast-1c
 conditions:
ready: true
  - addresses:
- 10.0.3.71
 hints:
forZones:
  - name: ap-northeast-1d
 nodeName: ip-10-0-3-300.compute.internal
 topology:
topology.kubernetes.io/zone: ap-northeast-1d
 conditions:
ready: true

ap-northeast-1a で動作する kube-proxy は 10.0.1.42 のみをルーティング先として選択し、AZ をまたぐリクエストは発生しません。

Pod Topology Spread Constraints による均等分散

Hints が正しく生成されるには Pod が各 AZ に均等配置されている必要があります。topologySpreadConstraints で均等分散を強制します:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
  namespace: production
spec:
  replicas: 9
  selector:
 matchLabels:
app: payment-service
  template:
 metadata:
labels:
  app: payment-service
 spec:
topologySpreadConstraints:
  - maxSkew: 1
 topologyKey: topology.kubernetes.io/zone
 whenUnsatisfiable: DoNotSchedule
 labelSelector:
matchLabels:
  app: payment-service
  - maxSkew: 1
 topologyKey: kubernetes.io/hostname
 whenUnsatisfiable: ScheduleAnyway
 labelSelector:
matchLabels:
  app: payment-service
containers:
  - name: payment
 image: my-registry/payment-service:v2.1.0
 resources:
requests:
  cpu: "250m"
  memory: "512Mi"
limits:
  cpu: "1000m"
  memory: "2Gi"

2 層の topologySpreadConstraints を設定するのがベストプラクティスです:

  • AZ 層 (topology.kubernetes.io/zone): DoNotSchedule で強制均等分散。AZ 間の Pod 数差を最大 1 に抑えます。
  • Node 層 (kubernetes.io/hostname): ScheduleAnyway でノード単位の分散を試行。1 ノードへの Pod 集中を防ぎます。

Karpenter の NodePool と組み合わせることで、スケールアウト時にも均等分散が維持されます。

Terraform による Topology Aware Routing の IaC 管理

本番環境では Kubernetes マニフェストを Terraform の kubernetes_manifest または kubernetes_service リソースで管理することで、Service annotation を Infrastructure as Code に含めることができます。

resource "kubernetes_service" "payment" {
  metadata {
 name= "payment-service"
 namespace = kubernetes_namespace.production.metadata[0].name
 annotations = {
"service.kubernetes.io/topology-mode" = "Auto"
 }
  }
  spec {
 selector = {
app = "payment-service"
 }
 port {
name  = "http"
port  = 80
target_port = 8080
 }
 port {
name  = "grpc"
port  = 9090
target_port = 9090
 }
 type = "ClusterIP"
  }
}

resource "kubernetes_deployment" "payment" {
  metadata {
 name= "payment-service"
 namespace = kubernetes_namespace.production.metadata[0].name
  }
  spec {
 replicas = 9
 selector {
match_labels = { app = "payment-service" }
 }
 template {
metadata {
  labels = { app = "payment-service" }
}
spec {
  topology_spread_constraint {
 max_skew  = 1
 topology_key = "topology.kubernetes.io/zone"
 when_unsatisfiable = "DoNotSchedule"
 label_selector {
match_labels = { app = "payment-service" }
 }
  }
  container {
 name  = "payment"
 image = "my-registry/payment-service:${var.app_version}"
 resources {
requests = { cpu = "250m", memory = "512Mi" }
limits= { cpu = "1000m", memory = "2Gi" }
 }
  }
}
 }
  }
}

Terraform で管理することにより、topology-mode annotation の適用漏れを terraform plan で事前検出できます。CI/CD パイプライン(§3 で解説した ArgoCD との連携)と組み合わせると、annotation の剥落(kubectl 直接編集による上書き)を防ぐことができます。

フォールバック動作の理解

Hints 生成条件を満たせない場合、コントローラは Hints の付与をスキップし、従来の全 endpoint への均等分散にフォールバックします。フォールバックは Silent Fail のため、意図せず発生していないか定期確認が必要です:

# Service イベントの確認
kubectl describe service payment-service -n production | tail -20

# EndpointSlice の hints フィールド有無を一覧表示
kubectl get endpointslices -n production \
  -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.endpoints[0].hints}{"\n"}{end}'

フォールバックの主な原因別の対処は §6-5「Topology Aware Routing 設定後も Cross-AZ 通信が減らない」で詳しく解説します。

Cross-AZ コスト最適化効果と測定方法

AWS の Cross-AZ データ転送料金は片方向 0.01 USD/GB です。マイクロサービス間の内部通信が多いシステムでは削減効果が顕著に現れます。

運用実績の参考値:

項目適用前適用後削減率
月次 Cross-AZ 転送量80 TB28 TB65% 削減
データ転送コスト800 USD/月280 USD/月520 USD 削減
年間コスト削減6,240 USD

効果測定には VPC Flow Logs と CloudWatch Logs Insights を組み合わせます:

# Cross-AZ トラフィック量を CloudWatch Logs Insights で計測
aws logs start-query \
  --log-group-name /aws/vpc/flowlogs \
  --query-string '
 fields @timestamp, srcAddr, dstAddr, bytes
 | filter srcAddr like /10\.0\.1\./ and dstAddr like /10\.0\.2\./
 | stats sum(bytes)/1073741824 as crossAZGB by bin(1d)
  ' \
  --start-time $(date -v-30d +%s) \
  --end-time $(date +%s)

Topology Hints 適用前後の比較は、kubectl rollout restart deployment で Pod を再起動し Hints を反映させた後、最低 24 時間の計測期間を設けてください。

Topology Aware Routing Zone-aware ルーティング図
図03: Service Topology Hints による Zone-aware エンドポイント選択フロー
⚠️ Topology Aware Routing が効かないケース

Pod 数不足(最多発): endpoint 数が AZ 数未満(3 AZ なら 2 以下)の場合、コントローラは Hints 生成を自動スキップします。kubectl get endpointslices -o yaml | grep hints で hints フィールドが存在しない場合はこのケースを最初に確認してください。対処は replica 数を AZ 数 × 最低 1 以上(推奨 AZ 数 × 3)に増やすことです。

AZ 間の偏り過多: Pod の AZ 間分布が 20% を超えて偏ると Hints が無効化されます。Karpenter の NodePool 空き容量不足や PodDisruptionBudget との競合により特定 AZ に Pod が集中する場合があります。topologySpreadConstraintswhenUnsatisfiableDoNotSchedule に変更し、均等分散を強制してください。

Node の zone label 欠損: カスタム AMI や Bottlerocket 使用時に topology.kubernetes.io/zone label が付与されていない Node が混在する場合があります。kubectl get nodes --show-labels | grep -v zone で欠損 Node を特定し、Node 起動スクリプト(UserData)に label 付与処理を追加してください。EKS マネージドノードグループでは自動付与されますが、セルフマネージドノードでは手動設定が必要です。

Hints 反映の遅延: EndpointSlice の更新は非同期のため、Pod 再起動・スケールアウト直後の数十秒〜数分間は古いルーティングが維持されます。Hints 安定後のタイミングから SLO 計測の基点を設定してください。kube-proxy の sync 周期(デフォルト 30 秒)も考慮が必要です。

✅ Cross-AZ コスト削減チェックリスト

1. 全 ClusterIP Service に service.kubernetes.io/topology-mode: "Auto" を適用済みか
2. kubectl get endpointslices -n production -o yaml | grep hintshints フィールドが存在するか
3. 各 Deployment に topologySpreadConstraints(AZ 均等分散、maxSkew:1)を設定済みか
4. 全 Node に topology.kubernetes.io/zone label が付与されているか
5. VPC Flow Logs で Cross-AZ トラフィックが適用前比 30〜60% 削減されているか
6. kubectl describe service <name> | grep EventsTopologyAwareHintsDisabled Warning がゼロか
7. ExternalTrafficPolicy: Local を使用するサービスを意図的に除外しているか

§4 では Topology Aware Routing による Cross-AZ コスト最適化を確立しました。次の §5 では、AZ 内外のマイクロサービス間通信にサービスディスカバリー・TLS・オブザーバビリティ・Cross-cluster 通信を統合した Service Connect(AWS VPC Lattice)の本番実装を解説します。


§5 Service Connect 詳細 — Service Discovery × TLS × Observability × Cross-cluster ★山場2

EKS における Service Connect の中核は AWS VPC Lattice との統合です。Vol1 で解説した ECS Service Connect とは異なり、EKS では Kubernetes Gateway API を通じて VPC Lattice を制御し、Cross-cluster・Cross-account・Cross-VPC の通信を単一の管理面で実現します。サービスディスカバリー・mTLS・X-Ray トレーシング・Multi-cluster 通信を一貫した設計で実装する方法を解説します。

ECS Service Connect vs EKS Service Connect(VPC Lattice)

Vol1 の ECS Service Connect との主な違いを整理します:

項目ECS Service ConnectEKS Service Connect(VPC Lattice)
対象ECS Task 間通信EKS Pod 間 / Cross-cluster 通信
Service DiscoveryCloud Map(自動登録)VPC Lattice Service Network
TLSService Connect 内蔵 TLSACM + VPC Lattice TLS ポリシー
ObservabilityCloudWatch ServiceLensCloudWatch Container Insights + X-Ray
Cross-cluster単一 ECS Cluster 内のみVPC Lattice で Multi-cluster 対応
設定粒度ECS Service 単位Kubernetes Service / HTTPRoute 単位
ProxyEnvoy sidecar(Auto-inject)Gateway API Controller

EKS での Service Connect 実装は VPC Lattice Gateway API Controller を中心に構成されます。

VPC Lattice Gateway API Controller のセットアップ

EKS クラスタに VPC Lattice Gateway API Controller をインストールします:

# Gateway API CRD のインストール
kubectl apply -f \
  https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml

# AWS Gateway API Controller のインストール(Helm)
helm install gateway-api-controller \
  oci://public.ecr.aws/aws-application-networking-k8s/aws-gateway-controller-chart \
  --version=v1.0.6 \
  --namespace aws-application-networking-system \
  --create-namespace \
  --set=aws.region=ap-northeast-1 \
  --set=serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=\
arn:aws:iam::123456789012:role/VPCLatticeControllerRole

# インストール確認
kubectl get pods -n aws-application-networking-system

Pod Identity を使用して Controller に VPC Lattice 管理権限を付与します(§2 で解説した Pod Identity Association の実践例):

aws eks create-pod-identity-association \
  --cluster-name my-eks-cluster \
  --namespace aws-application-networking-system \
  --service-account gateway-api-controller \
  --role-arn arn:aws:iam::123456789012:role/VPCLatticeControllerRole

Service Discovery — VPC Lattice Service Network と Namespace 設定

GatewayClass と Gateway を定義し、VPC Lattice Service Network への接続を確立します:

# GatewayClass: VPC Lattice を指定(クラスタスコープ)
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
  name: amazon-vpc-lattice
spec:
  controllerName: application-networking.k8s.aws/gateway-api-controller

---
# Gateway: VPC Lattice Service Network への接続(namespace スコープ)
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: my-service-network
  namespace: production
spec:
  gatewayClassName: amazon-vpc-lattice
  listeners:
 - name: http
protocol: HTTP
port: 80
 - name: https
protocol: HTTPS
port: 443
tls:
  mode: Terminate
  certificateRefs:
 - name: acm-cert-ref
group: ""
kind: Secret

HTTPRoute でサービスへのルーティングを定義します:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: payment-route
  namespace: production
spec:
  parentRefs:
 - name: my-service-network
namespace: production
  hostnames:
 - payment.internal.example.com
  rules:
 - matches:
  - path:
type: PathPrefix
value: /api/v1
backendRefs:
  - name: payment-service
 namespace: production
 port: 8080
 weight: 100
 - matches:
  - path:
type: PathPrefix
value: /api/v2
backendRefs:
  - name: payment-service-v2
 namespace: production
 port: 8080
 weight: 100

TLS — ACM 証明書と自動ローテーション

VPC Lattice の TLS ターミネーションは ACM 証明書を使用します。ACM が証明書の自動更新(有効期限 60 日前に開始)を管理するため、手動更新作業が不要です。

ACM プライベート CA を使用した内部 TLS の設定:

# ACM プライベート CA の作成
aws acm-pca create-certificate-authority \
  --certificate-authority-configuration \
 'KeyAlgorithm=RSA_2048,SigningAlgorithm=SHA256WITHRSA,
  Subject={Country=JP,Organization=MyOrg,CommonName=internal.example.com}' \
  --certificate-authority-type SUBORDINATE \
  --region ap-northeast-1

# プライベート CA からの証明書発行
aws acm request-certificate \
  --domain-name "*.internal.example.com" \
  --certificate-authority-arn \
 arn:aws:acm-pca:ap-northeast-1:123456789012:certificate-authority/abc-123 \
  --subject-alternative-names \
 "payment.internal.example.com" \
 "order.internal.example.com" \
  --region ap-northeast-1

証明書更新のモニタリングには CloudWatch メトリクス CertificateDaysToExpiry を使用します。有効期限 30 日未満でアラートを設定することを推奨します:

aws cloudwatch put-metric-alarm \
  --alarm-name acm-cert-expiry-warning \
  --namespace AWS/CertificateManager \
  --metric-name DaysToExpiry \
  --dimensions Name=CertificateArn,Value=arn:aws:acm:ap-northeast-1:123456789012:certificate/xxx \
  --statistic Minimum \
  --period 86400 \
  --threshold 30 \
  --comparison-operator LessThanThreshold \
  --alarm-actions arn:aws:sns:ap-northeast-1:123456789012:cert-expiry-alerts

Observability — CloudWatch Container Insights + X-Ray 統合

VPC Lattice は標準で CloudWatch との統合を提供します。Container Insights アドオンをインストールしてメトリクス収集を有効化します:

# CloudWatch Container Insights アドオンのインストール
aws eks create-addon \
  --cluster-name my-eks-cluster \
  --addon-name amazon-cloudwatch-observability \
  --service-account-role-arn arn:aws:iam::123456789012:role/CloudWatchAgentRole \
  --region ap-northeast-1

# アドオン状態確認
aws eks describe-addon \
  --cluster-name my-eks-cluster \
  --addon-name amazon-cloudwatch-observability \
  --query 'addon.status'

X-Ray 統合による分散トレーシングの設定:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
  namespace: production
spec:
  template:
 spec:
containers:
  - name: payment
 image: my-registry/payment-service:v2.1.0
 env:
- name: AWS_XRAY_DAEMON_ADDRESS
  value: "xray-service.amazon-cloudwatch:2000"
- name: AWS_XRAY_TRACING_NAME
  value: "payment-service"
  - name: xray-daemon
 image: public.ecr.aws/xray/aws-xray-daemon:latest
 ports:
- containerPort: 2000
  protocol: UDP
 resources:
requests:
  cpu: "50m"
  memory: "64Mi"
limits:
  cpu: "200m"
  memory: "256Mi"

VPC Lattice のアクセスログを CloudWatch Logs に配信します:

aws vpc-lattice create-access-log-subscription \
  --resource-identifier svc-abc123 \
  --destination-arn \
 arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/vpc-lattice/access-logs \
  --region ap-northeast-1

Cross-cluster 通信 — VPC Lattice Service Network

VPC Lattice Service Network を使用することで、複数の EKS クラスタ・ECS クラスタ・Lambda 関数を単一のサービスネットワークに接続できます。

マルチクラスタ接続の設定:

# クラスタ1 の VPC を Service Network に関連付け
aws vpc-lattice create-service-network-vpc-association \
  --service-network-identifier sn-shared123 \
  --vpc-identifier vpc-cluster1-abc \
  --security-group-ids sg-allow-lattice-xyz \
  --region ap-northeast-1

# クラスタ2 の VPC を同じ Service Network に関連付け
aws vpc-lattice create-service-network-vpc-association \
  --service-network-identifier sn-shared123 \
  --vpc-identifier vpc-cluster2-def \
  --security-group-ids sg-allow-lattice-xyz \
  --region ap-northeast-1

# クラスタ1 の Pod からクラスタ2 のサービスへの疎通確認
kubectl exec -n production payment-pod -- \
  curl -v https://order-service.internal.example.com/health

Cross-account アクセスには Resource Access Manager(RAM)でサービスネットワークを共有します:

aws ram create-resource-share \
  --name eks-service-network-share \
  --resource-arns \
 arn:aws:vpc-lattice:ap-northeast-1:123456789012:servicenetwork/sn-abc123 \
  --principals arn:aws:iam::987654321098:root \
  --region ap-northeast-1
Service Connect TLS × Observability × Cross-cluster 構成図
図04: Service Connect の Service Discovery × TLS終端 × X-Ray統合 × Cross-cluster Service Discovery


AWS VPC Lattice 公式ドキュメント

🔥 Service Connect よくある設定ミス

ミス1: GatewayClass と HTTPRoute の namespace 不一致
GatewayClass はクラスタスコープのリソースですが、HTTPRouteparentRefs.namespaceGateway の namespace と一致しないと、ルーティングルールが適用されず全リクエストが 404 を返し続けます。kubectl describe httproute <name> -n <namespace>Accepted: False のステータスと Reason を確認してください。parentRefs.namespace を Gateway の namespace と一致させることで解消されます。

ミス2: Security Group が VPC Lattice CIDR を許可していない
VPC Lattice のリンクローカル IP レンジ(169.254.171.0/24)への Inbound ルールが Security Group に設定されていないと、Health Check が失敗し Target Group が Unhealthy 状態になります。aws vpc-lattice list-target-groups --query 'items[*].{id:id,status:status}' でターゲットの Health Status を確認し、Security Group に 169.254.171.0/24 からの全 TCP を許可するルールを追加してください。

ミス3: Cross-cluster 通信時の DNS 解決失敗
VPC Lattice のカスタムドメイン名は、クライアント側 VPC に Route 53 プライベートホストゾーンが関連付けられていないと解決できません。Cross-cluster 通信設定後は kubectl exec から nslookup <domain> で DNS 解決を確認し、失敗する場合は Route 53 プライベートホストゾーンの VPC 関連付けを追加してください。

ミス4: ACM 証明書のリージョン不一致
VPC Lattice に ACM 証明書を関連付ける際、証明書のリージョンが VPC Lattice のリージョンと異なると関連付けに失敗します。必ずフル ARN(arn:aws:acm:region:account-id:certificate/xxx)で region 部分が一致していることを確認してください。

✅ Service Connect TLS 設計パターン

内部サービス間(Pod → Pod): VPC Lattice TLS ターミネーション + ACM プライベート CA で mTLS を実現。AuthPolicy リソースで送信元サービスアカウントを明示的に承認し、未承認サービスからのアクセスを拒否します。

外部公開サービス(ALB → Pod): VPC Lattice を ALB のバックエンドとして設定。ALB → VPC Lattice 区間は HTTPS、VPC Lattice → Pod 区間は内部 TLS で End-to-end 暗号化を実現します。

mTLS vs VPC Lattice TLS の使い分け: Istio/Linkerd の mTLS はサービスメッシュ内全 Pod の証明書管理が必要です。VPC Lattice TLS は AWS マネージドのため証明書管理が不要ですが、Pod 間の相互認証(mTLS)には AuthPolicy の追加設定が必要です。ゼロトラスト要件がある場合は AuthPolicy で明示的な送信元承認を設定してください。

§5 では Service Connect(VPC Lattice)による Service Discovery・TLS・Observability・Cross-cluster 通信の本番実装を確認しました。次の §6 では、Pod Identity / Karpenter / Topology Aware / Service Connect の 4 軸で発生する詰まりポイント 7 選をパターン分類し、判断ツリーと対処法を体系化します。


§6 詰まりポイント7選 図解 — EKS本番運用で詰まったら読む判断ツリー

EKS縦深化の 4 軸 (Pod Identity / Karpenter / Topology Aware / Service Connect) を本番導入すると、予想外のところで詰まる。実際の現場で多発する 7 パターンを「症状 → 原因 → 解」で体系化した。まず判断ツリーで該当番号を特定し、該当節に飛ぶこと。

flowchart TD
 A[EKSトラブル発生] --> B{Pod起動失敗?}
 B -->|Yes| C{Pod Identity エラー?}
 C -->|Yes| D[詰まり1: Trust Policy ARN確認]
 C -->|No| D2[kubectlログで別原因調査]
 B -->|No| E{スケール問題?}
 E -->|Yes| F{Karpenter limits?}
 F -->|Yes| G[詰まり2: NodePool limits設定]
 F -->|No| G2[詰まり3: Spot PDB確認]
 E -->|No| H{ネットワーク?}
 H -->|Yes| I{Topology Hints生成?}
 I -->|No| J[詰まり4: Pod数確認 ≥zone数×3]
 I -->|Yes| K[詰まり5: Readiness probe確認]
 H -->|No| L{Service Connect?}
 L -->|Yes| M[詰まり6: Namespace設定確認]
 L -->|No| N[詰まり7: TLS証明書ARN確認]

詰まり1: Pod Identity — Trust Policy ARN が IRSA 形式のまま → WebIdentityErr

症状: kubectl describe podWebIdentityErr: failed to retrieve credentials が出る。IAM Role の権限は正しいはずなのに AWS API が拒否される。

原因: Pod Identity に移行した際、IAM Role の Trust Policy が古い IRSA 形式 (oidc.eks.region.amazonaws.com エンドポイント) のまま残っている。Pod Identity は pods.eks.amazonaws.com を Principal として使う別の認証経路を持つ。

// 誤: IRSA 形式 Trust Policy (Pod Identity では機能しない)
{
  "Effect": "Allow",
  "Principal": {
 "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/XXXXXXXX"
  },
  "Action": "sts:AssumeRoleWithWebIdentity"
}
// 正: Pod Identity 形式 Trust Policy
{
  "Effect": "Allow",
  "Principal": {
 "Service": "pods.eks.amazonaws.com"
  },
  "Action": [
 "sts:AssumeRole",
 "sts:TagSession"
  ]
}

: Trust Policy を pods.eks.amazonaws.com 形式に更新し、Service Account の eks.amazonaws.com/role-arn annotation を削除する。aws eks create-pod-identity-association で Association を作成して紐付けを完了させる。

詰まり1 対処チェックリスト
1. IAM Role Trust Policy → Principal が pods.eks.amazonaws.com か確認
2. Service Account から eks.amazonaws.com/role-arn annotation を削除
3. aws eks describe-pod-identity-association で Association 存在確認
4. Pod 再起動後 kubectl execaws sts get-caller-identity を確認

詰まり2: Karpenter — NodePool limits 未設定でスケールアウト無限ループ

症状: 負荷試験中に Node が際限なく追加され続け、AWS クォータ上限またはコスト異常で発覚する。

原因: NodePool に spec.limits を設定しないと Karpenter はスケールアウト上限を持たない。バグのある HPA が Pod を大量生成すると Node も連動して無限増殖する。

# 誤: limits 未設定 → 無制限スケール
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
 spec:
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["on-demand", "spot"]
  # limits がない
# 正: limits で上限を明示
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
 spec:
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["on-demand", "spot"]
  limits:
 cpu: "200"
 memory: "800Gi"
  disruption:
 consolidationPolicy: WhenUnderutilized

: すべての NodePool に spec.limits.cpuspec.limits.memory を設定する。Critical / Standard / Spot の 3 階層に分けた上で各層に独立した上限を設ける。CloudWatch Metrics karpenter_nodes_total でアラートも設定する。

詰まり2 対処チェックリスト
1. 全 NodePool に spec.limits.cpu / memory を設定
2. CloudWatch karpenter_nodes_total アラーム設定 (閾値: 想定最大の 1.3 倍)
3. HPA の maxReplicas も NodePool limits に整合させる
4. kubectl get nodeclaims で NodeClaim 数を定期監視

詰まり3: Karpenter — Spot 中断 + PDB 設定なし → Deployment 停止

症状: Spot Instance の中断イベント (2 分前通知) が発生するたびに本番サービスが数十秒ダウンする。

原因: PodDisruptionBudget を設定していないと、Spot 中断 → Karpenter が Node を cordon → Deployment の全 Pod が同一 Node に乗っていた場合に一斉 Evict される。

# 正: PDB + Pod Anti-affinity で分散
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
spec:
  minAvailable: "50%"
  selector:
 matchLabels:
app: api
# Pod Anti-affinity (Deployment spec.template.spec に追加)
affinity:
  podAntiAffinity:
 requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
 matchExpressions:
- key: app
  operator: In
  values: ["api"]
  topologyKey: "kubernetes.io/hostname"

: 本番 Deployment すべてに PDB (minAvailable: "50%") を設定し、Pod Anti-affinity で複数 Node に分散させる。Spot 中断は必ず発生するものとして設計する。

詰まり3 対処チェックリスト
1. 全本番 Deployment に PDB (minAvailable ≥ 50%) を設定
2. Pod Anti-affinity で同一 Node への集中を防ぐ
3. Karpenter Interruption Handler (SQS 連携) が有効か確認
4. kubectl get pdb で全 Deployment の PDB 適用状況を確認

詰まり4: Topology Aware Routing — Hints が生成されない (Pod 数が zone 数×3 未満)

症状: service.kubernetes.io/topology-mode: Auto を設定したのに Cross-AZ 通信が減らない。kubectl get endpointslices -o yamlhints フィールドが空。

原因: Topology Aware Routing の Hints は各 Zone に十分な Pod が存在する場合のみ生成される。Pod 数 ≥ zone 数 × 3 が必要で、3 AZ 構成なら最低 9 Pod 必要。Pod 数が少ないと kube-proxy は Hints を無視して全 Zone に分散させる。

# 誤: replicas: 3 では 3 AZ 構成で Hints 生成条件を満たせない
spec:
  replicas: 3
# 正: 十分なレプリカ + Topology Spread Constraints
spec:
  replicas: 9
  template:
 spec:
topologySpreadConstraints:
  - maxSkew: 1
 topologyKey: topology.kubernetes.io/zone
 whenUnsatisfiable: DoNotSchedule
 labelSelector:
matchLabels:
  app: api

: レプリカ数を zone 数 × 3 以上に設定し、topologySpreadConstraints で Zone 間均等分散を強制する。Hints 生成状況は kubectl get endpointslices -o jsonpath='{.items[*].endpoints[*].hints}' で確認できる。

詰まり4 対処チェックリスト
1. Pod 数 ≥ zone 数 × 3 (3 AZ なら replicas ≥ 9)
2. topologySpreadConstraints で Zone 均等分散を強制
3. kubectl get endpointslices -o yaml で hints フィールドを確認
4. kube-proxy logs で “topology aware” 文言を grep して動作確認

詰まり5: Topology Aware Routing — Readiness Probe 失敗で Zone バランス崩れ

症状: 特定 Zone の Pod が Readiness Probe 失敗でダウンし、その Zone へのトラフィックが隣 Zone に集中してレイテンシが上昇する。Hints は生成されているが Zone 間不均衡が発生する。

原因: Topology Aware Routing は Readiness が True の Pod のみを Hints に含める。1 つの Zone で Pod が大量に NotReady になると、他 Zone の Pod が Hints に含まれてしまい Cross-AZ 通信が発生する。

# 誤: failureThreshold が低く一時的な負荷で NotReady になりやすい
readinessProbe:
  httpGet:
 path: /health
 port: 8080
  periodSeconds: 5
  failureThreshold: 1
# 正: 堅牢な Readiness Probe 設定
readinessProbe:
  httpGet:
 path: /health
 port: 8080
  initialDelaySeconds: 10
  periodSeconds: 10
  failureThreshold: 5
  successThreshold: 1
  timeoutSeconds: 3

: Readiness Probe の failureThreshold を 5 以上に調整し、一時的な負荷や GC pause での誤 NotReady を防ぐ。Zone 毎の Ready Pod 数を CloudWatch Container Insights で監視してアラートを設定する。

詰まり5 対処チェックリスト
1. Readiness Probe の failureThreshold を 5 以上に調整
2. Zone 毎の Ready Pod 数を CloudWatch Container Insights で監視
3. kubectl get endpointslices -o yamlconditions.ready を定期確認
4. PDB で Zone 毎の最小 Pod 数を保証

詰まり6: Service Connect — Namespace 設定漏れでサービス名前解決失敗

症状: Service Connect 経由でサービスを呼び出すと failed to resolve DNS エラー。curl http://api.production が解決できない。

原因: Service Connect の名前解決は AWS Cloud Map の Namespace に依存する。serviceConnectConfigurationnamespace フィールドを指定しないと Cloud Map Namespace が作成されず、DNS プライベートホストゾーンへの登録が行われない。

# 誤: namespace 指定なし → Cloud Map Namespace が作成されない
serviceConnectConfiguration:
  enabled: true
  services:
 - portName: api
clientAliases:
  - port: 80
# 正: namespace を明示
serviceConnectConfiguration:
  enabled: true
  namespace: "production"
  services:
 - portName: api
discoveryName: api
clientAliases:
  - port: 80
 dnsName: api

: serviceConnectConfiguration.namespace を明示し、対応する Cloud Map Namespace が作成されていることを aws servicediscovery list-namespaces で確認する。すべてのサービスが同一 Namespace に登録されているか検証する。

詰まり6 対処チェックリスト
1. serviceConnectConfiguration.namespace が全サービスで統一されているか確認
2. aws servicediscovery list-namespaces で Namespace 存在確認
3. aws servicediscovery list-services で全サービス登録状況確認
4. ECS Exec で curl http://api.production の名前解決をテスト

詰まり7: Service Connect — Cross-cluster TLS 証明書 ARN 未更新

症状: Cross-cluster Service Connect 設定後、TLS ハンドシェイクエラーが発生してサービス間通信が確立できない。curl -vSSL: certificate verify failed が出る。

原因: Cross-cluster Service Connect で TLS を使用する場合、証明書 ARN (ACM PCA) を明示的に設定する必要がある。クラスタ A の設定をクラスタ B にコピーした際に ARN を更新し忘れるか、証明書が期限切れになっている。

# 誤: 証明書 ARN が旧クラスタのもの (別アカウント ARN)
tls:
  issuerCertAuthority:
 awsPcaAuthorityArn: "arn:aws:acm-pca:ap-northeast-1:111111111111:certificate-authority/OLD-ARN"
# 正: 現クラスタ用 ACM PCA ARN を使用
tls:
  issuerCertAuthority:
 awsPcaAuthorityArn: "arn:aws:acm-pca:ap-northeast-1:222222222222:certificate-authority/CORRECT-ARN"
  kmsKey: "arn:aws:kms:ap-northeast-1:222222222222:key/KEY-ID"
  roleArn: "arn:aws:iam::222222222222:role/ServiceConnectTLSRole"

: 各クラスタの awsPcaAuthorityArn が正しいアカウント・リージョンを指しているか確認する。Terraform 変数で ARN を管理し、クラスタ間の誤コピーを防ぐ。ACM PCA Managed Renewal で証明書自動更新を有効化する。

詰まり7 対処チェックリスト
1. aws acm-pca describe-certificate-authority で PCA の状態と有効期限を確認
2. 各クラスタの awsPcaAuthorityArn が正しいアカウントの ARN か確認
3. Terraform 変数で ARN を管理しハードコードを禁止
4. 証明書自動更新 (ACM PCA Managed Renewal) を有効化
§6 詰まり7選 スナップショット
1. Pod Identity Trust Policy → pods.eks.amazonaws.com に更新
2. Karpenter limits → spec.limits.cpu/memory で上限設定必須
3. Karpenter Spot + PDB → minAvailable: "50%" + Anti-affinity
4. Topology Hints 生成 → Pod 数 ≥ zone 数 × 3 (3 AZ なら replicas ≥ 9)
5. Topology Zone バランス → Readiness Probe failureThreshold: 5 以上
6. Service Connect NS → namespace フィールドを全サービスで明示
7. Cross-cluster TLS → ACM PCA ARN を現クラスタ用に更新 + 自動更新有効化

§7 アンチパターン → 正解パターン変換演習 (5問)

EKS縦深化の本番設計力を身につけるには、アンチパターンを実際に見て「なぜ悪いか」を理解することが近道だ。以下の 5 問は実際の本番トラブルから抽出した。悪い例と良い例を比較して設計判断力を養う。


Q1: Self-managed Node Group → Karpenter NodePool

状況: EC2 Auto Scaling Group (Self-managed) で Node 管理をしていたが、Node のプロビジョニングが遅く、負荷ピーク時にスケールアウトが間に合わない。また Pod の Bin-packing が最適化されておらず、Node のリソース使用率が低い。

# 悪い例: EC2 Auto Scaling Group で Node を固定管理
resource "aws_autoscaling_group" "workers" {
  name = "eks-workers"
  min_size= 3
  max_size= 10
  desired_capacity = 5
  vpc_zone_identifier = var.subnet_ids

  launch_template {
 id= aws_launch_template.workers.id
 version = "$Latest"
  }

  # Cluster Autoscaler 連携
  tag {
 key  = "k8s.io/cluster-autoscaler/enabled"
 value= "true"
 propagate_at_launch = true
  }
}
# 良い例: Karpenter NodePool で Just-in-time プロビジョニング
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
 metadata:
labels:
  managed-by: karpenter
 spec:
nodeClassRef:
  group: karpenter.k8s.aws
  kind: EC2NodeClass
  name: default
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["spot", "on-demand"]
  - key: kubernetes.io/arch
 operator: In
 values: ["amd64"]
  - key: karpenter.k8s.aws/instance-category
 operator: In
 values: ["c", "m", "r"]
  - key: karpenter.k8s.aws/instance-generation
 operator: Gt
 values: ["2"]
  limits:
 cpu: "200"
 memory: "800Gi"
  disruption:
 consolidationPolicy: WhenUnderutilized
 consolidateAfter: 30s

解説: Karpenter は Pod のリソース要求から必要な Node を計算し、数秒〜数十秒でプロビジョニングする。Cluster Autoscaler と異なり Node Group のスケールではなく Node 単位で管理するため Bin-packing が最適化される。consolidationPolicy: WhenUnderutilized で低負荷 Node を自動統合してコストを削減する。

Q1 移行ポイント
Karpenter 導入後は Cluster Autoscaler を無効化すること。両方が同時に動作すると Node の競合が発生する。cluster-autoscaler.kubernetes.io/safe-to-evict: "false" annotation がある Pod は移行前に見直すこと。

Q2: IRSA → EKS Pod Identity (Association 設定)

状況: IRSA (IAM Roles for Service Accounts) で認証を管理しているが、クラスタが増えるごとに OIDC Provider と Trust Policy の管理コストが増大している。新規クラスタ作成のたびに IAM ロールの Trust Policy を全て更新する必要がある。

# 悪い例: IRSA — クラスタ毎に OIDC ARN を埋め込む必要がある
data "aws_iam_openid_connect_provider" "eks" {
  url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}

resource "aws_iam_role" "app_role" {
  name = "eks-app-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = {
  Federated = data.aws_iam_openid_connect_provider.eks.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
  StringEquals = {
 "${data.aws_iam_openid_connect_provider.eks.url}:sub" = "system:serviceaccount:production:app-sa"
  }
}
 }]
  })
}
# 良い例: EKS Pod Identity — クラスタ非依存の Trust Policy + Association
resource "aws_iam_role" "app_role" {
  name = "eks-app-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = {
  Service = "pods.eks.amazonaws.com"
}
Action = [
  "sts:AssumeRole",
  "sts:TagSession"
]
 }]
  })
}

resource "aws_eks_addon" "pod_identity_agent" {
  cluster_name  = aws_eks_cluster.main.name
  addon_name = "eks-pod-identity-agent"
  addon_version = "v1.3.2-eksbuild.2"
}

resource "aws_eks_pod_identity_association" "app" {
  cluster_name = aws_eks_cluster.main.name
  namespace = "production"
  service_account = "app-sa"
  role_arn  = aws_iam_role.app_role.arn
}

解説: EKS Pod Identity では Trust Policy にクラスタ固有の OIDC ARN を埋め込む必要がない。同一の IAM ロールを複数クラスタに Association で紐付けられるため、マルチクラスタ環境での管理コストが大幅に削減される。


Q3: Full-mesh Service 通信 → Topology Aware Routing

状況: 3 AZ に分散した Pod が全ての AZ の Pod にランダムに通信している。Cross-AZ データ転送コストが月額で数十万円に達し、かつレイテンシもばらつきが大きい。

# 悪い例: topology-mode 未設定 → Cross-AZ 通信が無制限に発生
apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
 app: api
  ports:
 - port: 80
targetPort: 8080
  # topology-mode なし → ランダムルーティング
# 良い例: Topology Aware Routing で同一 AZ 優先 + 十分なレプリカ
apiVersion: v1
kind: Service
metadata:
  name: api
  annotations:
 service.kubernetes.io/topology-mode: "Auto"
spec:
  selector:
 app: api
  ports:
 - port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 9
  template:
 spec:
topologySpreadConstraints:
  - maxSkew: 1
 topologyKey: topology.kubernetes.io/zone
 whenUnsatisfiable: DoNotSchedule
 labelSelector:
matchLabels:
  app: api
containers:
  - name: api
 image: api:latest
 readinessProbe:
httpGet:
  path: /health
  port: 8080
failureThreshold: 5

解説: topology-mode: Auto を設定すると kube-proxy が EndpointSlice の Hints を参照して同一 AZ 内の Pod を優先的に選択する。Cross-AZ 転送コストを 30〜60% 削減できる。ただし Hints 生成には replicas ≥ zone 数 × 3 が必要なことに注意する。


Q4: ELB 直結 → Service Connect (Service Discovery 統合)

状況: マイクロサービス間通信を全て ALB/NLB 経由で行っている。サービスごとに ELB を作成するため DNS 管理が複雑化し、ELB のコストも増大している。サービスが増えるにつれてクラスタ外の DNS レコードで内部通信を管理する設計が破綻しつつある。

# 悪い例: ELB 経由でサービス間通信 (クラスタ外を経由)
# service-a が service-b を呼ぶ場合
# service-a → ALB (internet-facing or internal) → service-b
# 問題: コスト増 / レイテンシ増 / DNS 管理煩雑

apiVersion: v1
kind: Service
metadata:
  name: service-b
  annotations:
 service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  type: LoadBalancer
  selector:
 app: service-b
  ports:
 - port: 80
targetPort: 8080
# 良い例: Service Connect でクラスタ内 Service Discovery
# ECS の場合 (serviceConnectConfiguration)
serviceConnectConfiguration:
  enabled: true
  namespace: "production"
  services:
 - portName: http
discoveryName: service-b
port: 80
clientAliases:
  - port: 80
 dnsName: service-b
# EKS + VPC Lattice の場合: Gateway API で Service Discovery 統合
kubectl apply -f - <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: service-b-route
spec:
  parentRefs:
 - name: my-gateway
sectionName: http
  rules:
 - backendRefs:
  - name: service-b
 port: 80
EOF

解説: Service Connect はクラスタ内部でサービスを名前解決できるため ELB が不要になる。ELB 料金の削減に加えて、レイテンシが数ミリ秒単位で改善する。サービスが増えても Namespace 内で自動的に Discovery が機能するため DNS 管理コストが下がる。


Q5: Karpenter NodePool フラット → 階層化 (Critical/Standard/Spot)

状況: 全ての Pod を 1 つの NodePool (Spot のみ) で管理している。Spot 中断時に本番系の Critical サービスも影響を受けてしまい、SLA を達成できない。

# 悪い例: 1 NodePool 全 Pod (Spot のみ)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
 spec:
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["spot"]  # 全 Pod が Spot → 中断リスクあり
  limits:
 cpu: "200"
# 良い例: 3 層 NodePool (Critical/Standard/Spot)
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: critical
spec:
  template:
 metadata:
labels:
  tier: critical
 spec:
taints:
  - key: tier
 value: critical
 effect: NoSchedule
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["on-demand"]
  - key: karpenter.k8s.aws/instance-category
 operator: In
 values: ["m", "r"]
  limits:
 cpu: "80"
 memory: "320Gi"
---
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: standard
spec:
  template:
 spec:
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["on-demand", "spot"]
  limits:
 cpu: "100"
 memory: "400Gi"
  disruption:
 consolidationPolicy: WhenUnderutilized
---
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: spot-batch
spec:
  template:
 metadata:
labels:
  tier: batch
 spec:
taints:
  - key: tier
 value: batch
 effect: NoSchedule
requirements:
  - key: karpenter.sh/capacity-type
 operator: In
 values: ["spot"]
  limits:
 cpu: "100"
 memory: "400Gi"
# Critical Pod の tolerations 設定
tolerations:
  - key: tier
 value: critical
 effect: NoSchedule
nodeSelector:
  tier: critical

解説: NodePool を Critical (On-demand) / Standard (On-demand + Spot 混在) / Spot-batch (Spot のみ) の 3 層に分けることで、SLA 要求に応じた配置が可能になる。Critical サービスは On-demand 固定で Spot 中断の影響を受けない。バッチ処理は Spot のみで最大限コストを削減する。

§7 アンチパターン回避チェックリスト
1. Node 管理: Self-managed ASG → Karpenter NodePool に移行
2. IAM 認証: IRSA の OIDC Provider 依存 → Pod Identity Association に移行
3. 通信コスト: ELB 経由サービス間通信 → Service Connect / VPC Lattice 内部 Discovery
4. Cross-AZ: topology-mode 未設定 → Auto + replicas ≥ zone 数 × 3
5. NodePool 設計: 全 Pod Spot フラット → Critical/Standard/Spot 3 層階層化

§8 まとめ + Container三部作完成 + 43記事化告知 + 全軸クロスリンクナビ

4 軸の一言まとめ

EKS縦深化の 4 軸は互いに補完する関係にある。

一言まとめ主な恩恵
EKS Pod IdentityOIDC Provider 不要で IAM 認証をシンプルにTrust Policy 管理コスト 70% 削減
KarpenterJust-in-time Node プロビジョニングで Spot を最大活用EC2 コスト 30〜50% 削減
Topology Aware Routing同一 AZ 優先で Cross-AZ 転送を最小化データ転送コスト 30〜60% 削減
Service Connectクラスタ内 Service Discovery で ELB 依存を排除レイテンシ改善 + ELB コスト削減

4 軸を同時に導入することで、認証 / コンピュート / ネットワーク / サービス通信 の全層でコストと複雑性を削減できる。Vol3 の実装パターンは Vol1 (ECS 基礎) / Vol2 (EKS+GitOps) の上に積み上がる縦深化であり、三部作を通じて AWS コンテナ本番運用の全体像が完成する。

Container本番運用シリーズ三部作 完結
Vol1: ECS × Fargate × ECR × ECS Exec × Service Connect 基礎編 — ECS コンテナ本番運用の全体像
Vol2: EKS × ArgoCD × Kustomize × Argo Rollouts GitOps編 — デプロイ自動化とカナリアリリース
Vol3: EKS Pod Identity × Karpenter × Topology Aware × Service Connect 縦深化編 (本記事) — EKS最新ベストプラクティス全実装
三部作を通じて ECS から EKS まで AWS コンテナ本番運用の全層が揃った。次は Storage / Serverless / Network の縦深化へ。
graph LR
 V1[Vol1 ECS基礎<br/>Fargate/ECR/ECS Exec] --> V2[Vol2 EKS+GitOps<br/>ArgoCD/Kustomize/Rollouts]
 V2 --> V3[Vol3 EKS縦深化<br/>Pod Identity/Karpenter/Topology/SC]
 V3 --> NET[Network Vol1-2<br/>VPC/Transit GW/Hybrid]
 V3 --> SEC[Security Vol1-3<br/>IAM/Pod Identity連携]
 V3 --> OBS[Observability Vol1-2<br/>CloudWatch/X-Ray]
 V3 --> SRV[Serverless Vol1-2<br/>Lambda/EventBridge]
 V3 --> STG[Storage Vol1-2<br/>EFS/EBS/S3]
AWS本番運用シリーズ 43記事化達成
本記事の公開により AWS本番運用シリーズが 43 記事に到達した。Container三部作の完結が 42→43 記事化のトリガーとなった。
シリーズ全体は Network / Security / IAM / Container / Observability / Serverless / Storage / Database / Edge / Analytics / Migration / DevOps CI/CD の 12 ドメインで構成されており、AWS 本番運用に必要な全領域をカバーする。今後も Storage Vol2 / Serverless Vol2 / Network Vol3 と縦深化を継続していく。

全軸クロスリンクナビ

カテゴリ記事関連ポイント
ContainerContainer本番運用 Vol1 (ECS Fargate)Service Connect 基礎 / ECS Exec / ECR
ContainerContainer本番運用 Vol2 (EKS GitOps)ArgoCD / Kustomize / Argo Rollouts
NetworkVPC Network Vol1VPC 設計 / Subnet / Security Group
NetworkVPC Network Vol2Transit Gateway / VPC Peering
NetworkHybrid NetworkDirect Connect / VPN
IAMIAM Vol1IAM ポリシー設計 / SCP / Permission Boundary
ObservabilityObservability Vol1CloudWatch / メトリクス / アラーム
ObservabilityObservability Vol2X-Ray / Container Insights / Log Insights
ServerlessServerless Vol1Lambda / API Gateway / SAM
ServerlessServerless Vol2EventBridge / Step Functions
StorageStorage Vol1EFS / EBS / S3 マウント
DatabaseDatabase Vol1-3RDS / Aurora / DynamoDB
EdgeEdge/CDN Vol1CloudFront / WAF / Shield
DevOpsDevOps CI/CD Vol1-4CodePipeline / CodeBuild / CodeDeploy


Container Vol1 — ECS × Fargate × ECR × ECS Exec × Service Connect 完全ガイド


Container Vol2 — EKS × ArgoCD × Kustomize × Argo Rollouts GitOps編

次のステップ

Vol3 まで読み切ったあなたは EKS 本番運用の最新ベストプラクティスを一通り習得した。次のステップとして以下をお勧めする。

  1. Pod Identity 移行: 既存クラスタの IRSA Association を aws eks list-pod-identity-associations で一覧し、段階的に移行する
  2. Karpenter 導入: Cluster Autoscaler を無効化し、Critical/Standard/Spot の 3 層 NodePool を設定する
  3. Topology Aware 適用: kubectl get services -A で topology-mode 未設定サービスを洗い出し、High-traffic サービスから順に適用する
  4. 詰まり7選をブックマーク: 本番トラブル発生時は §6 の判断ツリーを最初の診断ステップとして使う

EKS 縦深化の実装は一度で全て完成させる必要はない。優先度の高い軸から 1 つずつ着実に導入することで、コストと信頼性の両方を改善できる。

8-2. EKS 縦深化 4 軸 実装優先度マトリクス

実装優先度は「コスト削減効果」と「実装難易度」の 2 軸で評価する。すぐに着手して効果が大きいのは Karpenter と Topology Aware Routing。Pod Identity は段階的移行で確実に置き換える。Service Connect は新規サービスから優先導入する。

4 軸 実装優先度マトリクス (コスト削減 × 難易度)

削減効果実装難易度推奨着手順初期投入工数
Karpenter★★★ (EC2 30-50%減)中 (NodePool 設計)1 番目1-2 週間
Topology Aware Routing★★ (Cross-AZ 30-60%減)低 (annotation 1 行)2 番目1-3 日
Pod Identity★ (運用負荷 70%減)中 (段階的移行)3 番目2-4 週間
Service Connect★ (ELB コスト + レイテンシ)中 (Service 再設定)4 番目 (新規優先)1-2 週間

Karpenter は導入直後から EC2 コストが目に見えて下がるため経営層への説明が容易だ。Topology Aware Routing は annotation 1 行で適用できるため、最初の PoC として最適。Pod Identity と Service Connect は中長期の運用負荷削減に効くため、新規環境から先行して標準化する戦略が望ましい。

8-3. Container 本番運用シリーズ 三部作 読み順ガイド

本シリーズはあなたの現状と目標に応じて読む順番を変えることで効率的に学習できる。

読者タイプ別 推奨読み順

読者タイプ推奨読み順狙い
ECS 中心で EKS 未経験Vol1 → Vol3 §1+§5 → Vol2ECS で安定運用しつつ EKS 移行を視野に
EKS 中心で GitOps 未導入Vol2 → Vol3 → Vol1 (参照)EKS で GitOps + 縦深化を一気に
新規プロジェクト立ち上げVol1 → Vol2 → Vol3順序通りで全体像を確実に習得
コスト最適化が最優先Vol3 §3+§4 → Vol2 → Vol1Karpenter+Topology Aware で即効性のあるコスト削減から着手
セキュリティ強化が最優先Vol3 §2 → Security Vol1-3 → Vol2Pod Identity + IAM Vol1 で認証基盤を固める

三部作は「Vol1 = ECS 基礎」「Vol2 = EKS + GitOps」「Vol3 = EKS 縦深化」と階層構造になっており、後ろの巻ほど深く具体的なベストプラクティスに踏み込む。あなたが詰まっている領域に応じて優先する巻を選ぶことで、最短で課題を解決できる。

8-4. AWS 本番運用シリーズ 12 ドメイン全景

Container 本番運用シリーズは AWS 本番運用シリーズ全体のうちの 1 ドメインだ。12 ドメイン全体を俯瞰すると、Container は「コンピュート層」の中核として他ドメインと密接に連携している。

AWS 本番運用シリーズ 12 ドメイン マップ

レイヤドメインContainer との連携
コンピュートContainer (本シリーズ)
ServerlessLambda → EKS への移行パターン / EventBridge 統合
ネットワークNetworkVPC 設計 / Transit Gateway / Hybrid 接続
Edge/CDNCloudFront → ALB → EKS Service Connect 経路
データDatabaseRDS / Aurora / DynamoDB を Pod から接続
StorageEFS / EBS CSI Driver / S3 マウント
セキュリティIAMPod Identity Association / IRSA
SecurityVol1-3 でセキュリティ運用基盤
運用ObservabilityContainer Insights / X-Ray / Log Insights
MigrationApp Migration / DMS / Container 移行
開発支援DevOps CI/CDCodePipeline / CodeBuild → EKS Deploy
AnalyticsEMR on EKS / Glue with Container

シリーズ全体を読み進めるとき、Container 本番運用シリーズを起点に各レイヤへ展開していくと EKS / ECS の周辺技術が体系的に理解できる。特に Network / IAM / Observability の 3 ドメインは Container 運用と密接で、Vol3 を読み終えたら次はこれらを優先するとよい。

8-5. Vol3 読了後 想定質問 FAQ

読了後によく聞かれる質問に答える。

Q1. Pod Identity と IRSA、結局どちらを使うべきか?
新規クラスタは Pod Identity を選択する。既存クラスタは段階的移行を推奨する。Pod Identity は OIDC Provider が不要で trust policy 管理コストが大幅に下がるため、長期的に運用負荷が減る。ただし全 AWS サービスが Pod Identity 対応とは限らない (Lambda 連携など一部 IRSA のままが安全) ため、移行時はサービス対応表を確認する。

Q2. Karpenter で Spot 100% は本番で安全か?
Critical Workload は On-Demand、Standard は On-Demand + Spot 混在、Batch は Spot 100% という 3 階層構成を推奨する。Spot Interruption は不可避なため、Pod Disruption Budget + Interruption Handler + Diversification (instance-types 多様化) の 3 点セットで影響を最小化する。

Q3. Topology Aware Routing は本当に Cross-AZ コストが下がるか?
適用前後で VPC Flow Logs を比較し、Cross-AZ traffic が減少していることを実測で確認する。Pod Topology Spread Constraints が正しく設定されていれば 30-60% 削減が見込めるが、Zone 別 Pod 数が偏ると効果が出ないため、Pod Spread の併用が必須だ。

Q4. Service Connect は App Mesh の代替として完全か?
基本的な Service Discovery と TLS 終端は Service Connect で完結する。ただし Multi-cluster Service Mesh や複雑な Traffic Policy が必要な場合は App Mesh または Istio の方が適している。本番で使うサービス通信パターンを整理し、シンプルなパターンが大半なら Service Connect で十分だ。

Q5. 4 軸を全部一度に導入するべきか?
非推奨。1 軸ずつ段階的に導入する。優先順は §8-2 のマトリクス通り、Karpenter → Topology Aware → Pod Identity → Service Connect の順。各軸の導入後 2-4 週間運用してから次の軸に進む。

8-6. 戦略C 5/5 完結記念 + 後続予告

🎯 戦略C完結 + AWS本番運用シリーズ 43 記事化 達成
本記事 (Container Vol3) の公開で AWS本番運用シリーズは 戦略C 完結 + 43 記事化 を達成した。
戦略C は「Step Functions 基礎リライト → Storage Vol2 縦深化 → EventBridge×VPC Lattice×Fargate 新規 → Security Vol3 縦深化 → AWS Code* Vol1 リライト + Container Vol3 縦深化」の 5 連続実装で、AWS 本番運用シリーズの中枢ハブを完成させる戦略だった。
Container 三部作の完成により、ECS から EKS、基礎から縦深化まで全層が揃った。

次に予定している縦深化軸:
Storage Vol3: S3 Object Lambda × Express One Zone × CRR の本番運用パターン
Network Vol3: Cross-Region VPC Peering × Transit Gateway Inter-Region Peering × Cloud WAN
Serverless Vol3: Step Functions Distributed Map × Express Workflow × SDK Direct Integration 詳細

シリーズ全体は AWS 本番運用に必要な全ドメインを縦深化していく方針だ。あなたの本番運用で詰まっている領域があれば、シリーズの各巻を参照することで実装パターンと詰まりポイントの対処法が得られる。Container 三部作を起点に、ぜひ他ドメインのシリーズもご活用いただきたい。