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.
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:
- Elasticsearch 8.12.2 consume 1.47 GB de RAM. Sin un límite explícito de
memory: 2gendeploy.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-demandmediantedocker run --rmahorrarí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 incluyeServerAliveInterval=30,AUTOSSH_GATETIME=0y un healthcheck víanc. 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_timeouta 120 segundos para tareas de larga duración - Uso de
realpath_rootpara el manejo correcto deindex.php
SSL y Seguridad: Tres Estrategias en un Solo Host
La terminación SSL se organiza de forma híbrida:
- 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
Aún no hay comentarios.