SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Guía de Docker Compose para servidores reales

Consulta los comandos de Compose V2 para el trabajo diario: ciclo de vida, cambios, logs, shells, redes, volúmenes y limpieza segura desde tu servidor.

Los comandos de Compose que se usan realmente

Docker Compose incluye decenas de subcomandos. El trabajo diario en un servidor usa aproximadamente una docena. Esta página los agrupa según la tarea que realiza, explica con claridad el motivo de cada uno y enlaza con el análisis detallado cuando un comando oculta alguna particularidad.

Todo lo descrito aquí usa Compose V2 o V5: docker compose con un espacio, no el antiguo script docker-compose. Ambos son complementos escritos en Go. En Linux, el complemento de Compose se instala por separado de Docker Engine. Ubuntu 24.04 LTS todavía ofrece la herramienta heredada Python V1 como docker-compose versión 1.29.2-6ubuntu1 en su repositorio universe. Compruébelo con docker compose version. Si el comando no está disponible, configure el repositorio de Docker e instale el paquete docker-compose-plugin.

Todos los comandos siguientes se ejecutan desde el directorio que contiene compose.yaml. Compose usa el nombre de ese directorio como nombre de proyecto predeterminado, salvo que lo anule. Sin -f ni COMPOSE_FILE, Compose busca un archivo de configuración en el directorio de trabajo y sus directorios padre. Por tanto, ejecutar el comando un nivel más arriba sólo encuentra su stack si su archivo sigue dentro de esa ruta de búsqueda. Si el formato del archivo aún es nuevo para usted, empiece por un primer archivo de Compose en un VPS y vuelva aquí para consultar los comandos.

Ciclo de vida: los cuatro comandos que se escriben y el que elimina los contenedores

docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose down

up -d crea la red, crea los contenedores, los inicia y termina. Termina después de iniciar los contenedores sin esperar a que las aplicaciones estén listas. Por eso, un script de despliegue que ejecuta después una comprobación curl suele fallar en el primer intento. up -d --wait espera a que los servicios con comprobaciones de estado estén en estado saludable y a que los servicios sin ellas estén en ejecución. Un servicio en estado no saludable o un --wait-timeout vencido provocan una salida distinta de cero. El indicador sólo es tan fiable como la comprobación que ejecuta. Por eso, escriba una comprobación de estado en la que Compose pueda confiar antes de usarlo en automatizaciones.

stop detiene los contenedores y los conserva. Después, start vuelve a iniciar los mismos contenedores con la misma capa de escritura. down detiene los contenedores y luego elimina los contenedores y la red del proyecto. Todo lo escrito dentro del contenedor y fuera de un volumen se elimina con ellos. Es la confusión más costosa en Compose. La diferencia completa entre down y stop explica en qué casos afecta.

restart no es una recarga. Detiene e inicia el mismo contenedor con la configuración que ya tiene. Por tanto, una variable de entorno modificada, una etiqueta de imagen nueva o un mapeo de puertos editado no tienen ningún efecto. Para aplicar un cambio en el archivo, vuelva a ejecutar up -d. Compose compara cada servicio con su contenedor en ejecución y recrea los contenedores cuya configuración o imagen haya cambiado.

Aplicar un cambio: recrear, descargar o volver a compilar

docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build web

up -d reutiliza los contenedores en ejecución cuando su configuración y su imagen no han cambiado; la descarga y la compilación de imágenes siguen la política de descarga del servicio. --force-recreate ignora esa comparación y reemplaza todos los contenedores aunque la configuración sea idéntica, por lo que es la forma más rápida de eliminar estados extraños dentro de los contenedores.

La rutina explícita de actualización de imágenes usa dos comandos porque realizan tareas distintas. pull descarga la imagen actual para cada etiqueta indicada en el archivo. Después, up -d comprueba que el ID de imagen del servicio ya no coincide con el del contenedor en ejecución y lo recrea. Con la política de descarga predeterminada missing, se reutilizan las etiquetas almacenadas en la caché, excepto latest, que siempre se descarga. El riesgo contrario aparece en una pila con varios servicios: descargar latest para todos los servicios al mismo tiempo puede romper una aplicación que funcionaba diez segundos antes. Por eso, un espacio de trabajo AFFiNE autogestionado recomienda fijar la imagen de la aplicación y la imagen de migración al mismo digest. Fijar las imágenes también convierte una actualización en una edición deliberada de la etiqueta seguida de esa misma descarga y recreación. En una pila que migra la base de datos durante el arranque, conviene tener un volcado preparado antes de ejecutar cualquiera de los dos comandos. Esa es la rutina que sigue una mesa de soporte de Chatwoot autogestionada en cada actualización de versión.

build se aplica a los servicios que declaran una sección build:, incluidos los servicios que también declaran un image:. up -d --build compila e inicia en un solo paso. Este es el ciclo normal mientras se modifica el código. Use --no-cache sólo cuando una capa almacenada en la caché esté claramente obsoleta, porque vuelve a compilar todas las capas desde cero. Algunos proyectos ofrecen ambas rutas desde un mismo repositorio clonado. En ese caso, los dos ciclos son rutas de actualización alternativas: un rastreador de entrenamientos openGym autogestionado usa docker compose up -d --build para compilar su checkout fijado, porque descargar sus imágenes latest puede ejecutar una versión más reciente que la de ese checkout.

Qué está en ejecución

docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose ls

ps muestra sólo los contenedores en ejecución. Un servicio que falló durante el arranque no aparece ahí hasta que se añade -a, por lo que un contenedor ausente en ps mientras ps -a lo muestra como Exited (1) es el patrón normal de un fallo de arranque. Lea el código de salida y, después, los registros.

logs -f sigue todos los servicios a la vez y añade el nombre del servicio al principio de cada línea. Esta es la vista adecuada cuando los servicios se comunican entre sí y el orden de los eventos es importante. Indique un servicio para limitar la salida. --tail=100 es importante en un contenedor que lleva un mes en ejecución, porque la opción predeterminada muestra todo el historial y llena el terminal. --since 15m responde a la pregunta habitual: qué ocurrió durante el reinicio que acaba de hacer.

top muestra los procesos dentro de cada contenedor. Esto permite distinguir entre «el contenedor está en ejecución» y «el proceso dentro del contenedor está en ejecución». ls sale del directorio actual y muestra los proyectos de Compose en ejecución en el host junto con su estado; añada -a para incluir los proyectos detenidos.

Obtener un shell dentro de un servicio

docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web sh

exec ejecuta un comando dentro de un contenedor que ya está activo. run inicia un contenedor nuevo a partir de la misma definición de servicio. Esto es necesario cuando el servicio no permanece activo el tiempo suficiente para ejecutar un comando dentro de él. Combine siempre run con --rm. Sin esta opción, cada ejecución deja un contenedor detenido, y estos se acumulan hasta que docker compose ps -a deja de ser legible.

Pruebe sh antes que bash. Algunas imágenes basadas en Alpine incluyen bash, incluida la imagen oficial de PostgreSQL Alpine. Cuando no está disponible, el error muestra exec: "bash": executable file not found in $PATH. Añadir --no-deps a run omite las dependencias del servicio. Así, una comprobación rápida de la configuración no inicia toda la base de datos.

run --rm web env es la forma más rápida de ver el entorno que recibió realmente un servicio, después de combinar todos los archivos .env, los bloques environment: y las variables del shell. Cuando un valor es incorrecto, el orden de combinación suele ser la causa. cómo Compose resuelve los archivos env y los secretos explica qué origen tiene prioridad.

Redes, puertos y resolución de nombres

docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networks

De forma predeterminada, Compose coloca todos los servicios en una red del proyecto, y cada nombre de servicio funciona como un nombre DNS en ella. Ejecutar getent hosts db dentro de web, cuando la imagen incluye getent, comprueba la resolución de nombres; no verifica si db acepta conexiones. Si el nombre se resuelve pero la conexión es rechazada, compruebe que el servidor esté ejecutándose y escuchando en la dirección y el puerto solicitados; enlazarse sólo a 127.0.0.1 es una posible causa. El mismo límite explica por qué un contenedor iniciado fuera del proyecto, ya sea mediante docker run o como su propia pila, necesita una red compartida para resolver un nombre de servicio como jellyfin. Esto es lo primero que debe comprobar cuando un frontend de Halcyon para su biblioteca de Jellyfin no puede acceder al servidor al que apunta. El resto de este modelo se explica en cómo funcionan las redes de Compose y el DNS de los servicios.

port web 80 muestra la dirección del host y el puerto en los que está publicado un puerto del contenedor. Esto evita tener que deducirlos cuando la asignación procede de una variable. Publicar un puerto también escribe una regla de firewall que Docker gestiona por su cuenta, y esa regla se aplica antes que las suyas. Por tanto, un servicio que consideraba privado puede quedar abierto a Internet. Este caso se explica en por qué los puertos publicados de Docker omiten ufw. Es más seguro dejar esos puertos sin publicar y colocar delante de los servicios un único proxy con autenticación en la red del proyecto. Eso es lo que ofrece ejecutar Authentik como capa de inicio de sesión único.

Volúmenes y datos

docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -v

config --volumes muestra los volúmenes con nombre que declara el proyecto, uno por línea. Esa lista sólo es una parte del inventario de copias de seguridad: también hay que comprobar los montajes bind y los archivos de configuración. Cuando los volúmenes contienen datos irremplazables, el comando exacto de copia de seguridad es tan importante como la lista. Por eso, la comparación entre PhotoPrism e Immich detalla los comandos de volcado y copia que necesita cada servidor de fotos. cp copia un archivo hacia un contenedor o desde él sin abrir un shell, mediante la sintaxis service:path en el lado que corresponda al contenedor.

down -v elimina los volúmenes con nombre declarados, excepto los externos, además de los volúmenes anónimos conectados a los contenedores, junto con los contenedores. Es el comando adecuado para desmontar una pila de prueba y el incorrecto para cualquier pila que contenga datos importantes, porque no pide confirmación y no se puede deshacer. Los montajes bind sobreviven, porque residen en el sistema de archivos del host. Esta diferencia en el alcance del impacto es una de las razones para elegir deliberadamente entre montajes bind y volúmenes con nombre.

Limpieza que libera espacio en disco sin perder datos

docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune

--remove-orphans elimina los contenedores que pertenecen al proyecto pero que ya no aparecen en el archivo. Esto es exactamente lo que ocurre después de cambiar el nombre de un servicio. Sin esta opción, esos contenedores siguen ejecutándose y docker compose ps incluye los contenedores huérfanos en ejecución de forma predeterminada.

docker system df muestra dónde se ha usado el espacio en disco antes de eliminar nada. Divide el uso entre imágenes, contenedores, volúmenes locales y caché de compilación, e indica cuánto espacio se puede recuperar en cada categoría. image prune -a elimina todas las imágenes que ningún contenedor utiliza, tengan etiqueta o no. En un equipo que haya descargado varias versiones de una imagen grande, normalmente esta opción proporciona el mayor ahorro. builder prune elimina de forma predeterminada la caché de compilación no asociada. Añada -a para eliminar toda la caché de compilación no utilizada.

Ninguno de esos comandos afecta a un volumen con nombre. docker volume prune --all, docker compose down -v y docker volume rm eliminan volúmenes con nombre. docker volume prune sin opciones elimina sólo los volúmenes anónimos.

Comprobar el archivo antes de que cause problemas

docker compose config --quiet
docker compose config --services
docker compose --dry-run up -d

config --quiet valida el archivo y no muestra nada si la validación es correcta, por lo que resulta adecuado para una etapa previa al despliegue o un hook de Git. config sin opciones muestra el archivo completamente combinado e interpolado. Así puede confirmar que una variable se resolvió y que un archivo de sustituciones se aplicó en el orden esperado. Una variable no definida aparece como un valor vacío, junto con la advertencia The "X" variable is not set. Defaulting to a blank string.

--dry-run es una opción global, no una opción del subcomando, por lo que debe colocarse antes de up. Muestra todas las acciones que Compose ejecutaría y no modifica nada. Son treinta segundos bien invertidos antes de ejecutar down en una pila importante.

Trabajar con archivos, perfiles y proyectos

docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d

Varios indicadores -f se combinan en orden, y los archivos posteriores sobrescriben las claves de los anteriores. Esta es la forma estándar de mantener un archivo base con una pequeña sobreescritura para producción. Sin embargo, las reglas son diferentes para las listas y los mapas, así que consulte cómo combina Compose varios archivos antes de investigar un resultado inesperado.

--profile inicia los servicios etiquetados con ese perfil junto con los que no tienen etiqueta. Esto mantiene las herramientas de depuración fuera de un up normal. -p establece el nombre del proyecto, por lo que dos copias de una misma pila pueden ejecutarse en paralelo con redes y nombres de volúmenes independientes. Para recuperar la pila después de un reinicio, use una política de reinicio o una unidad que ejecute Compose automáticamente, como se describe en iniciar pilas de Compose durante el arranque.

FAQ

¿Qué sustituyó docker-compose con un guion?

Compose V2 y V5, que se ejecutan como docker compose con un espacio. En Linux, Compose es un plugin que se instala por separado; Ubuntu 24.04 LTS todavía ofrece la herramienta V1 escrita en Python en su repositorio universe. Si no está disponible la forma con espacio, configure el repositorio de Docker e instale el paquete docker-compose-plugin. Actualice los scripts antiguos para usar la forma con espacio en lugar de añadir un alias, porque V2 tiene flags que V1 no tenía.

¿Por qué docker compose restart no aplica mi cambio de configuración?

restart detiene e inicia el contenedor existente con la configuración con la que se creó, y nunca vuelve a leer compose.yaml. Cualquier cambio en las variables de entorno, los puertos, los volúmenes o la etiqueta de la imagen requiere docker compose up -d, que compara cada servicio con su contenedor en ejecución y vuelve a crear los que difieren. Añada --force-recreate si quiere que el reemplazo se realice aunque no haya cambiado nada en el archivo.

¿Cómo actualizo un servicio a una imagen más reciente?

Ejecute docker compose pull y después docker compose up -d. El comando pull obtiene la imagen actual para cada etiqueta del archivo, y up -d vuelve a crear cualquier servicio cuyo ID de imagen ya no coincida con el de su contenedor. Ejecutar up -d por separado sigue la política de pull: la política predeterminada missing reutiliza las imágenes en caché, excepto latest, que siempre se obtiene.

¿Qué comandos de limpieza son seguros en un servidor en producción?

docker system df informa del uso de disco sin eliminar nada; docker image prune -a y docker builder prune eliminan las imágenes y la caché de compilación que no se utilizan, por lo que los servicios en ejecución siguen funcionando y los volúmenes con nombre no se modifican. La pareja peligrosa es docker compose down -v, que elimina los volúmenes con nombre no externos declarados por el proyecto y los volúmenes anónimos asociados sin pedir confirmación, y docker volume prune --all, que elimina los volúmenes locales que no se utilizan, incluidos los que tienen nombre, después de una única confirmación y/N, o sin confirmación con -f. Ejecute primero docker compose config --volumes para saber qué elementos están en riesgo.

¿Puedo ejecutar un comando sin iniciar todo el stack?

Sí. docker compose run --rm --no-deps web sh inicia un único contenedor a partir de la definición del servicio web, omite sus dependencias y elimina el contenedor cuando se sale del comando. Use exec cuando el contenedor ya esté en ejecución, porque exec ejecuta el comando dentro del contenedor activo y muestra el estado real del servicio.

¿Te resultó útil este artículo?