Ejecutar Docker Compose como un servicio de Linux con systemd
Docker Compose en el arranque, gestionado por systemd.
Docker Compose en un servidor Linux debe iniciarse al arranque, detenerse correctamente al apagarse y sobrevivir a los reinicios sin intervención manual.
Docker Compose no es Kubernetes, y eso está bien para las cargas de trabajo que aborda esta guía. Para muchos sistemas reales, un proyecto de Compose en un único host Linux es la cantidad adecuada de infraestructura: simple, legible, fácil de respaldar y suficiente para herramientas internas, proyectos secundarios, servicios autoalojados, entornos de staging, aplicaciones de producción pequeñas e infraestructura de desarrollo.

La pieza que suele faltar es la gestión de servicios. Ejecutar esto manualmente no es suficiente:
docker compose up -d
Un solo comando inicia el stack, pero no documenta cómo debería iniciarse al arranque, detenerse durante el apagado, recargar cambios después de modificarlos, escribir registros, recuperarse de fallos o actualizarse de forma segura. Ahí es donde systemd ayuda.
Esta guía recorre cómo ejecutar un proyecto de Docker Compose como un servicio de Linux con systemd: archivos de unidad, orden de arranque, actualizaciones, registros y respaldos. La división de responsabilidades es deliberada: Docker ejecuta los contenedores, Compose define el stack y systemd inicia y detiene el proyecto en el host. Forma parte de Herramientas de desarrollo: una guía para flujos de trabajo de desarrollo.
Cuando tiene sentido ejecutar Docker Compose como un servicio
Ejecutar Compose bajo systemd tiene sentido cuando tienes:
- Un único servidor Linux
- Una pequeña aplicación autoalojada
- Un stack de proxy inverso
- Un stack de monitoreo
- Una plataforma de desarrollo local
- Una herramienta interna
- Un entorno de staging
- Un servicio de producción simple con límites conocidos
Ejemplos:
- Nginx Proxy Manager
- Traefik
- Gitea
- Grafana y Prometheus
- PostgreSQL más una pequeña aplicación web
- Uptime Kuma
- Servicios de asistencia de Home Assistant
- Registro privado
- API interna, worker y Redis
Compose es una buena opción cuando el modelo operativo sigue siendo comprensible para una sola persona leyendo un directorio.
Cuando Docker Compose no es suficiente
Usa otra cosa cuando necesites:
- Programación multinodo
- Replanificación automática entre hosts
- Descubrimiento de servicios a nivel de clúster
- Escalado horizontal automático
- Despliegues rodantes en muchas máquinas
- Identidad de carga de trabajo granular
- Políticas de red complejas
- Operaciones de plataforma grandes para múltiples equipos
En ese punto, Kubernetes, Nomad, Swarm o una plataforma gestionada pueden ser una mejor opción.
Mi regla práctica es evitar usar Kubernetes solo para evitar aprender systemd, y evitar usar Compose cuando la carga de trabajo claramente necesita orquestación en múltiples hosts.
La arquitectura básica
Una configuración limpia separa los archivos del proyecto, la unidad de systemd y los datos persistentes en el host. El proyecto de Compose vive bajo /opt/myapp/ con compose.yaml, .env, data/, backups/ y scripts opcionales como scripts/update.sh. El archivo de unidad de systemd está en /etc/systemd/system/myapp.service.
Cada capa tiene un trabajo claro: Docker ejecuta contenedores, Compose define el stack de la aplicación, systemd inicia y detiene el proyecto de Compose en el arranque y apagado, el sistema de archivos del host almacena datos persistentes, los respaldos se mantienen explícitos y las actualizaciones pasan por pasos scripteados y revisables. Esta disposición es deliberadamente aburrida, porque la infraestructura aburrida es más fácil de reparar cuando algo se rompe a las 2 a. m.
Preparar el directorio del proyecto de Compose
Crea un directorio bajo /opt:
sudo mkdir -p /opt/myapp
sudo chown -R "$USER":"$USER" /opt/myapp
cd /opt/myapp
Crea un archivo de Compose:
nano compose.yaml
Ejemplo:
services:
web:
image: nginx:stable
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
healthcheck:
test: ["CMD-SHELL", "nginx -t || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes: {}
Crea el directorio de contenido:
mkdir -p html
echo "Hello from Docker Compose" > html/index.html
Prueba primero manualmente:
docker compose up -d
docker compose ps
docker compose logs --tail=50
Luego deténlo antes de entregar el ciclo de vida a systemd:
docker compose down
No crees un servicio de systemd hasta que el proyecto de Compose funcione manualmente. Mientras pruebas, mantén cerca la Hoja de trucos de Docker Compose para ps, logs, pull y estructura del proyecto.
Usar el comando moderno docker compose
Docker Engine y el plugin de Compose deben estar instalados antes de escribir un archivo de unidad. En Ubuntu, Instalar Docker en Ubuntu recorre APT, Snap, modo rootless y seguridad postinstalación para que termines con un comando docker compose funcional.
Usa esto:
docker compose version
No esto:
docker-compose version
El antiguo binario docker-compose aún existe en muchas máquinas, pero Docker moderno usa Compose como un plugin de CLI de Docker.
En archivos de servicio y scripts, prefiere:
/usr/bin/docker compose
Puedes encontrar la ruta de Docker con:
command -v docker
Normalmente es:
/usr/bin/docker
Crear un servicio de systemd para Docker Compose
Si los archivos de unidad son nuevos para ti, Ejecutar cualquier ejecutable como un servicio en Linux explica Type, ExecStart, systemctl y el flujo de trabajo general de systemd. Esta sección aplica esos patrones específicamente a un stack de Compose.
Crea el archivo de servicio:
sudo nano /etc/systemd/system/myapp.service
Usa esta unidad:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Recarga systemd:
sudo systemctl daemon-reload
Inicia el servicio:
sudo systemctl start myapp.service
Habilitarlo en el arranque:
sudo systemctl enable myapp.service
Verifica el estado:
systemctl status myapp.service
Verifica contenedores:
cd /opt/myapp
docker compose ps
¿Por qué Type=oneshot y RemainAfterExit=yes?
Esta es la parte que muchas guías cometen sutilmente.
docker compose up -d inicia contenedores en modo desconectado y sale, por lo que no hay un proceso Compose de primer plano en ejecución prolongada para que systemd supervise. La unidad de systemd no debería fingir que docker compose up -d es un demonio de larga ejecución.
Usa:
Type=oneshot
RemainAfterExit=yes
Esto le dice a systemd:
- Ejecutar el comando de inicio.
- Considerar la unidad activa después de que el comando salga con éxito.
- Ejecutar
ExecStopcuando el servicio se detenga.
Eso coincide con el comportamiento real de Compose desconectado, por lo que Type=oneshot con RemainAfterExit=yes es el predeterminado correcto para la mayoría de los stacks.
¿Por qué no Type=simple?
Con Type=simple, systemd espera que el proceso ExecStart siga ejecutándose, pero docker compose up -d sale después de iniciar los contenedores. Eso puede hacer que systemd piense que el servicio terminó, luego llamar a la lógica de detención o marcar la unidad como inactiva dependiendo de la configuración.
Si quieres Type=simple, normalmente ejecutarías Compose en primer plano:
ExecStart=/usr/bin/docker compose up
Eso puede funcionar, pero normalmente no lo prefiero para stacks de Compose en servidores. Contenedores desconectados más ExecStop explícito son más fáciles de operar.
Una unidad más amigable para producción
Para un servidor real, prefiero una unidad ligeramente más estricta:
[Unit]
Description=MyApp Docker Compose stack
Documentation=https://example.com/docs/myapp
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/.env.systemd
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Detalles importantes:
WorkingDirectoryapunta al proyecto de Compose.ExecStartPrevalida la configuración de Compose.ExecReloadrecrea los servicios modificados.ExecStopdetiene y elimina los contenedores del proyecto de Compose y la red predeterminada.EnvironmentFile=-...significa que el archivo es opcional.
Crea el archivo de entorno de systemd opcional:
nano /opt/myapp/.env.systemd
Ejemplo:
COMPOSE_PROJECT_NAME=myapp
Luego recarga systemd:
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
Compose .env vs EnvironmentFile de systemd
Compose y systemd tienen sus propios mecanismos de entorno, y mezclarlos causa errores confusos de “variable no establecida” en el arranque.
Compose lee automáticamente un archivo .env en el directorio del proyecto para la sustitución de variables en el archivo de Compose.
Ejemplo .env:
APP_TAG=1.2.3
WEB_PORT=8080
Ejemplo compose.yaml:
services:
web:
image: nginx:${APP_TAG}
ports:
- "${WEB_PORT}:80"
Un EnvironmentFile de systemd establece variables de entorno para el propio comando docker compose.
Ejemplo:
EnvironmentFile=-/opt/myapp/.env.systemd
Para muchos proyectos, solo necesitas .env de Compose.
Usa un archivo de entorno de systemd cuando quieras definir cosas como:
COMPOSE_PROJECT_NAME=myapp
COMPOSE_FILE=compose.yaml
DOCKER_HOST=unix:///var/run/docker.sock
No uses ninguno de los archivos como un almacén de secretos casual. Si los secretos importan, usa secretos de Docker, un administrador de secretos externo, archivos cifrados o al menos permisos estrictos.
Establece permisos restrictivos:
chmod 600 /opt/myapp/.env
chmod 600 /opt/myapp/.env.systemd
Políticas de reinicio: Docker vs systemd
Hay dos capas de reinicio: política de reinicio de contenedores en Compose y política de reinicio de servicio de systemd, y no deben mezclarse ciegamente.
Para contenedores de larga ejecución, establece políticas de reinicio en Compose:
services:
web:
image: nginx:stable
restart: unless-stopped
Valores de reinicio comunes:
| Política | Significado |
|---|---|
| no | No reiniciar automáticamente |
| always | Reiniciar después de la salida y reinicio del demonio |
| on-failure | Reiniciar solo después de un fallo |
| unless-stopped | Reiniciar a menos que se detenga manualmente |
Para la mayoría de los servicios persistentes, prefiero:
restart: unless-stopped
Es predecible y respeta las detenciones manuales intencionales.
La propia unidad de systemd normalmente no debería reiniciarse repetidamente, porque docker compose up -d no es la carga de trabajo en ejecución. Los contenedores sí lo son.
Así que evita esto a menos que tengas un motivo específico:
Restart=always
En la mayoría de las unidades de Compose-como-servicio, deja que Docker maneje los reinicios de contenedores.
Verificaciones de salud
Las políticas de reinicio reinician contenedores cuando los procesos salen. No arreglan mágicamente cada aplicación no saludable.
Añade verificaciones de salud donde sean útiles:
services:
app:
image: example/app:latest
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Verifica la salud:
docker compose ps
Inspecciona un contenedor:
docker inspect container-name
Las verificaciones de salud son especialmente útiles para:
- Aplicaciones web
- Proxies inversos
- Bases de datos
- Colas
- APIs internas
- Workers con un endpoint de salud
Son menos útiles cuando solo verifican que un proceso existe, porque un proceso que está vivo pero atascado sigue pareciendo saludable. Una mala verificación de salud es solo otra mentira en YAML.
Orden de inicio y depends_on
Compose puede definir dependencias:
services:
app:
image: example/app:latest
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Esto puede ayudar con el orden de inicio, pero no confíes demasiado en ello. Las aplicaciones aún deben manejar reintentos: las bases de datos se reinician, las redes fluctúan, DNS toma tiempo, y una aplicación resiliente reintenta las conexiones en lugar de asumir un orden de inicio perfecto.
Registros: journalctl y docker compose logs
Dos vistas de registros cubren la mayoría de la depuración: systemd captura el ciclo de vida de la unidad misma, mientras que Compose captura la salida de la aplicación de los contenedores en ejecución.
Registros del servicio systemd:
journalctl -u myapp.service -n 100 --no-pager
Seguir registros de systemd:
journalctl -u myapp.service -f
Registros del servicio Compose:
cd /opt/myapp
docker compose logs --tail=100
docker compose logs -f
docker compose logs -f web
Para la mayoría de la depuración de aplicaciones, docker compose logs es más útil; para la depuración del ciclo de vida — fallos de inicio, crashes de unidad, errores de permisos — journalctl es más útil. Si systemctl start myapp falla, revisa journalctl primero. Si el stack inicia pero la aplicación está rota, revisa docker compose logs.
Rotación de registros
Los registros de Docker pueden crecer indefinidamente si no los configuras.
Para servidores pequeños, configura la rotación de registros de Docker en /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Reinicia Docker:
sudo systemctl restart docker
Luego reinicia el stack de Compose:
sudo systemctl restart myapp.service
Esto se aplica a contenedores recién creados. Recrea contenedores si es necesario:
cd /opt/myapp
docker compose up -d --force-recreate
La rotación de registros no es glamurosa, pero es una de las formas más fáciles de prevenir una interrupción por disco lleno en un servidor pequeño.
Actualizar un servicio de Compose
Un flujo de actualización manual simple:
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
Si es gestionado por systemd, puedes usar:
sudo systemctl reload myapp.service
Si tu unidad tiene:
ExecReload=/usr/bin/docker compose up -d --remove-orphans
Pero nota: ExecReload no extrae imágenes a menos que incluyas ese paso.
Para actualizaciones explícitas, crea un script.
mkdir -p /opt/myapp/scripts
nano /opt/myapp/scripts/update.sh
Script:
#!/usr/bin/env bash
set -euo pipefail
cd /opt/myapp
docker compose config --quiet
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
docker compose ps
Hazlo ejecutable:
chmod +x /opt/myapp/scripts/update.sh
Ejecútalo:
/opt/myapp/scripts/update.sh
Entonces la unidad del servicio puede permanecer enfocada en el ciclo de vida, mientras el script de actualización maneja el despliegue.
Script de actualización más seguro con gancho de respaldo
Para servicios con estado, actualiza solo después del respaldo.
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp/backups"
cd "$APP_DIR"
mkdir -p "$BACKUP_DIR"
echo "Validating compose file"
docker compose config --quiet
echo "Running backup hook"
if [ -x "$APP_DIR/scripts/backup.sh" ]; then
"$APP_DIR/scripts/backup.sh"
else
echo "No backup hook found"
fi
echo "Pulling images"
docker compose pull
echo "Recreating services"
docker compose up -d --remove-orphans
echo "Pruning unused images"
docker image prune -f
echo "Current status"
docker compose ps
Esto sigue siendo simple, pero ahora codifica un hábito operativo: respaldo antes del cambio.
Detener el servicio
Detén el stack:
sudo systemctl stop myapp.service
Eso ejecuta:
docker compose down
Por defecto, docker compose down elimina:
- Contenedores para servicios en el archivo de Compose
- Redes definidas por el archivo de Compose
- La red predeterminada
No elimina volúmenes nombrados a menos que se lo pidas.
No uses casualmente:
docker compose down -v
Eso elimina volúmenes nombrados declarados en el archivo de Compose y volúmenes anónimos adjuntos a contenedores. Para bases de datos y aplicaciones con estado, eso puede significar eliminar datos reales.
Usa down -v solo cuando signifique “destruir este entorno”.
Reiniciar el servicio
Reinicia la unidad de systemd:
sudo systemctl restart myapp.service
Esto ejecuta el comando de detención y luego el comando de inicio.
Para reiniciar solo contenedores sin recrearlos:
cd /opt/myapp
docker compose restart
Distinción importante:
docker compose restartreinicia contenedores existentes.docker compose up -daplica cambios de configuración o imagen recreando contenedores cuando es necesario.
Si modificaste compose.yaml, usa:
docker compose up -d
No solo:
docker compose restart
Manejar contenedores huérfanos
Si renombras o eliminas un servicio en compose.yaml, los contenedores antiguos pueden permanecer como huérfanos.
Usa:
docker compose up -d --remove-orphans
Por eso los ejemplos de servicio de systemd en esta guía usan:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Mantiene el stack más cerca del archivo de Compose actual.
Respaldos
Los respaldos dependen de la carga de trabajo, pero los principios son estables.
Para montajes de enlace:
/opt/myapp/data/
Haz un respaldo de ese directorio.
Para volúmenes nombrados:
docker volume ls
Inspecciona un volumen:
docker volume inspect volume-name
Para bases de datos, las copias del sistema de archivos no siempre son suficientes. Usa respaldos conscientes de la aplicación:
Ejemplo PostgreSQL:
docker compose exec -T db pg_dump -U postgres appdb > backups/appdb.sql
Ejemplo MariaDB:
docker compose exec -T db mariadb-dump -u root -p appdb > backups/appdb.sql
Ejemplo Redis:
docker compose exec redis redis-cli BGSAVE
Un stack de Compose sin un plan de respaldo no es un servicio, es un experimento temporal que resulta tener tiempo de actividad.
Línea base de seguridad
Para un pequeño servicio de Compose en Linux, comienza con esta línea base:
- Mantén el proyecto de Compose bajo
/opt/appname. - Usa etiquetas de imagen explícitas, no solo
latest, cuando la estabilidad importa. - Usa montajes de enlace o volúmenes nombrados deliberadamente.
- No expongas puertos que no necesites.
- Pon servicios públicos detrás de un proxy inverso.
- Usa HTTPS en el borde.
- Mantén los secretos fuera de Git.
- Restringe los permisos de
.env. - Evita contenedores privilegiados a menos que sean verdaderamente requeridos.
- Evita montar el socket de Docker dentro de contenedores.
- Mantén Docker e imágenes actualizados.
- Prueba el comportamiento del firewall desde otra máquina.
Un patrón peligroso:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Esto da al contenedor control sobre Docker. En la práctica, eso puede convertirse en control a nivel de host. Úsalo solo cuando entiendas el riesgo.
Límites de recursos
En servidores pequeños, un contenedor malo puede consumir el host.
Compose soporta configuraciones relacionadas con recursos, pero el comportamiento puede depender de la versión de Docker Engine y Compose. Para protección simple, comienza con límites a nivel de aplicación y límites de registro de Docker.
Para algunas cargas de trabajo, puedes añadir límites de memoria:
services:
app:
image: example/app:stable
restart: unless-stopped
mem_limit: 512m
También configura recuentos de workers a nivel de aplicación, límites de cola y tamaños de caché. Los límites de contenedor son útiles, pero no son un sustituto para entender la aplicación.
Ejemplo: Un servicio de Compose realista
Directorio:
/opt/whoami/
compose.yaml
.env
Archivo Compose:
services:
whoami:
image: traefik/whoami:v1.10
restart: unless-stopped
ports:
- "${WHOAMI_PORT}:80"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost || exit 1"]
interval: 30s
timeout: 5s
retries: 3
Archivo .env:
WHOAMI_PORT=8080
COMPOSE_PROJECT_NAME=whoami
Unidad systemd:
[Unit]
Description=Whoami Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/whoami
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Instálalo:
sudo systemctl daemon-reload
sudo systemctl enable --now whoami.service
Prueba:
curl http://localhost:8080
Verifica el estado:
systemctl status whoami.service
cd /opt/whoami
docker compose ps
Solución de problemas
El servicio inicia pero los contenedores no están en ejecución
Verifica systemd:
journalctl -u myapp.service -n 100 --no-pager
Valida Compose:
cd /opt/myapp
docker compose config
Verifica Docker:
systemctl status docker
docker info
WorkingDirectory es incorrecto
Si systemd no puede encontrar tu archivo de Compose, confirma:
WorkingDirectory=/opt/myapp
Luego verifica:
ls -la /opt/myapp
ls -la /opt/myapp/compose.yaml
El servicio se ejecuta desde WorkingDirectory, no desde tu directorio de shell actual.
Permisos de Docker denegados
Si la unidad se ejecuta como root, normalmente puede acceder a Docker.
Si estableces User=someuser, ese usuario debe poder acceder a Docker. Normalmente eso significa pertenencia al grupo docker, o una configuración de Docker sin privilegios de root.
Verifica:
groups someuser
Añade el usuario si es apropiado:
sudo usermod -aG docker someuser
Ten cuidado. El grupo Docker es efectivamente privilegiado.
Comando Compose no encontrado
Encuentra Docker:
command -v docker
Usa la ruta completa en la unidad:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Si el plugin de Compose falta:
docker compose version
Instálalo usando tu fuente de paquetes de Docker.
Variables de entorno faltantes
Verifica la configuración de Compose como systemd la vería:
cd /opt/myapp
docker compose config
Si systemd necesita variables de entorno extra, usa:
EnvironmentFile=-/opt/myapp/.env.systemd
Si Compose necesita variables para sustitución, usa:
/opt/myapp/.env
Estos están relacionados, pero no son idénticos.
Contenedores no inician después del reinicio
Verifica si el servicio de systemd está habilitado:
systemctl is-enabled myapp.service
Habilítalo:
sudo systemctl enable myapp.service
Verifica Docker:
systemctl is-enabled docker
systemctl status docker
Verifica registros de arranque:
journalctl -u myapp.service -b --no-pager
La aplicación inicia antes de que la base de datos esté lista
Añade una verificación de salud de la base de datos y depends_on con service_healthy.
También arregla la aplicación. Debería reintentar conexiones a la base de datos. El orden de inicio de infraestructura es útil, pero la lógica de reintento de la aplicación es mejor.
Disco lleno con registros de Docker
Verifica el uso de disco de Docker:
docker system df
Verifica registros grandes de contenedores:
sudo du -h /var/lib/docker/containers | sort -h | tail
Configura la rotación de registros de Docker en /etc/docker/daemon.json.
Luego recrea contenedores.
Errores comunes
Error 1: Ejecutar docker compose up en rc.local
Ejecutar docker compose up desde rc.local o un script de inicio funciona hasta que no — usa una unidad de systemd adecuada en su lugar.
Error 2: Usar Restart=always en systemd y restart: always en Compose
Normalmente solo necesitas políticas de reinicio de contenedores en Compose. Evita que dos supervisores luchen entre sí.
Error 3: Olvidar –remove-orphans
Renombrados y eliminaciones de servicios pueden dejar contenedores antiguos atrás. Usa:
docker compose up -d --remove-orphans
Error 4: Usar docker compose restart después de cambios de configuración
restart reinicia contenedores. No aplica todos los cambios de configuración.
Usa:
docker compose up -d
Error 5: Ejecutar down -v sin pensar
Esto puede eliminar volúmenes. Para servicios con estado, eso puede significar eliminar datos.
Error 6: Sin respaldo antes de pull
Las nuevas imágenes pueden romper. Las bases de datos pueden migrar. Las etiquetas pueden moverse. Haz un respaldo primero.
Error 7: Publicar cada puerto
Solo publica lo que el host necesita exponer. El tráfico interno de servicio a servicio puede permanecer en la red de Compose.
Patrón recomendado final
Para la mayoría de los servicios Linux de un solo host, usa este patrón:
Archivo Compose:
services:
app:
image: example/app:stable
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .env
Unidad systemd:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Habilítalo:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
Opéralo:
sudo systemctl status myapp.service
sudo systemctl restart myapp.service
journalctl -u myapp.service -f
cd /opt/myapp && docker compose logs -f
Este patrón no es sofisticado, y ese es el punto. Docker Compose es excelente para sistemas pequeños y comprensibles, systemd es excelente para iniciar y detener servicios del host, y juntos te dan un modelo de despliegue de servidor único confiable sin fingir que cada proyecto necesita un clúster. Para comandos a nivel de contenedor fuera de Compose — imágenes, volúmenes, redes y limpieza — consulta la Hoja de trucos de Docker.