Podman

Podman ist ein OCI-kompatibles Container-Management-Tool, dessen CLI explizit mit Docker kompatibel ist, was den Übergang für Docker-Nutzer erleichtert. Das Projekt wurde 2017 ins Leben gerufen und ursprünglich von Red Hat entwickelt. Es bietet erweiterte Sicherheitsfunktionen und unterstützt rootless Container. Im Gegensatz zu Docker benötigt Podman keinen Daemon, wodurch keine Privilegieneskalation für Benutzer in der Docker-Gruppe möglich ist.

Beim Umgang mit Podman stösst man auch auf folgende Tools:

  • buildah: zum Bauen von Container Images

  • podman: verwaltet Container und Container Images

  • skopeo: zur Signierung, zum Kopieren und Löschen von Container Images

podman Cheat Sheet

dnf install -y podman systemd-container

podman login $registry
podman search --no-trunc mariadb-103

# inspect without pulling first
skopeo inspect docker://$registry/rhel8/mariadb-103
# local
podman inspect $registry/rhel8/mariadb-103

podman pull $registry/rhel8/mariadb-103
podman images

podman run \
    --detach \
    --name=myname \
    --publish localport:containerport \
    --volume localdir:containerdir:z \
    --env ENV1=VAL1 \
    docker://$registry/rhel8/mariadb-103:tag

podman logs --follow myname

# open shell in running container
podman exec -it myname /bin/bash

# execute and delete
podman run --rm -it $registry/rhel8/mariadb-103 /bin/bash

podman ps --all
podman stop myname
podman kill myname
podman restart myname
podman info
podman rmi $registry/rhel8/mariadb-103:latest
podman rm myname

Im Unterschied zu Docker ein spezielles Feature von Podman: Rootless-Container „mariadb“ als User. Wichtig: statt sudo oder su sollte machinectl verwendet werden.

machinectl shell user@.host

podman run --detach $registry/rhel8/mariadb-103
podman ps

Container als Systemd-Service

Da Container unter Podman nicht über einen Daemon, sondern als einzelne Prozesse laufen, ist die Integration in systemd einfach. Pro Container wird ein Systemd-Service erstellt. Das funktioniert für rootful und rootless Container.

Zuerst muss der Container manuell erstellt werden:

podman create \
    --name httpd \
    --publish 127.0.0.1:8080:80/tcp \
    httpd:latest

podman ps --all

Der Systemd-Service kann nun generiert werden. Der Parameter --new sorgt dafür, dass der Container bei jedem Neustart des Services neu erstellt wird. Dies ist später für automatische Updates des Containers nützlich.

Unter dem root-User:

podman generate systemd httpd --new > /etc/systemd/system/httpd-container.service
systemctl daemon-reload

# double check result
systemctl cat httpd-container.service

systemctl enable --now httpd-container.service
systemctl status httpd-container.service
podman ps

Rootless:

loginctl enable-linger user

machinectl shell user@.host

mkdir -p ~/.config/systemd/user/
podman generate systemd httpd --new > ~/.config/systemd/user/httpd-container.service
systemctl --user daemon-reload

# double check result
systemctl --user cat httpd-container.service

systemctl --user enable --now httpd-container.service
systemctl --user status httpd-container.service
podman ps

Tipp

Der Exit Code der Applikation im Container wird richtig an Systemd weitergegeben und ist via systemctl status ... ersichtlich.

Automatische Updates der Container

Bei der Entwicklung von Podman wurde auch an die automatische Aktualisierung der Container gedacht. Podman wird mit der Funktion auto-update ausgeliefert, die alle markierten Container auf neue Versionen überprüft.

Damit dies funktioniert muss der Container in einem mit podman generate systemd --new generiertem Systemd-Service laufen und das --label "io.containers.autoupdate=registry" gesetzt haben.

podman create \
    --name httpd \
    --publish 127.0.0.1:8080:80/tcp \
    --label "io.containers.autoupdate=registry" \
    docker.io/httpd:latest

podman generate systemd httpd --new > /etc/systemd/system/httpd-container.service

Das Update kann manuell ausgeführt werden:

podman auto-update

Oder als Systemd-Timer (standardmässig täglich):

# rootful
systemctl enable --now podman-auto-update.timer

# rootless
systemctl --user enable --now podman-auto-update.timer

Healthchecks

Nur weil der Container (bzw. der Systemd-Service) gestartet wurde, heisst noch lange nicht, dass auch die Applikation innerhalb des Container bereit ist. Um dies zu prüfen können Healthchecks verwendet werden.

Ein Healthchecks besteht aus:

  • „Command“: Wird innerhalb des Containers ausgeführt. Muss den Status der Applikation ermitteln und als Exit-Code zurückliefern geben (0 = ok, sonst „failure“).

  • „Retries“: Anzahl der aufeinanderfolgenden Fehlversuche bevor der Container als „unhealthy“ markiert wird.

  • „Interval“: Zeitabstand zwischen den Ausführungen des Commands.

  • „Start-period“: Zeitraum, in dem die Healthchecks nach dem Start des Containers fehlschlagen dürfen („grace period“).

  • „Timeout“: Timeout des Commands selbst.

  • „Action“: Wie soll ein „unhealthy“ Container behandelt? Optionen: none, kill, restart und stop. Zusammen mit Systemd ist kill am sinnvollsten - ein Restart kann dann via Systemd Restart=on-failure erfolgen.

podman run \
    --detach \
    --name mariadb \
    --publish 127.0.0.1:3306:3306 \
    --env MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=1 \
    --health-cmd 'mysql --execute ";"' \
    --health-retries 5 \
    --health-interval 10s \
    --health-start-period 5s \
    --health-timeout 3s \
    --health-on-failure=kill \
    docker.io/library/mariadb:10.5

Die Healthchecks können auch manuell ausgeführt werden:

podman healthcheck run mariadb
echo $?

Troubleshooting

ERRO[0000] unable to get systemd connection to add healthchecks: lstat /tmp/podman-run-1001/systemd: no such file or directory
dnf install -y systemd-container
machinectl shell user@.host

Alternativ manuell:

sudo -u user -i
export XDG_RUNTIME_DIR=/run/user/$(id -u)

Built on 2024-07-16