I've been using Docker containers to test out the install process for a project I've been working on, and have found it can be a little tricky to get systemd booted up and running in Docker. Normally running a service manager like systemd within a container would be redundant and unnecessary, but in this case I'm specifically trying to test out systemd service files (and directory paths, and user permissions, etc) that have been set up by my install process.
With the base 18.04 Ubuntu image, there are 4 key steps to getting systemd running and testable in a Docker container:
- Install systemd
- Map a few key system directories
- Start up with /lib/systemd/systemd
- Use docker exec to test
1. Install systemd
With the base Ubuntu image, it's as simple as installing the systemd package with apt-get — like this Dockerfile:
FROM ubuntu:18.04
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y systemd
CMD ["/lib/systemd/systemd"]
2. Map a few key system directories
I found I had to mount /run and /run/lock as tmpfs directories and map /sys/fs/cgroup to my local /sys/fs/cgroup directory. You can do that with this docker-compose.yml file:
version: '3'
services:
my_test_container:
build: .
image: my_test_image
tmpfs:
- /run
- /run/lock
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
Or, alternately, when using the docker run command, specifying the --tmpfs /run --tmpfs /run/lock --volume /sys/fs/cgroup:/sys/fs/cgroup:ro flags.
3. Start up with /lib/systemd/systemd
I added CMD ["/lib/systemd/systemd"] to my Dockerfile to start the container with /lib/systemd/systemd by default; but you can instead add command: /lib/systemd/systemd to a service in your docker-compose.yml file, or just run /lib/systemd/systemd directly with the docker run command.
4. Use docker exec to test
With the above docker-compose.yml and Dockerfile, you can start up the test container with one command:
docker-compose up -d my_test_container
And then, with systemd running, use a second command to execute a shell on the container to test it out:
docker-compose exec my_test_container bash
Or use exec to run whatever other commands you need to test systemd:
docker-compose exec my_test_container systemctl list-units
Alternately, if you built and ran the above Dockerfile with docker commands instead of docker-compose, you'd use the following command to test the container out:
docker exec -it my_test_container bash
Cleaning up
To clean everything up, stop the container with docker-compose:
docker-compose stop my_test_container
Then remove the container:
docker-compose rm my_test_container
And finally, remove the image:
docker image rm my_test_image
Or execute all 3 clean-up steps at once (as well as removing all other containers/images referenced by your docker-compose.yml file), in a single command:
docker-compose down --rmi all
Without docker-compose
The following docker commands would allow you to build, run, and clean up the above Dockerfile without using docker-compose at all:
docker build --tag my_test_image .
docker run \
--tmpfs /run --tmpfs /run/lock \
--volume /sys/fs/cgroup:/sys/fs/cgroup:ro \
--detach --rm \
--name my_test_container my_test_image
docker exec --interactive --tty my_test_container bash
docker stop my_test_container
docker image rm my_test_image