メインコンテンツへスキップ
このガイドでは、Terragrunt を使用して AWS に EKB EKS インフラストラクチャを完全にデプロイする手順を説明します。ツールのインストール、環境セットアップ、およびすべてのインフラストラクチャ コンポーネントにわたって適切な依存関係の順序を確保するように設計された段階的な展開シーケンスについて説明します。 導入は 9 つのフェーズに分かれています。
  1. 状態管理 — 環境の Terraform 状態を保存するために使用される S3 バケットをブートストラップします。
  2. EKS インフラストラクチャ — VPC、サブネット、NAT ゲートウェイ、IAM ロール、EKS クラスターと管理対象ノード グループをプロビジョニングします。
  3. ストレージとロード バランシング — 永続ボリューム用の EBS CSI ドライバーと、ALB イングレス用の AWS ロード バランサー コントローラーをデプロイします。
  4. Karpenter Autoscaling — スポット インスタンスのサポートと、SQS および EventBridge を介した中断処理を備えた動的ノード プロビジョニングをセットアップします。
  5. KEDA 自動スケーリング — CPU とメモリのしきい値に基づいてポッド レベルの自動スケーリングのために KEDA をデプロイします。
  6. データ サービス — Supabase (セルフホストまたはクラウド)、ElastiCache Redis、および Amazon MQ RabbitMQ をプロビジョニングします。
  7. Odin サービス — Helm 経由で EKB アプリケーション スタック (Web、FastAPI、Celery、Automator) をデプロイします。
  8. SigNoz の可観測性 — SigNoz と k8s-infra エージェントを介して分散トレース、メトリクス、ログ集約を展開します。
  9. 最終展開 — 完全な terragrunt apply を実行して、残りのリソースを調整します。
開始する前に、お客様と一緒に前提条件チェックリストを完了し、環境テンプレート内のすべての <YOUR_*> プレースホルダーが入力されていることを確認してください。 VPC ID、EKS クラスター エンドポイント、Redis および RabbitMQ エンドポイントを含むいくつかの値は、特定のフェーズが完了した後でのみ使用できるため、ガイドでは、いつそれらを取得して適用するかを正確に示しています。

前提条件

  • 適切なアクセス許可が設定された AWS CLI
  • Terraform (>= 1.0)
  • Terragrunt (最新バージョン)
  • kubectl Kubernetes 管理用
  • helm : Helm チャート管理用

インストールガイド

Terragrunt のインストール

macOS (自作)bash brew install terragrunt Linux (apt)```bash

Add HashiCorp GPG key

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg —dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

Add HashiCorp repository

echo “deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/hashicorp.list

Update and install

sudo apt update sudo apt install terragrunt **Windows (チョコレート風)**bash choco install terragrunt
kubectl のインストール
 
**macOS (自作)**```bash
brew install kubectl
```**Linux**```bash
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
```**Windows (チョコレート風)**```bash
choco install kubernetes-cli
```### Helm のインストール
 
**macOS (自作)**```bash
brew install helm
```**Linux**```bash
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
```**Windows (チョコレート風)**```bash
choco install kubernetes-helm
```### インストールの確認```bash
terragrunt --version
terraform --version
kubectl version --client
helm version
```### AWS CLI 設定```bash
# Install AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
 
# Configure AWS credentials
aws configure
 
# Verify configuration
aws sts get-caller-identity
```---
 
## 新しい環境の作成
 
### ステップ 1: 環境テンプレートをコピーする
 
`env-template-folder` には、すぐに入力できる `<YOUR_*>` プレースホルダーを含む、事前に構造化されたファイルが含まれています。それを全体的にコピーして、新しい環境フォルダーを作成します。```bash
# Navigate to the terragrunt environments directory
cd terragrunt/environments
 
# Copy the full template folder to a new environment (replace 'your-env-name')
cp -r env-template-folder your-env-name
 
# The folder structure is ready:
# your-env-name/
# ├── terragrunt.hcl               # Core cluster configuration
# ├── state/
# │   └── terragrunt.hcl           # S3 state bucket configuration
# └── values/
#     ├── infrastructure.yaml      # AWS Load Balancer Controller
#     ├── karpenter-values.yaml    # Karpenter controller settings
#     ├── karpenter-nodeclasses.yaml  # EC2NodeClass definitions
#     ├── karpenter.yaml           # Karpenter NodePool definitions
#     ├── keda.yaml                # KEDA autoscaler
#     ├── aws-ebs-csi-driver.yaml  # EBS CSI driver
#     ├── odin-services.yaml       # Odin application services
#     ├── supabase.yaml            # Supabase (if self-hosting)
#     ├── ha-supabase-db.yaml      # Supabase HA DB (if self-hosting)
#     ├── cloudnative-pg.yaml      # CloudNativePG operator (if self-hosting)
#     ├── signoz.yaml              # SigNoz observability (optional)
#     └── signoz-k8s-infra.yaml    # SigNoz k8s metrics (optional)
```### ステップ 2: すべてのプレースホルダーが存在することを確認する```bash
cd your-env-name
 
# List all placeholders that need to be filled in
grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml" | sort
```すべてのプレースホルダーは `<YOUR_*>` 規則に従います。以下の手順では、ファイルごとに入力していきます。
 
### ステップ 3: SSL 証明書をプロビジョニングする (AWS ACM)
 
環境変数を設定する前に、証明書 ARN が必要です。 AWS コンソールを使用して、環境がサービスを提供するすべてのドメインの AWS Certificate Manager (ACM) の SSL 証明書をリクエストします。
 
**オプション A: 単一のワイルドカード証明書 (推奨)**
 
1 つのワイルドカード証明書は、1 つの ARN を持つすべてのサブドメインをカバーします。たとえば、ベース ドメインが `app.example.com` の場合、単一の `*.app.example.com` 証明書で以下がカバーされます。
 
| Service | Domain __PLACEHOLDER_30__ Web | __PLACEHOLDER_3__ __PLACEHOLDER_31__ FastAPI | __PLACEHOLDER_4__ __PLACEHOLDER_32__ Automator | __PLACEHOLDER_5__ __PLACEHOLDER_33__ Supabase | __PLACEHOLDER_6__ __PLACEHOLDER_34__ SigNoz | __PLACEHOLDER_7__ |
 
**オプション B: サービスごとの証明書**
 
ワイルドカードを使用できない場合は、ドメインごとに 1 つの証明書を要求します。各ドメインに対して以下の手順を繰り返します: `<YOUR_WEB_DOMAIN>`、`<YOUR_API_DOMAIN>`、`<YOUR_AUTOMATOR_DOMAIN>`、`<YOUR_SUPABASE_DOMAIN>` (`ENABLE_SUPABASE=true` の場合のみ)、`<YOUR_SIGNOZ_DOMAIN>` (`ENABLE_SIGNOZ=true` の場合のみ)。
 
**AWS コンソールでの証明書のリクエスト**
 
1. AWS Certificate Manager コンソールを開きます
2. 正しい領域 (右上) に切り替えます — `<YOUR_AWS_REGION>` と一致する必要があります
3. [**証明書の要求**] → [**公開証明書の要求**] → [**次へ**] をクリックします。
4. **完全修飾ドメイン名** の下に、ワイルドカード (例: `*.app.example.com`) または特定のドメインを入力します。
5. **検証方法**を**DNS検証**に設定します
6. [**リクエスト**] をクリックします。証明書は `Pending validation` 状態で作成されます。
 
**DNS CNAME 検証レコードの追加**
 
ACM は、ドメインの所有権を証明するために DNS プロバイダーに追加する必要がある CNAME レコードを生成します。 ACM コンソールから値を取得するには、証明書を開いて **ドメイン** の下のドメインを展開します。
 
| DNS Field | Value __PLACEHOLDER_35__ Record type | __PLACEHOLDER_18__ __PLACEHOLDER_36__ Name / Host | e.g., __PLACEHOLDER_19__ __PLACEHOLDER_37__ Value / Points to | e.g., __PLACEHOLDER_20__ |
 
<Info>
Include the trailing dot (__PLACEHOLDER_21__) at the end of the CNAME values if your DNS provider requires it.
</Info>
 
**クラウドフレア**
 
1. Cloudflareにログイン → ドメインを選択 → **DNS** → **レコード** → **レコードの追加**
2. **タイプ**を `CNAME` に設定します
3. ACM CNAME 名を **Name** に貼り付け、ACM CNAME 値を **Target** に貼り付けます。
4. **プロキシ ステータス**を **DNS のみ** (灰色の雲のアイコン) に設定します。証明書は Cloudflare プロキシを通じて検証されません。
5. [**保存**] をクリックします。
 
**国道53号線**
 
1. Route 53 コンソールを開く → **ホストゾーン** → ゾーンを選択 → **レコードの作成**
2. **レコード タイプ**を `CNAME` に設定します
3. ACM CNAME 名を **レコード名** (サブドメイン部分のみ) に貼り付け、値を **値** に貼り付けます。
4. TTL を `300` に設定し、**レコードの作成** をクリックします。
 
<Tip>
In ACM you can also click **Create records in Route 53** to have ACM add the record automatically if the hosted zone is in the same account.
</Tip>
 
DNS が伝播すると (通常は 1 ~ 5 分)、証明書のステータスが **発行済み** に変わります。証明書の先頭から ARN をコピーします。`arn:aws:acm:<region>:<account-id>:certificate/<uuid>` のようになります。次のステップのために ARN を手元に置いておいてください。
 
### ステップ 4: 環境変数を設定する
 
Terragrunt コマンドを実行する前に、これらのシェル環境変数を設定します。これらは、`get_env()` を介して `terragrunt.hcl` によって直接読み取られます。```bash
export AWS_REGION="<YOUR_AWS_REGION>"          # e.g., "eu-west-2", "us-east-2"
export CLUSTER_NAME="<env_folder_name>"          # e.g., "env-template-folder"
 
# Domain configuration
export WEB_DOMAIN="<YOUR_WEB_DOMAIN>"                    # e.g., "app.example.com"
export FASTAPI_DOMAIN="<YOUR_API_DOMAIN>"                # e.g., "api-app.example.com"
export AUTOMATOR_DOMAIN="<YOUR_AUTOMATOR_DOMAIN>"        # e.g., "automations-app.example.com"
export SUPABASE_DOMAIN="<YOUR_SUPABASE_DOMAIN>"          # e.g., "supabase-app.example.com"
export SIGNOZ_DOMAIN="<YOUR_SIGNOZ_DOMAIN>"              # e.g., "signoz-app.example.com"
 
# SSL Certificate ARNs — Option A: Single wildcard certificate (recommended)
export WILDCARD_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_WILDCARD_CERT_ID>"
 
# SSL Certificate ARNs — Option B: Per-service certificates
export WEB_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_WEB_CERT_ID>"
export FASTAPI_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_API_CERT_ID>"
export AUTOMATOR_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_AUTOMATOR_CERT_ID>"
export SUPABASE_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_SUPABASE_CERT_ID>"
export SIGNOZ_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_SIGNOZ_CERT_ID>"
 
# Service enablement flags
export ENABLE_ALB_CONTROLLER="true"
export ENABLE_AWS_SERVICES="true"      # Set to "true" to enable ElastiCache and AmazonMQ
 
# Supabase stack (self-hosted) — enable all three together if self-hosting Supabase
export ENABLE_CNPG="true"             # CloudNativePG operator  (namespace: cnpg-system)
export ENABLE_HA_SUPABASE_DB="true"   # Supabase HA database    (namespace: ha-supabase-db)
export ENABLE_SUPABASE="true"         # Supabase application    (namespace: supabase)
 
export ENABLE_SIGNOZ="true"           # Set to "true" to enable SigNoz observability
export SSL_TERMINATION="alb"
```#### スポット インスタンスとステートフル ワークロード
 
スポット インスタンスは、環境変数ではなく、`values/karpenter.yaml` のノードプールごとに構成されます。各ノードプールは、独自の容量戦略を宣言します。
 
| NodePool | __PLACEHOLDER_1__ label | Capacity Type | Rationale __PLACEHOLDER_27__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | Spot → On-Demand fallback | Cost-optimised for stateless batch/background workloads __PLACEHOLDER_28__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | Spot → On-Demand fallback | Cost-optimised for CPU-bound workloads __PLACEHOLDER_29__ __PLACEHOLDER_6__ | __PLACEHOLDER_7__ | On-Demand → Spot fallback | Stability prioritised for high-memory pods __PLACEHOLDER_30__ __PLACEHOLDER_8__ | __PLACEHOLDER_9__ | Spot → On-Demand fallback | Cost-optimised for AI/ML batch workloads __PLACEHOLDER_31__ __PLACEHOLDER_10__ | __PLACEHOLDER_11__ | On-Demand only | Stable user-facing services (Supabase, Kong, etc.) — no Spot interruptions __PLACEHOLDER_32__ __PLACEHOLDER_12__ | __PLACEHOLDER_13__ / __PLACEHOLDER_14__ | On-Demand only | Stateful — Spot interruption is unsafe for databases |
 
`application` ノードプールは、オンデマンドのみで m/c インスタンス ファミリー (第 5 世代以降) を使用します。 Supabase サービス ポッドは、スポット再利用イベントによって決して中断されないことを保証するために、`nodeSelector: workload-type: "application"` を介してここに固定されます。
 
`database-dedicated` ノードプールはスポットを使用しません。 `consolidationPolicy: WhenEmpty` を使用するため、Karpenter はまだ実行中のポッドがあるノードを削除せず、PostgreSQL や CloudNativePG レプリカなどのステートフル ワークロードに対して安全になります。
 
**スポット上のステートフル アプリケーションのガイドライン:**
 
- スポット ノードプール上の `PersistentVolumeClaim` を使用して、データベース、永続キュー、またはポッドをスケジュールしないでください。
- データベース ポッドに対して一致する `database-workload: "true"` 許容範囲を持つ `node-type: database-dedicated` をターゲットとする `nodeSelector` を使用します。
- 中断することなく利用可能な状態を維持する必要がある、ユーザー向けのステートレス サービスには `nodeSelector: workload-type: "application"` を使用します。
- バックグラウンド ワークロード (Web、API、Celery、Automator) の場合、`general` Spot NodePool が適切です。Karpenter の SQS 中断ハンドラーは、AWS がスポット ノードを再利用する前に正常にスポット ノードをドレインし、KEDA の最小レプリカ数 (≧ 2) により、ノード交換時の可用性が確保されます。
- スポットをグローバルに無効にするには、`values/karpenter.yaml` 内のすべてのノードプールの値リストから `"spot"` を削除します。
 
**Karpenter がスポット中断警告を処理する方法:**
 
AWS は、スポット インスタンスを終了する前に 2 分間の中断通知を出します。 Karpenter は、EventBridge と SQS を使用して、これに自動的に対処します。```
AWS Spot Interruption Event


Amazon EventBridge (CloudWatch Events)
  Rule: EC2 Spot Instance Interruption Warning


   SQS Queue (Karpenter interruption queue)


  Karpenter Controller (polls SQS continuously)

        ├── Cordons the node (no new pods scheduled)
        ├── Drains existing pods (respects PodDisruptionBudgets)
        ├── Provisions a replacement node in parallel
        └── Pods reschedule onto the new node before the 2-min window closes
```これは、`terragrunt.hcl` の `karpenter` ブロックで構成されます。```hcl
karpenter = {
  spot_interruption_handling = true   # creates the SQS queue and EventBridge rule
  enable_spot_instances       = true   # allows Spot in NodePool capacity requirements
}
```### ステップ 5: 環境固有のファイル値を更新する
 
次のプレースホルダーについて、新しい env フォルダー内のすべてのファイルに対して検索と置換を実行します。
 
| Placeholder | Description | Example __PLACEHOLDER_14__ __PLACEHOLDER_0__ | Unique environment identifier | __PLACEHOLDER_1__ __PLACEHOLDER_15__ __PLACEHOLDER_2__ | AWS region of the cluster | __PLACEHOLDER_3__, __PLACEHOLDER_4__ __PLACEHOLDER_16__ __PLACEHOLDER_5__ | 12-digit AWS account ID | __PLACEHOLDER_6__ __PLACEHOLDER_17__ __PLACEHOLDER_7__ | Environment tag value | __PLACEHOLDER_8__, __PLACEHOLDER_9__, __PLACEHOLDER_10__ __PLACEHOLDER_18__ __PLACEHOLDER_11__ | Project tag value | __PLACEHOLDER_12__, __PLACEHOLDER_13__ |```bash
# Run from your new env folder to find all remaining placeholders
grep -r "<YOUR_" .
```#### 5.1 `terragrunt.hcl` — コアクラスター構成```bash
nano terragrunt.hcl
```| Field | Placeholder | Notes __PLACEHOLDER_23__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | Must match EKS cluster name __PLACEHOLDER_24__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | AWS region __PLACEHOLDER_25__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | 12-digit account ID __PLACEHOLDER_26__ __PLACEHOLDER_6__ | __PLACEHOLDER_7__ | e.g., __PLACEHOLDER_8__ __PLACEHOLDER_27__ __PLACEHOLDER_9__ | __PLACEHOLDER_10__ | 3 AZs in your region __PLACEHOLDER_28__ __PLACEHOLDER_11__ | __PLACEHOLDER_12__ | e.g., __PLACEHOLDER_13__ __PLACEHOLDER_29__ __PLACEHOLDER_14__ | __PLACEHOLDER_15__ | e.g., __PLACEHOLDER_16__ __PLACEHOLDER_30__ __PLACEHOLDER_17__ | __PLACEHOLDER_18__ | RabbitMQ admin username (only when __PLACEHOLDER_19__) __PLACEHOLDER_31__ __PLACEHOLDER_20__ | __PLACEHOLDER_21__ | Min 12 chars; must include uppercase, lowercase, digits, and special characters |
 
#### 5.2 `state/terragrunt.hcl` — S3 状態バケット```bash
nano state/terragrunt.hcl
```| Field | Placeholder | Notes __PLACEHOLDER_6__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | Must be globally unique __PLACEHOLDER_7__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | Same region as cluster |
 
#### 5.3 `values/infrastructure.yaml` — AWS ロードバランサー コントローラー
 
<Warning>
Obtain the VPC ID **after** the EKS cluster is created before deploying the AWS Load Balancer Controller.
</Warning>```bash
# Get VPC ID after EKS cluster is created
aws eks describe-cluster --name <YOUR_ENV_NAME> \
  --query "cluster.resourcesVpcConfig.vpcId" --output text
nano values/infrastructure.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_11__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | EKS cluster name __PLACEHOLDER_12__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | AWS region __PLACEHOLDER_13__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | Required before ALB deploy __PLACEHOLDER_14__ __PLACEHOLDER_6__ | __PLACEHOLDER_7__, __PLACEHOLDER_8__ | IAM role for ALB controller |
 
#### 5.4 `values/karpenter-values.yaml` — Karpenter コントローラー
 
<Warning>
Obtain the EKS cluster endpoint **after** the EKS cluster is created and before deploying Karpenter.
</Warning>```bash
# Get cluster endpoint after EKS cluster is created
aws eks describe-cluster --name <YOUR_ENV_NAME> \
  --query "cluster.endpoint" --output text
nano values/karpenter-values.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_10__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__, __PLACEHOLDER_2__ | IAM role for Karpenter __PLACEHOLDER_11__ __PLACEHOLDER_3__ | __PLACEHOLDER_4__ | EKS cluster name __PLACEHOLDER_12__ __PLACEHOLDER_5__ | __PLACEHOLDER_6__ | Required before Karpenter deploy __PLACEHOLDER_13__ __PLACEHOLDER_7__ | __PLACEHOLDER_8__ | Karpenter node instance profile |
 
#### 5.5 `values/karpenter-nodeclasses.yaml` — Karpenter ノード クラス```bash
nano values/karpenter-nodeclasses.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_11__ All __PLACEHOLDER_0__ tags | __PLACEHOLDER_1__ | Cluster tag for subnet/SG selectors __PLACEHOLDER_12__ __PLACEHOLDER_2__ bootstrap cluster name | __PLACEHOLDER_3__ | Node bootstrap script __PLACEHOLDER_13__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | e.g., __PLACEHOLDER_6__ __PLACEHOLDER_14__ __PLACEHOLDER_7__ | __PLACEHOLDER_8__ | e.g., __PLACEHOLDER_9__ |
 
#### 5.6 `values/aws-ebs-csi-driver.yaml` — EBS CSI ドライバー```bash
nano values/aws-ebs-csi-driver.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_15__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__, __PLACEHOLDER_2__ | IAM role for EBS CSI controller __PLACEHOLDER_16__ __PLACEHOLDER_3__ | __PLACEHOLDER_4__, __PLACEHOLDER_5__ | IAM role for EBS CSI node __PLACEHOLDER_17__ __PLACEHOLDER_6__ | __PLACEHOLDER_7__ | AWS region __PLACEHOLDER_18__ __PLACEHOLDER_8__ | __PLACEHOLDER_9__ | AWS region __PLACEHOLDER_19__ __PLACEHOLDER_10__ | __PLACEHOLDER_11__ | AWS region __PLACEHOLDER_20__ __PLACEHOLDER_12__ | __PLACEHOLDER_13__ | AWS region |
 
#### 5.7 `values/karpenter.yaml` — Karpenter NodePools```bash
nano values/karpenter.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_15__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | Applied to all NodePool labels __PLACEHOLDER_16__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | AZs for all NodePools |
 
ノード クラス名 (`general``compute-intensive``memory-intensive``gpu``database`) は、`karpenter-nodeclasses.yaml` のエントリと一致する必要があります。
 
#### 5.8 `values/keda.yaml` — KEDA オートスケーラー
 
環境固有のプレースホルダーは必要ありません。リソース制限とレプリカ数は、適切なデフォルトで事前に構成されています。必要に応じて確認して調整します。
 
#### 5.9 `values/supabase.yaml` — Supabase アプリケーション (`ENABLE_SUPABASE=true` の場合のみ)
 
<Warning>
All keys below must be generated consistently and shared with __PLACEHOLDER_13__. Generate them once and use the same values in both files.
</Warning>```bash
# Generate JWT secret
openssl rand -hex 32
 
# Generate anon/service role JWTs (requires Supabase CLI)
brew install supabase/tap/supabase
supabase gen-keys
 
# Generate passwords and tokens
openssl rand -hex 24       # for passwords
openssl rand -base64 64    # for secretKeyBase
nano values/supabase.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_51__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | Must match __PLACEHOLDER_2__ __PLACEHOLDER_3__ __PLACEHOLDER_52__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | Must match __PLACEHOLDER_6__ __PLACEHOLDER_7__ __PLACEHOLDER_53__ __PLACEHOLDER_8__ | __PLACEHOLDER_9__ | Must match __PLACEHOLDER_10__ __PLACEHOLDER_11__ __PLACEHOLDER_54__ __PLACEHOLDER_12__ | __PLACEHOLDER_13__ | Must match __PLACEHOLDER_14__ __PLACEHOLDER_15__ __PLACEHOLDER_55__ __PLACEHOLDER_16__ | __PLACEHOLDER_17__ | Internal Logflare token __PLACEHOLDER_56__ __PLACEHOLDER_18__ | __PLACEHOLDER_19__ | Internal Logflare token __PLACEHOLDER_57__ __PLACEHOLDER_20__ | __PLACEHOLDER_21__ | Studio UI login __PLACEHOLDER_58__ __PLACEHOLDER_22__ | __PLACEHOLDER_23__ | Studio UI login __PLACEHOLDER_59__ __PLACEHOLDER_24__ | __PLACEHOLDER_25__ | Phoenix secret key __PLACEHOLDER_60__ __PLACEHOLDER_26__ | __PLACEHOLDER_27__ | __PLACEHOLDER_28__ __PLACEHOLDER_61__ __PLACEHOLDER_29__ | __PLACEHOLDER_30__ | Must match __PLACEHOLDER_31__ (__PLACEHOLDER_32__) __PLACEHOLDER_62__ __PLACEHOLDER_33__ | __PLACEHOLDER_34__ | Must match __PLACEHOLDER_35__ (__PLACEHOLDER_36__) __PLACEHOLDER_63__ __PLACEHOLDER_37__ | __PLACEHOLDER_38__ | Same value as __PLACEHOLDER_39__ __PLACEHOLDER_64__ __PLACEHOLDER_40__ | __PLACEHOLDER_41__ | Same value as __PLACEHOLDER_42__ |
 
#### 5.10 `values/ha-supabase-db.yaml` — Supabase HA Database (only if `ENABLE_HA_SUPABASE_DB=true`)
 
<Warning>
Secrets here must match __PLACEHOLDER_45__. Use the same generated values for __PLACEHOLDER_46__, __PLACEHOLDER_47__, __PLACEHOLDER_48__, and __PLACEHOLDER_49__.
</Warning>```bash
nano values/ha-supabase-db.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_29__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | Must match __PLACEHOLDER_2__ __PLACEHOLDER_3__ __PLACEHOLDER_30__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | Must be identical to __PLACEHOLDER_6__ __PLACEHOLDER_31__ __PLACEHOLDER_7__ | __PLACEHOLDER_8__ | Must be identical to __PLACEHOLDER_9__ __PLACEHOLDER_32__ __PLACEHOLDER_10__ | __PLACEHOLDER_11__ | Must match __PLACEHOLDER_12__ __PLACEHOLDER_13__ __PLACEHOLDER_33__ __PLACEHOLDER_14__ | __PLACEHOLDER_15__ | Must match __PLACEHOLDER_16__ __PLACEHOLDER_17__ __PLACEHOLDER_34__ __PLACEHOLDER_18__ | __PLACEHOLDER_19__ | Must match __PLACEHOLDER_20__ __PLACEHOLDER_21__ |
 
ストレージ クラス (`ebs-csi-gp2`)、インスタンス数、およびリソース制限は事前に構成されています。予想されるデータ量に合わせて `postgres.storage.size` と `postgres.walStorage.size` を調整します。
 
#### 5.11 `values/cloudnative-pg.yaml` — CloudNativePG オペレーター (`ENABLE_CNPG=true` の場合のみ)
 
環境固有のプレースホルダーは必要ありません。これにより、CNPG オペレーター コントローラーのみが展開されます。デフォルト設定 (3 レプリカ、リソース制限) は、ほとんどの環境に適しています。
 
#### 5.12 `values/odin-services.yaml` — Odin アプリケーション サービス
 
<Warning>
Redis and RabbitMQ endpoints are only available after Terraform creates those AWS resources. Certificate ARNs must be provisioned in ACM before deployment.
</Warning>```bash
nano values/odin-services.yaml
```**一般設定:**
 
| Field | Placeholder | Notes __PLACEHOLDER_42__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | Main web domain __PLACEHOLDER_43__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | Generate: __PLACEHOLDER_4__ |
 
**Supabase (`dataServiceConfig`) — セルフホスト型 (`ENABLE_SUPABASE=true`):**
 
| Field | Placeholder | Source __PLACEHOLDER_44__ __PLACEHOLDER_7__ | __PLACEHOLDER_8__ | Fixed internal Supabase Kong __PLACEHOLDER_45__ __PLACEHOLDER_9__ | __PLACEHOLDER_10__ | Same as __PLACEHOLDER_11__ in __PLACEHOLDER_12__ __PLACEHOLDER_46__ __PLACEHOLDER_13__ | __PLACEHOLDER_14__ | Fixed for self-hosted __PLACEHOLDER_47__ __PLACEHOLDER_15__ | __PLACEHOLDER_16__ | Fixed DB Pool service within the cluster __PLACEHOLDER_48__ __PLACEHOLDER_17__ | __PLACEHOLDER_18__ | Same as __PLACEHOLDER_19__ in __PLACEHOLDER_20__ __PLACEHOLDER_49__ __PLACEHOLDER_21__ | *(leave empty)* | Not used in self-hosted mode |
 
**Supabase (`dataServiceConfig`) — Supabase クラウド (`ENABLE_SUPABASE=false`):**
 
| Field | Placeholder | Source __PLACEHOLDER_50__ __PLACEHOLDER_24__ | __PLACEHOLDER_25__ | Supabase dashboard Project Settings API __PLACEHOLDER_51__ __PLACEHOLDER_26__ | __PLACEHOLDER_27__ | Supabase dashboard API __PLACEHOLDER_28__ key __PLACEHOLDER_52__ __PLACEHOLDER_29__ | __PLACEHOLDER_30__ | Supabase dashboard Project Settings Database __PLACEHOLDER_53__ __PLACEHOLDER_31__ | __PLACEHOLDER_32__ | Supabase dashboard Database (e.g., __PLACEHOLDER_33__) __PLACEHOLDER_54__ __PLACEHOLDER_34__ | __PLACEHOLDER_35__ | Supabase dashboard Project Settings Database __PLACEHOLDER_55__ __PLACEHOLDER_36__ | __PLACEHOLDER_37__ | From your Supabase project URL |
 
**レディス:**
 
| Field | Placeholder | Notes __PLACEHOLDER_56__ __PLACEHOLDER_38__ | __PLACEHOLDER_39__ | After Terraform creates ElastiCache __PLACEHOLDER_57__ __PLACEHOLDER_40__ | __PLACEHOLDER_41__ | ElastiCache primary endpoint |```bash
# Get Redis endpoint after Terraform apply
aws elasticache describe-cache-clusters \
  --show-cache-node-info \
  --query "CacheClusters[?starts_with(CacheClusterId,'<YOUR_ENV_NAME>')].CacheNodes[0].Endpoint.Address" \
  --output text
```**ウサギMQ:**
 
| Field | Placeholder | Notes __PLACEHOLDER_10__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | After Terraform creates AmazonMQ __PLACEHOLDER_11__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__ | AmazonMQ broker endpoint __PLACEHOLDER_12__ __PLACEHOLDER_4__ | __PLACEHOLDER_5__ | Set in __PLACEHOLDER_6__ __PLACEHOLDER_13__ __PLACEHOLDER_7__ | __PLACEHOLDER_8__ | Set in __PLACEHOLDER_9__ |```bash
# Get RabbitMQ endpoint after Terraform apply
aws mq list-brokers \
  --query "BrokerSummaries[?BrokerName=='odin-rabbitmq'].BrokerId" --output text | \
  xargs -I{} aws mq describe-broker --broker-id {} \
  --query "BrokerInstances[0].Endpoints[0]" --output text
```**SSL / 証明書 ARN:**
 
| Field | Placeholder | Notes __PLACEHOLDER_20__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | e.g., __PLACEHOLDER_2__ __PLACEHOLDER_21__ __PLACEHOLDER_3__ | __PLACEHOLDER_4__ | ACM certificate ARN __PLACEHOLDER_22__ __PLACEHOLDER_5__ | __PLACEHOLDER_6__ | e.g., __PLACEHOLDER_7__ __PLACEHOLDER_23__ __PLACEHOLDER_8__ | __PLACEHOLDER_9__ | ACM certificate ARN __PLACEHOLDER_24__ __PLACEHOLDER_10__ | __PLACEHOLDER_11__ | e.g., __PLACEHOLDER_12__ __PLACEHOLDER_25__ __PLACEHOLDER_13__ | __PLACEHOLDER_14__ | ACM certificate ARN __PLACEHOLDER_26__ __PLACEHOLDER_15__ | __PLACEHOLDER_16__ | e.g., __PLACEHOLDER_17__ __PLACEHOLDER_27__ __PLACEHOLDER_18__ | __PLACEHOLDER_19__ | ACM certificate ARN |```bash
# List ACM certificates in your region
aws acm list-certificates --region <YOUR_AWS_REGION> \
  --query "CertificateSummaryList[*].[DomainName,CertificateArn]" --output table
```**Web フロントエンド Supabase キー — 自己ホスト型 (`ENABLE_SUPABASE=true`):**
 
| Field | Placeholder | Source __PLACEHOLDER_29__ __PLACEHOLDER_1__ | __PLACEHOLDER_2__ | External URL routed via ALB ingress __PLACEHOLDER_30__ __PLACEHOLDER_3__ | __PLACEHOLDER_4__ | Same as __PLACEHOLDER_5__ in __PLACEHOLDER_6__ __PLACEHOLDER_31__ __PLACEHOLDER_7__ | __PLACEHOLDER_8__ | Same as __PLACEHOLDER_9__ in __PLACEHOLDER_10__ __PLACEHOLDER_32__ __PLACEHOLDER_11__ | __PLACEHOLDER_12__ | Same as __PLACEHOLDER_13__ in __PLACEHOLDER_14__ |
 
**Web フロントエンド Supabase キー — Supabase クラウド (`ENABLE_SUPABASE=false`):**
 
| Field | Placeholder | Source __PLACEHOLDER_33__ __PLACEHOLDER_16__ | __PLACEHOLDER_17__ | Supabase dashboard Project Settings API __PLACEHOLDER_34__ __PLACEHOLDER_18__ | __PLACEHOLDER_19__ | Supabase dashboard API __PLACEHOLDER_20__ key __PLACEHOLDER_35__ __PLACEHOLDER_21__ | __PLACEHOLDER_22__ | Supabase dashboard API __PLACEHOLDER_23__ key __PLACEHOLDER_36__ __PLACEHOLDER_24__ | __PLACEHOLDER_25__ | Same as __PLACEHOLDER_26__ key |
 
#### 5.13 `values/signoz.yaml` — SigNoz 可観測性 (`ENABLE_SIGNOZ=true` の場合のみ)```bash
nano values/signoz.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_11__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | EKS cluster name __PLACEHOLDER_12__ __PLACEHOLDER_2__ | __PLACEHOLDER_3__, __PLACEHOLDER_4__, __PLACEHOLDER_5__ | ACM certificate for SigNoz __PLACEHOLDER_13__ __PLACEHOLDER_6__ | __PLACEHOLDER_7__ | e.g., __PLACEHOLDER_8__ |
 
#### 5.14 `values/signoz-k8s-infra.yaml` — SigNoz K8s メトリクス (`ENABLE_SIGNOZ=true` の場合のみ)```bash
nano values/signoz-k8s-infra.yaml
```| Field | Placeholder | Notes __PLACEHOLDER_19__ __PLACEHOLDER_0__ | __PLACEHOLDER_1__ | EKS cluster name for metric labeling |
 
OTel コレクター エンドポイント (`signoz-otel-collector.monitoring.svc.cluster.local:4317`) は、SigNoz と k8s-infra の両方が `monitoring` 名前空間にデプロイされていることを前提として事前構成されています。カスタム リリース名を使用しない限り、変更する必要はありません。
 
#### 導入順序のリマインダー
 
一部の値は、特定のインフラストラクチャがデプロイされた後にのみ使用できます。次の順序に従います。
 
1. **展開前** 設定: `<YOUR_ENV_NAME>``<YOUR_AWS_REGION>``<YOUR_AWS_ACCOUNT_ID>``<YOUR_ENVIRONMENT>``<YOUR_PROJECT>``<YOUR_VPC_CIDR>`、すべてのドメイン名、すべての証明書 ARN、すべての Supabase 値、`<YOUR_TOOLKIT_ENCRYPTION_KEY>`、RabbitMQ ユーザー名/パスワード
2. **EKS クラスターの作成後** 設定: `<YOUR_VPC_ID>` (`infrastructure.yaml`)`<YOUR_EKS_CLUSTER_ENDPOINT>` (`karpenter-values.yaml`)
3. **AWS サービスの `terraform apply` の後** 設定: `<YOUR_REDIS_HOST>``<YOUR_RABBITMQ_HOST>` (`odin-services.yaml`)
 
### ステップ 6: プレースホルダーが残っていないことを確認する```bash
grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml"
```予期される出力は空であるか、作成されるリソース (VPC、Redis、MQ、EKS) への参照のみが含まれている必要があります。プレースホルダーが残っている場合は、上記のステップ 5 のサブセクションを参照してください。
 
**ファイルのチェックリスト:**
 
| File | Step | Required __PLACEHOLDER_20__ __PLACEHOLDER_0__ | 5.1 | Always __PLACEHOLDER_21__ __PLACEHOLDER_1__ | 5.2 | Always __PLACEHOLDER_22__ __PLACEHOLDER_2__ | 5.3 | Always __PLACEHOLDER_23__ __PLACEHOLDER_3__ | 5.4 | Always __PLACEHOLDER_24__ __PLACEHOLDER_4__ | 5.5 | Always __PLACEHOLDER_25__ __PLACEHOLDER_5__ | 5.7 | Always __PLACEHOLDER_26__ __PLACEHOLDER_6__ | 5.8 | Always __PLACEHOLDER_27__ __PLACEHOLDER_7__ | 5.6 | Always __PLACEHOLDER_28__ __PLACEHOLDER_8__ | 5.12 | Always __PLACEHOLDER_29__ __PLACEHOLDER_9__ | 5.11 | Only if __PLACEHOLDER_10__ __PLACEHOLDER_30__ __PLACEHOLDER_11__ | 5.10 | Only if __PLACEHOLDER_12__ __PLACEHOLDER_31__ __PLACEHOLDER_13__ | 5.9 | Only if __PLACEHOLDER_14__ __PLACEHOLDER_32__ __PLACEHOLDER_15__ | 5.13 | Only if __PLACEHOLDER_16__ __PLACEHOLDER_33__ __PLACEHOLDER_17__ | 5.14 | Only if __PLACEHOLDER_18__ |
 
---
 
## フェーズ 1: 状態管理のセットアップ
 
**目的:** Terraform 状態の S3 バケットの作成。
 
各環境の状態管理モジュールは、パターン `odin-terraform-state-{environment-name}`  S3 バケットを作成し、暗号化、バージョン管理、パブリック アクセス ブロックを設定し、状態モジュール自体 (ブートストラップ パターン) にローカル状態を使用します。```bash
cd terragrunt/environments/{your-env-name}/state
terragrunt init
terragrunt plan
terragrunt apply
```---
 
## フェーズ 2: EKS インフラストラクチャの導入
 
**目的:** コア ネットワーキング (VPC、サブネット、NAT ゲートウェイ)、IAM ロールとポリシー、EKS クラスターおよび管理対象ノード グループ。
 
### 2.1 ドライラン — EKS インフラストラクチャ
 
**コアインフラストラクチャ**```bash
cd terragrunt/environments/your-env-name
terragrunt plan -target="aws_vpc.main" \
  -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" \
  -target="aws_subnet.private" \
  -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" \
  -target="aws_route_table.public" \
  -target="aws_route_table.private" \
  -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private"
```**IAM の役割とポリシー**```bash
terragrunt plan -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" \
  -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly"
```**EKS クラスターとノード グループ**```bash
terragrunt plan -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"
```#### カスタム/プライベート Docker レジストリの使用
 
デフォルトでは、EKB イメージは `regcred` という名前のシークレットを使用して Docker Hub からプルされます。顧客が別のレジストリでイメージをホストしている場合は、`odin-services` を展開する前に次の手順に従ってください。
 
**ステップ 1 — ターゲット名前空間に `imagePullSecret` を作成します**```bash
# Generic private registry (Docker Hub, Quay, self-hosted, etc.)
kubectl create secret docker-registry regcred \
  --namespace default \
  --docker-server=<YOUR_REGISTRY_HOST> \
  --docker-username=<YOUR_REGISTRY_USERNAME> \
  --docker-password=<YOUR_REGISTRY_PASSWORD> \
  --docker-email=<YOUR_EMAIL>
 
# AWS ECR — token expires every 12h; refresh via a CronJob or use ECR pull-through cache
aws ecr get-login-password --region <YOUR_AWS_REGION> | \
  kubectl create secret docker-registry regcred \
    --namespace default \
    --docker-server=<YOUR_AWS_ACCOUNT_ID>.dkr.ecr.<YOUR_AWS_REGION>.amazonaws.com \
    --docker-username=AWS \
    --docker-password-stdin
```**ステップ 2 — `values/odin-services.yaml`** にシークレット名を設定します```yaml
# values/odin-services.yaml
imagePullSecrets:
  - name: regcred          # must match the secret name created above
  # - name: customer-registry-secret  # add additional registries if needed
```**ステップ 3 — 画像参照を更新します**```yaml
web:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG>
 
fastapiBackend:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/server:<TAG>
```**ステップ 4 — 完全な展開の前にプル アクセスを確認する**```bash
kubectl run registry-test \
  --image=<YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG> \
  --overrides='{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}' \
  --restart=Never --rm -it -- echo "Pull successful"
```### 2.2 EKS インフラストラクチャのデプロイ
 
**ステップ 1: コア インフラストラクチャ**```bash
cd terragrunt/environments/your-env-name
terragrunt apply -target="aws_vpc.main" \
  -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" \
  -target="aws_subnet.private" \
  -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" \
  -target="aws_route_table.public" \
  -target="aws_route_table.private" \
  -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private"
```<Warning>
After this step, update __PLACEHOLDER_0__ in __PLACEHOLDER_1__ before deploying the AWS Load Balancer Controller.
</Warning>
 
**ステップ 2: EKS クラスターと IAM のロールとポリシー**```bash
terragrunt apply -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" \
  -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly"
```**ステップ 3: ノード グループとアドオン**```bash
terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"
```<Warning>
After this step, update __PLACEHOLDER_0__ in __PLACEHOLDER_1__ before deploying Karpenter.
</Warning>
 
**EKS クラスターの接続を確認してください**```bash
aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER_NAME
 
kubectl cluster-info
kubectl get nodes
kubectl get secret regcred -n default
```---
 
## フェーズ 3: ストレージとロード バランシング
 
**目的:** 永続ボリューム用の EBS CSI ドライバー、管理対象ノード グループで実行される AWS ロード バランサー コントローラー。
 
### 3.1 ドライラン — ストレージとロードバランシング
 
**EBS CSI ドライバー**```bash
cd terragrunt/environments/your-env-name
terragrunt plan -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver"
```**AWS ロード バランサー コントローラー**```bash
terragrunt plan -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure"
```### 3.2 ストレージと負荷分散の導入
 
**ステップ 1: EBS CSI ドライバー**```bash
cd terragrunt/environments/your-env-name
terragrunt apply -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver"
```**検証**```bash
helm list -n kube-system | grep ebs
kubectl get pods -n kube-system | grep ebs-csi
kubectl get storageclass
aws iam get-role --role-name $CLUSTER_NAME-ebs-csi-driver-role --region $AWS_REGION
kubectl get sa -n kube-system | grep ebs-csi
kubectl describe sa ebs-csi-controller-sa -n kube-system
```**ステップ 2: AWS ロード バランサー コントローラー**```bash
terragrunt apply -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure"
```**検証**```bash
helm list -n infrastructure
kubectl get pods -n infrastructure | grep aws-load-balancer-controller
kubectl get sa -n infrastructure
kubectl describe sa aws-load-balancer-controller -n infrastructure
aws iam get-role --role-name $CLUSTER_NAME-aws-load-balancer-controller --region $AWS_REGION
kubectl logs -n infrastructure -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl get ingressclass
```---
 
## フェーズ 4: Karpenter の自動スケーリング
 
**目的:** Karpenter、スポット中断処理、Karpenter コントローラー、およびノード プールの IAM ロール。
 
### 4.1 予行演習 — Karpenter
 
**Karpenter IAM リソース**```bash
cd terragrunt/environments/your-env-name
terragrunt plan -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node"
```**EC2 スポット サービスにリンクされたロール (スポット インスタンスが有効な場合)**```bash
terragrunt plan -target="aws_iam_service_linked_role.ec2_spot[0]"
```**Karpenter スポット中断 (`terragrunt.hcl` で有効な場合)**```bash
terragrunt plan -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption"
```**カーペンター ヘルム チャート**```bash
terragrunt plan -target="helm_release.karpenter"
```**Karpenter ノードプールと EC2NodeClasses**```bash
terragrunt plan -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target="kubernetes_config_map.aws_auth"
```<Info>
An expected error may appear during plan: __PLACEHOLDER_0__. This is safe to ignore — Kubernetes validates resources against the live API at plan time, before CRDs are installed.
</Info>
 
### 4.2 Karpenter のデプロイ
 
**ステップ 1: Karpenter IAM リソース**```bash
cd terragrunt/environments/your-env-name
terragrunt apply -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node"
```**検証**```bash
aws iam get-role --role-name $CLUSTER_NAME-karpenter-controller --region $AWS_REGION
aws iam get-role --role-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
aws iam get-instance-profile --instance-profile-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
aws iam list-attached-role-policies --role-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
```**ステップ 2: EC2 スポット サービスにリンクされたロール (スポット インスタンスが有効な場合)**
 
<Warning>
The EC2 Spot service-linked role is account-wide (only one per AWS account) and must exist before Karpenter can launch Spot instances.
</Warning>
 
**オプション A: Terraform に作成させる (新規デプロイメントに推奨)**```bash
terragrunt apply -target="aws_iam_service_linked_role.ec2_spot[0]"
```**オプション B: ロールが既に存在する場合はインポートします**```bash
# Check if the role exists
aws iam get-role --role-name AWSServiceRoleForEC2Spot --region $AWS_REGION
 
# If it doesn't exist, create it manually
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com --region $AWS_REGION
 
# Import into Terraform (replace ACCOUNT_ID with your 12-digit AWS account ID)
terragrunt import 'aws_iam_service_linked_role.ec2_spot[0]' \
  arn:aws:iam::ACCOUNT_ID:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot
```<詳細>
<summary>スポット インスタンス作成の問題のトラブルシューティング</summary>
 
**Karpenter ログでスポット関連のエラーを確認してください:**```bash
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter -f | grep -i spot
```一般的なエラー: `AuthFailure.ServiceLinkedRoleCreationNotPermitted``UnfulfillableCapacity``InsufficientInstanceCapacity`
 
**サービスにリンクされたロールが存在することを確認します:**```bash
aws iam get-role --role-name AWSServiceRoleForEC2Spot --region $AWS_REGION
```**IAM ポリシーにスポット権限が含まれていることを確認してください:**```bash
aws iam get-policy-version \
  --policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`YOUR_CLUSTER_NAME-karpenter-controller`].Arn' --output text) \
  --version-id $(aws iam get-policy --policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`YOUR_CLUSTER_NAME-karpenter-controller`].Arn' --output text) --query 'Policy.DefaultVersionId' --output text) \
  --region $AWS_REGION | grep -i "CreateServiceLinkedRole"
```**スポット インスタンスの可用性を確認します:**```bash
aws ec2 describe-spot-price-history \
  --instance-types r6a.4xlarge r6a.large \
  --product-descriptions "Linux/UNIX" \
  --region $AWS_REGION \
  --max-items 10
```**ノードプールの容量タイプを確認してください:**```bash
kubectl get nodepool -o yaml | grep -A 5 "capacity-type"
```**スポット ノードとオンデマンド ノードを確認します:**```bash
kubectl get nodes -o json | jq -r '.items[] | "\(.metadata.name)\t\(.metadata.labels."karpenter.sh/capacity-type")\t\(.metadata.labels."node.kubernetes.io/instance-type")"'
```</詳細>
 
**ステップ 3: Karpenter スポット中断 (`terragrunt.hcl` で有効な場合)**```bash
terragrunt apply -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption"
```**検証**```bash
aws events describe-rule --name $CLUSTER_NAME-karpenter-interruption --region $AWS_REGION
aws events list-targets-by-rule --rule $CLUSTER_NAME-karpenter-interruption --region $AWS_REGION
aws sqs get-queue-url --queue-name $CLUSTER_NAME-karpenter-interruption-queue --region $AWS_REGION
```**ステップ 4: Karpenter Helm チャート**```bash
terragrunt apply -target="helm_release.karpenter"
```**検証**```bash
helm list -n kube-system | grep karpenter
kubectl get pods -n kube-system | grep karpenter
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
kubectl describe sa karpenter -n kube-system
```**ステップ 5: Karpenter Kubernetes マニフェスト**```bash
terragrunt apply -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass"
 
# Import the existing aws-auth ConfigMap
# Note: Use quotes to prevent zsh from interpreting brackets as glob patterns
terragrunt import 'kubernetes_config_map.aws_auth[0]' kube-system/aws-auth
 
# Then apply
terragrunt apply -target='kubernetes_config_map.aws_auth[0]'
```**検証**```bash
kubectl get nodepools -o wide
kubectl describe nodepool general
kubectl describe nodepool application
kubectl describe nodepool database
kubectl get ec2nodeclasses -o wide
kubectl get configmap aws-auth -n kube-system -o jsonpath='{.data.mapRoles}' | grep karpenter-node
kubectl get nodepools -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
kubectl get nodes -l karpenter.sh/nodepool --show-labels
kubectl get events -n kube-system --field-selector involvedObject.name=karpenter --sort-by='.lastTimestamp'
```---
 
## フェーズ 5: KEDA 自動スケーリング
 
**目的:** アプリケーションレベルの自動スケーリング用の KEDA。
 
### 5.1 予行演習 — KEDA```bash
cd terragrunt/environments/your-env-name
terragrunt plan -target="helm_release.keda"
```### 5.2 KEDA のデプロイ```bash
cd terragrunt/environments/your-env-name
terragrunt apply -target="helm_release.keda"
```**検証**```bash
helm list -n keda
kubectl get pods -n keda
kubectl get deployment -n keda
kubectl get crd | grep keda
kubectl get validatingwebhookconfigurations | grep keda
kubectl get svc -n keda
```---
 
## フェーズ 6: データ サービス
 
**目的:** Supabase (データベース)、ElastiCache (Redis)、RabbitMQ (メッセージ キュー)。
 
<Info>
Deploy CloudNativePG operator first, then the HA Supabase DB cluster, then the Supabase application. The DB cluster must be ready before Supabase starts.
</Info>
 
### 6.1 ドライラン - データサービス
 
**ステップ 1: CloudNativePG オペレーター (有効な場合)**```bash
cd terragrunt/environments/your-env-name
ENABLE_CNPG=true terragrunt plan \
  --target='helm_release.additional_charts["cloudnative-pg"]'
```**ステップ 2: HA Supabase DB (有効な場合)**```bash
ENABLE_HA_SUPABASE_DB=true terragrunt plan \
  --target='helm_release.additional_charts["ha-supabase-db"]'
```**ステップ 3: Supabase アプリケーション (有効な場合)**```bash
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt plan \
    --target='helm_release.supabase[0]'
fi
```**ステップ 4: AWS サービス — ElastiCache と RabbitMQ (有効な場合)**```bash
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt plan -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq"
fi
```### 6.2 Deploy Data Services
 
**ステップ 1: CloudNativePG オペレーター (有効な場合)**```bash
cd terragrunt/environments/your-env-name
ENABLE_CNPG=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["cloudnative-pg"]'
```**ステップ 2: HA Supabase DB (有効な場合)**```bash
ENABLE_HA_SUPABASE_DB=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["ha-supabase-db"]'
```**展開後に PgBouncer プーラーと認証情報を確認します:**```bash
kubectl get svc -n ha-supabase-db | grep pooler
kubectl get secrets -n ha-supabase-db
kubectl get secret ha-supabase-db-authenticator-credentials -n ha-supabase-db \
  -o jsonpath='{.data.username}' | base64 -d && echo ""
```プーラー ClusterIP (LoadBalancer の場合は `EXTERNAL-IP`) を、`values/odin-services.yaml` の `SUPABASE_POSTGRES_HOST` 値として、および `values/supabase.yaml` の `secret.db.postgresHost` として使用します。
 
**ステップ 3: Supabase アプリケーション (有効な場合)**
 
すべての Supabase サービス ポッドは、スポットの中断を防ぐために、Karpenter `application` ノードプール (オンデマンドのみ) 上で排他的に実行されます。```bash
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --auto-approve \
    --target='helm_release.supabase[0]'
fi
```**ステップ 4: AWS サービス — ElastiCache と RabbitMQ (有効な場合)**```bash
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt apply \
    -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq"
fi
```**検証**```bash
# Get connection details from Terraform outputs
terragrunt output elasticache_endpoint
terragrunt output elasticache_port
terragrunt output rabbitmq_endpoint
terragrunt output rabbitmq_port
 
# Test Redis connectivity from EKS cluster
kubectl run redis-test --image=redis:7-alpine --restart=Never -- \
  sh -c "redis-cli -h <redis-endpoint> -p 6379 --tls --insecure ping && echo 'Redis connection successful'"
kubectl logs redis-test
kubectl delete pod redis-test
 
# Check Redis encryption status
aws elasticache describe-replication-groups \
  --replication-group-id $CLUSTER_NAME-redis \
  --region $AWS_REGION \
  --query 'ReplicationGroups[0].{AtRestEncryption:AtRestEncryptionEnabled,TransitEncryption:TransitEncryptionEnabled}'
```<Warning>
Before deploying Odin Services, update __PLACEHOLDER_0__ with the Redis endpoint, RabbitMQ endpoint, and all certificate ARNs obtained in this phase.
</Warning>
 
---
 
## フェーズ 7: Odin サービス
 
**目的:** Helm を介したアプリケーションのデプロイメント。
 
<Info>
Before deploying, temporarily scale down __PLACEHOLDER_1__ to a single replica for the initial database migration run — set __PLACEHOLDER_2__, __PLACEHOLDER_3__, and __PLACEHOLDER_4__. Once the migration completes successfully, revert these values to their production defaults before re-deploying.
</Info>
 
### 7.1 ドライラン — Odin サービス```bash
cd terragrunt/environments/your-env-name
terragrunt plan -target="helm_release.odin_services"
```### 7.2 Odin サービスのデプロイ```bash
cd terragrunt/environments/your-env-name
terragrunt apply -target="helm_release.odin_services"
```**検証**```bash
kubectl get pods
kubectl get ingress  # Add the ALB endpoints to your DNS provider
```---
 
## フェーズ 8: SigNoz の可観測性
 
**目的:** ログとメトリクスの監視。
 
### 8.1 予行演習 — SigNoz チャート```bash
cd terragrunt/environments/your-env-name
terragrunt plan -target='helm_release.additional_charts["signoz"]'
terragrunt plan -target='helm_release.additional_charts["k8s-infra"]'
```### 8.2 SigNoz チャートの展開```bash
cd terragrunt/environments/your-env-name
terragrunt apply -target='helm_release.additional_charts["signoz"]'
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]'
```**検証**```bash
kubectl get pods -n monitoring
kubectl get ingress -n monitoring  # Add the ALB endpoints to your DNS provider
```---
 
## フェーズ 9: 最終展開
 
### 9.1 導入の完了```bash
cd terragrunt/environments/your-env-name
terragrunt apply
```この最後の適用では、前のフェーズで明示的にターゲットにされていない残りのリソースが処理されます。
 
### 9.2 デプロイメントの検証```bash
# Update kubeconfig
aws eks update-kubeconfig --region us-east-2 --name your-env-name
 
# Check cluster status
kubectl get nodes
kubectl get pods --all-namespaces
 
# Check Karpenter
kubectl get pods -n kube-system -l app.kubernetes.io/name=karpenter
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
 
# Check AWS Load Balancer Controller
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
 
# Check KEDA
kubectl get pods -n keda
 
# Check Odin Services
kubectl get pods -n default
kubectl get services -n default
kubectl get ingress -n default
 
# Check all Helm releases
helm list --all-namespaces
```---
 
## トラブルシューティング
 
**状態ロックの問題**```bash
terragrunt force-unlock <lock-id>
```**大工は仕事をしていません**```bash
kubectl describe nodes
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
```**ロード バランサーの問題**```bash
kubectl describe ingress -n default
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
```**ヘルム チャートの問題**```bash
helm status <release-name> -n <namespace>
helm rollback <release-name> <revision> -n <namespace>
```- -
 
## 掃除```bash
# Destroy infrastructure
cd terragrunt/environments/your-env-name
terragrunt destroy -auto-approve
 
# Destroy state bucket (use with caution)
cd terragrunt/environments/your-env-name/state
terragrunt destroy -auto-approve
```---
 
## 監視とロギング```bash
# AWS Resources
aws eks describe-cluster --name your-env-name --region us-east-2
aws ec2 describe-instances --filters "Name=tag:kubernetes.io/cluster/your-env-name,Values=owned"
 
# Kubernetes Resources
kubectl top nodes
kubectl top pods --all-namespaces
kubectl get events --sort-by=.metadata.creationTimestamp
```---
 
## クイック リファレンス — すべての展開コマンド```bash
# Phase 1: State Management
cd terragrunt/environments/your-env-name/state
terragrunt apply
 
# Phase 2: EKS Infrastructure
cd terragrunt/environments/your-env-name
 
terragrunt apply -target="aws_vpc.main" -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" -target="aws_subnet.private" -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" -target="aws_route_table.public" \
  -target="aws_route_table.private" -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private" -auto-approve
 
terragrunt apply -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly" \
  -auto-approve
 
terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" -target="kubernetes_secret.regcred" -auto-approve
 
# Phase 3: Storage and Load Balancing
terragrunt apply -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver" -auto-approve
 
terragrunt apply -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure" -auto-approve
 
# Phase 4: Karpenter Autoscaling
terragrunt apply -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node" -auto-approve
 
# Spot interruption handling (if spot_interruption_handling = true)
terragrunt apply -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption" -auto-approve
 
terragrunt apply -target="helm_release.karpenter" -auto-approve
 
terragrunt apply -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target='kubernetes_config_map.aws_auth[0]' -auto-approve
 
# Phase 5: KEDA Autoscaling
terragrunt apply -target="helm_release.keda" -auto-approve
 
# Phase 6: Data Services
ENABLE_CNPG=true terragrunt apply --target='helm_release.additional_charts["cloudnative-pg"]' -auto-approve
ENABLE_HA_SUPABASE_DB=true terragrunt apply --target='helm_release.additional_charts["ha-supabase-db"]' -auto-approve
 
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --target='helm_release.supabase[0]' -auto-approve
fi
 
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt apply -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq" -auto-approve
fi
 
# Phase 7: Odin Services
terragrunt apply -target="helm_release.odin_services" -auto-approve
 
# Phase 8: SigNoz (if enabled)
terragrunt apply -target='helm_release.additional_charts["signoz"]' -auto-approve
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]' -auto-approve
 
# Phase 9: Final Deployment
terragrunt apply -auto-approve
```<Info>
Replace __PLACEHOLDER_0__ with your actual environment name throughout. Always run dry runs (__PLACEHOLDER_1__) first to validate your configuration before applying changes.
</Info>