AWS DevOps Infrastructure Code: los 9 pasos clave para pasar de cero a operativo
AWS DevOps Infrastructure Code: lo esencial en un artículo — código real, diagramas y pasos concretos, extractos de un curso de 39 lecciones.
Todo el mundo puede aprender AWS DevOps Infrastructure Code — siempre que siga los pasos en el orden correcto. Hemos condensado un curso completo de 39 lecciones en un recorrido claro, con los extractos de código más útiles.
- Introducción y Configuración de AWS
- DevOps e Infraestructura como Código
- AWS CloudFormation
- AWS CDK Cloud Development Kit
- CICD con AWS CodePipeline
Introducción a AWS CDK — Cloud Development Kit
Capítulo 03 — Lección 01 · AWS DevOps : Infraestructura como Código
1. ¿Qué es AWS CDK?
CloudFormation es como rellenar un formulario administrativo CERFA a mano, casilla por casilla, respetando reglas de sintaxis estrictas. Es tedioso pero funciona. El CDK es tener un programa informático que rellena ese formulario por ti: le dices en Python «quiero un servidor de tamaño medio con una base de datos» y genera automáticamente el formulario CERFA completo, correctamente rellenado, con todas las casillas obligatorias. Escribes mucho menos, haces mucho más y aprovechas toda la potencia de un lenguaje de programación real como bucles, funciones y reutilización de código.
El AWS Cloud Development Kit (CDK) es un framework de código abierto que permite definir tu infraestructura AWS con un lenguaje de programación real: Python, TypeScript, Java, C# o Go. El CDK genera automáticamente plantillas CloudFormation a partir de tu código.
CDK vs CloudFormation — comparación
| Criterio | CloudFormation (YAML) | AWS CDK (Python) |
|---|---|---|
| Lenguaje | YAML / JSON declarativo | Python, TypeScript, Java, C#, Go |
| Reutilización | Copiar-pegar, Nested Stacks | Clases, módulos, herencia |
| Autocompletado IDE | Limitado (YAML) | Completo con tipos y documentación |
| Lógica | Condiciones y mapeos limitados | if/else, bucles for, funciones completas |
| Pruebas | Difícil | Pruebas unitarias con pytest, jest |
| Curva de aprendizaje | Baja para YAML, pero verboso | Requiere conocimiento de un lenguaje de programación |
| Bajo el capó | Ejecutado directamente por CloudFormation | Genera CloudFormation y luego lo despliega |
Los cuatro conceptos fundamentales del CDK
App (Aplicación CDK)
El punto de entrada de todo proyecto CDK. Una App contiene una o varias Stacks. Es el contenedor raíz de tu infraestructura.
Stack (Pila CDK)
Corresponde a una stack CloudFormation. Contiene Constructs (recursos AWS). Una App puede tener varias Stacks para diferentes entornos.
Construct
El bloque de construcción básico del CDK. Representa un recurso AWS (o un grupo de recursos). Existe en tres niveles: L1, L2, L3.
Environment (Entorno)
La combinación de cuenta AWS + región de destino para el despliegue. Permite desplegar la misma stack en varios entornos.
2. Instalación — Node.js, CDK CLI y Python
El CDK CLI es una herramienta Node.js. Aunque programes en Python, debes tener Node.js instalado.
Requisitos previos
# 1. Verificar Node.js (versión 18+ recomendada) node --version
# Bootstrap en la región actual cdk bootstrap # Bootstrap en una región específica cdk bootstrap aws://123456789012/eu-west-1
Los Constructs son los bloques básicos del CDK. Existen en tres niveles de abstracción, cada uno ofreciendo un compromiso diferente entre control y simplicidad.
L1 — Constructs de bajo nivel (CfnXxx)
Los constructs L1 (prefijados con Cfn) son envoltorios directos de los recursos CloudFormation. Dan acceso a todas las propiedades pero sin valores predeterminados: debes configurarlo todo explícitamente.
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 de alto nivel (recomendados)
Nested Stacks, StackSets, Change Sets y Buenas Prácticas
Capítulo 02 — Lección 03 · AWS DevOps : Infraestructura como Código
1. Nested Stacks — descomponer grandes infraestructuras
Imagina la construcción de un edificio de oficinas. En lugar de que un solo contratista lo haga todo de principio a fin y se vea rápidamente superado, se recurre a especialistas independientes: un electricista para toda la red eléctrica, un fontanero para la fontanería, un carpintero para los tabiques, un técnico de redes para la informática. Cada uno trabaja en su ámbito, produce su informe de trabajo y un jefe de obra coordina el conjunto. Las Nested Stacks funcionan de la misma manera: cada módulo (red, seguridad, base de datos, aplicación) es una plantilla independiente gestionada por un equipo diferente, y una stack padre coordina a todos.
Cuando una infraestructura se vuelve compleja (VPC, bases de datos, aplicaciones, seguridad...), agrupar todo en una sola plantilla se vuelve inmanejable. Las Nested Stacks (pilas anidadas) permiten dividir la infraestructura en módulos reutilizables, cada uno en su propia plantilla.
Arquitectura en capas con las Nested Stacks
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 padre que referencia los módulos
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.URLLoadBalancerEjemplo de la plantilla módulo reseau.yaml
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"Desplegar con las plantillas almacenadas en S3
# 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_IAM2. StackSets — desplegar en varias cuentas y regiones
Imagina una cadena de restaurantes que abre sucursales en todo el mundo. El director general crea una receta de menú estándar, una carta gráfica y procedimientos de funcionamiento que se aplican en todos los restaurantes, ya estén en París, Nueva York o Tokio. Cuando se añade una nueva norma (nueva alergia que mostrar, nuevo reglamento sanitario), se aplica simultáneamente en todos los restaurantes de la cadena con una única decisión central. Los StackSets funcionan igual: defines tu infraestructura una sola vez y la despliegas en todas tus cuentas AWS y todas tus regiones en una sola operación.
Los StackSets permiten desplegar la misma plantilla CloudFormation en varias cuentas AWS y/o varias regiones en una sola operación. Es la herramienta ideal para organizaciones con varias cuentas (Landing Zone, Control Tower).
Casos de uso típicos
Gobernanza centralizada
Desplegar reglas de AWS Config, CloudTrail, GuardDuty en todas las cuentas de la organización automáticamente.
Conformidad uniforme
Aplicar las mismas políticas IAM, grupos de seguridad básicos y notificaciones de alerta en cada cuenta.
Multirregión
Desplegar una infraestructura idéntica en us-east-1, eu-west-1 y ap-southeast-1 para la redundancia global.
Requisitos previos: configurar los permisos
# 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
Crear y desplegar un StackSet
Desplegar y gestionar aplicaciones en EKS
Capítulo 08 — Kubernetes en AWS EKS | AWS DevOps Infrastructure as Code
1. Desplegar una aplicación — Deployment YAML
Un Deployment de Kubernetes es como una cadena de comida rápida. Defines cuántos «mostradores» (replicas) quieres abiertos al mismo tiempo. Si uno falla, Kubernetes abre uno nuevo automáticamente sin que los clientes se den cuenta. Cuando quieres cambiar el menú (nueva versión de la imagen), Kubernetes actualiza los mostradores uno a uno (rolling update) para no cerrar nunca todos los mostradores al mismo tiempo. Si el nuevo menú no gusta, se puede volver al menú anterior inmediatamente (rollback).
Un Deployment de Kubernetes declara el estado deseado de tu aplicación: qué imagen usar, cuántas réplicas, cómo realizar las actualizaciones. Kubernetes mantiene ese estado permanentemente.
Deployment completo con todas las buenas prácticas
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-fastapiComandos de despliegue esenciales
# 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. Servicios Kubernetes: ClusterIP, NodePort, LoadBalancer
En Kubernetes, los Services son como direcciones postales estables en un edificio cuyos inquilinos cambian a menudo. ClusterIP es una oficina interna en el edificio: nadie del exterior puede acceder, es para la comunicación entre empleados. LoadBalancer es la puerta principal del edificio con un agente de seguridad (el Load Balancer AWS) que dirige a los visitantes externos a la oficina disponible correcta. Aunque los inquilinos cambien (los Pods se reinician), la dirección del edificio sigue siendo la misma.
Un Service expone un conjunto de Pods mediante una IP estable y un nombre DNS interno, independientemente del ciclo de vida de los Pods individuales.
| Tipo | Accesibilidad | Caso de uso |
|---|---|---|
| ClusterIP | Solo dentro del clúster | Comunicación entre servicios (base de datos, caché) |
| NodePort | Desde el exterior mediante la IP del Node + un puerto fijo (30000-32767) | Pruebas, desarrollo (no recomendado en producción) |
| LoadBalancer | Desde el exterior mediante un Load Balancer AWS (CLB/NLB) aprovisionado automáticamente | Exponer un servicio directamente (sin Ingress) |
| ExternalName | Resuelve a un nombre DNS externo | Acceder a servicios RDS, ElastiCache mediante un nombre interno |
---
# 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: 80803. ConfigMaps y Secrets de Kubernetes
ConfigMap — configuración no sensible
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: 300Secret de Kubernetes
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"
External Secrets Operator — sincronizar desde Secrets Manager
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"Este artículo cubre los extractos más útiles: el curso completo AWS DevOps Infrastructure Code (10 capítulos, 39 lecciones, ejercicios corregidos y proyecto final) te lleva hasta el final.
./acceder-au-cours-complet curso gratuito: Dominar Claude CodeFAQ
¿Cuánto tiempo se tarda en aprender AWS DevOps Infrastructure Code?
¿Se necesitan requisitos previos?
¿Por dónde empezar concretamente?
📬 ¿Quieres recibir este tipo de guía cada semana? Suscríbete gratis — código real, cero palabrería.