Arquitectura de Alta Disponibilidad: 24 Containers en Producción

Arquitectura de Alta Disponibilidad: 24 Containers en Producción

Arquitectura de Alta Disponibilidad: 24 Containers en Producción

Introducción

Cuando se escalan múltiples servicios en producción, la gestión de recursos se convierte en un arte. En este artículo exploramos una infraestructura real que maneja 24 containers Docker distribuidos en dos VPS, con uptime de hasta 124 días y optimización agresiva de memoria.

La arquitectura demuestra cómo es posible ejecutar 12 servicios simultáneos en apenas 7.8 GB de RAM, manteniendo disponibilidad del 83% en memoria y menos del 1% de uso de CPU en la mayoría de componentes.

Distribución de Carga: Dos VPS, Dos Estrategias

VPS1: Orquestación con Docker Swarm

El primer servidor ejecuta 12 containers activos usando Docker Swarm con Easypanel como panel de control. La distribución incluye:

  • Traefik como reverse proxy (34 MB RAM, 0.14% CPU)
  • 3 containers para un sistema CRM deportivo (PostgreSQL + API + nginx)
  • WhatsApp Business API con Evolution API (3 containers: app + PostgreSQL + Redis)
  • 2 aplicaciones cliente en puertos dedicados (5060, 5070)

La clave está en el uso de Traefik con file provider en lugar de Docker labels, permitiendo routing dinámico sin reiniciar el proxy.

VPS2: Simplicidad con Docker Compose

El segundo servidor, con el doble de RAM (15.6 GB), opera 12 containers usando Docker Compose directo:

services:
bot-api:
image: custom/bot-api
ports:
- "3000:3000"
bot-proxy:
image: custom/bot-proxy
ports:
- "3010:3010"

Esta configuración prioriza predictibilidad sobre flexibilidad, ideal para servicios críticos que requieren reinicio rápido.

Optimización de Recursos: El Arte de los Límites

Uno de los containers estudiados implementa límites estrictos:

deploy:
resources:
limits:
memory: 256M

Este contenedor CRM opera con apenas 28 MB de uso real contra un límite de 256 MB, demostrando que aplicaciones Flask bien optimizadas pueden servir interfaces React completas con consumo mínimo.

Estrategias de Despliegue Sin Downtime

Patrón 1: Bind Mounts para Hot Reload

Algunos containers usan bind mounts para actualizar código sin rebuild:

scp app.py vps:/opt/service/
docker restart service

Tiempo total de actualización: 3-5 segundos.

Patrón 2: Docker CP para Templates Cacheados

Cuando el framework cachea templates (Flask, Django), el patrón cambia:

docker cp chat.html container:/app/templates/
docker restart container

Esto invalida el cache interno sin reconstruir la imagen completa.

Patrón 3: Static HTML Deploy

Para SPAs con React/Babel in-browser:

scp index.html vps:/opt/service/public/

No restart needed - nginx sirve directamente

Downtime: 0 segundos.

Networking: Service Names vs Localhost

Un aprendizaje crítico en esta arquitectura:

❌ INCORRECTO en Docker networks

response = requests.post('http://localhost:3010/api')

✅ CORRECTO - usa service name

response = requests.post('http://bot-proxy:3010/api')

Docker Compose crea una red interna donde `localhost` apunta al propio container, no al host. Los service names resuelven automáticamente vía DNS interno.

Gestión de Uptime: 124 Días Sin Reinicio

El VPS1 mantiene 124 días de uptime continuo mediante:

  1. SSH en puerto no estándar (2222) - reduce ataques automatizados
  2. Fail2ban activo - 283 IPs baneadas acumuladas
  3. UFW configurado - solo puertos esenciales expuestos
  4. Actualizaciones sin reinicio - `apt-get upgrade` sin kernel updates

La estrategia de seguridad multicapa permite operar sin reiniciar el host, mientras los containers se actualizan individualmente.

Monitoreo de Recursos en Tiempo Real

La supervisión usa `docker stats` con formato personalizado:

docker stats --no-stream --format \
"table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}"

Esto genera snapshots exactos del consumo sin herramientas externas como Prometheus, ideal para infraestructuras pequeñas.

Reverse Proxy: Traefik File Provider vs Labels

File Provider (VPS1)

http:
routers:
varela-chat:
rule: "Host(`chat.varela.guru`)"
service: varela-chat
services:
varela-chat:
loadBalancer:
servers:
- url: "http://varela-chat:5000"
Ventajas: Actualizar routing sin reiniciar Traefik, ideal para Swarm.

Docker Labels (VPS2)

labels:
- "traefik.http.routers.bot.rule=Host(`bot.varelainsights.com`)"
- "traefik.http.services.bot.loadbalancer.server.port=3000"
Ventajas: Configuración junto al servicio, autodiscovery.

Estrategia de Backups: Apagar para Crecer

La arquitectura implementa "apagado estratégico":

  • OpenProject (4 containers) - removido, liberó ~800 MB
  • Metabase (2 containers) - removido, liberó 600 MB
  • Bot inactivo - removido, liberó ~200 MB

Total recuperado: 1.6 GB sin pérdida de datos (backups en `tar.gz`).

Esta estrategia permite escalar horizontalmente solo cuando es necesario, manteniendo costos bajos.

Lecciones de Arquitectura

1. RAM Sobre CPU

La mayoría de containers usan <1% CPU pero requieren RAM fija. Optimizar para memoria es más crítico que para procesamiento.

2. Timezone Matters

Todos los containers usan `TZ=America/Mexico_City`. Inconsistencias de timezone causan bugs sutiles en logs y cronjobs.

3. Port Mapping Inteligente

Puertos dedicados (5060, 5070) permiten múltiples instancias del mismo servicio sin conflictos de Traefik.

Conclusión

Esta arquitectura demuestra que es posible ejecutar docenas de servicios en producción sin Kubernetes ni orquestadores complejos. Las claves son:

  1. Conocer el consumo real de cada componente (monitoring continuo)
  2. Elegir el patrón de deploy según el caso (bind mount vs docker cp vs static)
  3. Optimizar para el cuello de botella (RAM en este caso, no CPU)

Con 24 containers distribuidos, uptime de 124 días y apenas 23% de RAM usada en el servidor principal, esta infraestructura prueba que la simplicidad bien ejecutada supera a la complejidad prematura.

Regresar al blog

Deja un comentario