3

I'm launching Docker containers (probably with https://github.com/ibuildthecloud/systemd-docker , which I just discovered) from "systemd --user" unit files. I want them to launch on start.

The problem is that you can't do After=docker.service, because the systemd user mode units can't see the systemd system mode unit.

Does anyone have a good way to fix this?

The "best" idea I've had so far is to make a run-once systemd unit that runs a script that sleep-loops until "docker info" returns something reasonable, and then After= that, but that seems hacky in a bad way.

2

One good solution for this problem is to have the Docker daemon (running on the system instance of systemd) use socket activation.

That way, when you launch a docker command (say from a user systemd unit), it will have a socket to connect to, but it will block until the Docker daemon is actually ready to serve it.

The basic idea of socket activation to elide explicit dependencies is described on this article in the systemd blog, which talks about four services which traditionally have been handled through explicit dependencies, but with socket activation no longer need them to be configured. Here's an excerpt (it's long, but really makes the point):

Socket activation makes it possible to start all four services completely simultaneously, without any kind of ordering. Since the creation of the listening sockets is moved outside of the daemons themselves we can start them all at the same time, and they are able to connect to each other's sockets right-away. I.e. in a single step the /dev/log and /run/dbus/system_bus_socket sockets are created, and in the next step all four services are spawned simultaneously. When D-Bus then wants to log to syslog, it just writes its messages to /dev/log. As long as the socket buffer does not run full it can go on immediately with what else it wants to do for initialization. As soon as the syslog service catches up it will process the queued messages. And if the socket buffer runs full then the client logging will temporarily block until the socket is writable again, and continue the moment it can write its log messages. That means the scheduling of our services is entirely done by the kernel: from the userspace perspective all services are run at the same time, and when one service cannot keep up the others needing it will temporarily block on their request but go on as soon as these requests are dispatched. All of this is completely automatic and invisible to userspace. Socket activation hence allows us to drastically parallelize start-up, enabling simultaneous start-up of services which previously were thought to strictly require serialization. Most Linux services use sockets as communication channel. Socket activation allows starting of clients and servers of these channels at the same time.

The Docker daemon supports socket activation since 2014, so it's likely the version you're using already supports that.

Check if your distribution ships a docker.socket unit, in which case, all you need to do is enable it.

If your Docker daemon supports socket activation, but your distribution doesn't include a docker.socket unit, take a look at this tutorial for instructions on how to set it up.


One more alternative to consider is to switch from Docker to podman.

Podman tries to be a drop-in compatible replacement for Docker (so you can use the same command lines, simply replacing docker with podman.)

The main difference between them is that podman doesn't need a daemon, so you don't need to wait for one to be up before you start a container. Podman is available as a package in most recent versions of Linux distributions. That and the fact that you can use it just as you use docker today should make it easy to get started with it.

  • 1
    Oooh, Podman looks lovely; I had actually been talking to Dan Walsh about these sorts of issues last year, but I didn't know they had already put out a solution. Thanks! – rlpowell Nov 18 '18 at 2:12
0

By the way, instead of running containers with systemd, I do skip that requirement with the docker-systemctl-replacement script altogether.

In that context, user-mode has a different meaning in that the container is run with a "USER=" setting pushing all processes to a non-root owner. It's a requirement by some docker-cloud implementations - examples can be found in docker-systemctl-images

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.