Una de las desventajas de Docker respecto a Kubernetes, es que en caso de fallo del nodo donde corren los contenedores, éstos no arrancan automáticamente cuando el nodo se recupera. El caso más sencillo es cuando hay que apagar/reiniciar el nodo por algún motivo.

En mi caso, el motivo de fallo del nodo ha sido que lo he apagado durante las vacaciones ;)

De todas formas, he decidido configurar los contenedores de forma que se inicien automáticamente con el arranque del sistema. En este artículo te explico cómo.

Como en Hypriot OS (un derivado de Debian) se usa systemd para gestionar el arranque, parada, etc de procesos del sistema operativo. Para conseguir que el contenedor arranque al iniciar el sistema crearemos un unit file, el fichero que define las propiedades del proceso que quieres ejecutar. En este caso, el “proceso” será el comando Docker que lanza un contenedor.

systemd se organiza alrededor de dos conceptos: el unit file y el target. El unit file es el fichero de configuración que describe las propiedades del proceso, mientras que el target es el mecanismo para agrupar procesos y arrancarlos a la misma vez (durante los init levels del arranque del sistema).

Creando el unit file

Los ficheros unit file se encuentran en /etc/systemd/system.

Creamos un fichero home-dns.service para el servicio de DNS creado en la entrada anterior usando dnsmasq.

[Unit]
Description=Home DNS (dnsmasq)
After=docker.service
Requieres=docker.service

[Service]
TimeoutStartSec=0
ExecStartPre=/usr/bin/docker stop home-dns
ExecStartPre=/usr/bin/docker rm home-dns
ExecStart=/usr/bin/docker run --name home-dns -p 53:53 -p 53:53/udp --cap-add=NET_ADMIN -v /home/pirate/rpi-alpine-dnsmasq/dnsmasq.conf:/etc/dnsmasq.conf -v /home/pirate/rpi-alpine-dnsmasq/hosts:/etc/hosts xaviaznar/rpi-dnsmasq

[Install]
WantedBy=multi-user.target

El fichero está dividido en tres secciones:

  • Unit Indica en qué orden debe lanzarse el proceso, en este caso, después del arranque del servicio docker.service. Para que el proceso funcione también especificamos que se requiere docker.service. En cuanto a Description, el valor indicado aparece en los logs de sistema, etc.

  • Service En esta sección del fichero se describe el proceso:

    • ExecStartPre son tareas que se realizan antes de la ejecución del proceso. Del mismo modo tenemos ExceStartPost, para ejecutar tareas después de arrancar el proceso. Si usamos =- en vez de =, systemd ignorará los errores que devuelva la tarea especificada.
    • ExecStartes donde especificamos el comando a ejecutar. En nuestro caso, un comando docker run.

    No hay que usar la opción -d en docker run para evitar que el proceso pase a segundo plano, lo que haría que el contenedor no fuera un descendiente de proceso systemd; esto se interpretaría como que ha fallado y el daemon se detendría.

  • Install En esta sección del fichero se indica en qué grupo se iniciará el proceso especificado en la sección anterior.

Para crerar el nuevo servicio, habilitamos la nueva unit y lo arrancamos:

sudo systemctl enable home-dns.service
sudo systemctl start home-dns

Puedes verificar que el contenedor ha arrancado mediante docker ps, por ejemplo.

Podemos ampliar el fichero unit incluyendo también comandos para la acción stop:

[Unit]
Description=Home DNS (dnsmasq)
After=docker.service
Requieres=docker.service

[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker stop home-dns
ExecStartPre=-/usr/bin/docker rm home-dns
ExecStart=/usr/bin/docker run --name home-dns -p 53:53 -p 53:53/udp --cap-add=NET_ADMIN -v /home/pirate/rpi-alpine-dnsmasq/dnsmasq.conf:/etc/dnsmasq.conf -v /home/pirate/rpi-alpine-dnsmasq/hosts:/etc/hosts xaviaznar/rpi-dnsmasq
ExecStop=/usr/bin/docker stop home-dns
ExecStopPost=/usr/bin/docker rm home-dns

[Install]
WantedBy=multi-user.target

Ahora, al arrancar el equipo, el servicio de DNS arrancará como un servicio más del sistema operativo.

Puedes leer más sobre los unit files en: