Passer au contenu principal
Ce guide décrit le déploiement complet de l’infrastructure EKB EKS sur AWS à l’aide de Terragrunt. Il couvre l’installation des outils, la configuration de l’environnement et une séquence de déploiement par phases conçue pour garantir un ordre de dépendance correct entre tous les composants d’infrastructure. Les déploiements sont organisés en neuf phases :
  1. Gestion de l’état — Prépare le compartiment S3 utilisé pour stocker l’état Terraform de l’environnement.
  2. Infrastructure EKS — Provisionne le VPC, les sous-réseaux, les passerelles NAT, les rôles IAM et le cluster EKS avec les groupes de nœuds gérés.
  3. Stockage et équilibrage de charge — Déploie le pilote EBS CSI pour les volumes persistants et le contrôleur de équilibrage de charge AWS pour l’entrée ALB.
  4. Mise à l’échelle Karpenter — Configure le provisionnement dynamique des nœuds avec support des instances Spot et gestion des interruptions via SQS et EventBridge.
  5. Mise à l’échelle KEDA — Déploie KEDA pour la mise à l’échelle au niveau des pods basée sur les seuils CPU et mémoire.
  6. Services de données — Provisionne Supabase (auto-hébergé ou Cloud), ElastiCache Redis et Amazon MQ RabbitMQ.
  7. Services Odin — Déploie la pile d’application EKB (Web, FastAPI, Celery, Automator) via Helm.
  8. Observabilité SigNoz — Déploie la traçabilité distribuée, les métriques et l’agrégation des journaux via SigNoz et l’agent k8s-infra.
  9. Déploiement final — Exécute un terragrunt apply complet pour réconcilier les ressources restantes.
Avant de commencer, complétez la liste de prérequis avec le client et assurez-vous que tous les espaces réservés <YOUR_*> dans le modèle d’environnement sont remplis. Certaines valeurs — notamment l’ID VPC, le point de terminaison du cluster EKS et les points de terminaison Redis et RabbitMQ — ne sont disponibles qu’après l’achèvement de certaines phases, c’est pourquoi le guide indique exactement quand les capturer et les appliquer.

Prérequis

  • AWS CLI configuré avec les permissions appropriées
  • Terraform (>= 1.0)
  • Terragrunt (dernière version)
  • kubectl pour la gestion Kubernetes
  • helm pour la gestion des graphiques Helm

Guide d’installation

Installation de Terragrunt

macOS (Homebrew)
brew install terragrunt
Linux (apt)
# 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 (Chocolatey)
choco install terragrunt

Installation de kubectl

macOS (Homebrew)
brew install kubectl
Linux
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 (Chocolatey)
choco install kubernetes-cli

Installation de Helm

macOS (Homebrew)
brew install helm
Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Windows (Chocolatey)
choco install kubernetes-helm

Vérification de l’installation

terragrunt --version
terraform --version
kubectl version --client
helm version

Configuration de l’AWS CLI

# 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

Créer un nouvel environnement

Étape 1 : Copier le modèle d’environnement

Le dossier env-template-folder contient des fichiers pré-structurés avec des espaces réservés <YOUR_*> prêts à être remplis. Copiez-le entièrement pour créer votre nouveau dossier d’environnement.
# 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)

Étape 2 : Vérifier que tous les espaces réservés sont présents

cd your-env-name

# List all placeholders that need to be filled in
grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml" | sort
Tous les espaces réservés suivent la convention <YOUR_*>. Les étapes suivantes guident leur remplissage fichier par fichier.

Étape 3 : Provisionner les certificats SSL (AWS ACM)

Avant de définir les variables d’environnement, vous avez besoin des ARN des certificats. Utilisez la console AWS pour demander des certificats SSL dans AWS Certificate Manager (ACM) pour tous les domaines que votre environnement desservira. Option A : Un seul certificat wildcard (recommandé) Un seul certificat wildcard couvre tous les sous-domaines avec un ARN. Par exemple, si votre domaine de base est app.example.com, un seul certificat *.app.example.com couvre :
ServiceDomaine
Webapp.example.com
FastAPIapi-app.example.com
Automatorautomations-app.example.com
Supabasesupabase-app.example.com
SigNozsignoz-app.example.com
Option B : Certificats par service Demandez un certificat par domaine si vous ne pouvez pas utiliser de wildcard. Répétez les étapes ci-dessous pour chaque domaine : <YOUR_WEB_DOMAIN>, <YOUR_API_DOMAIN>, <YOUR_AUTOMATOR_DOMAIN>, <YOUR_SUPABASE_DOMAIN> (uniquement si ENABLE_SUPABASE=true), <YOUR_SIGNOZ_DOMAIN> (uniquement si ENABLE_SIGNOZ=true). Demander un certificat dans la console AWS
  1. Ouvrez la console AWS Certificate Manager
  2. Passez à la bonne région (en haut à droite) — elle doit correspondre à <YOUR_AWS_REGION>
  3. Cliquez sur Demander un certificatDemander un certificat publicSuivant
  4. Sous Nom de domaine pleinement qualifié, saisissez le wildcard (par ex. *.app.example.com) ou un domaine spécifique
  5. Définissez la Méthode de validation sur Validation DNS
  6. Cliquez sur Demander — le certificat est créé dans l’état En attente de validation
Ajouter l’enregistrement CNAME DNS de validation ACM génère un enregistrement CNAME que vous devez ajouter à votre fournisseur DNS pour prouver la propriété du domaine. Obtenez les valeurs depuis la console ACM en ouvrant le certificat et en développant le domaine sous Domaines.
Champ DNSValeur
Type d’enregistrementCNAME
Nom / Hôtepar ex. _fa187f22ac17bce6f508bf3c56439c61.signoz-app.example.com.
Valeur / Pointe verspar ex. _c7c97325fe38061e168e232d122c7ff3.jkddzztszm.acm-validations.aws.
Incluez le point final (.) à la fin des valeurs CNAME si votre fournisseur DNS l’exige.
Cloudflare
  1. Connectez-vous à Cloudflare → sélectionnez votre domaine → accédez à DNSEnregistrementsAjouter un enregistrement
  2. Définissez le Type sur CNAME
  3. Collez le nom CNAME d’ACM dans Nom et la valeur CNAME d’ACM dans Cible
  4. Définissez l’État du proxy sur DNS uniquement (icône nuage gris) — le certificat ne sera pas validé via le proxy Cloudflare
  5. Cliquez sur Enregistrer
Route 53
  1. Ouvrez la console Route 53 → Zones hébergées → sélectionnez votre zone → Créer un enregistrement
  2. Définissez le Type d’enregistrement sur CNAME
  3. Collez le nom CNAME d’ACM dans Nom de l’enregistrement (partie sous-domaine uniquement) et la valeur dans Valeur
  4. Définissez le TTL sur 300 et cliquez sur Créer les enregistrements
Dans ACM, vous pouvez également cliquer sur Créer des enregistrements dans Route 53 pour qu’ACM ajoute l’enregistrement automatiquement si la zone hébergée se trouve dans le même compte.
Une fois la propagation DNS effectuée (généralement 1 à 5 minutes), le statut du certificat passe à Émis. Copiez l’ARN depuis le haut du certificat — il ressemble à arn:aws:acm:<region>:<account-id>:certificate/<uuid>. Conservez le(s) ARN pour l’étape suivante.

Étape 4 : Définir les variables d’environnement

Définissez ces variables d’environnement shell avant d’exécuter les commandes Terragrunt. Elles sont lues directement par terragrunt.hcl via get_env().
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"

Instances Spot et charges de travail persistantes

Les instances Spot sont configurées par NodePool dans values/karpenter.yaml, pas via les variables d’environnement. Chaque NodePool déclare sa propre stratégie de capacité :
NodePoolLibellé workload-typeType de capacitéJustification
generalgeneralSpot → On-Demand de repliOptimisé pour les charges de travail batch/arrière-plan sans état
compute-intensivecompute-intensiveSpot → On-Demand de repliOptimisé pour les charges de travail CPU-bound
memory-intensivememory-intensiveOn-Demand → Spot de repliStabilité prioritaire pour les pods à haute mémoire
gpugpuSpot → On-Demand de repliOptimisé pour les charges de travail batch IA/ML
applicationapplicationOn-Demand uniquementServices stables面向utilisateur (Supabase, Kong, etc.) — pas d’interruptions Spot
databasedatabase / node-type: database-dedicatedOn-Demand uniquementPersistant — l’interruption Spot est dangereuse pour les bases de données
Le NodePool application utilise les familles d’instances m/c (génération 5+) avec On-Demand uniquement. Les pods de service Supabase sont épinglés ici via nodeSelector: workload-type: "application" pour garantir qu’ils ne sont jamais interrompus par un événement de récupération Spot. Le NodePool database-dedicated n’utilise jamais Spot. Il utilise consolidationPolicy: WhenEmpty afin que Karpenter n’évince pas un nœud qui a encore un pod en cours d’exécution, ce qui le rend sûr pour les charges de travail persistantes telles que PostgreSQL et les réplicas CloudNativePG. Directives pour les charges de travail persistantes sur Spot :
  • N’exécutez pas de bases de données, de files d’attente persistantes ou de pod avec un PersistentVolumeClaim sur les NodePools Spot.
  • Utilisez un nodeSelector ciblant node-type: database-dedicated avec la tolérance correspondante database-workload: "true" pour les pods de base de données.
  • Utilisez nodeSelector: workload-type: "application" pour les services sans état面向utilisateur qui doivent rester disponibles sans interruption.
  • Pour les charges de travail en arrière-plan (Web, API, Celery, Automator), le NodePool Spot general est approprié — le gestionnaire d’interruptions SQS de Karpenter évacue gracieusement les nœuds Spot avant qu’AWS ne les récupère, et le nombre minimum de réplicas KEDA (≥ 2) garantit la disponibilité pendant le remplacement des nœuds.
  • Pour désactiver Spot globalement, supprimez "spot" de la liste des valeurs dans chaque NodePool dans values/karpenter.yaml.
Comment Karpenter gère les avertissements d’interruption Spot : AWS donne un préavis d’interruption de 2 minutes avant de résilier une instance Spot. Karpenter utilise EventBridge et SQS pour agir automatiquement :
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
Ceci est configuré dans le bloc karpenter de terragrunt.hcl :
karpenter = {
  spot_interruption_handling = true   # creates the SQS queue and EventBridge rule
  enable_spot_instances       = true   # allows Spot in NodePool capacity requirements
}

Étape 5 : Mettre à jour les valeurs spécifiques à l’environnement

Effectuez un rechercher-remplacer dans tous les fichiers de votre nouveau dossier d’environnement pour les espaces réservés suivants :
Espace réservéDescriptionExemple
<YOUR_ENV_NAME>Identifiant unique de l’environnementapp-eks-prod
<YOUR_AWS_REGION>Région AWS du clustereu-west-2, us-east-2
<YOUR_AWS_ACCOUNT_ID>ID de compte AWS à 12 chiffres123456789012
<YOUR_ENVIRONMENT>Valeur du tag d’environnementprod, staging, dev
<YOUR_PROJECT>Valeur du tag projetodin, ekb
# Run from your new env folder to find all remaining placeholders
grep -r "<YOUR_" .

5.1 terragrunt.hcl — Configuration principale du cluster

nano terragrunt.hcl
ChampEspace réservéNotes
cluster_name<YOUR_ENV_NAME>Doit correspondre au nom du cluster EKS
cluster_region<YOUR_AWS_REGION>Région AWS
aws_account_id<YOUR_AWS_ACCOUNT_ID>ID de compte à 12 chiffres
vpc_cidr<YOUR_VPC_CIDR>par ex. 192.168.0.0/16
availability_zones<YOUR_REGION>a/b/c3 AZ dans votre région
tags.Environment<YOUR_ENVIRONMENT>par ex. prod
tags.Project<YOUR_PROJECT>par ex. odin
aws_services.amazon_mq.rabbitmq.username<YOUR_RABBITMQ_USERNAME>Nom d’utilisateur admin RabbitMQ (uniquement quand ENABLE_AWS_SERVICES=true)
aws_services.amazon_mq.rabbitmq.password<YOUR_RABBITMQ_PASSWORD>Min 12 caractères ; doit inclure des majuscules, des minuscules, des chiffres et des caractères spéciaux

5.2 state/terragrunt.hcl — Compartiment d’état S3

nano state/terragrunt.hcl
ChampEspace réservéNotes
bucket_nameodin-terraform-state-<YOUR_ENV_NAME>Doit être unique à l’échelle mondiale
region<YOUR_AWS_REGION>Même région que le cluster

5.3 values/infrastructure.yaml — Contrôleur de équilibrage de charge AWS

Obtenez l’ID VPC après la création du cluster EKS avant de déployer le contrôleur de équilibrage de charge AWS.
# 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
ChampEspace réservéNotes
clusterName<YOUR_ENV_NAME>Nom du cluster EKS
region<YOUR_AWS_REGION>Région AWS
vpcId<YOUR_VPC_ID>Requis avant le déploiement ALB
serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Rôle IAM pour le contrôleur ALB

5.4 values/karpenter-values.yaml — Contrôleur Karpenter

Obtenez le point de terminaison du cluster EKS après la création du cluster EKS et avant de déployer Karpenter.
# 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
ChampEspace réservéNotes
serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Rôle IAM pour Karpenter
env.CLUSTER_NAME<YOUR_ENV_NAME>Nom du cluster EKS
env.CLUSTER_ENDPOINT<YOUR_EKS_CLUSTER_ENDPOINT>Requis avant le déploiement Karpenter
settings.aws.defaultInstanceProfile<YOUR_ENV_NAME>Profil d’instance nœud Karpenter

5.5 values/karpenter-nodeclasses.yaml — Classes de nœuds Karpenter

nano values/karpenter-nodeclasses.yaml
ChampEspace réservéNotes
Toutes les balises kubernetes.io/cluster/<YOUR_ENV_NAME><YOUR_ENV_NAME>Balise cluster pour les sélecteurs subnet/SG
user_data nom de cluster d’amorçage<YOUR_ENV_NAME>Script d’amorçage du nœud
tags.Environment<YOUR_ENVIRONMENT>par ex. prod
tags.Project<YOUR_PROJECT>par ex. odin

5.6 values/aws-ebs-csi-driver.yaml — Pilote EBS CSI

nano values/aws-ebs-csi-driver.yaml
ChampEspace réservéNotes
controller.serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Rôle IAM pour le contrôleur EBS CSI
node.serviceAccount.annotations.eks.amazonaws.com/role-arn<YOUR_AWS_ACCOUNT_ID>, <YOUR_ENV_NAME>Rôle IAM pour le nœud EBS CSI
controller.env.AWS_DEFAULT_REGION<YOUR_AWS_REGION>Région AWS
controller.env.AWS_REGION<YOUR_AWS_REGION>Région AWS
node.env.AWS_DEFAULT_REGION<YOUR_AWS_REGION>Région AWS
node.env.AWS_REGION<YOUR_AWS_REGION>Région AWS

5.7 values/karpenter.yaml — NodePools Karpenter

nano values/karpenter.yaml
ChampEspace réservéNotes
*.labels.Environment<YOUR_ENVIRONMENT>Appliqué à toutes les balises de NodePool
*.requirements topology.kubernetes.io/zone["<YOUR_REGION>a", "<YOUR_REGION>b", "<YOUR_REGION>c"]AZ pour tous les NodePools
Les noms de classes de nœuds (general, compute-intensive, memory-intensive, gpu, database) doivent correspondre aux entrées de karpenter-nodeclasses.yaml.

5.8 values/keda.yaml — Mise à l’échelle KEDA

Aucun espace réservé spécifique à l’environnement requis. Les limites de ressources et les nombres de réplicas sont préconfigurés avec des valeurs par défaut raisonnables. Examinez et ajustez si nécessaire.

5.9 values/supabase.yaml — Application Supabase (uniquement si ENABLE_SUPABASE=true)

Toutes les clés ci-dessous doivent être générées de manière cohérente et partagées avec ha-supabase-db.yaml. Générez-les une seule fois et utilisez les mêmes valeurs dans les deux fichiers.
# 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
ChampEspace réservéNotes
secret.jwt.anonKey<YOUR_SUPABASE_ANON_KEY>Doit correspondre à anonKey de ha-supabase-db.yaml
secret.jwt.serviceKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Doit correspondre à serviceRoleKey de ha-supabase-db.yaml
secret.jwt.secret<YOUR_SUPABASE_JWT_SECRET>Doit correspondre à jwtSecret de ha-supabase-db.yaml
secret.db.password<YOUR_SUPABASE_DB_PASSWORD>Doit correspondre à postgresPassword de ha-supabase-db.yaml
secret.analytics.publicAccessToken<YOUR_SUPABASE_ANALYTICS_PUBLIC_TOKEN>Token interne Logflare
secret.analytics.privateAccessToken<YOUR_SUPABASE_ANALYTICS_PRIVATE_TOKEN>Token interne Logflare
secret.dashboard.username<YOUR_SUPABASE_DASHBOARD_USERNAME>Connexion à l’interface Studio
secret.dashboard.password<YOUR_SUPABASE_DASHBOARD_PASSWORD>Connexion à l’interface Studio
secret.realtime.secretKeyBase<YOUR_SUPABASE_REALTIME_SECRET_KEY_BASE>Clé secrète Phoenix
secret.meta.cryptoKey<YOUR_SUPABASE_META_CRYPTO_KEY>openssl rand -hex 32
secret.s3.keyId<YOUR_MINIO_KEY_ID>Doit correspondre à secret.minio.user (openssl rand -hex 16)
secret.s3.accessKey<YOUR_MINIO_ACCESS_KEY>Doit correspondre à secret.minio.password (openssl rand -hex 32)
secret.minio.user<YOUR_MINIO_KEY_ID>Même valeur que secret.s3.keyId
secret.minio.password<YOUR_MINIO_ACCESS_KEY>Même valeur que secret.s3.accessKey

5.10 values/ha-supabase-db.yaml — Base de données HA Supabase (uniquement si ENABLE_HA_SUPABASE_DB=true)

Les secrets ici doivent correspondre à supabase.yaml. Utilisez les mêmes valeurs générées pour postgresPassword, jwtSecret, anonKey et serviceRoleKey.
nano values/ha-supabase-db.yaml
ChampEspace réservéNotes
secrets.inline.postgresPassword<YOUR_SUPABASE_DB_PASSWORD>Doit correspondre à secret.db.password de supabase.yaml
secrets.inline.authenticatorPassword<YOUR_SUPABASE_DB_PASSWORD>Doit être identique à postgresPassword
secrets.inline.pgbouncerPassword<YOUR_SUPABASE_DB_PASSWORD>Doit être identique à postgresPassword
secrets.inline.jwtSecret<YOUR_SUPABASE_JWT_SECRET>Doit correspondre à secret.jwt.secret de supabase.yaml
secrets.inline.anonKey<YOUR_SUPABASE_ANON_KEY>Doit correspondre à secret.jwt.anonKey de supabase.yaml
secrets.inline.serviceRoleKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Doit correspondre à secret.jwt.serviceKey de supabase.yaml
La classe de stockage (ebs-csi-gp2), le nombre d’instances et les limites de ressources sont préconfigurés. Ajustez postgres.storage.size et postgres.walStorage.size en fonction du volume de données attendu.

5.11 values/cloudnative-pg.yaml — Opérateur CloudNativePG (uniquement si ENABLE_CNPG=true)

Aucun espace réservé spécifique à l’environnement requis. Ceci déploie uniquement le contrôleur de l’opérateur CNPG. Les paramètres par défaut (3 réplicas, limites de ressources) conviennent à la plupart des environnements.

5.12 values/odin-services.yaml — Services d’application Odin

Les points de terminaison Redis et RabbitMQ ne sont disponibles qu’après que Terraform a créé ces ressources AWS. Les ARN de certificat doivent être provisionnés dans ACM avant le déploiement.
nano values/odin-services.yaml
Paramètres généraux :
ChampEspace réservéNotes
server<YOUR_WEB_DOMAIN>Domaine web principal
toolkitEncryptionKey<YOUR_TOOLKIT_ENCRYPTION_KEY>Générer : python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
Supabase (dataServiceConfig) — auto-hébergé (ENABLE_SUPABASE=true) :
ChampEspace réservéSource
supabase.projectUrlhttp://supabase-kong:8000Fixe — Kong Supabase interne
supabase.key<YOUR_SUPABASE_SERVICE_ROLE_KEY>Même que secret.jwt.serviceKey dans supabase.yaml
supabase.postgres.userpostgresFixe pour l’auto-hébergement
supabase.postgres.hostha-supabase-db-postgres-pooler-rw.ha-supabase-db.svc.cluster.localFixe — service DB Pool dans le cluster
supabase.postgres.password<YOUR_SUPABASE_DB_PASSWORD>Même que secret.db.password dans supabase.yaml
supabase.projectId(laisser vide)Non utilisé en mode auto-hébergé
Supabase (dataServiceConfig) — Supabase Cloud (ENABLE_SUPABASE=false) :
ChampEspace réservéSource
supabase.projectUrl<YOUR_SUPABASE_PROJECT_URL>Dashboard Supabase → Paramètres du projet → API
supabase.key<YOUR_SUPABASE_SERVICE_ROLE_KEY>Dashboard Supabase → API → clé service_role
supabase.postgres.user<YOUR_SUPABASE_DB_USER>Dashboard Supabase → Paramètres du projet → Base de données
supabase.postgres.host<YOUR_SUPABASE_DB_HOST>Dashboard Supabase → Base de données (par ex. aws-0-eu-west-2.pooler.supabase.com)
supabase.postgres.password<YOUR_SUPABASE_DB_PASSWORD>Dashboard Supabase → Paramètres du projet → Base de données
supabase.projectId<YOUR_SUPABASE_PROJECT_ID>Depuis l’URL de votre projet Supabase
Redis :
ChampEspace réservéNotes
redis.urlrediss://<YOUR_REDIS_HOST>:6379?ssl_cert_reqs=noneAprès que Terraform a créé ElastiCache
redis.host<YOUR_REDIS_HOST>Point de terminaison principal ElastiCache
# 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
RabbitMQ :
ChampEspace réservéNotes
rabbitmq.urlamqps://<YOUR_RABBITMQ_USERNAME>:<YOUR_RABBITMQ_PASSWORD>@<YOUR_RABBITMQ_HOST>:5671Après que Terraform a créé AmazonMQ
rabbitmq.host<YOUR_RABBITMQ_HOST>Point de terminaison du broker AmazonMQ
rabbitmq.username<YOUR_RABBITMQ_USERNAME>Défini dans terragrunt.hcl
rabbitmq.password<YOUR_RABBITMQ_PASSWORD>Défini dans terragrunt.hcl
# 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 de certificat :
ChampEspace réservéNotes
ssl.services.web.domain<YOUR_WEB_DOMAIN>par ex. app.example.com
ssl.services.web.certificateArn<YOUR_WEB_CERTIFICATE_ARN>ARN de certificat ACM
ssl.services.fastapiBackend.domain<YOUR_API_DOMAIN>par ex. api-app.example.com
ssl.services.fastapiBackend.certificateArn<YOUR_API_CERTIFICATE_ARN>ARN de certificat ACM
ssl.services.automator.domain<YOUR_AUTOMATOR_DOMAIN>par ex. automations-app.example.com
ssl.services.automator.certificateArn<YOUR_AUTOMATOR_CERTIFICATE_ARN>ARN de certificat ACM
ssl.services.supabase.domain<YOUR_SUPABASE_DOMAIN>par ex. supabase-app.example.com
ssl.services.supabase.certificateArn<YOUR_SUPABASE_CERTIFICATE_ARN>ARN de certificat ACM
# List ACM certificates in your region
aws acm list-certificates --region <YOUR_AWS_REGION> \
  --query "CertificateSummaryList[*].[DomainName,CertificateArn]" --output table
Clés Supabase du frontend Web — auto-hébergé (ENABLE_SUPABASE=true) :
ChampEspace réservéSource
web.supabase.urlhttps://<YOUR_SUPABASE_DOMAIN>URL externe acheminée via l’entrée ALB
web.supabase.anonKey<YOUR_SUPABASE_ANON_KEY>Même que secret.jwt.anonKey dans supabase.yaml
web.supabase.serviceRoleKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Même que secret.jwt.serviceKey dans supabase.yaml
web.supabase.clientanonKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Même que secret.jwt.serviceKey dans supabase.yaml
Clés Supabase du frontend Web — Supabase Cloud (ENABLE_SUPABASE=false) :
ChampEspace réservéSource
web.supabase.url<YOUR_SUPABASE_PROJECT_URL>Dashboard Supabase → Paramètres du projet → API
web.supabase.anonKey<YOUR_SUPABASE_ANON_KEY>Dashboard Supabase → API → clé anon
web.supabase.serviceRoleKey<YOUR_SUPABASE_SERVICE_ROLE_KEY>Dashboard Supabase → API → clé service_role
web.supabase.clientanonKey<YOUR_SUPABASE_CLIENT_ANON_KEY>Même que la clé service_role

5.13 values/signoz.yaml — Observabilité SigNoz (uniquement si ENABLE_SIGNOZ=true)

nano values/signoz.yaml
ChampEspace réservéNotes
global.clusterName<YOUR_ENV_NAME>Nom du cluster EKS
signoz.ingress.annotations.alb.ingress.kubernetes.io/certificate-arn<YOUR_AWS_REGION>, <YOUR_AWS_ACCOUNT_ID>, <YOUR_SIGNOZ_CERTIFICATE_ID>Certificat ACM pour SigNoz
signoz.ingress.hosts[0].host<YOUR_SIGNOZ_DOMAIN>par ex. signoz-app.example.com

5.14 values/signoz-k8s-infra.yaml — Métriques K8s SigNoz (uniquement si ENABLE_SIGNOZ=true)

nano values/signoz-k8s-infra.yaml
ChampEspace réservéNotes
global.clusterName<YOUR_ENV_NAME>Nom du cluster EKS pour l’étiquetage des métriques
Le point de terminaison du collecteur OTel (signoz-otel-collector.monitoring.svc.cluster.local:4317) est préconfiguré en supposant que SigNoz et k8s-infra sont déployés dans le namespace monitoring. Aucune modification n’est nécessaire sauf si vous utilisez un nom de release personnalisé.

Rappel de l’ordre de déploiement

Certaines valeurs ne sont disponibles qu’après le déploiement de certaines infrastructures. Suivez cet ordre :
  1. Avant tout déploiement — Définir : <YOUR_ENV_NAME>, <YOUR_AWS_REGION>, <YOUR_AWS_ACCOUNT_ID>, <YOUR_ENVIRONMENT>, <YOUR_PROJECT>, <YOUR_VPC_CIDR>, tous les noms de domaine, tous les ARN de certificat, toutes les valeurs Supabase, <YOUR_TOOLKIT_ENCRYPTION_KEY>, nom d’utilisateur/mot de passe RabbitMQ
  2. Après la création du cluster EKS — Définir : <YOUR_VPC_ID> (infrastructure.yaml), <YOUR_EKS_CLUSTER_ENDPOINT> (karpenter-values.yaml)
  3. Après terraform apply pour les services AWS — Définir : <YOUR_REDIS_HOST>, <YOUR_RABBITMQ_HOST> (odin-services.yaml)

Étape 6 : Vérifier qu’aucun espace réservé ne subsiste

grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml"
La sortie attendue doit être vide ou ne contenir que des références à des ressources sur le point d’être créées (VPC, Redis, MQ, EKS). Si des espaces réservés subsistent, reportez-vous aux sous-sections de l’étape 5 ci-dessus. Liste de contrôle des fichiers :
FichierÉtapeRequis
terragrunt.hcl5.1Toujours
state/terragrunt.hcl5.2Toujours
values/infrastructure.yaml5.3Toujours
values/karpenter-values.yaml5.4Toujours
values/karpenter-nodeclasses.yaml5.5Toujours
values/karpenter.yaml5.7Toujours
values/keda.yaml5.8Toujours
values/aws-ebs-csi-driver.yaml5.6Toujours
values/odin-services.yaml5.12Toujours
values/cloudnative-pg.yaml5.11Uniquement si ENABLE_CNPG=true
values/ha-supabase-db.yaml5.10Uniquement si ENABLE_HA_SUPABASE_DB=true
values/supabase.yaml5.9Uniquement si ENABLE_SUPABASE=true
values/signoz.yaml5.13Uniquement si ENABLE_SIGNOZ=true
values/signoz-k8s-infra.yaml5.14Uniquement si ENABLE_SIGNOZ=true

Phase 1 : Configuration de la gestion de l’état

Objectif : Création du compartiment S3 pour l’état Terraform. Le module de gestion de l’état de chaque environnement crée un compartiment S3 avec le motif odin-terraform-state-{environment-name}, configure le chiffrement, le versionnage et le blocage d’accès public, et utilise l’état local pour le module d’état lui-même (modèle d’amorçage).
cd terragrunt/environments/{your-env-name}/state
terragrunt init
terragrunt plan
terragrunt apply

Phase 2 : Déploiement de l’infrastructure EKS

Objectif : Réseau principal (VPC, sous-réseaux, passerelle NAT), rôles et politiques IAM, cluster EKS et groupes de nœuds gérés.

2.1 Exécution à blanc — Infrastructure EKS

Infrastructure principale
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"
Rôles et politiques IAM
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"
Cluster EKS et groupes de nœuds
terragrunt plan -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"

Utiliser un registre Docker personnalisé / privé

Par défaut, les images EKB sont tirées de Docker Hub à l’aide d’un secret nommé regcred. Si le client héberge les images dans un autre registre, suivez ces étapes avant de déployer odin-services. Étape 1 — Créer le imagePullSecret dans le namespace cible
# 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
Étape 2 — Définir le nom du secret dans values/odin-services.yaml
# values/odin-services.yaml
imagePullSecrets:
  - name: regcred          # must match the secret name created above
  # - name: customer-registry-secret  # add additional registries if needed
Étape 3 — Mettre à jour les références d’images
web:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG>

fastapiBackend:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/server:<TAG>
Étape 4 — Vérifier l’accès de tirage avant le déploiement complet
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 Déployer l’infrastructure EKS

Étape 1 : Infrastructure principale
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"
Après cette étape, mettez à jour vpcId dans values/infrastructure.yaml avant de déployer le contrôleur de équilibrage de charge AWS.
Étape 2 : Cluster EKS et rôles et politiques IAM
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"
Étape 3 : Groupes de nœuds et add-ons
terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"
Après cette étape, mettez à jour CLUSTER_ENDPOINT dans values/karpenter-values.yaml avant de déployer Karpenter.
Vérifier la connectivité du cluster EKS
aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER_NAME

kubectl cluster-info
kubectl get nodes
kubectl get secret regcred -n default

Phase 3 : Stockage et équilibrage de charge

Objectif : Pilote EBS CSI pour les volumes persistants, contrôleur de équilibrage de charge AWS fonctionnant sur le groupe de nœuds géré.

3.1 Exécution à blanc — Stockage et équilibrage de charge

Pilote EBS CSI
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"
Contrôleur de équilibrage de charge AWS
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 Déployer le stockage et l’équilibrage de charge

Étape 1 : Pilote EBS CSI
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"
Vérification
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
Étape 2 : Contrôleur de équilibrage de charge AWS
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"
Vérification
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

Phase 4 : Mise à l’échelle Karpenter

Objectif : Rôles IAM pour Karpenter, gestion des interruptions Spot, contrôleur Karpenter et pools de nœuds.

4.1 Exécution à blanc — Karpenter

Ressources IAM Karpenter
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"
Rôle lié de service EC2 Spot (si les instances Spot sont activées)
terragrunt plan -target="aws_iam_service_linked_role.ec2_spot[0]"
Interruption Spot Karpenter (si activée dans terragrunt.hcl)
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"
Graphiques Helm Karpenter
terragrunt plan -target="helm_release.karpenter"
NodePools et EC2NodeClasses Karpenter
terragrunt plan -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target="kubernetes_config_map.aws_auth"
Une erreur attendue peut apparaître lors du plan : API did not recognize GroupVersionKind from manifest (CRD may not be installed). C’est normal et peut être ignoré — Kubernetes valide les ressources par rapport à l’API en direct au moment du plan, avant l’installation des CRD.

4.2 Déployer Karpenter

Étape 1 : Ressources IAM Karpenter
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"
Vérification
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
Étape 2 : Rôle lié de service EC2 Spot (si les instances Spot sont activées)
Le rôle lié de service EC2 Spot est au niveau du compte (un seul par compte AWS) et doit exister avant que Karpenter puisse lancer des instances Spot.
Option A : Laisser Terraform le créer (recommandé pour les nouveaux déploiements)
terragrunt apply -target="aws_iam_service_linked_role.ec2_spot[0]"
Option B : Importer si le rôle existe déjà
# 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
Étape 3 : Interruption Spot Karpenter (si activée dans terragrunt.hcl)
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"
Vérification
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
Étape 4 : Graphique Helm Karpenter
terragrunt apply -target="helm_release.karpenter"
Vérification
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
Étape 5 : Manifestes Kubernetes Karpenter
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]'
Vérification
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'

Phase 5 : Mise à l’échelle KEDA

Objectif : KEDA pour la mise à l’échelle au niveau de l’application.

5.1 Exécution à blanc — KEDA

cd terragrunt/environments/your-env-name
terragrunt plan -target="helm_release.keda"

5.2 Déployer KEDA

cd terragrunt/environments/your-env-name
terragrunt apply -target="helm_release.keda"
Vérification
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

Phase 6 : Services de données

Objectif : Supabase (base de données), ElastiCache (Redis), RabbitMQ (file d’attente de messages).
Déployez d’abord l’opérateur CloudNativePG, puis le cluster de base de données HA Supabase, puis l’application Supabase. Le cluster de base de données doit être prêt avant le démarrage de Supabase.

6.1 Exécution à blanc — Services de données

Étape 1 : Opérateur CloudNativePG (si activé)
cd terragrunt/environments/your-env-name
ENABLE_CNPG=true terragrunt plan \
  --target='helm_release.additional_charts["cloudnative-pg"]'
Étape 2 : Base de données HA Supabase (si activée)
ENABLE_HA_SUPABASE_DB=true terragrunt plan \
  --target='helm_release.additional_charts["ha-supabase-db"]'
Étape 3 : Application Supabase (si activée)
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt plan \
    --target='helm_release.supabase[0]'
fi
Étape 4 : Services AWS — ElastiCache et RabbitMQ (si activés)
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 Déployer les services de données

Étape 1 : Opérateur CloudNativePG (si activé)
cd terragrunt/environments/your-env-name
ENABLE_CNPG=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["cloudnative-pg"]'
Étape 2 : Base de données HA Supabase (si activée)
ENABLE_HA_SUPABASE_DB=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["ha-supabase-db"]'
Vérifier le pooler PgBouncer et les identifiants après le déploiement :
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 ""
Utilisez le ClusterIP du pooler (ou EXTERNAL-IP si LoadBalancer) comme valeur SUPABASE_POSTGRES_HOST dans values/odin-services.yaml et comme secret.db.postgresHost dans values/supabase.yaml. Étape 3 : Application Supabase (si activée) Tous les pods de service Supabase s’exécutent exclusivement sur le NodePool application Karpenter (On-Demand uniquement) pour prévenir les interruptions Spot.
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --auto-approve \
    --target='helm_release.supabase[0]'
fi
Étape 4 : Services AWS — ElastiCache et RabbitMQ (si activés)
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
Vérification
# 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}'
Avant de déployer les services Odin, mettez à jour values/odin-services.yaml avec le point de terminaison Redis, le point de terminaison RabbitMQ et tous les ARN de certificat obtenus dans cette phase.

Phase 7 : Services Odin

Objectif : Déploiement de l’application via Helm.
Avant le déploiement, réduisez temporairement le nombre de réplicas de fastapiBackend à un seul pour l’exécution initiale de la migration de base de données — définissez replicaCount: 1, workers: 1 et keda.minReplicas: 1. Une fois la migration terminée avec succès, rétablissez ces valeurs à leurs valeurs par défaut de production avant de redéployer.

7.1 Exécution à blanc — Services Odin

cd terragrunt/environments/your-env-name
terragrunt plan -target="helm_release.odin_services"

7.2 Déployer les services Odin

cd terragrunt/environments/your-env-name
terragrunt apply -target="helm_release.odin_services"
Vérification
kubectl get pods
kubectl get ingress  # Add the ALB endpoints to your DNS provider

Phase 8 : Observabilité SigNoz

Objectif : Surveillance des journaux et des métriques.

8.1 Exécution à blanc — Graphiques SigNoz

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 Déployer les graphiques SigNoz

cd terragrunt/environments/your-env-name
terragrunt apply -target='helm_release.additional_charts["signoz"]'
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]'
Vérification
kubectl get pods -n monitoring
kubectl get ingress -n monitoring  # Add the ALB endpoints to your DNS provider

Phase 9 : Déploiement final

9.1 Déploiement complet

cd terragrunt/environments/your-env-name
terragrunt apply
Cet apply final gère les ressources restantes qui n’ont pas été explicitement ciblées dans les phases précédentes.

9.2 Vérifier le déploiement

# 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

Dépannage

Problèmes de verrouillage d’état
terragrunt force-unlock <lock-id>
Karpenter ne fonctionne pas
kubectl describe nodes
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
Problèmes de équilibrage de charge
kubectl describe ingress -n default
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
Problèmes de graphique Helm
helm status <release-name> -n <namespace>
helm rollback <release-name> <revision> -n <namespace>

Nettoyage

# 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

Surveillance et journalisation

# 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

Référence rapide — Toutes les commandes de déploiement

# 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
Remplacez your-env-name par le nom réel de votre environnement. Exécutez toujours des exécutions à blanc (terragrunt plan) pour valider votre configuration avant d’appliquer les modifications.