Alternativas a Docker Compose
Docker Compose no es una mala herramienta, y la mayoría de los sistemas que se le quedan grandes nunca tuvieron la forma para la que se pensó. Esta página va del punto en el que deja de compensar, y de a qué renuncia de verdad cada alternativa —incluida la nuestra, que no es la respuesta correcta para todo el mundo—.
Cuándo Compose sigue siendo la respuesta
Si tu entorno local es «una base de datos, una cola y dos servicios», Compose es un fichero que escribes una vez y olvidas. Está en todas partes, todo el mundo lee YAML y no hace falta que entre una herramienta nueva en el equipo. No lo sustituyas por moda.
Dónde empieza a doler
- Tu código tiene que ser una imagen. Cada cambio significa reconstruir, o un bind mount más un truco de recarga por lenguaje, inventado una vez en cada repositorio.
- Es todo o nada. Compose levanta lo que dice el fichero. Para levantar tres servicios y apuntar el resto a un entorno compartido, editas el fichero o mantienes varios.
- Depurar es una faena. Un depurador contra un contenedor necesita un puerto, un mapeo y una configuración del IDE que alguien tiene que mantener viva.
- El fichero se desactualiza. Vive en un repositorio, describe servicios de otros y no es tarea de nadie mantenerlo.
- No sabe nada de salud.
depends_onespera a un contenedor, no a un servicio listo para responder.
El mismo entorno, en los dos sitios
Esto es la forma en la que acaba un docker-compose.yml de un sistema
pequeño —dos servicios y su infraestructura— cuando alguien ya ha peleado el bucle
de cambio:
services:
postgres:
image: postgres:16
environment: { POSTGRES_PASSWORD: dev }
ports: ['5432:5432']
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 5s
kafka:
image: bitnami/kafka:3.7
environment:
KAFKA_CFG_NODE_ID: '0'
KAFKA_CFG_PROCESS_ROLES: controller,broker
KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka:9093
ports: ['9092:9092']
orders:
build: ../orders # reconstruir en cada cambio
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/orders
PAYMENTS_URL: http://payments:8081
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
ports: ['8080:8080', '5005:5005'] # el segundo, para el depurador
depends_on:
postgres: { condition: service_healthy }
payments:
build: ../payments
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/payments
ports: ['8081:8081']
Funciona. Lo que cuesta no está en el fichero, está alrededor: cada cambio en
orders pasa por un build; el puerto 5005 hay que
acordarlo, mapearlo y configurarlo en el IDE de cada uno; PAYMENTS_URL
está escrito a mano y apuntar payments a la nube significa editar el
fichero (y acordarse de no comitearlo); y este fichero vive en un repositorio que
no es el de payments, así que nadie lo actualiza cuando
payments cambia de variable.
El equivalente en Aseptic no es otro fichero como este: es que los servicios no se
empaquetan. orders y payments arrancan como procesos, con
el hot reload que ya trae su framework y el depurador enganchado como a cualquier
proceso local. Lo único que sigue en Docker es la infraestructura —Postgres y
Kafka—, que la levanta la app y remapea sus puertos si están ocupados. Y las URLs
entre servicios no se escriben: se inyectan al levantar, según a dónde hayas
apuntado cada dependencia.
orders ← proceso local, puerto 8080
├── postgres → infraestructura en Docker (la levanta Aseptic)
├── kafka → infraestructura en Docker
└── payments → local | nube | mock ← esto se cambia en un clic
El cambio que importa es el de la última línea. En Compose, «hoy quiero
payments contra el entorno de la nube» es editar YAML; aquí es cambiar
el destino de una dependencia, y el resto del escenario se entera solo. Y nada de
esto se guarda dentro de tus repositorios: el escenario vive fuera, así que no hay
fichero de entorno que revisar en un pull request.
Las alternativas, honestamente
| Herramienta | Qué es en realidad | Coste de entrada |
|---|---|---|
| Tilt | Un bucle interno rápido contra Kubernetes, con una interfaz que enseña builds, logs y salud | Un clúster, imágenes y un Tiltfile por repo |
| Skaffold | Build, push y deploy a Kubernetes en un solo comando, con perfiles | Un clúster, imágenes, manifiestos y un skaffold.yaml |
| DevSpace | Tu código corriendo dentro de un contenedor de desarrollo en el clúster, con sincronización de ficheros | Un clúster, y estar cómodo depurando al otro lado |
| Garden | Un grafo de dependencias para construir, desplegar y testear, compartido por desarrollo y CI | Una decisión de plataforma, y alguien que se haga cargo del grafo |
| Telepresence | Un proceso local metido en un clúster real interceptando su tráfico | Un clúster compartido sano, y conectividad hasta él |
| Kubernetes local (kind, minikube) | Las primitivas de verdad en tu máquina, para que lo que pruebas tenga la forma de producción | Memoria, y el ciclo de despliegue en cada cambio |
| Aseptic | Servicios como procesos nativos, cada dependencia apuntada a local, nube o un mock | Instalarlo; Docker solo para la infraestructura común |
El patrón que hay detrás de la lista
Cinco de las siete responden a «Compose no basta» con «pues usa Kubernetes en local». Es una respuesta coherente, y si despliegas en Kubernetes te compra un parecido que no te da ninguna otra cosa. También importa el ciclo de construir y desplegar del clúster al bucle que repites doscientas veces al día.
Aseptic es la rara de la lista a propósito: da por hecho que no quieres un clúster en tu máquina para probar un flujo. Tus servicios corren como procesos, la infraestructura común —Kafka, Redis, PostgreSQL— te la levantan en Docker, y cada dependencia se resuelve a un servicio local, a vuestro entorno compartido en la nube o a un mock, con las URLs reescritas al levantar para no tocar ningún repositorio.
Dónde Aseptic es la elección equivocada
Si lo que necesitas probar es la parte de Kubernetes —ingress, network policies, sidecars, probes, límites de recursos— Aseptic no ejecuta nada de eso y no te sirve. Si tus servicios solo arrancan dentro de un namespace preparado, ejecutarlos fuera no es un atajo: es una reescritura. Y si la comprobación diaria de que tus imágenes y tus manifiestos siguen funcionando vale para ti más que un bucle rápido, eso te lo dan Skaffold o Tilt y Aseptic no.
Está además en beta pública, se publica para Windows, macOS y Linux, y no es código abierto. Todas las demás herramientas de esta lista son de código abierto, y para algunos equipos eso ya lo decide todo.
Cómo elegir sin una hoja de cálculo
- ¿Tus servicios arrancan con variables de entorno y una base de datos? Si es que sí, ejecutarlos nativos es el bucle más barato que puedes tener.
- ¿Estás probando tu código o tu despliegue? Tu código no necesita un clúster. Tu despliegue no necesita otra cosa.
- ¿Cabe el sistema en una máquina? Si de verdad no cabe, Telepresence o un clúster compartido es la respuesta honesta.
- ¿Quién mantiene la configuración? Una herramienta cuya configuración no es de nadie estará abandonada en dos trimestres, elijas la que elijas.
La comparativa amplia pone Docker Compose, un Kubernetes local y Aseptic uno al lado del otro con más detalle.
Preguntas frecuentes
¿Cuál es la alternativa a Docker Compose para microservicios?
Depende de qué te está costando. Si es el parecido con producción, un Kubernetes local con Tilt o Skaffold; si es el bucle diario de trabajar sobre varios servicios, un orquestador local. La página compara los cinco enfoques y dónde falla cada uno.
¿Docker Compose se queda corto para microservicios?
No para la infraestructura, que es lo que mejor hace. Se queda corto cuando dentro del compose están tus servicios: construir una imagen por cada cambio, sin recarga en caliente cómoda, y con la comunicación entre ellos resuelta a mano.
¿Hay alguna opción que no necesite Kubernetes?
Sí: seguir con Compose, o un orquestador local como Aseptic, que usa Docker para la infraestructura y ejecuta tus servicios como procesos de la máquina.