AWS DevOps Infrastructure Code: as 9 etapas-chave para passar de zero a operacional

AWS DevOps Infrastructure Code: o essencial em um artigo — código real, diagramas e etapas concretas, extratos de um curso de 39 lições.

AWS DevOps Infrastructure Code: as 9 etapas-chave para passar de zero a operacional

Todos podem aprender AWS DevOps Infrastructure Code — desde que sigam as etapas na ordem correta. Condensamos um curso completo de 39 lições em um percurso claro, com os trechos de código mais úteis.

tl;dr
  • Introdução e Configuração AWS
  • DevOps e Infraestrutura como Código
  • AWS CloudFormation
  • AWS CDK Cloud Development Kit
  • CICD com AWS CodePipeline
~$ cat ./parcours.md # AWS DevOps Infrastructure Code — 10 capítulos
01
Introduction et Configuration AWS
→ Capítulo 00 — Criar uma conta AWS Free Tier→ Capítulo 00 — IAM : Usuários, Funções e Políticas+ 2 mais lições
02
DevOps et Infrastructure as Code
→ Capítulo 01 — A Filosofia DevOps→ Capítulo 01 — Infraestrutura como Código (IaC)+ 2 mais lições
03
AWS CloudFormation
→ Introdução ao AWS CloudFormation→ Parameters, Outputs, Mappings e Conditions+ 2 mais lições
04
AWS CDK Cloud Development Kit
→ Introdução ao AWS CDK — Cloud Development Kit→ CDK em profundidade — Criar uma infraestrutura real+ 2 mais lições
05
CICD com AWS CodePipeline
→ CodeCommit e CodeBuild→ CodeDeploy e CodePipeline+ 2 mais lições
06
Containers sur AWS Docker ECS Fargate
→ Docker e Amazon ECR→ Amazon ECS e Fargate+ 2 mais lições
07
Monitoring et Observabilité
→ CloudWatch — Logs, Métricas e Alarmes→ AWS X-Ray e CloudTrail+ 2 mais lições
08
Terraform sur AWS
→ Introdução ao Terraform na AWS→ Terraform — State, Variables e Modules+ 2 mais lições
🏁
Projeto final (+ 2 capítulos no caminho)
→ Você sai com um projeto concreto e demonstrável

Introdução ao AWS CDK — Cloud Development Kit

Capítulo 03 — Lição 01 · AWS DevOps : Infraestrutura como Código

1. O que é o AWS CDK ?

CloudFormation é como preencher manualmente um formulário administrativo CERFA, campo por campo, seguindo regras de sintaxe rigorosas. É cansativo, mas funciona. O CDK é ter um programa que preenche esse formulário para você: você diz em Python “quero um servidor de tamanho médio com um banco de dados” e ele gera automaticamente o formulário CERFA completo, corretamente preenchido, com todos os campos obrigatórios. Você escreve muito menos, faz muito mais e aproveita todo o poder de uma linguagem de programação real, como loops, funções e reutilização de código.

O AWS Cloud Development Kit (CDK) é um framework open-source que permite definir sua infraestrutura AWS com uma linguagem de programação real: Python, TypeScript, Java, C# ou Go. O CDK gera automaticamente templates CloudFormation a partir do seu código.

NOTEO princípio : você escreve Python (ou TypeScript, etc.), o CDK compila esse código em um template CloudFormation válido, depois o CloudFormation implanta os recursos AWS. Você aproveita todo o poder de uma linguagem real (loops, condições, funções, herança) para descrever sua infraestrutura.

CDK vs CloudFormation — comparação

CritérioCloudFormation (YAML)AWS CDK (Python)
LinguagemYAML / JSON declarativoPython, TypeScript, Java, C#, Go
ReutilizaçãoCopiar-colar, Nested StacksClasses, módulos, herança
Autocompletar no IDELimitado (YAML)Completo com tipos e documentação
LógicaCondições e mappings limitadosif/else, loops for, funções completas
TestesDifícilTestes unitários com pytest, jest
Curva de aprendizadoBaixa para YAML, mas verbosoExige conhecimento de uma linguagem de programação
Por baixo dos panosExecutado diretamente pelo CloudFormationGera CloudFormation e depois implanta

Os quatro conceitos fundamentais do CDK

App (Aplicação CDK)

O ponto de entrada de todo projeto CDK. Um App contém uma ou mais Stacks. É o contêiner raiz da sua infraestrutura.

Stack (Stack CDK)

Corresponde a uma stack CloudFormation. Contém Constructs (recursos AWS). Um App pode ter várias Stacks para diferentes ambientes.

Construct

O bloco de construção básico do CDK. Representa um recurso AWS (ou um grupo de recursos). Existe em três níveis: L1, L2, L3.

Environment (Env)

A combinação de conta AWS + região de destino para a implantação. Permite implantar a mesma stack em vários ambientes.

2. Instalação — Node.js, CDK CLI e Python

O CDK CLI é uma ferramenta Node.js. Mesmo programando em Python, você precisa ter o Node.js instalado.

Pré-requisitos

bash
# 1. Verificar Node.js (versão 18+ recomendada)
node --version
bash
# Bootstrap na região atual
cdk bootstrap

# Bootstrap em uma região específica
cdk bootstrap aws://123456789012/eu-west-1

Os Constructs são os blocos básicos do CDK. Existem em três níveis de abstração, cada um oferecendo um compromisso diferente entre controle e simplicidade.

L1 — Constructs de baixo nível (CfnXxx)

Os constructs L1 (prefixados com Cfn) são wrappers diretos em torno dos recursos CloudFormation. Eles dão acesso a todas as propriedades, mas sem valores padrão — você deve configurar tudo explicitamente.

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 direto 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 de alto nível (recomendados)

Nested Stacks, StackSets, Change Sets e Boas Práticas

Capítulo 02 — Lição 03 · AWS DevOps : Infraestrutura como Código

1. Nested Stacks — decompor grandes infraestruturas

Imagine a construção de um prédio de escritórios. Em vez de um único empreiteiro fazer tudo do zero e ficar sobrecarregado, recorremos a especialistas independentes: um eletricista para toda a rede elétrica, um encanador para a hidráulica, um carpinteiro para as divisórias, um técnico de rede para a TI. Cada um trabalha em sua área, produz seu relatório e um mestre de obras coordena o conjunto. As Nested Stacks funcionam da mesma forma: cada módulo (rede, segurança, banco de dados, aplicação) é um template independente gerenciado por equipes diferentes, e uma stack pai coordena todos.

Quando uma infraestrutura se torna complexa (VPC, bancos de dados, aplicações, segurança...), agrupar tudo em um único template fica inviável. As Nested Stacks (stacks aninhadas) permitem dividir a infraestrutura em módulos reutilizáveis, cada um em seu próprio template.

Arquitetura em camadas com as 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

A stack pai que referencia os módulos

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

Exemplo do template módulo 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"

Implantar com os templates armazenados no 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
TIPVantagens das Nested Stacks : modularidade (cada módulo é independente), reutilização (o mesmo módulo de rede para dev e prod), legibilidade (os templates permanecem curtos) e limite do CloudFormation (máximo de 500 recursos por stack — as nested stacks contornam esse limite).

2. StackSets — implantar em várias contas e regiões

Imagine uma rede de restaurantes que abre filiais pelo mundo. O diretor-geral cria uma receita de menu padrão, uma identidade visual e procedimentos operacionais que se aplicam em todos os restaurantes, seja em Paris, Nova York ou Tóquio. Quando uma nova regra é adicionada (nova alergia a informar, novo regulamento sanitário), ela é aplicada simultaneamente em todos os restaurantes da rede com uma única decisão central. Os StackSets funcionam da mesma forma: você define sua infraestrutura uma única vez e a implanta em todas as suas contas AWS e todas as regiões em uma única operação.

Os StackSets permitem implantar o mesmo template CloudFormation em várias contas AWS e/ou várias regiões em uma única operação. É a ferramenta ideal para organizações com múltiplas contas (Landing Zone, Control Tower).

Casos de uso típicos

Governança centralizada

Implantar regras AWS Config, CloudTrail, GuardDuty em todas as contas da organização automaticamente.

Conformidade uniforme

Aplicar as mesmas políticas IAM, grupos de segurança básicos e notificações de alerta em cada conta.

Multi-região

Implantar uma infraestrutura idêntica em us-east-1, eu-west-1 e ap-southeast-1 para redundância global.

Pré-requisito: configurar as permissões

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

Criar e implantar um StackSet

Implantar e gerenciar aplicações no EKS

Capítulo 08 — Kubernetes na AWS EKS | AWS DevOps Infrastructure as Code

1. Implantar uma aplicação — Deployment YAML

Um Deployment Kubernetes é como uma cadeia de fast-food. Você define quantos “balcões” (réplicas) quer abertos ao mesmo tempo. Se um cair, o Kubernetes abre outro automaticamente sem que os clientes percebam. Quando você quer mudar o cardápio (nova versão da imagem), o Kubernetes atualiza os balcões um a um (rolling update) para nunca fechar todos os balcões ao mesmo tempo. Se o novo cardápio não agradar, é possível voltar ao anterior imediatamente (rollback).

Um Deployment Kubernetes declara o estado desejado da sua aplicação: qual imagem usar, quantas réplicas, como realizar as atualizações. O Kubernetes mantém esse estado permanentemente.

Deployment completo com todas as boas práticas

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

Comandos essenciais de implantação

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. Serviços Kubernetes : ClusterIP, NodePort, LoadBalancer

No Kubernetes, os Services são como endereços postais estáveis em um prédio cujos inquilinos mudam com frequência. ClusterIP é como uma sala interna no prédio: ninguém de fora pode acessá-la, é para comunicação entre funcionários. LoadBalancer é a porta de entrada principal do prédio com um agente de segurança (o Load Balancer AWS) que direciona os visitantes externos para a sala correta disponível. Mesmo que os inquilinos mudem (os Pods reiniciem), o endereço do prédio permanece o mesmo.

Um Service expõe um conjunto de Pods por meio de um IP estável e um nome DNS interno, independentemente do ciclo de vida dos Pods individuais.

TipoAcessibilidadeCaso de uso
ClusterIP Apenas dentro do cluster Comunicação entre serviços (banco de dados, cache)
NodePort De fora via IP do Node + porta fixa (30000-32767) Testes, desenvolvimento (não recomendado em produção)
LoadBalancer De fora via Load Balancer AWS (CLB/NLB) provisionado automaticamente Expor um serviço diretamente (sem Ingress)
ExternalName Resolve para um nome DNS externo Acessar serviços RDS, ElastiCache via nome interno
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 e Secrets Kubernetes

ConfigMap — configuração não sensível

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"
WARNINGAtenção : Por padrão, os Secrets Kubernetes são apenas codificados em base64 (não criptografados) no etcd. Para maior segurança no EKS, ative a criptografia de Secrets com uma chave KMS e considere usar o AWS Secrets Manager + External Secrets Operator para sincronizar os segredos automaticamente.

External Secrets Operator — sincronizar a partir do 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

Este artigo cobre os trechos mais úteis — o curso completo AWS DevOps Infrastructure Code (10 capítulos, 39 lições, exercícios corrigidos e projeto final) leva você até o fim.

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

FAQ

Quanto tempo para aprender AWS DevOps Infrastructure Code ?
Com uma progressão estruturada (10 capítulos, 39 lições curtas e práticas), você atinge um nível operacional em algumas semanas, dedicando 30 a 60 minutos por dia. O importante é praticar cada conceito imediatamente.
É preciso ter pré-requisitos ?
É melhor estar confortável com os fundamentos da área: este conteúdo vai em profundidade, com casos reais.
Por onde começar na prática ?
Reproduza os comandos deste artigo e depois siga o curso completo AWS DevOps Infrastructure Code: ele encadeia as 39 lições em ordem, com exercícios e projeto final.

📬 Quer receber este tipo de guia toda semana? Inscreva-se gratuitamente — código real, zero enrolação.