How to start a Docker container at boot time

Systemd to the rescue

This is not the first time I want to start a Docker container when my computer starts, but I always forget about how to do it, I will take the chance with this article to document two different ways of doing it.

Restart Policies

This is the official technique provided by Docker. You could control whether your containers start automatically when they exit, or when Docker restarts.

To configure the restart policy for a container use the --restart <value> flag when using the docker run command. From potential restart values I suggest to use unless-stopped value, using this value you are saying to Docker: Ey man!, restart always this container unless it is explicitly stopped.

For more information about potential values please refer to the official documentation.

Let’s use as an example a game that I recently set up inside a container on the Raspberry. Agario Clone is an open source clone from the well-known game Agar.io and I would like this container to start every time my Raspberry goes up. To accomplish this just type:

1
sudo docker run --name my-agario-server -p 3000:3000 --restart unless-stopped kafebob/rpi-agario

To check status of the restart policy:

1
sudo docker inspect -f "{{ .HostConfig.RestartPolicy }}" my-agario-server

To update the restart policy (for instance remove restart):

1
sudo docker update --restart=no my-agario-server

You could also have a look about my kafebob/rpi-agario container in the article Your own Agario server on Raspberry Pi.

Init system

There maybe times when other services depend on your Docker containers, in these cases it’s much better to use the init system from your operating system. Steps below are useful for Linux users using systemd as their init system. Nowadays systemd is one of the most popular init systems; Debian, Ubuntu, Raspbian, Arch, Red Hat and many other distributions are using it.

I will try not to go into much detail, since there are many articles describing how to use systemd, I’m just going to document a couple examples about how you can boot a Docker container using systemd.

For more information about systemd I suggest you check out these links:

Step 1 - Create file rpi-agario.service

Assuming that we want to start previous Agario container using systemd and this container already exists in your host and is called my-agario-server, create a file named rpi-agario.service and include following code:

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=My Agario Server
Requires=docker.service
After=docker.service
[Service]
#Restart=always
ExecStart=/usr/bin/docker start -a my-agario-server
ExecStop=/usr/bin/docker stop -t 2 my-agario-server
[Install]
WantedBy=default.target

It looks straightforward, isn’t it?. ExecStart (Line 8) and ExecStop (Line 9) are the directives in charge to start and stop the container.

Line 7 is commented out, because I don’t want systemd restart the service in any case but you could pass values like “always”, “on-success”, “on-failure”, “on-abnormal”, “on-abort”, or “on-watchdog” and these will trigger a restart according to the way that the service was stopped.

Step 2 - Make systemd see your service

Copy file from step 1 in /etc/systemd/system/ and give execution rights to the file.

Now you are going to be able of:

  • Enable the service on boot
1
sudo systemctl enable rpi-agario
  • Check current status
1
sudo systemctl status rpi-agario
  • Disable the service from boot
1
sudo systemctl disable rpi-agario

Aha Moment

An important point to notice from previous init file is the -a flag in ExecStart directive, it took me a few hours to realize what was the problem before the Aha Moment.

According to Docker help, -a or --attach will attach STDOUT/STDERR and forward signals, if you don’t include this flag Docker is going to start the container through ExecStart and it will send a success signal, then systemd will interpret this signal as the process has successfully completed and it will proceed to call ExecStop and maybe your face will be like mine face during some minutes.

systemd beauty

So be aware, always remember to attach consoles and forward signals on the ExecStart directive.

Scripts at start up

As a final note, if you want to execute scripts instead of docker containers it would be useful directives type=oneshot and remainafterexit=yes.

These directives will inform to systemd that the script shall be considered active even when all its processes exited. For instance, I have configured a script to mount some encrypted folders and turn on a nextcloud container, this is how it looks the service descriptor.

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=NextCloud Secure Drive mount
Requires=docker.service
After=network-online.target docker.service
[Service]
Type=oneshot
ExecStart=/home/pi/laboratory/geheim/secure-mount.sh
RemainAfterExit=yes
ExecStop=/home/pi/laboratory/geheim/secure-unmount.sh
[Install]
WantedBy=multi-user.target

I hope these notes are useful to someone in the world!

Resources

Happy coding!