La afirmación suena sencilla: Docker Compose es para desarrollo local y en producción se deben usar Kubernetes, Helm y Argo CD. También está incompleta.
Una respuesta más honesta sería esta:
- Docker Compose es excelente para desarrollo
- Docker Compose también puede ser una opción razonable para producción en un solo servidor sencillo
- Kubernetes resulta más atractivo cuando tu sistema es más grande, está más distribuido o necesita garantías operativas más sólidas
- Helm y Argo CD no son alternativas a Docker Compose; son capas que resultan útiles cuando ya operas en Kubernetes
La distinción importa porque los equipos suelen adoptar infraestructura más compleja demasiado pronto. Cambian un modelo de despliegue que funciona por uno que impresiona y luego pasan meses pagando un costo operativo innecesario.
Este artículo se investigó y contrastó con documentación primaria el March 31, 2026.
TL;DR
- La propia documentación de Docker dice explícitamente que Compose funciona en entornos de desarrollo, pruebas, CI y producción, así que «Compose es solo para desarrollo local» no es una limitación oficial.
- Compose es especialmente útil cuando basta con una máquina: una aplicación web, una API, un worker, un proxy inverso y una base de datos en un solo servidor pueden ser una solución perfectamente razonable si cuentan con buenos backups, health checks, imágenes con versiones fijadas, políticas de reinicio y monitoreo.
- Kubernetes es mejor cuando necesitas comportamiento a nivel de clúster: programación de cargas en múltiples nodos, recuperación automática entre nodos, descubrimiento de servicios entre pods cambiantes, autoescalado, actualizaciones graduales y patrones de alta disponibilidad.
- Helm es una capa de empaquetado y plantillas para recursos de Kubernetes. Te ayuda a administrar charts, valores predeterminados y valores específicos de cada entorno cuando ya usas Kubernetes.
- Argo CD es una herramienta de despliegue GitOps para Kubernetes. Compara continuamente lo que está en Git con lo que se ejecuta en el clúster y sincroniza las diferencias.
- La pregunta correcta no es «¿Qué herramienta es más apta para producción?». Es «¿Cuánta complejidad operativa necesita realmente este sistema hoy?».
Qué aprenderás aquí
- Por qué existe la afirmación de que «Compose es solo para desarrollo»
- En qué casos Docker Compose es realmente sólido en producción
- Cuándo Kubernetes se convierte en la mejor opción
- Qué aporta Helm sobre Kubernetes
- Qué aporta Argo CD sobre Helm y los manifiestos
- Mitos comunes frente a la realidad
- Problemas comunes cuando un proyecto usa Compose para desarrollo y Kubernetes para producción
- Un marco práctico de decisión para equipos que eligen entre estas opciones
La respuesta corta: en realidad son dos filosofías de despliegue distintas
A grandes rasgos, estas herramientas resuelven problemas diferentes:
| Herramienta | Función principal | Mejor opción para |
|---|---|---|
| Docker Compose | Definir y ejecutar una aplicación de múltiples contenedores a partir de un solo modelo | Desarrollo local, entornos efímeros y producción sencilla en un solo servidor |
| Kubernetes | Orquestar contenedores entre nodos mientras mantiene el estado deseado | Producción compleja, con múltiples servicios, alta disponibilidad o múltiples nodos |
| Helm | Empaquetar recursos de Kubernetes y parametrizarlos | Equipos que ya despliegan en Kubernetes |
| Argo CD | Reconciliar continuamente el estado de Kubernetes a partir de Git | Equipos que usan GitOps en Kubernetes |
Esto significa que la afirmación original confunde la definición de la aplicación con la orquestación de clústeres y la entrega mediante GitOps.
Compose responde: «¿Qué contenedores componen esta aplicación y cómo se ejecutan juntos?».
Kubernetes responde: «¿Cómo opero esta aplicación de forma confiable en un clúster?».
Helm responde: «¿Cómo empaqueto y configuro esos recursos de Kubernetes de forma ordenada?».
Argo CD responde: «¿Cómo hago de Git la fuente de verdad de lo que se ejecuta en el clúster?».
Estas herramientas tienen sentido juntas, pero solo si tu problema realmente las requiere.
Por qué se dice que «Compose es solo para desarrollo local»
La frase suele partir de una observación real, pero lleva la conclusión demasiado lejos.
Compose es fantástico para desarrollo porque:
- es rápido de entender
- es rápido de ejecutar
- está cerca del código de la aplicación
- facilita levantar servicios dependientes como bases de datos, cachés, colas y proxies inversos locales
La documentación de Docker destaca esta fortaleza, especialmente en los flujos de trabajo locales y las definiciones de aplicaciones basadas en Compose. Esto lleva a muchos ingenieros a clasificar mentalmente Compose como una «herramienta para desarrolladores».
Pero la documentación oficial de Docker también dice que Compose funciona en distintos entornos, incluido producción. Docker también documenta cómo configurar aplicaciones Compose para producción e incluso ofrece Compose Bridge como una forma de transformar aplicaciones Compose en manifiestos de Kubernetes.
Así que una interpretación más precisa es:
- Compose está orientado primero a facilitar el trabajo de desarrollo
- Compose no se limita al desarrollo
- Compose no reemplaza por completo a un orquestador de clústeres cuando tus necesidades de producción requieren un clúster
Ese último punto es el verdadero problema.
Cuándo Docker Compose es una muy buena opción para producción
Si tu entorno de producción es un solo servidor, Compose puede ser práctico, claro y suficiente.
Piensa en sistemas como estos:
- un dashboard interno para una empresa
- un SaaS en etapa inicial con una API, un worker, PostgreSQL y Redis
- un sitio de marketing con un backend de CMS
- un pequeño servicio de integración B2B con tráfico moderado
- un negocio paralelo o un producto desarrollado por una sola persona, donde la simplicidad operativa importa más que la escalabilidad teórica
En esos casos, Compose ofrece varias ventajas prácticas:
1. Operaciones más sencillas
Un solo compose.yaml suele ser más fácil de entender que un conjunto de Deployments, Services, Ingresses, ConfigMaps, Secrets, HPAs, reglas de RBAC y archivos de valores de Helm.
Esa simplicidad no es trivial. Afecta a:
- el tiempo de incorporación al equipo
- la velocidad de depuración
- la respuesta a incidentes
- la cantidad de componentes que pueden fallar
2. Menor costo operativo
Kubernetes resuelve problemas reales, pero también introduce costos reales:
- aprovisionamiento y actualizaciones del clúster
- controladores de ingress
- clases de almacenamiento
- patrones de gestión de secretos
- configuración de observabilidad
- RBAC y capas de políticas
- complejidad de red
- más YAML y más abstracciones
Si todavía no necesitas esas capacidades, quizá solo estés agregando procesos innecesarios.
3. Aislamiento y reproducibilidad suficientes
Para muchos sistemas pequeños en producción, la mayor ventaja no es la orquestación entre múltiples nodos. Es simplemente contar con:
- imágenes de contenedor consistentes
- arranque reproducible
- conectividad de red estable entre servicios
- variables de entorno y volúmenes explícitos
- reinicios sencillos después de reiniciar el servidor
Compose proporciona todo eso de forma eficaz.
4. Un camino claro de desarrollo local a producción sencilla
Usar el mismo modelo de aplicación en desarrollo local y en un servidor de producción puede reducir las diferencias accidentales entre entornos.
Aquí tienes un ejemplo realista de un solo servidor:
services:
app:
image: ghcr.io/acme/myapp:2026-03-31.1
restart: unless-stopped
env_file:
- .env.production
depends_on:
- db
- redis
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 5
worker:
image: ghcr.io/acme/myapp:2026-03-31.1
command: ["node", "worker.js"]
restart: unless-stopped
env_file:
- .env.production
depends_on:
- db
- redis
db:
image: postgres:16
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
redis:
image: redis:7
restart: unless-stopped
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
depends_on:
- app
volumes:
postgres_data:
Esa configuración no es «infraestructura de juguete». Puede sostener un negocio real si:
- el tráfico es moderado
- existe una tolerancia razonable al tiempo de inactividad
- la conmutación por error entre múltiples nodos no es un requisito indispensable
- el equipo puede administrar con solvencia los backups, logs, alertas y el mantenimiento del servidor
La salvedad es importante: Compose en un solo servidor no equivale a infraestructura de alta disponibilidad. Si el servidor falla, tu aplicación estará fuera de servicio hasta que vuelva a funcionar o la restaures en otro lugar. Para muchos productos, especialmente en sus primeras etapas, ese compromiso es aceptable. Para otros, no.
El límite menos evidente: cuando producción deja de parecerse a una sola máquina
Aquí es donde Kubernetes empieza a destacar claramente.
Una vez que tu sistema necesita comportarse como un clúster, usar Compose se vuelve cada vez más manual y propenso a fallas.
Señales típicas:
- necesitas múltiples nodos
- necesitas mayor disponibilidad de la que puede ofrecer un solo servidor
- quieres actualizaciones graduales entre muchas réplicas
- necesitas descubrimiento de servicios entre cargas de trabajo cambiantes
- quieres que las cargas se reasignen automáticamente después de la falla de un nodo
- distintos servicios necesitan escalar de forma independiente
- operas muchos microservicios en varios entornos
- distintos equipos necesitan una plataforma operativa compartida
Ese es exactamente el tipo de entorno para el que se creó Kubernetes.
Lo que Kubernetes ofrece y Compose no ofrece con la misma naturalidad
Kubernetes no es solo «más YAML». Es un plano de control para sistemas distribuidos.
Según la documentación oficial, Kubernetes está diseñado para administrar cargas de trabajo y servicios en contenedores mientras mantiene el estado deseado. La documentación actual de Kubernetes también describe explícitamente mecanismos de recuperación automática como:
- reiniciar contenedores que fallaron
- reemplazar pods que fallaron
- reasignar cargas de trabajo cuando fallan los nodos
- eliminar pods que no están saludables de los endpoints de un Service
Ese es un modelo operativo distinto de «ejecuta estos contenedores en este servidor».
Un modelo mental sencillo
Docker Compose
-> one machine
-> start containers together
-> restart containers on that host
Kubernetes
-> many machines
-> schedule workloads across nodes
-> maintain desired replicas
-> route traffic to healthy pods
-> replace failed workloads automatically
Por qué importa en producción real
Imagina una API que necesita seis réplicas distribuidas entre tres nodos.
Con Kubernetes, la plataforma ya te ofrece conceptos integrados para:
- cantidad deseada de réplicas
- descubrimiento de servicios
- actualizaciones graduales
- control del tráfico según el estado de preparación
- autoescalado
- reasignación de cargas con conocimiento de los nodos
Con Compose, una vez que vas más allá de un solo servidor, empiezas a construir esas garantías fuera de la herramienta o a cambiar de plataforma por completo.
Eso no hace que Compose sea «malo». Solo significa que el problema cambió.
Helm no reemplaza a Compose
Esta es una de las fuentes de confusión más comunes.
Helm no es un orquestador. Helm es un sistema de empaquetado para Kubernetes.
Una forma útil de entenderlo:
Compose
-> app definition for Docker environments
Kubernetes manifests
-> raw runtime definition for Kubernetes
Helm
-> packaging + templating + versioning layer over Kubernetes manifests
Helm resulta útil cuando ya sabes que:
- estás desplegando en Kubernetes
- quieres charts reutilizables
- necesitas una configuración ordenada y específica para cada entorno
Por ejemplo, un chart de Helm puede empaquetar:
- un Deployment
- un Service
- un Ingress
- referencias a ConfigMaps y Secrets
- configuración de autoescalado
- probes y solicitudes de recursos
Con valores diferentes para staging y producción.
Ejemplo:
# values.yaml
image:
repository: ghcr.io/acme/myapp
tag: "2026-03-31.1"
replicaCount: 3
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
Eso es valioso cuando la plataforma es Kubernetes. Es innecesario si todo tu sistema de producción está en un solo servidor con Compose.
Argo CD tampoco reemplaza a Compose
Argo CD entra en juego aún más adelante.
La función de Argo CD no es definir la arquitectura de tu aplicación. Su función es reconciliar el estado de Kubernetes a partir de Git.
Según la documentación oficial, Argo CD sigue el patrón GitOps al usar Git como fuente de verdad para el estado deseado de la aplicación y luego automatiza el despliegue de ese estado en los entornos de destino. Su modelo de sincronización automática permite que CI envíe un cambio a Git en lugar de tener credenciales de despliegue directo al clúster.
Eso es potente, especialmente para los equipos que quieren:
- despliegues basados en pull
- cambios de entorno auditables
- detección de diferencias en el clúster
- una separación más segura entre CI y las credenciales del clúster
- un historial claro de despliegues en Git
Pero, de nuevo, Argo CD importa después de que ya estás trabajando con Kubernetes.
Si tu aplicación se ejecuta en una máquina virtual con Compose, Argo CD no es la pieza que te falta.
Una comparación realista de arquitecturas
Opción A: producción sencilla en un solo servidor con Compose
Developer push
|
v
CI builds image
|
v
Registry
|
v
SSH / pull / restart on one server
|
v
Docker host
-> reverse proxy
-> app
-> worker
-> database
-> cache
Esto suele ser suficiente durante más tiempo del que imaginas.
Opción B: producción basada en clúster con Kubernetes, Helm y Argo CD
Developer push
|
v
CI builds image
|
v
Registry + manifest update in Git
|
v
Argo CD detects Git change
|
v
Helm renders chart values for environment
|
v
Kubernetes reconciles desired state
-> Deployments
-> Services
-> Ingress
-> Autoscaling
-> multi-node scheduling
Esta opción es mejor cuando necesitas garantías más sólidas, más servicios, más entornos o más coordinación entre equipos.
Mitos frente a la realidad
| Mito | Realidad |
|---|---|
| Compose es solo para desarrollo local. | La documentación de Docker describe explícitamente el uso de Compose en distintos entornos, incluido producción. |
| Si es producción, Kubernetes es automáticamente la respuesta correcta. | Solo si tus necesidades de producción requieren un clúster lo suficiente como para justificar el costo operativo. |
| Helm reemplaza a Compose. | Helm empaqueta manifiestos de Kubernetes. Resuelve un problema diferente. |
| Argo CD reemplaza a CI/CD. | Argo CD complementa CI al reconciliar el estado de Kubernetes a partir de Git. CI sigue compilando, ejecutando pruebas y, por lo general, publicando artefactos. |
| Usar Compose en producción es poco profesional. | Usar una herramienta más sencilla para un sistema más sencillo suele ser la opción más profesional. |
| Kubernetes siempre reduce el trabajo operativo. | Kubernetes automatiza muchas cosas, pero también genera trabajo de plataforma que los equipos pequeños quizá todavía no necesiten. |
Ventajas y desventajas en términos sencillos
Este es el intercambio práctico:
Compose prioriza la simplicidad
Renuncias a algunas garantías propias de un clúster, pero ganas:
- menor carga cognitiva
- incorporación más rápida al equipo
- depuración más rápida
- infraestructura más económica
- menos abstracciones entre la aplicación y quien la opera
Kubernetes prioriza el control y la resiliencia a escala
Obtienes:
- estado deseado declarativo
- programación de cargas en el clúster
- mecanismos de recuperación automática
- abstracciones de servicio para cargas de trabajo dinámicas
- patrones de escalado horizontal
- componentes más sólidos para construir soluciones de disponibilidad
Pero pagas el precio de:
- más infraestructura
- más conceptos de plataforma
- más aspectos que configurar
- más formas de configurar mal el sistema
Por eso una «mejor práctica» sin contexto termina siendo costosa.
Escenarios reales
Escenario 1: aplicación empresarial interna
Tienes:
- 1 API
- 1 instancia de PostgreSQL
- 1 worker de cola
- quizá Redis
- un equipo pequeño
- tráfico moderado
Recomendación:
- empieza con Docker Compose en un servidor bien administrado
- agrega backups, alertas, fijación de versiones de imágenes, health checks, TLS y endurecimiento del servidor
Por qué:
- probablemente el costo operativo de Kubernetes todavía no se justifica
Escenario 2: SaaS en etapa inicial con tráfico creciente
Tienes:
- una API de cara a los clientes
- tareas en segundo plano
- staging y producción
- ciertas expectativas de disponibilidad
- una probable necesidad futura de escalado horizontal
Recomendación:
- Compose todavía puede funcionar en las primeras etapas
- pasa a Kubernetes cuando la presión de escalado, la cantidad de equipos o los requisitos de disponibilidad hagan riesgosa la operación en un solo servidor
Por qué:
- esta es la zona gris donde buenos equipos pueden elegir razonablemente cualquiera de las dos opciones
Escenario 3: plataforma con múltiples servicios y varios equipos
Tienes:
- muchos servicios
- múltiples entornos
- ritmos de despliegue independientes
- límites de seguridad más estrictos
- expectativas de actualizaciones graduales
- fallas de nodos que quieres que la plataforma absorba
Recomendación:
- Kubernetes + Helm
- Argo CD si quieres GitOps y reconciliación dentro del clúster
Por qué:
- el problema de plataforma ya es real y Kubernetes está diseñado para resolverlo
Escenario 4: entorno regulado o con cambios frecuentes
Tienes:
- necesidades importantes de auditoría
- cambios frecuentes en los entornos
- interés en aprobaciones basadas en Git y control de diferencias
Recomendación:
- Kubernetes con Helm y Argo CD
Por qué:
- aquí los beneficios de GitOps empiezan a ser mucho más evidentes
Problemas comunes cuando un proyecto usa Compose para desarrollo y Kubernetes para producción
Esta configuración es muy común:
- Docker Compose para desarrollo local
- Kubernetes para staging o producción
No hay nada malo en esa división. De hecho, suele ser un modelo operativo saludable. Pero crea un riesgo sutil: los equipos empiezan a asumir que «funciona en Compose» significa «está listo para Kubernetes».
La dificultad es que Compose y Kubernetes favorecen hábitos diferentes.
- Compose está optimizado para obtener feedback local rápido en una sola máquina
- Kubernetes está optimizado para cargas de trabajo replicadas y dinámicas que se ejecutan en un clúster
Eso significa que algunos problemas no aparecen hasta que cruzas ese límite.
1. El arranque de dependencias funciona localmente, pero falla en el clúster
Esta es una de las sorpresas más comunes.
La documentación de Docker sobre el orden de arranque es explícita: Compose inicia los servicios en orden de dependencia, pero no espera hasta que una dependencia esté realmente lista, a menos que uses condiciones basadas en su estado de salud. Por eso, un stack local ya puede ser frágil si la aplicación arranca antes de que la base de datos pueda aceptar conexiones.
Kubernetes es más estricto de otra manera: los Deployments separados no proporcionan un orden de arranque global sencillo. La plataforma espera que tu aplicación tolere reintentos, demoras de preparación y dependencias temporalmente no disponibles.
Síntoma típico:
- la aplicación arranca bien con
docker compose up - el Pod de Kubernetes arranca, pero inmediatamente muestra errores de conexión a Postgres, Redis u otra API
Lo que suele ayudar:
- usa health checks de Compose localmente, no solo
depends_on - en Kubernetes, usa
startupProbeyreadinessProbecorrectamente - si un Pod realmente debe esperar algo, usa un
initContainerpara comprobar las dependencias - aun así, haz que la aplicación reintente las conexiones de forma controlada en lugar de asumir un orden de arranque perfecto
Cómo diagnosticarlo:
- ejecuta
docker compose logsy confirma si la dependencia solo está en ejecución o si realmente está lista - ejecuta
kubectl describe pod <pod>e inspecciona las fallas de probes y los Events - ejecuta
kubectl logs <pod>y busca errores de conexión rechazada, timeout o DNS
2. Las migraciones se ejecutan durante el arranque de la aplicación y crean condiciones de carrera
Este es el problema delicado que mencionaste, y es muy real.
Muchos proyectos empiezan con un entrypoint como este:
./migrate-db && ./start-app
En Compose, eso suele funcionar porque puede haber un solo contenedor app en ejecución.
En Kubernetes, un Deployment con 2 o más réplicas puede convertir ese patrón en una condición de carrera:
Pod A starts
-> runs migration
Pod B starts
-> runs the same migration
Result
-> lock contention
-> duplicate DDL
-> partial rollout
-> CrashLoopBackOff or stuck deployment
Aquí es donde los equipos suelen recurrir a un initContainer. Eso puede ayudar con la preparación que debe ocurrir una vez por Pod, pero no convierte la migración en una acción que se ejecute una sola vez en todo el clúster. Si tienes 3 réplicas, el init container se ejecuta 3 veces.
Los patrones más seguros suelen ser:
- un Job de Kubernetes dedicado a la migración del esquema
- un paso de CI/CD que ejecute las migraciones antes del rollout del Deployment
- un hook de Helm o un sync hook de Argo CD cuando tu proceso ya se basa en esas herramientas
- herramientas de migración que sean idempotentes y usen bloqueos a nivel de base de datos cuando sea posible
La idea operativa es sencilla:
Build image
|
v
Run one migration task
|
v
Only then roll out app replicas
Cómo diagnosticarlo:
- busca intentos de migración repetidos en los logs de varios Pods
- revisa si hay timeouts de bloqueo de la base de datos, «relation already exists» o errores de DDL concurrente
- inspecciona el estado del rollout con
kubectl rollout status deployment/<name> - si usas un Job, inspecciónalo directamente con
kubectl get jobsykubectl logs job/<name>
3. Los bind mounts locales ocultan problemas que la imagen real todavía tiene
En desarrollo con Compose, es común montar código fuente, archivos de configuración y recursos generados desde la máquina host.
Eso acelera mucho la iteración, pero puede ocultar problemas de producción como:
- falta un archivo en la imagen construida
- el contenedor espera una ruta con permisos de escritura que no existe
- un script funciona localmente solo porque está montado desde el repositorio
Luego, la misma aplicación llega a Kubernetes y falla aunque «funcionaba en Docker».
Lo que suele ayudar:
- prueba la imagen localmente sin bind mounts antes de promoverla
- trata la imagen como el artefacto desplegable, no al sistema de archivos local
- define explícitamente las rutas que requieren escritura
- si los datos deben persistir, usa un volumen persistente adecuado o almacenamiento externo, no el sistema de archivos del contenedor
Cómo diagnosticarlo:
- compara el comportamiento local de Compose con un
docker runsin configuraciones adicionales o con un override de Compose que elimine los bind mounts - inspecciona directamente el contenido de la imagen
- en Kubernetes, comprueba si la ruta que falla debería provenir de la imagen, un Secret, un ConfigMap o un PersistentVolumeClaim
4. Las suposiciones de red divergen entre Compose y Kubernetes
Compose asigna a cada servicio un nombre en la red de la aplicación. La documentación de red de Docker muestra que los servicios pueden descubrirse entre sí por su nombre de servicio, como db.
Kubernetes también admite el descubrimiento de servicios, pero la abstracción es diferente:
- los Pods son efímeros
- los Services proporcionan acceso estable a backends cambiantes
- los límites de DNS y namespace importan más
Esto genera algunos errores comunes:
- usar
localhostpara otro servicio - codificar directamente las IP de los Pods
- asumir que
dben desarrollo local significa lo mismo que el DNS de producción en otro namespace - depender de variables de servicio inyectadas en el entorno en lugar de DNS y configuración explícita
Lo que suele ayudar:
- define explícitamente los parámetros de conexión:
DATABASE_HOST,REDIS_URL,API_BASE_URL - conéctate a Services de Kubernetes, no a IP de Pods
- prefiere el descubrimiento de servicios basado en DNS
- mantén consistentes los nombres entre entornos cuando sea posible, aunque la plataforma subyacente sea diferente
Cómo diagnosticarlo:
- ejecuta
kubectl get svcpara confirmar que el Service realmente existe - ejecuta
kubectl exec <pod> -- nslookup <service-name>para probar la resolución DNS - compara los nombres de servicio locales de Compose con los nombres y namespaces de los Services de Kubernetes
5. El manejo de secretos y configuración diverge entre entornos
Con Compose, es común empezar con .env, env_file y quizá un archivo de configuración montado.
Kubernetes suele llevar a los equipos a usar:
- Secrets
- ConfigMaps
- archivos montados
- inyección de variables de entorno desde recursos del clúster
La falla no siempre es evidente. A veces la aplicación arranca, pero con una configuración incorrecta:
- el nombre de un Secret es incorrecto
- falta una clave en un ConfigMap
- un valor que existe localmente nunca se creó en el clúster
- la ruta de un archivo de configuración difiere entre entornos
Lo que suele ayudar:
- define un contrato claro de ejecución para las variables de entorno y los archivos requeridos
- mantén explícita la configuración de producción en Git o en tu sistema externo de secretos
- evita depender de comportamientos locales de
.envque no estén documentados - valida la configuración al arrancar y falla con un mensaje claro
Cómo diagnosticarlo:
- usa
docker compose configpara inspeccionar la configuración local efectiva - usa
kubectl describe pod <pod>para inspeccionar la configuración referenciada y los Events recientes - verifica que los Secrets y ConfigMaps requeridos existan en el namespace correcto
6. Las probes y los límites de recursos convierten una aplicación saludable en un bucle de reinicios
Compose normalmente no somete tu aplicación a restricciones de liveness, readiness, startup, CPU y memoria como las de Kubernetes.
Por eso, una aplicación que parece funcionar bien localmente puede fallar en el clúster porque:
- el arranque tarda más de lo que permite la probe
- se verifica la preparación antes de que se carguen las cachés o los modelos
- los límites de memoria son demasiado bajos
- la limitación de CPU hace que el calentamiento sea mucho más lento de lo esperado
Esto es especialmente común en:
- aplicaciones con un arranque pesado
- aplicaciones que ejecutan migraciones o calientan cachés al arrancar
- servicios de IA que cargan modelos o dependencias grandes
Lo que suele ayudar:
- usa
startupProbepara secuencias de arranque lentas - usa
readinessProbepara impedir el tráfico hasta que la aplicación esté realmente lista - usa
livenessProbecon más cautela - establece las solicitudes y los límites de recursos según mediciones reales, no suposiciones
Cómo diagnosticarlo:
- ejecuta
kubectl describe pod <pod>y busca fallas de probes yOOMKilled - inspecciona la cantidad de reinicios y los Events
- compara el tiempo de arranque de la aplicación localmente y dentro del clúster bajo los límites reales
7. El estado local funciona en un contenedor, pero falla con réplicas
Las configuraciones de Compose en un solo servidor pueden normalizar accidentalmente patrones como:
- escribir archivos subidos en el sistema de archivos del contenedor
- almacenar sesiones en memoria
- guardar estado importante en caché en una sola instancia
Esos atajos pueden funcionar durante un tiempo en una sola máquina. Fallan mucho más rápido en Kubernetes cuando varias réplicas atienden tráfico.
Síntomas:
- un Pod ve un archivo que otro Pod no ve
- las sesiones desaparecen cuando las solicitudes llegan a otra réplica
- las tareas en segundo plano se comportan de manera inconsistente entre Pods
Lo que suele ayudar:
- mueve el estado compartido a la base de datos, Redis, almacenamiento de objetos o un volumen persistente diseñado correctamente
- trata los contenedores como reemplazables
- asume que cualquier Pod puede desaparecer
Cómo diagnosticarlo:
- rastrea dónde se escribe realmente el estado
- comprueba si ese estado debe compartirse entre réplicas
- verifica si la aplicación depende del disco local o de la memoria del proceso de formas que solo funcionaban en un servidor
La lección práctica
Usar Compose para desarrollo y Kubernetes para producción no es una señal de un problema. A menudo es la división correcta.
La disciplina real consiste en evitar que las suposiciones locales se conviertan silenciosamente en suposiciones de producción.
Si estuviera preparando un proyecto para que sea más robusto en ambos entornos, revisaría primero:
- el arranque de la aplicación y los reintentos de conexión a dependencias
- las migraciones que se ejecutan una sola vez frente a la inicialización por Pod
- que la imagen funcione correctamente sin bind mounts
- el descubrimiento de servicios y las expectativas de DNS
- que el contrato de configuración y secretos esté completo
- la configuración de probes y los recursos asignados
- el estado oculto en sistemas de archivos locales o en la memoria del proceso
Un marco práctico para tomar decisiones
Si estás tomando la decisión hoy, haz estas preguntas en orden.
1. ¿Puede un solo servidor manejar la carga de trabajo y el modelo de fallas?
Si sí, Compose sigue siendo una opción.
Si no, te estás acercando al terreno de Kubernetes.
2. ¿Necesitas programar cargas en múltiples nodos o reasignarlas automáticamente tras la pérdida de un nodo?
Si sí, Kubernetes es la opción más sólida.
3. ¿Necesitas muchas réplicas, rollouts controlados o autoescalado?
Si sí, Kubernetes suele justificar la complejidad adicional.
4. ¿Operas muchos servicios entre distintos equipos y entornos?
Si sí, Kubernetes suele proporcionar una mejor estructura a largo plazo.
5. ¿Quieres específicamente GitOps, detección de diferencias y entrega basada en pull?
Si sí, eso apunta a Argo CD, pero solo cuando Kubernetes ya es tu plataforma.
6. ¿Necesitas empaquetar charts y reutilizar manifiestos específicos para cada entorno?
Si sí, eso apunta a Helm, de nuevo solo cuando Kubernetes ya forma parte de la solución.
En resumen:
Single host + modest complexity
-> Compose is reasonable
Multiple nodes + higher availability + many services
-> Kubernetes becomes reasonable
Kubernetes + reusable packaging
-> add Helm
Kubernetes + Git as deployment source of truth
-> add Argo CD
Entonces, ¿qué deberían hacer realmente la mayoría de los equipos?
Mi recomendación es deliberadamente poco emocionante:
- empieza con Compose cuando tu producto y tu equipo todavía sean sencillos
- adopta Kubernetes cuando tus necesidades operativas lo justifiquen claramente
- adopta Helm cuando los manifiestos de Kubernetes sin procesar empiecen a ser repetitivos y difíciles de administrar
- adopta Argo CD cuando GitOps y la reconciliación declarativa justifiquen los componentes adicionales
Esa secuencia suele ser más saludable que empezar con todo el stack porque está de moda.
También hay un punto estratégico importante: la complejidad prematura de plataforma es una forma de deuda técnica. Solo parece más sofisticada que otros tipos de deuda.
Conclusión final
La afirmación original acierta en algo: para sistemas complejos en producción, Kubernetes suele ser la mejor plataforma, y Helm junto con Argo CD pueden hacer que esa plataforma sea mucho más fácil de administrar.
Pero se equivoca en la primera parte por ser demasiado absoluta.
Docker Compose no es «solo para desarrollo local». Es una opción operativa válida para cierto tipo de sistemas en producción, especialmente cuando:
- un servidor es suficiente
- el equipo valora la simplicidad
- la arquitectura todavía es compacta
- los requisitos de disponibilidad son importantes, pero no exigen las garantías de un clúster
Kubernetes no es «más correcto». Tiene más capacidades y es más costoso operativamente. Ese intercambio vale la pena cuando el sistema es lo suficientemente grande, crítico o distribuido.
La herramienta de despliegue correcta no es la que tiene el ecosistema más grande. Es la que se ajusta a tu realidad operativa actual sin limitar tus opciones futuras.
Si ya sabes que tu sistema se dirige hacia una configuración completa de Kubernetes con GitOps, también podría interesarte From Repo to Cluster: An End-to-End Deployment Pipeline for AI SaaS.
Fuentes
Verificadas el March 31, 2026 contra documentación primaria:
- Documentación de Docker: visión general de Docker Compose
- Documentación de Docker: usar Compose en producción
- Documentación de Docker: controlar el orden de arranque en Compose
- Documentación de Docker: redes en Compose
- Documentación de Docker: Compose Bridge
- Documentación de Docker: especificación de despliegue de Compose
- Documentación de Kubernetes: qué es Kubernetes
- Documentación de Kubernetes: Deployment
- Documentación de Kubernetes: Job
- Documentación de Kubernetes: init containers
- Documentación de Kubernetes: Service
- Documentación de Kubernetes: autoescalado horizontal de Pods
- Documentación de Kubernetes: recuperación automática de Kubernetes
- Documentación de Kubernetes: configurar probes de liveness, readiness y startup
- Documentación de Kubernetes: volúmenes persistentes
- Documentación de Helm: página principal de Helm
- Documentación de Helm: charts
- Documentación de Argo CD: visión general
- Documentación de Argo CD: política de sincronización automática
Algunos juicios de este artículo son interpretaciones de esa documentación y no afirmaciones directas de los proveedores. En particular, la recomendación de mantener Compose para producción sencilla en un solo servidor y pasar a Kubernetes cuando el sistema requiere múltiples nodos, alta disponibilidad o coordinación compleja entre equipos es una inferencia de ingeniería basada en las capacidades y los compromisos documentados arriba.