Regresamos a vueltas con contenedores y docker. En este nuevo post vamos a ver como generar un servicio de systemd para nuestros ficheros docker compose o docker-compose.yml. Así que sí, después de la larga espera para hablar un poco de contenedores, vamos a encadenar un par de artículos consecutivos sobre este tema.
Iniciando tus contenedores automáticamente al inicio con docker compose y systemd
Nuestro objetivo es hacer que nuestros servicios y contenedores definidos en un fichero docker-compose.yml se inicien automáticamente con el arranque del sistema. Para ello necesitaremos:
- Un fichero docker-compose.yml con la definición de los servicios y contenedores.
- Un fichero de unidad o unit file de systemd donde se define el servicio asociado a nuestro fichero compose.
- Probar el inicio y parada de nuestros servicios contenerizados con systemd.
- Habilitar nuestro servicio para que se inicie al arranque del sistema.
Fichero docker-compose.yml base para integrar con systemd
Como parece lógico, lo primero que necesitamos para poder gestionar nuestro fichero docker compose mediante systemd es un fichero docker-compose.yml.
Como ejemplo para este artículo vamos a usar un fichero docker compose bastante simple. Solo contendrá un servicio web que será un servidor web nginx. Si sientes curiosidad por manejar ficheros docker-compose.yml más complejos puedes echarle un ojo a nuestro artículo sobre Gluetun y los ejemplos en nuestro repositorio que en él se muestran, o visitar la documentación oficial de Docker Compose.
Nuestro fichero docker-compose.yml será este:
---
services:
web:
image: nginx
container_name: nginx_noroute2host
ports:
- "8080:80"
Y lo vamos a colocar, por ejemplo, en el siguiente directorio: /store/docker-compose-nginx. Pero tú puedes colocarlo donde prefieras. Eso sí, recuerda donde lo haces porque lo vamos a necesitar más adelante.
Unit File o fichero de unidad de systemd
Una vez que tenemos el fichero docker compose, el siguiente paso es generar un servicio de systemd asociado a nuestro fichero docker-compose.yml.
Llegados a este punto habrá alguno que se pregunte ¿qué es systemd? Aunque muchos de los que estéis leyendo esto ya lo sabréis, systemd es un gestor de sistemas y de servicios para Linux. Y esto se traduce en que es el sistema de inicialización por defecto en muchas distribuciones Linux, incluidas Debian, Redhat y sus derivadas. Así que se puede decir que hoy en día es el sistema de arranque de muchas distribuciones Linux.
Systemd funciona en base a unidades, y estas unidades se definen en ficheros de unidad. En concreto, en la ruta /etc/systemd/system/ se incluyen los ficheros de unidad personalizados del usuario entre otros.
Además, estas unidades pueden ser de diferente tipo, pero la unidad que nos interesa para llevar a cabo nuestra tareas es la de servicio o service.
Así que vamos a crear un fichero de unidad o unit file en la siguiente ruta y, por ejemplo, con el siguiente nombre: /etc/systemd/system/docker-compose-nginx.service.
[Unit]
Description=Docker compose de NGINX como servicio
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=true
User=adrimcgrady
WorkingDirectory=[TU/DIRECTORIO/QUE/CONTIENE/EL/FICHERO/DOCKER/COMPOSE]
ExecStart=[/RUTA/ABSOLUTA/A/TU/COMANDO]/docker-compose up -d --remove-orphans
ExecStop=[/RUTA/ABSOLUTA/A/TU/COMANDO]/docker-compose down
[Install]
WantedBy=multi-user.target
En el fichero de unidad de arriba hay varios parámetros que aparecen parametrizados. Para mayor claridad te dejo aquí abajo el fichero de unidad completo para nuestro ejemplo.
[Unit]
Description=Docker compose de NGINX como servicio
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=true
User=adrimcgrady
WorkingDirectory=/store/docker-compose-nginx
ExecStart=/usr/local/bin/docker-compose up -d --remove-orphans
ExecStop=/usr/local/bin/docker-compose down
[Install]
WantedBy=multi-user.target
Usando systemd para iniciar los contenedores definidos en el fichero docker-compose.yml
Antes de correr hay que aprender a andar. Pues siguiendo el símil, antes de arrancar los contenedores con el inicio del sistema hay que probar que se pueden arrancar y parar sin problemas con systemd, o más concretamente con systemctl
.
Como ya tenemos definido tanto nuestro fichero docker-compose.yml como nuestro unit file de systemd, lo único que queda es probarlo.
El inicio de un servicio con systemctl
es tan sencillo como:
sytemctl start NOMBRE_DE_SEVICIO
Por lo que si queremos arrancar el servicio que hemos definido como ejemplo, habrá que ejecutar simplemente:
root@raspibox:~# systemctl start docker-compose-nginx.service
Y para comprobar el estado del servicio lo podemos hacer vía systemctl status
:
root@raspibox:~# systemctl status docker-compose-nginx.service
● docker-compose-nginx.service - Docker compose de NGINX como servicio
Loaded: loaded (/etc/systemd/system/docker-compose-nginx.service; disabled; vendor preset: enabled)
Active: active (exited) since Sun 2025-04-06 13:25:37 CEST; 1min 21s ago
Process: 25345 ExecStart=/usr/local/bin/docker-compose up -d --remove-orphans (code=exited, status=0/SUCCES>
Main PID: 25345 (code=exited, status=0/SUCCESS)
CPU: 578ms
Apr 06 13:25:24 raspibox systemd[1]: Starting Docker compose de NGINX como servicio...
Apr 06 13:25:27 raspibox docker-compose[25345]: Container nginx_noroute2host Created
Apr 06 13:25:27 raspibox docker-compose[25345]: Container nginx_noroute2host Starting
Apr 06 13:25:37 raspibox docker-compose[25345]: Container nginx_noroute2host Started
Apr 06 13:25:37 raspibox systemd[1]: Finished Docker compose de NGINX como servicio
También podemos ver el si el contenedor está funcionando vía docker ps
:
root@raspibox:~# docker ps --last 1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c6d145c6e64a nginx "/docker-entrypoint.…" 3 weeks ago Up 3 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx_noroute2host
O lo que es mejor, simplemente se puede hacer la prueba de conectar a nuestro servidor web nginx contenerizado:
Llegados a este punto, toca probar la parada del servicio. De manera genérica esto puede hacerse de la siguiente manera:
sytemctl stop NOMBRE_DE_SEVICIO
Por tanto, para parar el servicio de ejemplo:
root@raspibox:~# systemctl stop docker-compose-nginx.service
Y se puede comprobar que nuestro contenedor nginx_noroute2host ya no está corriendo:
root@raspibox:~# docker ps --filter name=nginx_noroute2host
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Así que si volvemos a repetir la prueba de conexión al servidor Nginx, ahora obtendremos un error:
Último paso: Habilitar el servicio al arranque
Ya está todo probado y definido así que nos queda simplemente el último paso, habilitar nuestro servicio de systemd. Esto es algo bastante sencillo y parecido a los comandos anteriores con systemctl
. La sintaxis es esta:
systemctl enable NOMBRE_DE_SEVICIO
Lo que aplicado al servicio que estamos usando de ejemplo es simplemente:
systemctl enable docker-compose-nginx.service
Y ya está, ya sabes todo lo necesario para:
- Definir tus contenedores y servicios en un fichero docker-compose.yml
- Integrar el fichero docker-compose.yml con systemd mediante un fichero de unidad o unit file.
- Iniciar tus contenedores del fichero compose mediante el servicio de systemd definido.
- Habilitar este servicio al arranque del sistema.
Antes de acabar: Ficheros de ejemplo
Además de la explicación disponible en este post, se han dejado los ficheros compose y de unidad en el repositorio del blog a modo de referencia. Este es el acceso directo a cada fichero:
- Fichero docker-compose básico para servidor web nginx
- Fichero de unidad o unit file de systemd para nuestro docker compose de nginx
Enlaces de interés:
Artículo anterior
Artículos relacionados:
- Guía de Gluetun: VPN y Proxy para tus contenedores o para cualquier dispositivo o aplicación en tu red
- Ordenación por número de versión en la terminal con sort y ls
- Previsualización de ficheros Markdown en Vim en la terminal
- Como hacer que bash no distinga entre mayúsculas y minúsculas
- El comando tee