31 März 2020

Podman - Run Container with user permissions

Kategorien: HowTos
Tags: Buildah Container Open Source Software Podman

In unserem vorhergehenden Artikel über Buildah haben wir erläutert wie man Container auch ohne Docker und root-Berechtigungen erstellt.

In diesem Artikel soll es darum gehen wie man eben jene Container auch ohne erweiterte Rechte nutzen kann.

Podman gehört neben dem bereits erwähnten Buildah und Skopeo zu den RedHat Container Tools und ist, kurz Zusammengefasst, eine daemonlose Laufzeitumgebung für Container. Es ist dabei, wie der Docker-Daemon, für den Betrieb eines einzelnen Hosts ausgelegt und bietet auch keine Clusterfunktionalität.

Entwicklung

Podman wurde in der Version 1.0 am 11.01.2019 released und steht ebenfalls unter der Apache 2.0 Lizenz.
Die Implementierung erfolgt in Golang und wird von der „containers organisation“ in erster Instanz vorangetrieben. Diese beinhaltet sowohl RedHat-Mitarbeiter als auch externe Entwickler.
Der Code kann auf Github eingesehen werden. Die Entwicklung erfolgt dabei in keinem festen Releasezyklus. So können sowohl Monate wie auch Wochen zwischen den Versionen liegen, je nachdem wenn Entschieden wird, dass genügend neue Features für einen Release implementiert wurden.

Podman selbst baut komplett auf die libpod auf, bzw. könnte man auch sagen, dass es das Tool zur libpod ist. Daher ist der Name des Repositorys auch libpod und nicht podman.

Container ohne root-Berechtigungen

Eine zentrale Komponente von Buildah und auch Podman ist hier die libpod welche es ermöglicht Container nur mit Nutzerberechtigungen zu starten und Images zu erstellen.
Diese setzt auf slirp4netns, fuse-overlayfs und die /etc/sub(u|g)id.

Dieser Bereich wurde bereits ausführlich im Artikel zu Buildah behandelt, weswegen hier nur auf diesen verwiesen wird, um Wiederholungen zu vermeiden.

Installation

Podman ist bei den gängigen RedHat-Distributionen direkt in den Repositories verfügbar.
Diese können dort je nach Version via dnf install podman oder yum install podman installiert werden.
Zu beachten ist, dass die Pakete in den CentOS-Distributionen nicht unbedingt aktuell sind. Daher bietet es sich hier an ebenfalls auf Kubic auszuweichen.

Für Debian und Derivate sowie Suse stehen analog zu Buildah Pakete in Kubic bereit.

Weitere Informationen dazu finden sich in der Dokumentation

[podmanager@buildah ~]$ podman -v
podman version 1.8.2

Konfiguration

Die Konfigurationsdatei für Podman ist analog zu Builder unter /etc/containers/libpod.conf für die globale und unter ~/.config/containers/libpod.conf für die benutzerspezifische Konfiguration zu finden.
Die Vorlage mit den Default-Werten findet sich unter /usr/share/containers/libpod.conf. Diese sollte jedoch nicht direkt, sondern durch die beiden Alternativen angepasst werden.
In der Datei lassen sich verschiedene Parameter für Podman konfigurieren; welches CNI-Plugin genutzt werden soll, welche Container-Runtime oder auch wo die Volumes der Container zu finden sind.

Ein Online-Beispiel findet sich auf Github

Für einen ersten Testbetrieb sind hier jedoch keine Änderungen erforderlich, es dient lediglich dazu ggf. podman an die eigenen Wünsche anzupassen.

Arbeiten mit Podman

Podman wurde als Drop-In-Replacement für Docker entworfen und daher funktionieren die meisten Befehle wie ps, rm, inspect, logs oder exec analog zu docker und sollen hier wenn dann nur kurz erwähnt werden. Die Funktionalität ist dabei nicht nur auf den Betrieb von Container beschränkt, es ist im begrenzten Maße auch möglich Container zu erstellen. Im Hintergrund setzt Podman auf die Funktionalität von Buildah, kann jedoch Container nur aus einem Containerfile heraus erstellen.
Details dazu finden sich in der Dokumentation

Auch ein podman top $ContainerID funktioniert ebenso wie das Erstellen, Migrieren und Restore eines Checkpoints.

[user@system1 ~]$ podman container checkpoint <container_id> -e /tmp/checkpoint.tar.gz
[user@system1 ~]$ scp /tmp/checkpoint.tar.gz <destination_system>:/tmp

[user@system2 ~]$ podman container restore -i /tmp/checkpoint.tar.gz

In den folgenden Bereichen soll daher in erster Linie auf die Unterschiede in der Containerhandhabe zwischen Docker und Podman eingegangen werden.

Einen Container starten

Um einen Container der Wahl (hier postgres) zu starten, pullen wir das Image und starten dies anschließend.

[podmanager@buildah ~]$ podman pull postgres
...
Copying config 73119b8892 done  
Writing manifest to image destination
Storing signatures
73119b8892f9cda38bb0f125b1638c7c0e71f4abe9a5cded9129c3f28a6d35c3

[podmanager@buildah ~]$ podman inspect postgres | grep "PG_VERSION="
    "PG_VERSION=12.2-2.pgdg100+1",
    "created_by": "/bin/sh -c #(nop)  ENV PG_VERSION=12.2-2.pgdg100+1",

[podmanager@buildah ~]$ podman run -d -e POSTGRES_PASSWORD=SuperDB --name=postgres_dev postgres
c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7
[podmanager@buildah ~]$ podman ps
CONTAINER ID  IMAGE                              COMMAND   CREATED        STATUS            PORTS  NAMES
c8b9732b6ad2  docker.io/library/postgres:latest  postgres  5 seconds ago  Up 4 seconds ago         postgres_dev

Es läuft nun ein PostgreSQL-Container mit dem Namen „postgres_dev“. Dies unterscheidet sich soweit nicht von Docker.

Die Besonderheit von podman ist erst in der Prozessliste ersichtlich:

podmana+  2209     1  0 13:11 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -u c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -r /usr/bin/runc -b

232070    2219  2209  0 13:11 ?        Ss     0:00  \_ postgres

Der PostgreSQL-Prozess läuft nicht als Kind eines Daemon-Prozesses, sondern der Komponente „conmon“.
Diese überwacht den Zustand des Containers nach dem Start. Außerdem stellt es den Socket für die Kommunikation bereit und den Stream für den Output, welche
in das von podman konfigurierte Log geschrieben werden.
Weiterführende Informationen zu conmon finden sich auf Github

Starten wir jetzt einen zweiten Container (postgres_prod) via podman wird ein weiterer conmon-Prozess gestartet:

[podmanager@buildah ~]$ podman run -d -e POSTGRES_PASSWORD=SuperDB --name=postgres_prod postgres
6581a25c82620c725fe1cfb6546479edac856228ecb3c11ad63ab95a453c1b64

[podmanager@buildah ~]$ podman ps
CONTAINER ID  IMAGE                              COMMAND   CREATED         STATUS             PORTS  NAMES
6581a25c8262  docker.io/library/postgres:latest  postgres  15 seconds ago  Up 15 seconds ago         postgres_prod
c8b9732b6ad2  docker.io/library/postgres:latest  postgres  7 minutes ago   Up 7 minutes ago          postgres_dev
podmana+  2209     1  0 13:11 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -u c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -r /usr/bin/runc -b
232070    2219  2209  0 13:11 ?        Ss     0:00  \_ postgres
...
podmana+  2337     1  0 13:19 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c 6581a25c82620c725fe1cfb6546479edac856228ecb3c11ad63ab95a453c1b64 -u 6581a25c82620c725fe1cfb6546479edac856228ecb3c11ad63ab95a453c1b64 -r /usr/bin/runc -b
232070    2348  2337  0 13:19 ?        Ss     0:00  \_ postgres
...

Hier finden sich im Prozess jeweils die UUIDs der Container wieder.
Der cmdline des Prozesses ist natürlich sehr viel länger als hier dargestellt. Folgend noch ein komplettes Beispiel manuell formatiert:

[podmanager@buildah ~]$ ps -ef f  | grep conmon
...
podmana+  2209     1  0 13:11 ?        Ssl    0:00 /usr/bin/conmon
--api-version 1
-c c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7
-u c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7
-r /usr/bin/runc
-b /home/podmanager/.local/share/containers/storage/overlay-containers/c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7/userdata
-p /var/tmp/run-1002/containers/overlay-containers/c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7/userdata/pidfile
-l k8s-file:/home/podmanager/.local/share/containers/storage/overlay-containers/c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7/userdata/ctr.log
--exit-dir /var/tmp/run-1002/libpod/tmp/exits
--socket-dir-path /var/tmp/run-1002/libpod/tmp/socket
--log-level error
--runtime-arg --log-format=json
--runtime-arg --log
--runtime-arg=/var/tmp/run-1002/containers/overlay-containers/c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7/userdata/oci-log
--conmon-pidfile /var/tmp/run-1002/containers/overlay-containers/c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7/userdata/conmon.pid
--exit-command /usr/bin/podman
--exit-command-arg --root 
--exit-command-arg /home/podmanager/.local/share/containers/storage 
--exit-command-arg --runroot 
--exit-command-arg /var/tmp/run-1002/containers 
--exit-command-arg --log-level 
--exit-command-arg error 
--exit-command-arg --cgroup-manager 
--exit-command-arg cgroupfs 
--exit-command-arg --tmpdir 
--exit-command-arg /var/tmp/run-1002/libpod/tmp 
--exit-command-arg --runtime 
--exit-command-arg runc 
--exit-command-arg --storage-driver 
--exit-command-arg overlay 
--exit-command-arg --storage-opt 
--exit-command-arg overlay.mount_program=/usr/bin/fuse-overlayfs 
--exit-command-arg --storage-opt 
--exit-command-arg overlay.mount_program=/usr/bin/fuse-overlayfs 
--exit-command-arg --events-backend 
--exit-command-arg file 
--exit-command-arg container 
--exit-command-arg cleanup 
--exit-command-arg c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7
...

Durch die Formatierung ist sehr schön zu sehen, wie die Übergabe von Parametern zwischen podman und conmon über die *args funktioniert.

Zusätzlich zu conmon wird natürlich auch jeweils eine Instanz von slirp4netns und fuse-overlayfs pro container gestartet um Netzwerk und Storage ohne root-Berechtigungen bereitzustellen.

podmana+  2201     1  0 13:11 ?        Ss     0:00 /usr/bin/fuse-overlayfs -o lowerdir=/home/podmanager/.local/share/containers/storage/overlay/l/FX4RZGGJ5HSNVMGVFG6K3I7PIL:/home/podmanager/.local/share/containers/storage/overlay/l/AIHUOS

podmana+  2206     1  0 13:11 pts/0    S      0:00 /usr/bin/slirp4netns --disable-host-loopback --mtu 65520 --enable-sandbox -c -e 3 -r 4 --netns-type=path /tmp/run-1002/netns/cni-18902a12-5b1b-15d3-0c31-138efe1d66ba tap0

podmana+  2209     1  0 13:11 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -u c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -r /usr/bin/runc -b

232070    2219  2209  0 13:11 ?        Ss     0:00  \_ postgres

Erstellen eines Systemd-service-files

Da die Container ohne Daemon laufen und einzeln angestartet werden können, bietet es sich natürlich auch an diese nicht via Docker, sondern via Systemd zu steuern.
Das Schreiben von Service-files ist jedoch im allgemeinen mühsam, weswegen podman dafür direkt eine Funktion eingebaut hat.

Folgend ein Beispiel für unsere postgres_dev

[podmanager@buildah ~]$ podman generate systemd postgres_dev
# container-c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7.service
# autogenerated by Podman 1.8.2
# Tue Mar 24 13:47:11 CET 2020

[Unit]
Description=Podman container-c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7.service
Documentation=man:podman-generate-systemd(1)
Wants=network.target
After=network-online.target

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
ExecStart=/usr/bin/podman start c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7
ExecStop=/usr/bin/podman stop -t 10 c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7
PIDFile=/var/tmp/run-1002/containers/overlay-containers/c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7/userdata/conmon.pid
KillMode=none
Type=forking

[Install]
WantedBy=multi-user.target default.target

Einen Fehler gibt es hier jedoch noch. Es muss im Servicefile der User ergänzt werden unter dem der Container gestartet werden soll, insofern dies nicht als root passieren soll. Dazu muss in der Sektion [Service] nur User=podmanager ergänzt werden (bzw. der Username auf ihrem System).

Um den Container als Service zu hinterlegen wären unter CentOS 8 folgende Schritte durchzuführen:

[podmanager@buildah ~]$ podman generate systemd --files --name postgres_dev
/home/podmanager/container-postgres_dev.service
# User= im servicefile ergänzen
[podmanager@buildah ~]$ sudo cp /home/podmanager/container-postgres_dev.service /etc/systemd/system/
[podmanager@buildah ~]$ sudo systemctl daemon-reload
[podmanager@buildah ~]$ sudo systemctl start container-postgres_dev.service
[podmanager@buildah ~]$ systemctl status container-postgres_dev.service 
● container-postgres_dev.service - Podman container-postgres_dev.service
   Loaded: loaded (/etc/systemd/system/container-postgres_dev.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2020-03-24 14:04:14 CET; 1s ago
     Docs: man:podman-generate-systemd(1)
  Process: 7691 ExecStart=/usr/bin/podman start postgres_dev (code=exited, status=0/SUCCESS)
 Main PID: 7717 (conmon)
    Tasks: 11 (limit: 25028)
   Memory: 46.7M
   CGroup: /system.slice/container-postgres_dev.service
           ├─7710 /usr/bin/fuse-overlayfs -o lowerdir=/home/podmanager/.local/share/containers/storage/overlay/l/FX4RZGGJ5HSNVMGVFG6K3I7PIL:/home/podmanager/.local/share/containers/storage/overlay/l/AIHUOSIVGT5DN5GCUR7PRELVKK:/home/podma>
           ├─7714 /usr/bin/slirp4netns --disable-host-loopback --mtu 65520 --enable-sandbox -c -e 3 -r 4 --netns-type=path /tmp/run-1002/netns/cni-a0ee9d78-2f8c-a563-1947-92d0766a43b7 tap0
           ├─7717 /usr/bin/conmon --api-version 1 -c c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -u c8b9732b6ad253710ae6e75f934a74e8469e61bc5b5d88c2fa92c7257d00d2e7 -r /usr/bin/runc -b /home/podmanager/.local/share/c>
           ├─7727 postgres
           ├─7758 postgres: checkpointer
           ├─7759 postgres: background writer
           ├─7760 postgres: walwriter
           ├─7761 postgres: autovacuum launcher
           ├─7762 postgres: stats collector
           └─7763 postgres: logical replication launcher

Mär 24 14:04:13 buildah.localdomain systemd[1]: Starting Podman container-postgres_dev.service...
Mär 24 14:04:14 buildah.localdomain podman[7691]: postgres_dev
Mär 24 14:04:14 buildah.localdomain systemd[1]: Started Podman container-postgres_dev.service.

Wichtig zu erwähnen ist noch, dass man den über Systemd gestarteten Container natürlich auch via podman administrieren / erreichen kann, zumindest das Starten und Stoppen aber dem Service überlassen sollte.

Erstellen eines Pods

Wie der Name vermuten lässt ist es mit Podman nicht nur möglich Container zu erstellen, sondern diese auch in Pods zu organisieren.
Ein Pod stellt dabei analog zu Kubernetes einen organisatorischen Verbund von Containern dar die sich auch bestimmte Namespaces wie pids, network o.ä. teilen können.
Diese werden dann via podman pod $cmd administriert.

Im Folgenden laden wir das Image des postgres-exporters für prometheus und erstellen daraus einen Pod mit der Bezeichnung postgres-prod-pod.

[podmanager@buildah ~]$ podman pull docker.io/wrouesnel/postgres_exporter

[podmanager@buildah ~]$ podman pod create --name postgres-prod-pod
727e7544515e0e683525e555934e02a341a42009a9c49fb2fd53094187a1e97c

[podmanager@buildah ~]$ podman run -d --pod postgres-prod-pod -e POSTGRES_PASSWORD=SuperDB postgres:latest
8f313260973ef6eb6fa84d2893875213cee89b48c93d08de7642b0a8b03c4a88

[podmanager@buildah ~]$ podman run -d --pod postgres-prod-pod -e DATA_SOURCE_NAME="postgresql://postgres:password@localhost:5432/postgres?sslmode=disable" postgres_exporter
fee22f24ff9b2ace599831fa022fb1261ef836846e0ba938c7b469d8dfb8a48a

[podmanager@buildah ~]$ podman pod ps
POD ID         NAME                STATUS    CREATED          # OF CONTAINERS   INFRA ID
727e7544515e   postgres-prod-pod   Running   48 seconds ago   3                 6edc862441f1

[podmanager@buildah ~]$ podman pod inspect postgres-prod-pod
{
     "Config": {
          "id": "727e7544515e0e683525e555934e02a341a42009a9c49fb2fd53094187a1e97c",
          "name": "postgres-prod-pod",
          "hostname": "postgres-prod-pod",
          "labels": {

          },
          "cgroupParent": "/libpod_parent",
          "sharesCgroup": true,
          "sharesIpc": true,
          "sharesNet": true,
          "sharesUts": true,
          "infraConfig": {
               "makeInfraContainer": true,
               "infraPortBindings": null
          },
          "created": "2020-03-24T14:44:27.01249721+01:00",
          "lockID": 0
     },
     "State": {
          "cgroupPath": "/libpod_parent/727e7544515e0e683525e555934e02a341a42009a9c49fb2fd53094187a1e97c",
          "infraContainerID": "6edc862441f18234f0c61693f11d946f601973a71b85fa9d777273feed68ed3c",
          "status": "Running"
     },
     "Containers": [
          {
               "id": "6edc862441f18234f0c61693f11d946f601973a71b85fa9d777273feed68ed3c",
               "state": "running"
          },
          {
               "id": "8f313260973ef6eb6fa84d2893875213cee89b48c93d08de7642b0a8b03c4a88",
               "state": "running"
          },
          {
               "id": "fee22f24ff9b2ace599831fa022fb1261ef836846e0ba938c7b469d8dfb8a48a",
               "state": "running"
          }
     ]
}

Hier ist nun zu sehen, dass der Pod die beiden Container postgres und postgres-exporter beinhaltet (Vergleich UUIDs).
Der dritte Container ist der Infra-Container für das Bootstrapping und soll hier nicht weiter Thema sein.

In der Prozessliste zeigt sich das Ganze dann wie folgt:

podmana+  6279     1  0 14:44 ?        Ss     0:00 /usr/bin/fuse-overlayfs -o lowerdir=/home/podmanager/.local/share/containers/storage/overlay/l/
podmana+  6281     1  0 14:44 pts/2    S      0:00 /usr/bin/slirp4netns --disable-host-loopback --mtu 65520 --enable-sandbox -c -e 3 -r 4 --netns-type=path /tmp/run-1002/netns/cni-5fe4356e-77c0-8127-f72b-7335c2ed05c4 tap0
podmana+  6284     1  0 14:44 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c 6edc862441f18234f0c61693f11d946f601973a71b85fa9d777273feed68ed3c -u 6edc862441f18234f0c61693f11d946f601973a71b85fa9d777273feed68ed3c -r /usr/bin/runc -b
podmana+  6296  6284  0 14:44 ?        Ss     0:00  \_ /pause
podmana+  6308     1  0 14:44 ?        Ss     0:00 /usr/bin/fuse-overlayfs -o lowerdir=/home/podmanager/.local/share/containers/storage/overlay/l/FX4RZGGJ5HSNVMGVFG6K3I7PIL:/home/podmanager/.local/share/containers/storage/overlay/l/AIHUOS
podmana+  6312     1  0 14:44 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c 8f313260973ef6eb6fa84d2893875213cee89b48c93d08de7642b0a8b03c4a88 -u 8f313260973ef6eb6fa84d2893875213cee89b48c93d08de7642b0a8b03c4a88 -r /usr/bin/runc -b
232070    6322  6312  0 14:44 ?        Ss     0:00  \_ postgres
...
232070    6549  6322  0 14:44 ?        Ss     0:00      \_ postgres: postgres postgres ::1(51290) idle
podmana+  6520     1  0 14:44 ?        Ss     0:00 /usr/bin/fuse-overlayfs -o lowerdir=/home/podmanager/.local/share/containers/storage/overlay/l/P5NJW4TB6JUFOBBIN2MOHW7272:/home/podmanager/.local/share/containers/storage/overlay/l/KVC54Z
podmana+  6523     1  0 14:44 ?        Ssl    0:00 /usr/bin/conmon --api-version 1 -c fee22f24ff9b2ace599831fa022fb1261ef836846e0ba938c7b469d8dfb8a48a -u fee22f24ff9b2ace599831fa022fb1261ef836846e0ba938c7b469d8dfb8a48a -r /usr/bin/runc -b
251072    6534  6523  0 14:44 ?        Ssl    0:00  \_ /postgres_exporter

Hier ist zu sehen, dass es zwar mehrere conmon und overlayfs-Prozesse für die Container gibt, jedoch nur einen slirp4netns, da die Container sich diesen teilen und darüber auch via localhost kommunizieren können.
Auch ist zu sehen dass die PostgreSQL-Datenbank eine Verbindung von localhost hat (PID 6549) wobei es sich um den Exporter handelt.

Im Normalfall werden bei der Erstellung eines Pods via podman pod create folgende Namespaces für die Container zusammengefasst: net,ipc,uts und user.
Somit hat auch jeder Container trotz der Zusammenfassung im Pod noch seinen eigenen PID-namespace.
Sollte dies jedoch gewünscht sein, so kann mittels dem Parameter --share bei der Erstellung angegeben werden was alles geteilt werden soll.

So sieht z.B. die Prozessliste des Pods ohne gemeinsamen pid-namespace aus. Jeder Container hat seine eigene Prozesstruktur.

[podmanager@buildah ~]$ podman pod top postgres-prod-pod
USER                PID   PPID   %CPU    ELAPSED            TTY   TIME   COMMAND
0                   1     0      0.000   11m45.845291911s   ?     0s     /pause 
postgres            1     0      0.000   11m45.854330176s   ?     0s     postgres 
postgres            25    1      0.000   11m45.854387876s   ?     0s     postgres: checkpointer    
postgres            26    1      0.000   11m45.854441615s   ?     0s     postgres: background writer    
postgres            27    1      0.000   11m45.854483844s   ?     0s     postgres: walwriter    
postgres            28    1      0.000   11m45.854525645s   ?     0s     postgres: autovacuum launcher    
postgres            29    1      0.000   11m45.854567082s   ?     0s     postgres: stats collector    
postgres            30    1      0.000   11m45.854613262s   ?     0s     postgres: logical replication launcher    
postgres            31    1      0.000   11m45.854653703s   ?     0s     postgres: postgres postgres ::1(51292) idle 
postgres_exporter   1     0      0.000   11m45.859505449s   ?     0s     /postgres_exporter

Als Alternative die Ausgabe bei der Erstellung des Pods mittels podman pod create --name postgres-prod-pod --share=pid,net,ipc,uts,user

[podmanager@buildah ~]$ podman pod top postgres-prod-pod
USER       PID   PPID   %CPU    ELAPSED         TTY     TIME   COMMAND
root       1     0      0.000   20.396867487s   ?       0s     /pause 
postgres   6     0      0.000   20.396936905s   pts/0   0s     postgres 
postgres   60    6      0.000   18.396997034s   ?       0s     postgres: checkpointer    
postgres   61    6      0.000   18.397086198s   ?       0s     postgres: background writer    
postgres   62    6      0.000   18.39713465s    ?       0s     postgres: walwriter    
postgres   63    6      0.000   18.39718056s    ?       0s     postgres: autovacuum launcher    
postgres   64    6      0.000   18.397229737s   ?       0s     postgres: stats collector    
postgres   65    6      0.000   18.397279102s   ?       0s     postgres: logical replication launcher    
20001      66    0      0.000   16.397325377s   pts/0   0s     /postgres_exporter

Zur Auswahl stehen bei --share ipc, net, pid, user und uts.

Der gesamte pod kann nun auch via podman pod stop/start gestartet und gestoppt werden.
Ebenso können für Pods wie Container systemd-service-files generiert werden.

Podman und Kubernetes

Podman bietet einige Unterstützung im Bereich Kubernetes-YAML.

So ist es z.B. möglich aus den Pods, welche man mit podman erstellt hat, kubernes-Pod YAML zu generieren.

[podmanager@buildah ~]$ podman generate kube postgres-prod-pod -f postgres-prod-pod.yaml
[podmanager@buildah ~]$ cat postgres-prod-pod.yaml
# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-1.8.2
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2020-03-24T14:08:14Z"
  labels:
    app: postgres-prod-pod
  name: postgres-prod-pod
spec:
  containers:
  - command:
    - postgres
    env:
    ...
    image: docker.io/library/postgres:latest
    name: reverentptolemy
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities: {}
      privileged: false
      readOnlyRootFilesystem: false
      seLinuxOptions: {}
    workingDir: /
  - env:
    ...
    image: docker.io/wrouesnel/postgres_exporter:latest
    name: friendlyshirley
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities: {}
      privileged: false
      readOnlyRootFilesystem: false
      runAsGroup: 20001
      runAsUser: 20001
      seLinuxOptions: {}
    workingDir: /
status: {}

Mit der Option -s wird sogar noch ein Service mit ggf. published-Ports generiert:

---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2020-03-24T14:10:42Z"
  labels:
    app: postgres-prod-pod
  name: postgres-prod-pod
spec:
  selector:
    app: postgres-prod-pod
  type: NodePort
status:
  loadBalancer: {}

Die generate-yaml Funktionalität greift dabei für Pods wie auch für Services und auch in beide Richtungen.
Mit podman play ist es möglich Pod und Container-Definitionen in podman zu testen.

Fazit

Dies war ein grober Einblick in die Möglichkeiten Container ohne Daemon und root-Berechtigungen auf einem Host zu betreiben.
Natürlich ist mit podman noch viel mehr möglich, jedoch würde die Erläuterung jeder Option hier den Rahmen sprengen.

Zu erwähnen ist vielleicht noch, dass Podman mit aktiviertem cgroupsV2 auch z.B. Resourcennutzung in Pods auswerten kann.
Dies ist jedoch aktuell nur unter Fedora31 standardmäßig aktiviert.

Kategorien: HowTos
Tags: Buildah Container Open Source Software Podman

über den Autor

Danilo Endesfelder

Berater

zur Person

Danilo ist seit 2016 Berater bei der credativ GmbH. Sein fachlicher Fokus liegt bei Containertechnologien wie Kubernetes, Podman, Docker und deren Ökosystem. Außerdem hat er Erfahrung mit Projekten und Schulungen im Bereich RDBMS (MySQL/Mariadb und PostgreSQL). Seit 2015 ist er ebenfalls im Organisationsteam der deutschen PostgreSQL Konferenz PGConf.DE.

Beiträge ansehen


Beitrag teilen: