We went with the following solution:
Podman
We decided to go with Podman. Podman is a wrapper around RunC, with the CLI tools tuned to be a drop-in replacement for Docker. However, because it's not running the containers under a daemon (which I like a bit better anyway), hardly any plumbing is required to make systemd-notify work.
Just specifying Environment=NOTIFY_SOCKET=/run/systemd/notify
in the sytemd service file suffices.
See here as well.
systemd-notify
Full example:
I'm using the systemd-notify test-script from: https://github.com/bb4242/sdnotify
Dockerfile
FROM python
COPY test.py /
RUN pip install sdnotify
RUN chmod 755 /test.py
ENTRYPOINT ["/usr/local/bin/python", "test.py"]
CMD ["run"]
EXPOSE 8080
build.sh - Creates the Podman container, needs to be in the same folder as Dockerfile and test.py script.
#!/bin/bash
IMAGE_NAME=python-test
CONTAINER_NAME=python-test
sudo podman build . -t ${IMAGE_NAME}
sudo podman rm ${CONTAINER_NAME}
sudo podman create -e PYTHONUNBUFFERED=true -d --name=${CONTAINER_NAME} ${IMAGE_NAME}
notify-test.service
[Unit]
Description=A test service written in Python
[Service]
# Note: setting PYTHONUNBUFFERED is necessary to see the output of this service in the journal
# See https://docs.python.org/2/using/cmdline.html#envvar-PYTHONUNBUFFERED
Environment=PYTHONUNBUFFERED=true
Environment=NOTIFY_SOCKET=/run/systemd/notify
SyslogIdentifier=notify-test
NotifyAccess=all
ExecStart=/usr/bin/podman start -a python-test
ExecStop=/usr/bin/podman stop python-test
# Note that we use Type=notify here since test.py will send "READY=1"
# when it's finished starting up
Type=notify
[Install]
WantedBy=multi-user.target
So first install podman, and put the test.py from the url above, Dockerfile, and build.sh in a separate folder. Run ./build.sh
.
Then take the .service file, and put it with other systemd service files in /usr/lib/systemd/user
. Do sudo systemctl daemon-reload
.
Now, the service can be started and stopped with sudo systemctl start notify-test
and sudo systemctl stop notify-test
.
Logging
systemd will by default automatically log whatever is written to stdout/stderr to both its own journal (accessible with journalctl
), and to the syslog.
See: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
SyslogLevelPrefix=
Takes a boolean argument. If true and
StandardOutput= or StandardError= are set to journal or kmsg (or to
the same settings in combination with +console), log lines written by
the executed process that are prefixed with a log level will be
processed with this log level set but the prefix removed. If set to
false, the interpretation of these prefixes is disabled and the logged
lines are passed on as-is. This only applies to log messages written
to stdout or stderr. For details about this prefixing see
sd-daemon(3). Defaults to true.
Two issues:
Problem: When using podman as ExecStart=
, the log-source will by default be the name of the executable, which is 'podman'.
Solution: Use the SyslogIdentifier=
to specify the name for logging, like in the .service file example above.
Problem: There won't be any difference between log-levels for log-lines.
Solution: Like described here in the systemd documentation, prepend the log-lines with <7> (for debug), <6> (for info), <4> (for warn) etc. to have systemd set the right log levels everywhere, including for syslog. Even get colors in the journalctl tool for free!