Hace unas semanas me cansé de entrar manualmente a la página de AWS What's New para ver qué habían lanzado. Así que hice lo que cualquier persona razonable haría: construí una app, la metí en Docker y la subí a ECS. En este artículo te cuento exactamente cómo, con todos los comandos y sin saltarme pasos.
¿Qué vamos a construir?
Una pequeña app web en Python (Flask) que consume el RSS público de AWS y muestra las últimas novedades clasificadas por categoría (AI/ML, Seguridad, Data, FinOps, CloudOps). Tiene modo oscuro y claro, animaciones de entrada y muestra hace cuánto tiempo se publicó cada novedad.
El flujo completo es:
Código local → Docker image → Amazon ECR → Amazon ECS (Fargate) → URL pública
Repositorio: github.com/carotechie/docker-ecs-feedaws
Lo que necesitas antes de empezar
- Docker Desktop instalado y corriendo
- AWS CLI configurada (
aws configure) - Una cuenta de AWS con permisos para ECR y ECS
- Python 3.12+ (solo para desarrollo local)
1. La app: Flask + feedparser
El código principal es minimalista. app.py hace tres cosas: consume el RSS de AWS, limpia el HTML que viene en los summaries y detecta la categoría de cada novedad según sus palabras clave.
# app.py (fragmento)
AWS_RSS_URL = "https://aws.amazon.com/about-aws/whats-new/recent/feed/"
@app.route("/")
def index():
feed = feedparser.parse(AWS_RSS_URL)
# ...procesa y clasifica cada entrada
return render_template("index.html", items=items, fetched_at=fetched_at)
No hay base de datos, no hay caché. Cada vez que alguien entra a la URL, la app hace un request al RSS de AWS en ese instante. Simple y siempre actualizado.
Las dependencias van en requirements.txt:
flask==3.1.1
feedparser==6.0.11
gunicorn==23.0.0
2. El Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "app:app"]
Nada del otro mundo. Usamos python:3.12-slim para mantener la imagen liviana y gunicorn como servidor WSGI (más robusto que el servidor de desarrollo de Flask para producción).
Un detalle importante: copiamos requirements.txt antes que el resto del código. Esto aprovecha el caché de capas de Docker — si no cambias las dependencias, Docker reutiliza esa capa y el build es mucho más rápido.
3. Probar localmente
# Construir la imagen
docker build -t mifeed-aws .
# Correr el contenedor
docker run -d -p 8080:8080 --name mifeed mifeed-aws
# Verificar que levantó
curl http://localhost:8080/health
# → {"status": "ok"}
Abre http://localhost:8080 en tu navegador y deberías ver algo así:
Para detenerlo:
docker stop mifeed && docker rm mifeed
4. Subir la imagen a Amazon ECR
Amazon ECR (Elastic Container Registry) es el registro privado de imágenes Docker de AWS. Piénsalo como un Docker Hub pero dentro de tu cuenta de AWS.
4.1 Crear el repositorio en ECR
aws ecr create-repository \
--repository-name demos/mifeed-aws \
--region us-east-1
El comando devuelve un JSON. Copia el valor de repositoryUri, lo vas a necesitar. Se ve así:
url.dkr.ecr.us-east-1.amazonaws.com/demos/mifeed-aws
4.2 Autenticarte con ECR
aws ecr get-login-password --region us-east-1 \
| docker login \
--username AWS \
--password-stdin \
url.dkr.ecr.us-east-1.amazonaws.com
Si ves Login Succeeded, estás lista para el siguiente paso.
4.3 Etiquetar y subir la imagen
ECR_URI=url.dkr.ecr.us-east-1.amazonaws.com/demos/mifeed-aws
# Etiquetar la imagen local con el URI de ECR
docker tag mifeed-aws:latest $ECR_URI:latest
# Subir al registro
docker push $ECR_URI:latest
El push puede tardar unos minutos la primera vez. Verás las capas subiendo una por una.
5. Configurar y desplegar en Amazon ECS
ECS (Elastic Container Service) es el servicio administrado de AWS para correr contenedores. Usaremos Fargate, que es el modo serverless: no tienes que gestionar servidores ni instancias EC2.
El flujo en ECS tiene tres piezas:
Task Definition → Cluster → Service
(qué correr) (dónde) (cuántas copias y cómo)
5.1 Crear el Cluster
Ve a la consola de AWS → ECS → Clusters → Create Cluster.
Configuración:
-
Cluster name:
mifeed-aws - Infrastructure: AWS Fargate (serverless)
- Deja el resto por defecto y haz clic en Create
5.2 Crear la Task Definition
La Task Definition le dice a ECS qué imagen correr, cuánta CPU/memoria usar y en qué puerto escucha.
Ve a Task Definitions → Create new task definition.
Configuración:
-
Task definition family:
mifeed-aws - Launch type: AWS Fargate
- CPU: 0.25 vCPU
- Memory: 0.5 GB
-
Container name:
mifeed-aws -
Image URI:
url.dkr.ecr.us-east-1.amazonaws.com/demos/mifeed-aws:latest -
Container port:
8080 - Protocol: TCP
Haz clic en Create.
5.3 Crear el Service
El Service mantiene corriendo el número de Tasks que definas y las reinicia si fallan.
En tu cluster mifeed-aws → pestaña Services → Create.
Configuración:
-
Family:
mifeed-aws -
Service name:
mifeed-service -
Desired tasks:
1 - Launch type: Fargate
- VPC: la VPC por defecto está bien para empezar
- Subnets: selecciona al menos 2 subnets públicas
- Security group: crea uno nuevo (o usa uno existente) con la siguiente regla de entrada:
| Tipo | Puerto | Origen |
|---|---|---|
| Custom TCP | 8080 | 0.0.0.0/0 |
- Public IP: Enabled ← importante, sin esto no tendrás IP pública
Haz clic en Create Service y espera unos minutos a que el Task pase a estado RUNNING.
6. Conectarme a mi aplicación
Una vez que el Task está en RUNNING, la app ya está viva en internet.
Obtener la IP pública
En la consola: Clusters → mifeed-aws → Tasks → clic en el Task ID → busca la sección Network → copia la Public IP.
Abre en tu navegador:
http://<PUBLIC_IP>:8080
Y deberías ver tu feed funcionando en la nube:
Verificar el health check
curl http://<PUBLIC_IP>:8080/health
# → {"status": "ok"}
¿Y las actualizaciones automáticas?
La app no necesita ninguna configuración especial. Como el feed se parsea en cada request, cada vez que alguien carga la página obtiene los datos más recientes de AWS. El contenedor puede estar corriendo semanas sin ningún reinicio y el feed siempre estará actualizado.
Si quieres que ECS descargue automáticamente una nueva versión de tu imagen cuando hagas cambios:
- Sube la nueva imagen a ECR con el mismo tag
latest - En ECS → tu Service → Update service → activa Force new deployment
- ECS descargará la nueva imagen y reemplazará el Task sin downtime
Reflexión final
Lo que me gustó de este ejercicio fue lo poco que tuve que tocar para pasar de "corre en mi máquina" a "corre en la nube":
- El
Dockerfileno cambió - La app no sabe si está en local o en ECS
- La única diferencia real es de dónde viene la imagen (local vs ECR)
Eso es exactamente lo que hace valioso a Docker en un contexto de nube. El artefacto que pruebas localmente es el mismo artefacto que corre en producción.
Próximos pasos
Si quisieras llevar esto a producción real, los siguientes pasos serían:
- Agregar un Load Balancer (ALB) para tener una URL fija en vez de una IP efímera
- Dominio propio con Route 53 y un certificado SSL en ACM
-
CI/CD con GitHub Actions para que cada push a
mainactualice la imagen en ECR y fuerce un nuevo deploy en ECS - Auto Scaling para que el servicio escale según la carga










Top comments (0)