AWS DevOps Infrastructure Code : les 9 étapes clés pour passer de zéro à opérationnel

AWS DevOps Infrastructure Code : l'essentiel en un article — vrai code, schémas et étapes concrètes, extraits d'un cours de 39 leçons.

AWS DevOps Infrastructure Code : les 9 étapes clés pour passer de zéro à opérationnel

Tout le monde peut apprendre AWS DevOps Infrastructure Code — à condition de suivre les étapes dans le bon ordre. On a condensé un cours complet de 39 leçons en un parcours clair, avec les extraits de code les plus utiles.

tl;dr
  • Introduction et Configuration AWS
  • DevOps et Infrastructure as Code
  • AWS CloudFormation
  • AWS CDK Cloud Development Kit
  • CICD avec AWS CodePipeline
~$ cat ./parcours.md # AWS DevOps Infrastructure Code — 10 chapitres
01
Introduction et Configuration AWS
→ Chapitre 00 — Créer un compte AWS Free Tier→ Chapitre 00 — IAM : Utilisateurs, Rôles et Politiques+ 2 autres leçons
02
DevOps et Infrastructure as Code
→ Chapitre 01 — La Philosophie DevOps→ Chapitre 01 — Infrastructure as Code (IaC)+ 2 autres leçons
03
AWS CloudFormation
→ Introduction à AWS CloudFormation→ Parameters, Outputs, Mappings et Conditions+ 2 autres leçons
04
AWS CDK Cloud Development Kit
→ Introduction à AWS CDK — Cloud Development Kit→ CDK en profondeur — Créer une vraie infrastructure+ 2 autres leçons
05
CICD avec AWS CodePipeline
→ CodeCommit et CodeBuild→ CodeDeploy et CodePipeline+ 2 autres leçons
06
Containers sur AWS Docker ECS Fargate
→ Docker et Amazon ECR→ Amazon ECS et Fargate+ 2 autres leçons
07
Monitoring et Observabilité
→ CloudWatch — Logs, Métriques et Alarmes→ AWS X-Ray et CloudTrail+ 2 autres leçons
08
Terraform sur AWS
→ Introduction à Terraform sur AWS→ Terraform — State, Variables et Modules+ 2 autres leçons
🏁
Projet final (+ 2 chapitres en chemin)
→ Tu repars avec un projet concret et démontrable

Introduction à AWS CDK — Cloud Development Kit

Chapitre 03 — Leçon 01 · AWS DevOps : Infrastructure as Code

1. Qu'est-ce que l'AWS CDK ?

CloudFormation, c'est comme remplir un formulaire administratif CERFA à la main, case par case, en respectant des règles de syntaxe strictes. C'est fastidieux mais ça fonctionne. Le CDK, c'est avoir un programme informatique qui remplit ce formulaire à votre place : vous lui dites en Python "je veux un serveur de taille moyenne avec une base de données", et il génère automatiquement le formulaire CERFA complet, correctement rempli, avec toutes les cases obligatoires. Vous écrivez beaucoup moins, vous faites beaucoup plus, et vous bénéficiez de toute la puissance d'un vrai langage de programmation comme les boucles, les fonctions et la réutilisation de code.

L'AWS Cloud Development Kit (CDK) est un framework open-source qui permet de définir votre infrastructure AWS avec un vrai langage de programmation : Python, TypeScript, Java, C# ou Go. Le CDK génère ensuite automatiquement des templates CloudFormation à partir de votre code.

NOTELe principe : vous écrivez du Python (ou TypeScript, etc.), le CDK compile ce code en un template CloudFormation valide, puis CloudFormation déploie les ressources AWS. Vous bénéficiez de toute la puissance d'un vrai langage (boucles, conditions, fonctions, héritage) pour décrire votre infrastructure.

CDK vs CloudFormation — comparaison

CritèreCloudFormation (YAML)AWS CDK (Python)
LangageYAML / JSON déclaratifPython, TypeScript, Java, C#, Go
RéutilisabilitéCopier-coller, Nested StacksClasses, modules, héritage
Autocomplétion IDELimitée (YAML)Complète avec types et documentation
LogiqueConditions et mappings limitésif/else, boucles for, fonctions complètes
TestsDifficileTests unitaires avec pytest, jest
Courbe d'apprentissageFaible pour YAML, mais verboseNécessite connaissance d'un langage de prog.
Sous le capotExécuté directement par CloudFormationGénère du CloudFormation puis le déploie

Les quatre concepts fondamentaux du CDK

App (Application CDK)

Le point d'entrée de tout projet CDK. Une App contient une ou plusieurs Stacks. C'est le conteneur racine de votre infrastructure.

Stack (Pile CDK)

Correspond à une stack CloudFormation. Contient des Constructs (ressources AWS). Une App peut avoir plusieurs Stacks pour différents environnements.

Construct

Le bloc de construction de base du CDK. Représente une ressource AWS (ou un groupe de ressources). Existe à trois niveaux : L1, L2, L3.

Environment (Env)

La combinaison compte AWS + région cible pour le déploiement. Permet de déployer la même stack dans plusieurs environnements.

2. Installation — Node.js, CDK CLI et Python

Le CDK CLI est un outil Node.js. Même si vous codez en Python, vous devez avoir Node.js installé.

Prérequis

bash
# 1. Vérifier Node.js (version 18+ recommandée)
node --version
bash
# Bootstrap dans la région courante
cdk bootstrap

# Bootstrap dans une région spécifique
cdk bootstrap aws://123456789012/eu-west-1

Les Constructs sont les briques de base du CDK. Ils existent à trois niveaux d'abstraction, chacun offrant un compromis différent entre contrôle et simplicité.

L1 — Constructs bas niveau (CfnXxx)

Les constructs L1 (préfixés Cfn) sont des wrappers directs autour des ressources CloudFormation. Ils donnent accès à toutes les propriétés mais sans aucune valeur par défaut — vous devez tout configurer explicitement.

output
from aws_cdk import aws_s3 as s3
import aws_cdk as cdk

class MaStack(cdk.Stack):
    def __init__(self, scope, id, **kwargs):
        super().__init__(scope, id, **kwargs)

        # L1 : CfnBucket = wrapper direct CloudFormation AWS::S3::Bucket
        bucket_l1 = s3.CfnBucket(self, "BucketL1",
            bucket_name="mon-bucket-l1",
            versioning_configuration=s3.CfnBucket.VersioningConfigurationProperty(
                status="Enabled"
            ),
            lifecycle_configuration=s3.CfnBucket.LifecycleConfigurationProperty(
                rules=[s3.CfnBucket.RuleProperty(
                    id="expiration-anciens-objets",
                    status="Enabled",
                    expiration_in_days=90
                )]
            )
        )

L2 — Constructs haut niveau (recommandés)

Nested Stacks, StackSets, Change Sets et Bonnes Pratiques

Chapitre 02 — Leçon 03 · AWS DevOps : Infrastructure as Code

1. Nested Stacks — décomposer les grandes infrastructures

Imaginez la construction d'un immeuble de bureaux. Plutôt qu'un seul entrepreneur qui ferait tout de A à Z et serait vite dépassé, on fait appel à des spécialistes indépendants : un électricien pour tout le réseau électrique, un plombier pour la plomberie, un menuisier pour les cloisons, un technicien réseau pour l'informatique. Chacun travaille dans son domaine, produit son rapport de travail, et un chef de chantier coordonne l'ensemble. Les Nested Stacks fonctionnent de la même façon : chaque module (réseau, sécurité, base de données, application) est un template indépendant géré par une équipe différente, et une stack parente coordonne tout le monde.

Quand une infrastructure devient complexe (VPC, bases de données, applications, sécurité...), regrouper tout dans un seul template devient ingérable. Les Nested Stacks (stacks imbriquées) permettent de découper l'infrastructure en modules réutilisables, chacun dans son propre template.

Architecture en couches avec les Nested Stacks

output
infrastructure/
├── stack-parent.yaml         # Stack racine — orchestre tout
├── modules/
│   ├── reseau.yaml           # VPC, subnets, Internet Gateway
│   ├── securite.yaml         # Security Groups, IAM Roles
│   ├── base-de-donnees.yaml  # RDS, cache ElastiCache
│   └── application.yaml      # EC2, Load Balancer, Auto Scaling

La stack parent qui référence les modules

output
AWSTemplateFormatVersion: "2010-09-09"
Description: "Stack parent — orchestre toute l'infrastructure"

Parameters:
  Environnement:
    Type: String
    AllowedValues: [dev, prod]
  URLTemplates:
    Type: String
    Description: "URL S3 de base où sont stockés les templates"
    Default: "https://s3.amazonaws.com/mon-bucket-templates/v1"

Resources:
  # Module réseau
  StackReseau:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub "${URLTemplates}/reseau.yaml"
      Parameters:
        Environnement: !Ref Environnement
        CIDRVpc: "10.0.0.0/16"
      TimeoutInMinutes: 15

  # Module sécurité — dépend du réseau
  StackSecurite:
    Type: AWS::CloudFormation::Stack
    DependsOn: StackReseau
    Properties:
      TemplateURL: !Sub "${URLTemplates}/securite.yaml"
      Parameters:
        Environnement: !Ref Environnement
        VpcId: !GetAtt StackReseau.Outputs.VpcId

  # Module base de données
  StackBDD:
    Type: AWS::CloudFormation::Stack
    DependsOn: StackSecurite
    Properties:
      TemplateURL: !Sub "${URLTemplates}/base-de-donnees.yaml"
      Parameters:
        Environnement: !Ref Environnement
        VpcId: !GetAtt StackReseau.Outputs.VpcId
        SubnetIds: !GetAtt StackReseau.Outputs.SubnetsPrives
        SGBaseDeDonnees: !GetAtt StackSecurite.Outputs.SGBaseDeDonnees
      TimeoutInMinutes: 30

  # Module application
  StackApplication:
    Type: AWS::CloudFormation::Stack
    DependsOn: StackBDD
    Properties:
      TemplateURL: !Sub "${URLTemplates}/application.yaml"
      Parameters:
        Environnement: !Ref Environnement
        VpcId: !GetAtt StackReseau.Outputs.VpcId
        SubnetPublics: !GetAtt StackReseau.Outputs.SubnetsPublics
        URLBDD: !GetAtt StackBDD.Outputs.EndpointBDD
        SGApplication: !GetAtt StackSecurite.Outputs.SGApplication

Outputs:
  URLApplication:
    Description: "URL du Load Balancer de l'application"
    Value: !GetAtt StackApplication.Outputs.URLLoadBalancer

Exemple du template module reseau.yaml

output
AWSTemplateFormatVersion: "2010-09-09"
Description: "Module réseau — VPC, subnets publics et privés"

Parameters:
  Environnement:
    Type: String
  CIDRVpc:
    Type: String

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref CIDRVpc
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub "vpc-${Environnement}"

  SubnetPublic1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.1.0/24"
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: true

  SubnetPrive1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: "10.0.10.0/24"
      AvailabilityZone: !Select [0, !GetAZs ""]

Outputs:
  VpcId:
    Value: !Ref VPC
    Export:
      Name: !Sub "${AWS::StackName}-VpcId"
  SubnetsPublics:
    Value: !Join [",", [!Ref SubnetPublic1]]
    Export:
      Name: !Sub "${AWS::StackName}-SubnetsPublics"
  SubnetsPrives:
    Value: !Join [",", [!Ref SubnetPrive1]]
    Export:
      Name: !Sub "${AWS::StackName}-SubnetsPrives"

Déployer avec les templates stockés dans S3

bash
# Uploader les templates dans S3 d'abord
aws s3 sync ./modules/ s3://mon-bucket-templates/v1/ --exclude "*.md"

# Déployer la stack parent
aws cloudformation deploy \
  --stack-name infra-prod \
  --template-file stack-parent.yaml \
  --parameter-overrides \
    Environnement=prod \
    URLTemplates=https://s3.amazonaws.com/mon-bucket-templates/v1 \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
TIPAvantages des Nested Stacks : modularité (chaque module est indépendant), réutilisabilité (le même module réseau pour dev et prod), lisibilité (les templates restent courts), et limite CloudFormation (500 ressources max par stack — les nested stacks contournent cette limite).

2. StackSets — déployer sur plusieurs comptes et régions

Imaginez une chaîne de restaurants qui ouvre des succursales dans le monde entier. Le directeur général crée une recette de menu standard, une charte graphique, et des procédures de fonctionnement qui s'appliquent dans tous les restaurants, qu'ils soient à Paris, New York ou Tokyo. Quand une nouvelle règle est ajoutée (nouvelle allergie à afficher, nouveau règlement sanitaire), elle est appliquée simultanément dans tous les restaurants de la chaîne en une seule décision centrale. Les StackSets fonctionnent pareil : vous définissez votre infrastructure une seule fois et vous la déployez dans tous vos comptes AWS et toutes vos régions en une seule opération.

Les StackSets permettent de déployer le même template CloudFormation dans plusieurs comptes AWS et/ou plusieurs régions en une seule opération. C'est l'outil idéal pour les organisations multi-comptes (Landing Zone, Control Tower).

Cas d'usage typiques

Gouvernance centralisée

Déployer des règles AWS Config, CloudTrail, GuardDuty dans tous les comptes de l'organisation automatiquement.

Conformité uniforme

Appliquer les mêmes politiques IAM, groupes de sécurité de base et notifications d'alerte dans chaque compte.

Multi-région

Déployer une infrastructure identique dans us-east-1, eu-west-1 et ap-southeast-1 pour la redondance globale.

Prérequis : configurer les permissions

bash
# Deux modes de fonctionnement :

# Mode 1 : Self-Managed (rôles IAM manuels dans chaque compte)
# Créer AWSCloudFormationStackSetAdministrationRole dans le compte admin
# Créer AWSCloudFormationStackSetExecutionRole dans chaque compte cible

# Mode 2 : Service-Managed (via AWS Organizations — recommandé)
# Activer la confiance avec Organizations dans CloudFormation
aws organizations enable-aws-service-access \
  --service-principal cloudformation.amazonaws.com

Créer et déployer un StackSet

Déployer et gérer des applications sur EKS

Chapitre 08 — Kubernetes sur AWS EKS | AWS DevOps Infrastructure as Code

1. Déployer une application — Deployment YAML

Un Deployment Kubernetes, c'est comme une chaîne de fast food. Vous définissez combien de "comptoirs" (replicas) vous voulez ouverts en même temps. Si l'un tombe en panne, Kubernetes en ouvre un nouveau automatiquement sans que les clients s'en aperçoivent. Quand vous voulez changer le menu (nouvelle version de l'image), Kubernetes met à jour les comptoirs un par un (rolling update) pour ne jamais fermer tous les comptoirs en même temps. Si le nouveau menu ne plaît pas, on peut revenir à l'ancien menu immédiatement (rollback).

Un Deployment Kubernetes déclare l'état désiré de votre application : quelle image utiliser, combien de réplicas, comment effectuer les mises à jour. Kubernetes maintient cet état en permanence.

Deployment complet avec toutes les bonnes pratiques

output
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mon-api-fastapi
  namespace: mon-application
  labels:
    app: mon-api-fastapi
    version: "1.0.0"
    equipe: backend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mon-api-fastapi
  # Stratégie de déploiement rolling update
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1      # Au plus 1 Pod indisponible pendant la mise à jour
      maxSurge: 1            # Au plus 1 Pod en surplus pendant la mise à jour
  template:
    metadata:
      labels:
        app: mon-api-fastapi
        version: "1.0.0"
    spec:
      serviceAccountName: sa-mon-api  # IRSA — IAM Role for Service Account
      terminationGracePeriodSeconds: 30
      # Sécurité au niveau du Pod
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 1000
      containers:
        - name: mon-api-fastapi
          image: 123456789012.dkr.ecr.ca-central-1.amazonaws.com/mon-api-fastapi:1.0.0
          ports:
            - containerPort: 8080
              protocol: TCP
          # Limites de ressources obligatoires en production
          resources:
            requests:
              cpu: "250m"        # 0.25 vCPU garanti
              memory: "256Mi"    # 256 Mo garantis
            limits:
              cpu: "500m"        # Maximum 0.5 vCPU
              memory: "512Mi"    # Maximum 512 Mo
          # Variables d'environnement depuis ConfigMap et Secret
          env:
            - name: ENVIRONNEMENT
              value: production
            - name: PORT
              value: "8080"
          envFrom:
            - configMapRef:
                name: config-mon-api
            - secretRef:
                name: secrets-mon-api
          # Sondes de santé
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 20
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
          startupProbe:
            httpGet:
              path: /health
              port: 8080
            failureThreshold: 30
            periodSeconds: 5
          # Sécurité du conteneur
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL
      # Distribution entre les zones de disponibilité
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: mon-api-fastapi

Commandes de déploiement essentielles

bash
# Appliquer le manifeste
kubectl apply -f deployment.yaml -n mon-application

# Suivre le déploiement en temps réel
kubectl rollout status deployment/mon-api-fastapi -n mon-application

# Voir l'historique des déploiements
kubectl rollout history deployment/mon-api-fastapi -n mon-application

# Mettre à jour l'image (déclenche un rolling update)
kubectl set image deployment/mon-api-fastapi \
  mon-api-fastapi=123456789012.dkr.ecr.ca-central-1.amazonaws.com/mon-api-fastapi:1.1.0 \
  -n mon-application

# Revenir à la version précédente (rollback)
kubectl rollout undo deployment/mon-api-fastapi -n mon-application

# Revenir à une révision spécifique
kubectl rollout undo deployment/mon-api-fastapi --to-revision=2 -n mon-application

2. Services Kubernetes : ClusterIP, NodePort, LoadBalancer

Dans Kubernetes, les Services sont comme des adresses postales stables dans un immeuble dont les locataires changent souvent. ClusterIP, c'est un bureau interne dans l'immeuble : personne de l'extérieur ne peut y accéder, c'est pour la communication entre employés. LoadBalancer, c'est la porte d'entrée principale de l'immeuble avec un agent de sécurité (le Load Balancer AWS) qui dirige les visiteurs extérieurs vers le bon bureau disponible. Même si les locataires changent (les Pods redémarrent), l'adresse de l'immeuble reste la même.

Un Service expose un ensemble de Pods via une IP stable et un nom DNS interne, indépendamment du cycle de vie des Pods individuels.

TypeAccessibilitéCas d'usage
ClusterIP Uniquement à l'intérieur du cluster Communication inter-services (base de données, cache)
NodePort Depuis l'extérieur via l'IP du Node + un port fixe (30000-32767) Tests, développement (pas recommandé en production)
LoadBalancer Depuis l'extérieur via un Load Balancer AWS (CLB/NLB) provisionné automatiquement Exposer un service directement (sans Ingress)
ExternalName Résout vers un nom DNS externe Accéder à des services RDS, ElastiCache via un nom interne
output
---
# Service ClusterIP — pour la communication interne
apiVersion: v1
kind: Service
metadata:
  name: svc-mon-api
  namespace: mon-application
  labels:
    app: mon-api-fastapi
spec:
  type: ClusterIP
  selector:
    app: mon-api-fastapi      # Correspond aux labels du Deployment
  ports:
    - name: http
      port: 80                # Port du Service (interne)
      targetPort: 8080        # Port du conteneur
      protocol: TCP

---
# Service LoadBalancer — expose via un NLB AWS
apiVersion: v1
kind: Service
metadata:
  name: svc-mon-api-public
  namespace: mon-application
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
  type: LoadBalancer
  selector:
    app: mon-api-fastapi
  ports:
    - name: http
      port: 80
      targetPort: 8080

3. ConfigMaps et Secrets Kubernetes

ConfigMap — configuration non sensible

output
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-mon-api
  namespace: mon-application
data:
  # Variables d'environnement
  LOG_LEVEL: "info"
  WORKERS: "4"
  TIMEOUT: "30"
  DATABASE_HOST: "rds-mon-app.ca-central-1.rds.amazonaws.com"
  DATABASE_NAME: "production"
  # Fichier de configuration complet
  application.yaml: |
    server:
      host: 0.0.0.0
      port: 8080
    database:
      pool_size: 10
      max_overflow: 5
    cache:
      backend: redis
      ttl: 300

Secret Kubernetes

output
apiVersion: v1
kind: Secret
metadata:
  name: secrets-mon-api
  namespace: mon-application
type: Opaque
stringData:
  # stringData accepte les valeurs en clair — K8s les encode en base64 automatiquement
  DATABASE_PASSWORD: "MonMotDePasseSecret"
  API_KEY: "sk-abc123..."
  JWT_SECRET: "ma-cle-jwt-super-secrete"
WARNINGAttention : Par défaut, les Secrets Kubernetes sont simplement encodés en base64 (pas chiffrés) dans etcd. Pour une sécurité renforcée sur EKS, activez le chiffrement des Secrets avec une clé KMS, et envisagez d'utiliser le AWS Secrets Manager + External Secrets Operator pour synchroniser les secrets automatiquement.

External Secrets Operator — synchroniser depuis Secrets Manager

output
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: secrets-aws-synchronises
  namespace: mon-application
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: secrets-mon-api   # Nom du Secret Kubernetes à créer
    creationPolicy: Owner
  data:
    - secretKey: DATABASE_PASSWORD
      remoteRef:
        key: "mon-app/production/secrets"
        property: "database_password"
    - secretKey: API_KEY
      remoteRef:
        key: "mon-app/production/secrets"
        property: "api_key"
va-plus-loin

Cet article couvre les extraits les plus utiles — le cours complet AWS DevOps Infrastructure Code (10 chapitres, 39 leçons, exercices corrigés et projet final) t'emmène jusqu'au bout.

./acceder-au-cours-complet cours gratuit : Maîtriser Claude Code

FAQ

Combien de temps pour apprendre AWS DevOps Infrastructure Code ?
Avec une progression structurée (10 chapitres, 39 leçons courtes et pratiques), on atteint un niveau opérationnel en quelques semaines à raison de 30 à 60 minutes par jour. L'important est de pratiquer chaque notion immédiatement.
Faut-il des prérequis ?
Mieux vaut être à l'aise avec les fondamentaux du domaine : ce contenu va en profondeur, avec des cas réels.
Par où commencer concrètement ?
Reproduis les commandes de cet article, puis suis le cours complet AWS DevOps Infrastructure Code : il enchaîne les 39 leçons dans l'ordre, avec exercices et projet final.

📬 Tu veux recevoir ce type de guide chaque semaine ? Abonne-toi gratuitement — code réel, zéro blabla.