Running systemd inside a docker container
Infrastructure Estimated reading time: ~3 minutes
Recently I ran into a situation where log messages from a
service implemented in Golang were missing
from a Linux system. To be able to easily troubleshoot this problem and quickly
iterate over possible solutions I utilized Docker and
ran systemd
inside a Docker container.
Introduction
The Golang service in question sometimes generates a lot of log output.
Sometimes up to 50,000 log messages in just a few seconds. And sometimes
e.g. the last 20,000 log messages of the service were just missing
from the logs managed by journald / systemd
.
To be able to reproduce this problem I implemented 2 simple
programs (one written in C, the other writen in Go). My
first guess was that this had something to do with
buffered / unbuffered output streams.
Running systemd inside a Docker container
So to be able to easily troubleshoot this problem and quickly
iterate over possible solutions I utilized Docker. To start
systemd
inside a Docker container a few pre-requisites have
to be met:
systemd
has to be installed inside the container of course. It provides e.g. the/sbin/init
binary. Using thefedora:34
Docker image this can be achieved by installinghttpd
for example (the Apache web server).The
cgroup
file system has to be mounted inside the container (-v /sys/fs/cgroup:/sys/fs/cgroup:ro
). We do this in read-only mode.The
/tmp
and/run
mount points have to be present inside the container (--tmpfs /tmp --tmpfs /run
).
So if you just want to get systemd
and the Apache web server
up and running inside a Docker container just clone
the source code repository located here and execute the
following command inside the folder running-systemd-inside-a-docker-container
:
Build the container image:
docker build . -t sysd
Start a container:
docker run --tmpfs /tmp --tmpfs /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 9090:80 --name sysd --rm sysd
To get a shell inside the container execute the following command in a second shell:
docker exec -it sysd bash
Now you may also open the URL http://localhost:9090/ in your web browser to view he page served by the Apache web server running as a child process of
systemd
inside the container.
Troubleshooting journald
If you want to play around with the integration of
C or Golang programs with journalctl
you can take a closer
look at the cprinter
and goprinter
programs, their
corresponding systemd
service files and the journald
config file.
To build the cprinter
program change into it’s folder and execute
the following command:
gcc -Wall cprinter.c -o cprinter
To build the goprinter
program change into it’s folder and execute
the following command:
go build
Next start the container using the following command:
docker run --tmpfs /tmp --tmpfs /run -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 9090:80 --name sysd --rm \
-v $(pwd)/cprinter/cprinter:/appl/cprinter \
-v $(pwd)/cprinter/cprinter.service:/etc/systemd/system/cprinter.service \
-v $(pwd)/goprinter/goprinter:/appl/goprinter \
-v $(pwd)/goprinter/goprinter.service:/etc/systemd/system/goprinter.service \
-v $(pwd)/journald.conf:/etc/systemd/journald.conf \
sysd
After the container is up and running you can then get a shell inside the container and test the generation of log messages using the following commands:
[root@08e24ab748c8 /]# systemctl start cprinter
[root@08e24ab748c8 /]# journalctl -u cprinter
Summary
At first I thought this had something to do
with buffered / unbuffered output streams, but in the end
it all boiled down to the default log message rate limits enforced
by journald
. Writing to stdout or stderr using the Go stdlib is
never buffered by the way (no matter if using fmt.Printf or log.Logger).
Also see here.
Environment
The following programs / tools were used while writing this blog post:
- Kubuntu 21.04
- Docker 20.10.2
- Go 1.16.3
A note about Netcup (advertisement)
Netcup is a German hosting company. Netcup offers inexpensive, yet powerfull web hosting packages, KVM-based root servers or dedicated servers for example. Using a coupon code from my Netcup coupon code web app you can even save more money (6$ on your first purchase, 30% off any KVM-based root server, ...).