Los primeros contenedores
Buenas prácticas y troubleshooting
Escribir templates que se puedan mantener
Un template funciona o no funciona, pero entre dos templates que funcionan hay una gran diferencia de calidad: uno se entiende y se modifica con confianza, el otro es un campo minado. Estas son las prácticas que separan a uno del otro.
Nombres lógicos descriptivos
El nombre lógico de un recurso es para las personas que leen el template. TablaApp o
ServicioApp dicen qué es el recurso; Resource1 o MyTable2 no dicen nada. Como el
nombre lógico es además cómo el resto del template se refiere al recurso con !Ref, un
buen nombre hace legible cada conexión.
Dejar que AWS genere los nombres físicos
Salvo que haya una razón concreta, no se fija el nombre físico de un recurso (TableName,
RoleName, etc.). Si se deja sin especificar, CloudFormation genera uno único. Esto
evita un problema común: lanzar el mismo template dos veces y que falle porque el nombre
físico ya existe.
Parámetros con valores por defecto
Un parámetro con Default documenta el valor habitual y permite lanzar el stack sin
tener que completarlo cada vez. Se reservan los parámetros sin default para lo que de verdad
cambia entre lanzamientos —como el ImageUri del template.
Parameters:
DesiredCount:
Type: Number
Default: 1
Description: Número de tareas en ejecución.
DeletionPolicy para lo que no debe perderse
Por defecto, borrar un stack borra todos sus recursos. Para los que guardan datos —una
tabla, un bucket— eso puede ser un desastre. DeletionPolicy: Retain indica a
CloudFormation conservar el recurso aunque se borre el stack.
TablaApp:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain
Nunca modificar a mano, desde la consola, un recurso que gestiona un stack. El template y la realidad dejan de coincidir —eso es drift— y la próxima actualización del stack puede revertir el cambio sin avisar. Si un recurso lo gestiona un stack, cambiarlo solo a través del stack.
Los outputs son un contrato
La sección Outputs es la interfaz pública del stack: lo que expone para que otros lo
usen. La URL del ALB es un output porque alguien —otro stack, un script, una persona— necesita
ese valor sin tener que entrar a buscarlo. Los outputs son un contrato: se nombran
con claridad y se expone lo que realmente se consume desde afuera.
Buenas prácticas, en una línea
- Nombres lógicos descriptivos.
- Deje que AWS genere los nombres físicos.
- Parámetros con
Defaultpara lo habitual. DeletionPolicy: Retainpara los datos.- Nunca edite a mano un recurso gestionado por un stack.
Troubleshooting: leer un fallo
Tarde o temprano un stack falla. Saber leer el fallo es lo que convierte media hora de frustración en dos minutos de diagnóstico.
El primer evento fallido es la causa
Cuando un stack entra en ROLLBACK_IN_PROGRESS, la pestaña Events se llena de
mensajes: el recurso que falló, y luego todos los que se deshacen en el rollback. El
ruido del rollback puede esconder la causa real.
La técnica: ordene los eventos por tiempo y busque el primer evento con estado
CREATE_FAILED (o UPDATE_FAILED). Ese, y no los posteriores, contiene el motivo real
—el resto son consecuencias. La columna de razón (status reason) suele decir
exactamente qué pasó.
Fallos comunes y qué los causa
| Síntoma | Causa habitual |
|---|---|
requires capabilities: [CAPABILITY_IAM] | El template crea roles de IAM; falta marcar la casilla de capacidades al lanzar. |
already exists | Colisión de nombre físico: el recurso ya existe (a menudo, por fijar un nombre a mano). |
is not authorized to perform | Permisos insuficientes en el usuario o rol que lanza el stack. |
limit exceeded | Se alcanzó un límite de la cuenta (por ejemplo, número de VPC o de EIP). |
La primera fila explica la casilla de capacidades que marcó en la Semana 1: no era un trámite, era CloudFormation pidiendo permiso explícito para crear roles de IAM.
Validar el template antes de lanzarlo
La herramienta de línea de comandos cfn-lint revisa un template en busca de errores
de sintaxis, propiedades inválidas, y referencias rotas, sin necesidad de lanzar nada.
Integrada en el editor o en el pipeline, atrapa la mayoría de los errores antes de llegar
a la consola. La consola también ofrece un botón Validate que hace una verificación
básica de sintaxis al subir el template.
Los primeros contenedores — ECS y Fargate
Del recurso en el template al contenedor en ejecución
En el template se ven tres recursos relacionados: un clúster, un servicio, y una task definition. Esta sección los explica como lo que son cuando el stack ya corre: las piezas que mantienen el contenedor vivo y accesible. Al terminar, se los reconoce en la consola de ECS y se entiende qué hace cada uno.
El modelo de ECS
Amazon ECS (Elastic Container Service) es el orquestador de contenedores de AWS: decide dónde corren los contenedores, los mantiene en ejecución, y los reemplaza si fallan. Tres conceptos lo estructuran.
ECS en tres piezas
| Pieza | Qué es |
|---|---|
| Clúster | El espacio lógico donde corren las tareas. |
| Task definition | La plantilla de ejecución de un contenedor (imagen, CPU, memoria, puertos). |
| Service | El controlador que mantiene N tareas vivas y las reemplaza si caen. |
El clúster
El clúster es la agrupación lógica donde viven las tareas. Con Fargate no contiene servidores que administrar —es solo el contexto bajo el cual ECS organiza lo que corre. En la consola, se accede desde ECS → Clusters.
La task definition
La task definition es la plantilla de ejecución de un contenedor: el documento que dice cómo es una tarea. Sus campos principales:
- Imagen: el URI en ECR de la imagen a ejecutar (el que llega vía el parámetro
ImageUri). - CPU y memoria: los recursos reservados (en su template,
256CPU y512MB). - Puertos (port mappings): el puerto que el contenedor expone (
8080). - Rol de ejecución: el rol de IAM que permite a Fargate descargar la imagen de ECR y escribir logs.
- Configuración de logs: a qué grupo de CloudWatch Logs envía la salida del contenedor.
- Variables de entorno: pares clave-valor inyectados al contenedor en tiempo de ejecución. Hay dos formas de pasarlos, y la diferencia importa.
Variables de entorno vs. secretos en una task definition
La task definition tiene dos campos distintos para configurar el contenedor con valores en tiempo de ejecución:
environment — texto plano, almacenado dentro de la task definition:
"environment": [
{ "name": "CB_APPS_GATED", "value": "all" }
]
secrets — referencia a un secreto en AWS Secrets Manager (o SSM Parameter
Store); ECS lo resuelve y lo inyecta al arrancar la tarea:
"secrets": [
{
"name": "CB_APPS_SECRET",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:cb-apps-secret-AbCdEf"
}
]
El contenedor recibe CB_APPS_SECRET igual que una variable de entorno normal,
pero el valor nunca queda escrito en la task definition.
Por qué el texto plano es un problema. Una tarea definida con environment
expone su valor en cualquier lugar donde la task definition sea legible:
aws ecs describe-task-definitionlo devuelve en claro.- La consola de ECS lo muestra en la pestaña de configuración del contenedor.
- Un template de CloudFormation con el valor hardcodeado queda en el repositorio.
Para un secreto de acceso —como CB_APPS_SECRET, la clave que desbloquea los
escenarios del taller— el texto plano significa que cualquier persona con permiso
ecs:DescribeTaskDefinition puede leerlo.
Con secrets + valueFrom, el valor vive en Secrets Manager. La task definition
solo guarda el ARN. Para leerlo hace falta permiso sobre Secrets Manager, no sobre
ECS.
Requisito de IAM. El execution role de la tarea debe tener permiso
secretsmanager:GetSecretValue (o ssm:GetParameters) sobre el recurso
referenciado. ECS usa ese rol —no el task role— al resolver secretos antes de
lanzar el contenedor.
Las task definitions son versionadas: cada cambio crea una nueva revisión
(taller:1, taller:2, …). Esto permite saber exactamente qué configuración está
corriendo, y volver a una anterior si hace falta.
El service
El service es el controlador que mantiene el número deseado de tareas en ejecución.
Es lo que cambió en la sección anterior cuando subió DesiredCount a 2. Sus
responsabilidades:
- Lanzar tantas tareas como indique
DesiredCount, a partir de la task definition. - Vigilarlas: si una tarea falla o termina, lanzar una de reemplazo.
- Registrar las tareas en el target group del balanceador, para que reciban tráfico.
La distinción clave: la task definition describe cómo es una tarea; el service decide cuántas hay y las mantiene vivas.
flowchart TD CL["Clúster ECS"] --> SV["Service<br/>(DesiredCount = 2)"] TD["Task definition<br/>imagen · CPU · memoria · puertos"] -.->|plantilla| SV SV --> T1["Tarea 1 (RUNNING)"] SV --> T2["Tarea 2 (RUNNING)"] SV -->|registra| TG["Target Group del ALB"]
Fargate vs. EC2: ¿quién pone los servidores?
ECS puede ejecutar tareas de dos formas. Con el tipo de lanzamiento EC2, se administra una flota de servidores donde corren los contenedores. Con Fargate, AWS pone y administra esa capacidad: se especifican CPU y memoria por tarea, y no hay servidores que mantener. Este taller usa Fargate porque elimina la administración de servidores —el foco queda en la aplicación, no en la infraestructura que la ejecuta.
Práctica guiada: reconocer las piezas en la consola
Abrir el clúster
- Abrir ECS y seleccionar el clúster.
- En la pestaña Services, aparece el servicio con la cuenta de tareas deseadas y en
ejecución (ahora
2).
Inspeccionar el servicio y sus tareas
- Pulsar sobre el nombre del servicio.
- En la pestaña Tasks, aparecen las tareas en estado
RUNNING. Pulsar una de ellas. - En el detalle de la tarea, localizar la task definition que la originó (con su número de revisión) y el grupo de logs al que escribe.
Leer la task definition
- Pulsar sobre el nombre de la task definition para abrir la revisión.
- Identificar la imagen (el URI de ECR), la CPU y memoria, y el port mapping —los mismos valores del template.
Ejercicio 11 — Reconocer lo que está corriendo
Desde la consola de ECS, identificar para la aplicación: la tarea en ejecución, la revisión de la task definition que la originó, el URI de la imagen que ejecuta, y el grupo de CloudWatch Logs al que escribe.
- Abrir ECS → Clusters y seleccionar el clúster.
- Entrar al servicio y abrir la pestaña Tasks. Pulsar una tarea en estado
RUNNING. - En el detalle de la tarea, anotar:
- La task definition y su número de revisión (por ejemplo,
taller:2). - El grupo de logs (Log group), bajo la sección de logs del contenedor.
- La task definition y su número de revisión (por ejemplo,
- Pulsar la task definition para abrir la revisión, y localizar en el contenedor:
- La imagen: el URI de ECR con su etiqueta (el mismo pasado como
ImageUri). - La CPU y memoria reservadas.
- La imagen: el URI de ECR con su etiqueta (el mismo pasado como
- Comprobar que estos valores coinciden con los del template
taller-semana1.yaml: el recurso del template y el contenedor en ejecución son la misma cosa, vista desde dos lados.
Dónde estamos
Al cerrar la Semana 2, la caja negra ya no es una caja negra:
- Lee un template de CloudFormation: reconoce sus secciones, sigue las funciones intrínsecas, y conecta cada recurso con lo que ve en la consola.
- Actualiza el stack con seguridad, usando change sets para ver el cambio antes de aplicarlo, y sabe leer un fallo desde la pestaña de eventos.
- Entiende los contenedores por dentro: el clúster, la task definition que describe cada tarea, y el servicio que las mantiene vivas y las pone detrás del balanceador.
Pasó de lanzar el ambiente a entenderlo y modificarlo.
Qué sigue en la Semana 3
La próxima semana se opera y automatiza lo que ya se entiende:
- Operar el workload: la red que conecta el balanceador con las tareas, el escalado automático, y el troubleshooting cuando una tarea no arranca.
- Automatizar el flujo completo con CodePipeline: del commit al despliegue, con disparo automático y una etapa de aprobación manual —y las notificaciones a Teams que adelantamos en la Semana 1.
- Abrir la observabilidad con las métricas y los logs de CloudWatch.
Llegará al final de la Semana 3 con el ciclo de entrega automatizado y los primeros ojos puestos sobre cómo se comporta el sistema en ejecución.