|

Desplegar Docker en AWS sin EC2: guía ECR y ECS Fargate

En pocas palabras: Para desplegar un contenedor Docker en AWS sin administrar servidores, hay que construir la imagen con Docker, subirla a Amazon ECR y correrla con Amazon ECS usando AWS Fargate, que asigna vCPU y memoria (por ejemplo 0,25 vCPU / 0,5 GB) según la task definition del servicio.

Desplegar Docker en AWS sin tocar un servidor EC2 es posible combinando tres piezas: Docker para armar la imagen, Amazon ECR para guardarla y Amazon ECS con AWS Fargate para correrla. Podés tener un contenedor corriendo con IP pública, sin servers que parchear ni agentes que mantener.

Amazon ECS (Elastic Container Service) es el orquestador de contenedores de AWS que administra el ciclo de vida de tus tareas y servicios. AWS Fargate es el motor de cómputo serverless de ECS: pagás por la vCPU y la memoria que consume tu contenedor, sin aprovisionar instancias EC2. Amazon ECR es el registro privado donde subís y versionás las imágenes Docker antes de que ECS las descargue, según detalla la documentación oficial de Amazon ECS.

En resumen

  • Fargate corre contenedores sin EC2 que administrar: la CPU y la memoria se definen en la task definition (0.25 vCPU / 0.5 GB en el ejemplo de referencia).
  • El flujo completo es Dockerfile, build local, push a ECR, task definition y servicio en ECS, sin pasos intermedios ocultos.
  • Usar node:20-alpine como imagen base reduce el tamaño y la superficie de ataque del contenedor.
  • El error “exec format error” aparece cuando armás la imagen en Apple Silicon sin el flag --platform linux/amd64.
  • En producción nunca se usa el tag latest: versionar con v1, v2 permite hacer rollback sin drama.

ECS con Fargate vs EC2: ¿cuál conviene para correr contenedores sin administrar servidores?

Fargate conviene cuando no querés tocar instancias EC2: AWS aprovisiona, parchea y escala la infraestructura por debajo, y vos solo definís cuánta CPU y memoria necesita tu tarea. EC2 dentro de ECS conviene cuando necesitás control sobre el tipo de instancia, GPU específica o estás optimizando costos a gran escala con reservas.

El tema es que la mayoría de los proyectos chicos y medianos no necesitan ese control fino. Si tu app es un servicio stateless que escala horizontal, Fargate te saca de encima parcheo de AMIs, gestión del agente ECS y capacity planning. La guía de AWS describe tres capas en ECS: capacidad, controlador y provisioning, y Fargate resuelve la primera sin que vos intervengas.

AWS también sumó Amazon ECS Managed Instances como opción intermedia: corrés sobre instancias EC2 específicas (con GPU, por ejemplo) pero AWS se encarga del aprovisionamiento y el parcheo. No es Fargate ni es EC2 puro, es un punto medio para cargas que necesitan hardware particular sin que el equipo administre la capa de sistema operativo.

Criterio práctico para decidir: si podés responder “sí” a las tres preguntas siguientes, Fargate es la opción por defecto. ¿Tu contenedor es stateless (no guarda datos en disco local que necesites conservar)? ¿El tráfico es variable o bajo, sin necesidad de hardware específico como GPU? ¿El equipo que mantiene esto es chico y prefiere no tocar parches de sistema operativo? Si la respuesta a alguna es “no” —por ejemplo, necesitás GPU para inferencia de modelos o ya tenés instancias reservadas que amortizar—, ahí entra a jugar EC2 o la opción intermedia de Managed Instances.

AspectoAWS FargateAmazon EC2 (en ECS)
Gestión de servidoresNinguna, AWS la manejaVos elegís y administrás las instancias
Control de hardwareLimitado a vCPU/memoria por tareaTotal: tipo de instancia, GPU, spot
EscaladoPor tarea, automáticoRequiere Auto Scaling configurado
Mejor paraApps stateless, demos, equipos chicosCargas con requisitos de hardware específico
Modelo de costoPago por vCPU/memoria consumidaPago por instancia EC2 completa
desplegar docker en aws diagrama explicativo

¿Qué necesitás antes de desplegar Docker en AWS Fargate?

Necesitás cuatro cosas antes de arrancar: una cuenta de AWS, Docker instalado en tu máquina, la AWS CLI configurada y, opcionalmente, Node.js para probar la app fuera del contenedor. Con eso alcanza para seguir el tutorial de Vishal Patil en dev.to de punta a punta.

  • Cuenta de AWS: el nivel Free Tier alcanza perfectamente para esta prueba, no necesitás plan pago.
  • Docker instalado: para buildear la imagen local antes de subirla.
  • AWS CLI configurada: corré aws configure con tu Access Key y región default.
  • Node.js (opcional): solo si querés correr la app fuera de Docker para comparar comportamiento.

Cómo escribir un Dockerfile liviano y por qué usar node:20-alpine

Un Dockerfile liviano para Node.js arranca con node:20-alpine como base, copia primero package*.json, instala dependencias y recién después copia el resto del código. Esa secuencia aprovecha el cache de capas de Docker: si no cambiaste dependencias, el rebuild es casi instantáneo. Te puede servir nuestra cobertura de desplegar Coolify en una instancia EC2.

La imagen alpine pesa una fracción de lo que pesa la imagen completa de Node, así que los pulls son más rápidos y la superficie de ataque es menor (menos paquetes de sistema instalados, menos CVEs potenciales). El Dockerfile de referencia expone el puerto 3000 y arranca con CMD ["node", "app.js"].

Ojo con esto: si estás en una Mac con Apple Silicon, buildeá con --platform linux/amd64. Fargate corre en arquitectura estándar, y si no agregás ese flag la imagen se compila para ARM y después falla en producción con un error de arquitectura.

Ejemplo hipotético: de una API interna a Fargate en una tarde

Ejemplo hipotético, con fines ilustrativos: pensemos en un equipo de tres personas que tiene una API interna chica —un servicio que devuelve datos a otro sistema, sin estado que persistir en disco— corriendo hoy en una laptop o en un servidor que nadie actualiza hace meses. El objetivo es sacarla de ahí sin sumar la carga de mantener un EC2.

Siguiendo el orden del flujo descripto arriba, el camino sería: escribir el Dockerfile con node:20-alpine, probarlo local con docker run, crear el repositorio en ECR, pushear la imagen versionada como v1 (nunca latest), definir una task de 0.25 vCPU / 0.5 GB —de sobra para una API chica— y lanzar el servicio con IP pública solo para validar que responde. Si ese servicio después necesita estar disponible 24/7 para usuarios externos, el paso siguiente lógico es sacar la IP pública de la tarea y poner un Application Load Balancer delante, como se menciona en las buenas prácticas de más abajo. Para este equipo, el punto de decisión es simple: no tienen requisitos de GPU ni hardware específico, así que Fargate les ahorra justamente lo que no quieren hacer, que es mantener parches de sistema operativo.

Cómo subir la imagen Docker a Amazon ECR paso a paso

Subir una imagen a ECR implica cuatro comandos: crear el repositorio, autenticar Docker, tagear la imagen y hacer push. Todo corre desde la terminal con la AWS CLI ya configurada.

  • Crear el repositorio: aws ecr create-repository --repository-name my-docker-app --region ap-south-1 (cambiá la región según dónde operes).
  • Autenticar Docker contra ECR: aws ecr get-login-password --region ap-south-1 | docker login --username AWS --password-stdin <account-id>.dkr.ecr.ap-south-1.amazonaws.com.
  • Tagear la imagen local: docker tag my-docker-app:v1 <account-id>.dkr.ecr.ap-south-1.amazonaws.com/my-docker-app:v1.
  • Hacer push: docker push <account-id>.dkr.ecr.ap-south-1.amazonaws.com/my-docker-app:v1, y después verificás en la consola que la imagen quedó listada.

Reemplazá <account-id> por tu ID de cuenta de 12 dígitos. Si te equivocás en ese dato o en la región, el push falla con un error de autenticación que no siempre deja claro cuál fue el problema real. Cubrimos ese tema en detalle en automatizar el deploy de Docker Compose a EC2.

Cómo crear el cluster, la task definition y el servicio en ECS Fargate

Crear un contenedor corriendo en Fargate requiere tres piezas en orden: un cluster, una task definition y un servicio. Cada una se configura desde la consola de ECS sin tocar una sola línea de Terraform o CloudFormation si estás arrancando.

  • Cluster: en ECS, creás un cluster (por ejemplo docker-demo-cluster) y dejás seleccionada la infraestructura “AWS Fargate (serverless)”.
  • Task definition: es el blueprint del contenedor. Definís launch type Fargate, 0.25 vCPU / 0.5 GB de memoria, el ecsTaskExecutionRole (ECS lo crea solo si no existe), la URI de la imagen en ECR y el puerto 3000.
  • Servicio: dentro del cluster, creás el servicio con esa task definition, elegís VPC y subred pública, armás un security group que permita tráfico entrante en el puerto 3000 y activás la IP pública.

Con la tarea en estado Running, copiás la IP pública desde la sección de networking de la tarea y la abrís en el navegador en el puerto 3000. Ahí aparece la respuesta del contenedor, sin un solo servidor que vos hayas tenido que levantar a mano.

Errores comunes al desplegar en ECS Fargate y cómo solucionarlos

El error más común es que la tarea se detenga apenas arranca, y casi siempre la causa está en los logs de CloudWatch o en un CMD mal escrito en el Dockerfile. Los otros tres problemas típicos tienen solución igual de directa.

  • La tarea se detiene inmediatamente: revisá los logs del contenedor en CloudWatch y confirmá que el CMD del Dockerfile sea correcto.
  • No puede descargar la imagen: el execution role no tiene permisos sobre ECR, o hay un typo en la URI de la imagen.
  • La página no carga: el security group no permite el puerto 3000, o la IP pública de la tarea no está activada.
  • “exec format error”: la imagen se construyó para la arquitectura de CPU equivocada. Revisá el flag --platform linux/amd64 si venís de Apple Silicon.

¿Vale la pena perder tiempo en estos cuatro puntos antes de tocar nada más? Sí, porque cubren las causas más frecuentes de que una tarea de Fargate no arranque. Para más detalles técnicos, mirá desplegar una API NestJS en Lambda.

Buenas prácticas para producción: versionado, escaneo y costos

En producción, nunca se usa el tag latest. Versionar con tags como v1 y v2 permite hacer rollback inmediato si algo se rompe, en vez de intentar reconstruir qué imagen estaba corriendo antes.

  • Activá el escaneo de imágenes de ECR: detecta vulnerabilidades conocidas antes de que lleguen a producción.
  • Usá roles IAM de mínimo privilegio: el execution role de la tarea no necesita más permisos que los estrictamente necesarios para pullear imágenes y escribir logs.
  • Poné un Application Load Balancer delante: expone el servicio, no la IP pública de una tarea individual que puede cambiar en cada reinicio.
  • Mandá logs a CloudWatch con alarmas: así te enterás de una falla antes que el usuario.
  • Limpiá los recursos al terminar una prueba: poné el desired count del servicio en 0, borrá el servicio, el cluster, el repositorio de ECR y los security groups creados para la demo. Fargate cobra por lo que corre, no por lo que dejaste olvidado.

Si además necesitás un dominio o hosting para la parte web que acompaña a este backend en contenedores, donweb.com es una opción local para esa capa, separada de la infraestructura de AWS que armaste en ECS.

Preguntas Frecuentes

¿Cómo despliego un contenedor Docker en AWS sin usar EC2?

Usando Amazon ECS con AWS Fargate: subís la imagen a Amazon ECR, creás una task definition con el launch type Fargate y lanzás un servicio. AWS maneja la infraestructura de cómputo por debajo, sin que vos aprovisiones una sola instancia EC2.

¿Qué diferencia hay entre ECS con Fargate y ECS con EC2?

Con Fargate, AWS administra la infraestructura y vos solo definís vCPU y memoria por tarea. Con EC2, vos elegís el tipo de instancia, la cantidad y te hacés cargo del parcheo y el escalado de esas máquinas.

¿Cómo subo una imagen Docker a Amazon ECR?

Creás el repositorio con aws ecr create-repository, autenticás Docker con aws ecr get-login-password, tageás la imagen con docker tag y hacés docker push apuntando a la URI del repositorio en tu región. Ya lo cubrimos antes en publicar imágenes Docker con GitHub Actions.

¿Por qué mi tarea de ECS Fargate se detiene apenas arranca?

La causa más frecuente es un CMD mal escrito en el Dockerfile o un error en el arranque de la app que queda registrado en CloudWatch. Revisar esos logs resuelve la mayoría de los casos en minutos.

¿Cómo expongo públicamente un contenedor corriendo en Fargate?

Al crear el servicio, elegís una subred pública, activás la IP pública de la tarea y configurás un security group que permita tráfico entrante en el puerto del contenedor. Para producción, conviene poner un Application Load Balancer delante en vez de exponer la IP de la tarea directamente.

Conclusión

El patrón Dockerfile, ECR y ECS Fargate resuelve algo puntual: correr contenedores en AWS sin administrar servidores. Para una demo o un servicio chico, el flujo completo (build, push, task definition, servicio) se hace sin tocar una instancia EC2.

Lo que no resuelve por sí solo es la arquitectura de producción real. Un Application Load Balancer, auto scaling y un pipeline de CI/CD son el siguiente paso lógico, no un detalle opcional. Si vas a dejar esto corriendo más de una tarde, versioná las imágenes, activá el escaneo de ECR y no te olvides de limpiar los recursos de prueba antes de que la factura te lo recuerde.

Fuentes

Te puede interesar...