Linux – How to run systemd services in Arch Linux Docker container

arch linuxdockersystemd

There seems to be tons of different ways people have been able to run systemd services within Docker containers. The latest example of direct advice I've found is to run Docker with --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro --cap-add=SYS_ADMIN --security-opt=seccomp:unconfined. However, it still just fails:

Error: Could not start Service[ntpd]: Execution of '/usr/sbin/systemctl start ntpd' returned 1: Failed to connect to bus: No such file or directory

What is the absolute minimum I need to do to get simple services running under systemd 231 on a docker 1.12.1 container with an up-to-date Arch Linux distribution?

Best Answer

I ran into the same problem testing my Ansible playbooks which require systemd. And as you said, docker seems like the best approach here as it is much easier to bring up and down a container rather than a virtual machine.
First of all base/archlinux image is deprecated - you should use archlinux/base instead. Then, to run systemd totally unprivileged, number of things should be done:

  • provide a container= variable, so systemd won't try to do number of things it usually does booting a hardware machine
  • systemd actively uses cgroups, so bind mount /sys/fs/cgroup file system from a host
  • bind mounting /sys/fs/fuse is not required but helps to avoid issues with fuse-dependent software
  • systemd thinks that using tmpfs everywhere is a good approach, but running unprivileged makes it impossible for it to mount tmpfs where ever it wants, so pre-mount tmpfs to /tmp, /run and /run/lock
  • as the last bit you need to specify sysinit.target as default unit to boot instead of multi-user.target or whatever, as you really do not want to start graphical things inside a container

The resulting command line is

docker run \
  --entrypoint=/usr/lib/systemd/systemd \
  --env container=docker \
  --mount type=bind,source=/sys/fs/cgroup,target=/sys/fs/cgroup \
  --mount type=bind,source=/sys/fs/fuse,target=/sys/fs/fuse \
  --mount type=tmpfs,destination=/tmp \
  --mount type=tmpfs,destination=/run \
  --mount type=tmpfs,destination=/run/lock \
    archlinux/base --log-level=info --unit=sysinit.target

If we are talking about running particular service there like ntpd from your example you will need to add

--cap-add=SYS_TIME

otherwise ntpd will fail with permission deny as nobody wants a container to set system time by default.

P.s I spent quite a while learning how systemd behaves and managed to get it working on number of operating system images. I described my experience in an article Running systemd in docker container. It is in Russian but I believe google translate should work in your browser. Thanks

Related Question