Volver al inicio

Docker en VPS: 24 contenedores en producción

El artículo desglosa el despliegue en producción de 24 contenedores Docker en un VPS con 6 GB de RAM. Cubre principios arquitectónicos de aislamiento, gestión de dependencias vía healthcheck, optimización del uso de memoria para Elasticsearch y Chrome Headless, trabajo seguro con DBs remotas vía túneles SSH, y monitoreo ligero sin Prometheus.

24 contenedores en un servidor: desglose técnico
Advertisement 728x90

24 Contenedores en un Solo VPS: Arquitectura Técnica de Alta Densidad para DevOps Intermedio/Senior

Un servidor, 6 GB de RAM, 24 contenedores — y todo funciona de manera estable durante más de un año. Esto no es un experimento, sino una infraestructura de producción que soporta siete proyectos activos: un bot de EdTech, un servicio anti-spam, un backend de IA, un motor de meta-búsqueda, inferencia de LLM local y dos servicios utilitarios. Ninguno genera ingresos, pero todos son críticos para las actividades operativas. El objetivo no era recortar costos por sí mismo, sino un compromiso consciente: gestión manual en lugar de servicios gestionados, carga predecible en lugar de elasticidad en la nube e integración profunda en lugar de abstracción.

Principios Arquitectónicos: Aislamiento, Observabilidad, Resiliencia

El enfoque central se basa en un aislamiento de red estricto. Cada proyecto reside en su propia red Docker (bridge), eliminando dependencias cruzadas y minimizando la superficie de ataque. Una red compartida shared se utiliza solo para servicios del sistema (por ejemplo, monitoreo o Redis común). Los puertos internos (9200, 8088, 9222) son accesibles exclusivamente vía 127.0.0.1; el acceso externo está bloqueado a nivel de configuración de iptables y nginx.

La resiliencia se garantiza mediante dependencias de healthcheck en docker-compose.yml. Por ejemplo, los servicios PHP del proyecto EdTech no inician hasta que un túnel SSH a la base de datos remota pasa una verificación nc -z 127.0.0.1 3306. Esto garantiza que la aplicación no intente conectarse a una base de datos no disponible y colapse la cola con errores.

Google AdInline article slot

La observabilidad se construye sin Prometheus/Grafana debido a las restricciones de RAM. En su lugar, un script Bash se ejecuta cada 15 minutos:

  • Verifica códigos de estado HTTP de puntos finales públicos (/health, /webhook/advert)
  • Identifica contenedores no saludables mediante docker ps --filter "health=unhealthy"
  • Monitorea espacio en disco y uso de swap
  • Envía alertas a un chat de Telegram vía curl a la API Bot

Esto proporciona visibilidad mínima pero suficiente para un único administrador.

Componentes Críticos: Elasticsearch, Chrome Headless y Túneles SSH

Tres componentes definen los límites de rendimiento del VPS:

Google AdInline article slot
  • Elasticsearch 8.12.2 consume 1.47 GB de RAM. Sin un límite explícito de memory: 2g en deploy.resources.limits, la JVM comienza a intercambiar procesos vecinos, causando inestabilidad. Para un índice de ~50K documentos y registro de logs, esto ofrece el equilibrio óptimo entre funcionalidad y carga. Una alternativa como Meilisearch requeriría migrar índices existentes y modificar el código cliente, calificada como una tarea de alto esfuerzo y bajo ROI en esta etapa.
  • Chrome Headless (zenika/alpine-chrome) ocupa 636 MB de RAM, aunque se usa solo una vez por hora para scraping de renderizado JS. Ejecutarlo on-demand mediante docker run --rm ahorraría memoria pero añadiría un retraso de 5–10 segundos por llamada. Para servicios con SLAs estrictos, esto es inaceptable; aquí, es un compromiso aceptable.
  • Túneles SSH se implementan en contenedores alpine separados con autossh. Proporcionan acceso seguro a MySQL en un host compartido sin abrir puertos externamente. La configuración incluye ServerAliveInterval=30, AUTOSSH_GATETIME=0 y un healthcheck vía nc. Esta solución funciona con todos los hosts que admiten SSH y reemplaza completamente las bases de datos gestionadas de pago.

Optimización de Nginx y PHP: Reducción de Latencia en Milisegundos

Nginx está configurado exclusivamente para webhooks y APIs — ningún archivo estático excepto /health. La optimización clave es descargar el procesamiento de webhooks de Telegram a un archivo PHP separado (webhook-advert.php) que evita el arranque de Laravel. Esto reduce el tiempo de respuesta de 80–120 ms a 15–25 ms, lo cual es crítico durante llamadas masivas de webhook desde la API de Telegram (timeout máximo — 60 segundos).

La configuración también incluye:

  • Redirección forzada de HTTP → HTTPS
  • Rechazo de procesar cualquier ruta que no sea /health, /webhook/ y /api/telegram/
  • Aumento de fastcgi_read_timeout a 120 segundos para tareas de larga duración
  • Uso de realpath_root para el manejo correcto de index.php

SSL y Seguridad: Tres Estrategias en un Solo Host

La terminación SSL se organiza de forma híbrida:

Google AdInline article slot
  • getssl + Let's Encrypt — para dominios que requieren cifrado de extremo a extremo sin Cloudflare
  • Proxy Cloudflare — para la mayoría de dominios: SSL termina en el borde, el tráfico hacia el VPS va sobre HTTP, pero protegido por filtrado IP (solo ASN de Cloudflare)
  • Actualización Manual — una medida temporal para el backend de IA, actualmente en proceso de automatización vía Caddy

La configuración de Cloudflare incluye Always Use HTTPS, WAF y Rate Limiting (100 solicitudes/min por IP) obligatorios, compensando la falta de WAF en el lado del VPS.

Conclusiones Clave

  • El aislamiento de red estricto mediante redes Docker separadas previene fallos en cascada y simplifica las auditorías de seguridad.
  • Las dependencias de healthcheck en docker-compose aseguran que los servicios inicien solo después de que sus dependencias estén listas (por ejemplo, túnel SSH a DB).
  • Elasticsearch requiere un límite duro de memoria (2 GB); de lo contrario, la JVM intercambiará contenedores vecinos, activando el killer OOM.
  • Mantener Chrome Headless en modo siempre activo está justificado a baja frecuencia de uso si la latencia de inicio es crítica para la lógica empresarial.
  • El monitoreo Bash con alertas de Telegram es un reemplazo funcional para Prometheus/Grafana bajo restricciones de RAM, siempre que los SLOs estén claramente definidos.

— Editorial Team

Advertisement 728x90

Leer después