Compose profiles para un agente IA: migrate no es el webhook
Resumen
Cómo no dejar Adminer y el job migrate 24/7 en prod: profiles de Compose, COMPOSE_PROFILES y el webhook sin profile. Distinto de depends_on healthy. Regex de nombres, --profile '*' y compose run que auto-activa. Techos oficiales Docker Compose, curl 3 de septiembre de 2026.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
Adminer, migrate y un worker de debug en el mismo yaml sin profile salen con up -d en prod. Profiles: opt-in. El webhook no lleva profiles (siempre on). Fuentes oficiales consultadas el 3 de septiembre de 2026.
depends_on healthy ordena Postgres. Esta guía es qué ni siquiera se crea.
La regla
services:
agent:
image: agent:pinned
postgres:
image: postgres:18
migrate:
image: agent:pinned
command: ["node", "migrate.mjs"]
profiles: ["tools"]
depends_on:
postgres:
condition: service_healthy
adminer:
image: adminer
profiles: ["tools"]
Prod: docker compose up -d sin COMPOSE_PROFILES. Tools: COMPOSE_PROFILES=tools docker compose up o docker compose --profile tools up.
El spec (curl 2026-09-03): sin profiles, el servicio siempre está habilitado. Con lista, Compose lo ignora si ningún nombre coincide con los perfiles activos.
Nombres válidos: regex [a-zA-Z0-9][a-zA-Z0-9_.-]+. tools, debug, migrate sí. Empieza con letra o dígito.
La guía oficial dice que los servicios core no lleven profile. El agente, Postgres y Caddy son core. Adminer no.
Cómo se encienden
CLI (docs docker compose, curl 2026-09-03): --profile “Specify a profile to enable”. Varios: --profile frontend --profile debug. Equivale a COMPOSE_PROFILES=frontend,debug (coma, sin espacio en el ejemplo oficial).
COMPOSE_PROFILES (envvars oficiales): al correr docker compose up, arranca los que coinciden más los que no tienen profile. COMPOSE_PROFILES=frontend no apaga Postgres.
Todos a la vez: docker compose --profile "*". No lo dejes en el unit de systemd del VPS.
.env del directorio del compose sí puede setear COMPOSE_PROFILES. Si copias el .env del laptop al VPS “porque así arranca todo”, Adminer vive 24/7. dockerignore no cubre el env del host.
Target explícito (migrate one-shot)
Si apuntas el servicio en la línea de comando, Compose añade su profile al set activo. No hace falta --profile tools para un one-shot:
docker compose up -d
docker compose run --rm migrate
--rm (docs compose run): borra el contenedor al terminar aunque el servicio tenga restart policy. Eso es el job de migrate, no un daemon.
Ojo: al targetear migrate, arranca él y sus depends_on (Postgres). No arranca el resto del profile tools. Adminer sigue off hasta --profile tools o COMPOSE_PROFILES=tools.
Si el target tiene depends_on a otro servicio también con profile, ese dependency tiene que: compartir profile, arrancar aparte, o no tener profile. Si no, el modelo es inválido.
depends_on vs profiles
No pongas depends_on: migrate en el webhook. En prod migrate no existe. required default true (Compose 2.20.0+): Compose se queja. El webhook no espera un one-shot.
Migraciones: compose run --rm migrate en el deploy, o condition: service_completed_successfully en un up de CI, no en el daemon 24/7.
Postgres sí es service_healthy y sin profile.
links, extends y service:xxx no encienden un profile ignorado: Compose error. No uses un alias para “traer” Adminer.
Qué no cubre el profile
El spec: solo el top-level services filtra. Networks, volumes, secrets, configs siguen activos aunque Adminer esté off. Una network tools declarada no desaparece. Networks sigue haciendo falta: no publiques 8080.
Profile no es firewall. Quien tenga SSH hace --profile tools up. Cierra ports igual.
Tabla

| Servicio | Profile | up -d prod | Cómo encenderlo |
|---|---|---|---|
| agente | (ninguno) | sí | siempre |
| postgres | (ninguno) | sí | siempre |
| caddy | (ninguno) | sí | siempre |
| migrate | tools | no | compose run --rm migrate |
| adminer | tools | no | --profile tools |
Ensayo: docker compose config --services (flag oficial: un nombre por línea) sin env no lista adminer. Con COMPOSE_PROFILES=tools, sí. docker compose config --profiles lista los nombres de profile.
docker compose down sin profile solo baja los unassigned (agente/postgres/caddy). COMPOSE_PROFILES=tools docker compose down baja tools y unassigned. Para bajar solo Adminer: docker compose down adminer / stop adminer.
Varios profiles
Un servicio en ["tools", "debug"] se enciende si cualquiera está activo (unión). COMPOSE_PROFILES=tools no enciende un servicio que solo tiene debug.
No pongas prod como profile del webhook. El core va sin atributo.
Preview vs prod
Preview del VPS puede COMPOSE_PROFILES=tools. Prod: vacío. Preview vs production es el criterio; aquí el knob es el env.
CI (Actions): job de migrate con compose run --rm, no up --profile tools -d que deja Adminer.
Fly / Railway / Workers
No hay profiles: de Compose. Fly: [processes] / process groups en fly.toml (docs de configuration, curl 2026-09-03): HTTP processes limita qué grupo recibe requests. Un migrate es otro process group o una Machine one-shot, no un profile. Railway: otro servicio. Workers no es Compose.
Errores comunes

| Síntoma | Causa | Fix |
|---|---|---|
| Adminer en :8080 prod | sin profiles | profiles: ["tools"] |
| webhook no arranca | profile en el agente | quítalo |
up falla por migrate | depends_on + required true | job run --rm |
.env con COMPOSE_PROFILES=tools | copy del laptop | vacío en prod |
down deja Adminer | down sin profile | down adminer o profile en down |
run migrate levanta Adminer | no: solo target + depends_on | no uses --profile tools para un job |
Fly profiles: | no existe | process groups |
scale: 0 “como profile” | el servicio sigue existiendo | profile ni se crea |
Relación con el resto
- Orden DB: healthy.
- Redes: compose networks.
- Preview: preview vs prod.
- Health del bot: healthchecks no mira Adminer.
- Kill switch: kill switch apaga el agente, no “apaga tools” que ya debería estar off.
- Restart de tools: unless-stopped en Adminer →
no. Si alguien hace--profile tools upy crashea, no loops.
Checklist
- Agente / postgres / caddy sin
profiles - adminer / migrate con
tools(regex válida) - Prod sin
COMPOSE_PROFILESen systemd ni.envdel host - Ensayo:
compose config --servicesen prod no lista adminer - Migraciones:
compose run --rm migrate, no daemon - Documenta
up --profile toolspara debug - Sin
portsde tools 24/7 -
depends_ondel webhook no apunta a migrate
FAQ
¿scale: 0 en vez de profiles? Peor: el servicio existe en el modelo. Profile ni se crea.
¿Un compose.prod.yml? Válido. Profiles evitan dos archivos si el yaml es uno.
¿K8s? Jobs vs Deployments. Mismo criterio: migrate no es ReplicaSet del webhook.
¿Un worker de cola? Si es 24/7, sin profile. Si es batch semanal, profile batch y un cron compose --profile batch run --rm.
¿enabled: false de un plugin? No. El knob oficial es profiles.
¿Profile en Postgres “para ahorrar”? El agente sin DB es crash loop. Core siempre on.
El ensayo extra: clone del yaml de prod; up -d; ps sin adminer. up --profile tools; aparece. COMPOSE_PROFILES=tools compose config --services incluye adminer; sin env, no.
Siguiente paso: si tools ya están off y 8080 igual abre, networks y ports. Sin runtime: curso.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



