Eine Tutorialreihe zum Einsatz von Podman: Anwendung, Vorteile und Funktionsweise.
Inhaltsverzeichnis
- Teil: Einleitung und Installation
- Teil: Podman CLI
- Teil: Wie funktioniert die Restart-Policy? Oder: Podman hat keinen Daemon
- Teil: Quadlets
- Teil: Updates
- Teil: Healthchecks
- Teil: Ports publishing – rootful & rootless
- Teil: Volumes & Mounts (Das ist dieser Artikel)
- Teil: Netzwerk: Kommunikation zwischen Containern
- Teil: Capabilities
Einleitung
Im letzten Artikel haben wir uns am Beispiel von Caddy das Port-Mapping bei rootless Containern angeschaut. Wir haben gemerkt, dass rootless Container ihre Ports nicht einfach so auf Ports mappen können, die kleiner als 1024 sind, weil diese als privilegiert gelten. Wir mussten zuerst entweder die Privilegierung neu konfigurieren oder die Firewall den Traffic umleiten lassen.
In diesem Artikel beschäftigen wir uns mit dem Speichern von Daten. Wir werden dazu Bind Mounts und Volumes nutzen, je nachdem, was besser passt.
Aufräumen
Ich gehe davon aus, dass du am Ende des letzten Artikels deine ursprüngliche /etc/hosts-Datei wiederhergestellt hast und it-tools sowie der Caddy-Container nicht mehr am Laufen sind. Falls etwas davon nicht stimmt, solltest du das noch nachholen:
Wiederherstellen der /etc/hosts-Datei
sudo mv /etc/hosts.backup /etc/hosts
Laufende Container anzeigen, stoppen und entfernen
# Laufende Container anzeigen:
podman ps
Kopiere die Container-IDs. Beim folgenden Beispiel wären es b7d0b765d95a und 5f28056e0cad.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7d0b765d95a docker.io/sharevb/it-tools:latest nginx -g daemon o... 3 hours ago Up 3 hours 0.0.0.0:8080->8080/tcp laughing_lamarr
5f28056e0cad docker.io/library/caddy:latest caddy run --confi... 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:443->443/udp, 2019/tcp caddy
Stoppe die Container mit den kopierten IDs.
podman stop b7d0b765d95a 5f28056e0cad
podman rm b7d0b765d95a 5f28056e0cad
Gestoppte Container anzeigen und entfernen
Evtl. hast du noch alte gestoppte Container, die du nicht mehr möchtest. Zeige sie mit podman ps -a an. Ich kopiere auch hier die Container-IDs. Beim Beispiel unten sind es je ein IT Tools- und ein Caddy-Container. Die solltest du entfernen, da du sonst eine Fehlermeldung erhältst, weil die Namen bereits vergeben sind.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c252677c72f docker.io/sharevb/it-tools:latest nginx -g daemon o... 6 minutes ago Created 0.0.0.0:8080->8080/tcp it-tools
5f28056e0cad docker.io/library/caddy:latest caddy run --confi... 6 minutes ago Exited (0) 55 seconds ago 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:443->443/udp, 2019/tcp caddy
Entferne die Container mit den kopierten IDs.
podman rm 5c252677c72f 5f28056e0cad
Disposability von Containern
Hast du schon mal eine Applikation, die du installiert hast, wieder gelöscht? Da bleiben oft Konfigurationsdateien oder alte Daten zurück. Das hat seine Vor- und Nachteile: Wenn ich neue Apps testen möchte, dann lade ich mir oft zwei, drei neue Apps herunter und teste sie. Alle, die mir nicht gefallen, lösche ich dann wieder. Meist bleibt dann aber pro Applikation ein Konfigurationsfile oder von mir generierte Test-Daten zurück. Gleichzeitig gibt es auch Situationen, in denen ich die Daten behalten möchte, die Applikation aber nicht mehr. Das passiert mir beispielsweise bei Markdown-Editoren immer wieder. In diesem Fall bin ich dann aber froh, dass meine Markdown-Dateien nicht mit der App mitgelöscht wurden.
Bei Containern ist das anders. Die sollen disposable, zu Deutsch wegwerfbar, sein. Wenn wir einen Container löschen, dann wird alles, was Teil dieses Containers ist, gelöscht. Nichts bleibt übrig.
Das ist ein sehr wichtiges Konzept. Beispielsweise bei einem Update: Wenn wir einen Container aktualisieren, wird der alte Container gelöscht und ein neuer mit der aktualisierten Version erstellt. Alles, was bisher Teil des alten Containers war, wird gelöscht. Alle Daten, alle Konfigurationen, alle Datenbanken, alle Dateien werden gelöscht. Nach dem Update hast du einen aktualisierten Container, aber alle allfällig gemachten Konfigurationen sind verloren.
Bei IT Tools funktioniert das gut: Wir können den Container erstellen, wieder löschen und wieder erstellen. Wir kriegen beide Male die gleichen, voll funktionsfähigen IT Tools. Es geht nichts verloren, weil es gar nichts gibt, das verloren gehen könnte.
Anders sieht es bei Caddy aus. Caddy benötigt eine Konfiguration, damit es weiss, welche URL es auf welchen Container umleiten muss. Würden wir den Caddy-Container, wie beim IT-Tools-Container, erstellen, löschen und wieder erstellen, wären diese Konfigurationen weg, sie wurden ja gelöscht. Zudem wären alle SSL-Zertifikate verloren, die Caddy für unsere Seiten angefordert hat. Nach jedem erneuten Erstellen des Containers müssten auch alle SSL-Zertifikate neu angefordert werden. Das ist nicht sehr praktisch.
Die Lösung sind Volumes und Bind Mounts.
Volumes und Bind Mounts
Wir lösen das Problem, indem wir die Daten, die im Container erhalten bleiben sollen, nicht im Container selbst speichern, sondern auf dem Host-System. Dort sind sie nicht vom Container-Lifecycle beeinflusst. Doch jetzt haben wir das Problem, dass wir die Daten ja im Container benötigen, nicht ausserhalb. Der Container kann aber nicht auf Daten auf dem Host-System zugreifen. Das ist ja genau die Idee von Containern: Sie sind isoliert.
Sowohl Podman als auch Docker ermöglichen es, Daten vom Host-System einen Container einzubinden. Volumes und Bind Mounts sind hierbei die zwei am häufigsten verwendeten Möglichkeiten. Wir werden uns zuerst mit den Bind Mounts beschäftigen, um damit bei Caddy die Konfiguration aus dem Host-System zu laden. Danach werden wir mit Volumes weiterarbeiten. Wir werden damit Caddy einen Behälter für die SSL-Zertifikate zur Verfügung stellen.
Wenn wir nochmals den Docker-Befehl auf Docker-Hub betrachten, sehen wir wieder den ursprünglichen Befehl, den wir im letzten Artikel an Podman angepasst (und gekürzt) haben.
docker run -d -p 80:80 -p 443:443 -p 443:443/udp \
-v /site:/srv \
-v caddy_data:/data \
-v caddy_config:/config \
caddy caddy file-server --domain example.com
Unser letzter, daraus abgeleiteter Podman-Befehl:
podman run -p 80:80 -p 443:443 -p 443:443/udp docker.io/caddy
Wir ergänzen den Befehl um die Zeilen mit den -v-Flags. Ausserdem will ich noch vier Änderungen vornehmen: Ich ersetze /site durch $HOME/site und setze das :ro-Suffix, um das Verzeichnis als read-only zu mounten, sowie das :z-Suffix, um die SELinux-Zone zu setzen. Ich ergänze um eine -v-Zeile, damit wir später das Caddyfile mounten können. Zu guter Letzt gebe ich dem Container einen Namen, damit wir ihn später identifizieren können: --name caddy. Dann erhalten wir den folgenden Befehl:
podman run -p 80:80 -p 443:443 -p 443:443/udp \
-v "$HOME/site:/srv:ro,z" \
-v "$HOME/caddy:/etc/caddy:ro,z" \
-v caddy_data:/data \
-v caddy_config:/config \
--name caddy \
docker.io/caddy
Noch eine Anmerkung zu diesem podman run-Befehl:
Im letzten Artikel haben wir zwei Warnungen erhalten, weil wir das nackte docker.io/caddy-Image ohne expliziten Befehl (caddy file-server --domain example.com) gestartet haben. Dieser Befehl startet Caddy ohne Konfigurationsdatei. Er stellt dann aber lediglich statische HTML-Dateien aus dem /srv-Verzeichnis bereit. Mit der Option --domain example.com fordert Caddy für diese Domain Let’s-Encrypt-Zertifikate an.
Diesmal lassen wir den Befehl wieder weg, kriegen aber keine Warnungen mehr. Der Grund dafür ist, dass Caddy nie wirklich ohne Befehl läuft. Vielmehr läuft er mit dem Standard-Befehl caddy run, der die Konfigurationsdatei /etc/caddy/Caddyfile verwendet. Diese Konfigurationsdatei (Caddyfile) binden wir mit -v "$HOME/caddy:/etc/caddy:ro,z" ein. Dort definieren wir selbst, was Caddy tun soll und woher die SSL-Zertifikate kommen.
--mount vs. -v
Das -v-Flag oder lang --volume ist die alte Syntax für Volumes und Bind Mounts, sowohl bei Docker als auch bei Podman. Es gibt eine neue Syntax für Volumes und Bind Mounts, die --mount ist. Dieses Flag verlangt, dass alles explizit angegeben wird. Der oben beschriebene Befehl würde in der neuen Syntax wie folgt aussehen:
podman run -p 80:80 -p 443:443 -p 443:443/udp \
--mount type=bind,source=$HOME/site,target=/srv,readonly,relabel=shared \
--mount type=bind,source=$HOME/caddy,target=/etc/caddy,readonly,relabel=shared \
--mount type=volume,source=caddy_data,target=/data \
--mount type=volume,source=caddy_config,target=/config \
--name caddy \
docker.io/caddy
Die alte Syntax ist also kürzer. Sie kann aber problematisch sein, da sie die Bedeutung der Optionen nicht klar macht und oft Annahmen macht. Tippfehler können dazu führen, alles fehlerlos durchläuft, trotzdem aber nichts funktioniert. Beispielsweise kann ein Tippfehler dazu führen, dass du ein Volume statt eines Pfades nutzt. Genau diese Situation siehst du weiter unten bei den Volumes. Viel Spass beim Debuggen solcher Fehler!
Die Empfehlung ist daher, die lange Syntax mit --mount für Produktivumgebungen und die alte Syntax mit -v für kurze Tests zu nutzen. Ich werde dir beides angeben.
Bind Mounts
Bind Mounts sind eine Möglichkeit, Daten aus dem Host-System in den Container einzubinden. Sie werden verwendet, um Dateien oder Verzeichnisse aus dem Host-System in den Container einzubinden.
--mount type=bind
Mit dem --mount-Flag und type=bind in deinem Podman-Befehl definierst du einen Bind Mount. Zusätzlich bestimmst du die Optionen für den Bind Mount getrennt durch Kommas.
Im untenstehendenBeispiel habe ich den Pfad $HOME/site aus dem Host-System in den Container gemountet. Das ist die Quelle (source) des Bind Mounts. Der Zielpfad im Container (target) ist /srv. Ausserdem will ich verhindern, dass die Dateien, die im Verzeichnis $HOME/site liegen, im Container geändert werden können. Daher setze ich das readonly-Flag. Auf Systemen mit SELinux kann es sein, dass der Zugriff des Containers auf die Dateien im Verzeichnis $HOME/site blockiert wird. Für diesen Fall setze ich das relabel=shared-Flag, um die Zugriffsrechte zu ändern.
--mount type=bind,source=$HOME/site,target=/srv,readonly,relabel=shared
-v / --volume
Für einen Bind Mount mit -v werden die Quell- und Zielpfade durch einen Doppelpunkt (:) getrennt. Ein weiterer Doppelpunkt zeigt an, dass weitere Optionen folgen. Mehrere Optionen, wie ro und z für Read-Only und SELinux-Zone, werden durch Kommas getrennt.
-v $HOME/site:/srv:ro,z
Stolpersteine von Bind Mounts
Bei Bind Mounts können einige Probleme auftreten. Schauen wir uns zwei Beispiele an:
- Du deployst Caddy mit dem Bind Mount
$HOME/site:/srv. Nach einem halben Jahr willst du dein Home-Verzeichnis aufräumen und du alle Dateien, die zum Container gehören, in ein eigenes~/container_data-Verzeichnis verschieben. Also verschiebst du$HOME/sitein~/container_data/siteund schon funktioniert nichts mehr, weil Caddy die Daten nicht findet. Oder du veränderst die Zugriffsrechte von$HOME/siteund plötzlich hat Caddy keine Berechtigung mehr, die Daten zu lesen. Fazit: Du bist zuständig für das Quellverzeichnis auf dem Host-System. - Ein anderes Problem entsteht, wenn du eine Datei, statt einem Verzeichnis, als Quelle für den Bind Mount verwendest. In diesem Fall wird die Datei in den Container kopiert, anstatt ein Verzeichnis zu mounten. Das hat die Auswirkung, dass Änderungen an der Datei auf dem Host-System nicht automatisch in den Container übertragen werden. Hast du stattdessen ein Verzeichnis verwendet, um die Daten zu mounten, werden Änderungen automatisch synchronisiert. In unserem Caddy-Container spielt genau das eine Rolle. Wir wollen die HTML-Dateien in
$HOME/siteändern können, ohne gleich den Container neu starten zu müssen. Fazit: Immer Verzeichnisse, nie Dateien mounten.
Volumes
Volumes sind eine andere Möglichkeit, Daten persistent auf dem Host-System zu speichern und in einen Container einzubinden und entledigen sich einiger der Stolpersteine von Bind Mounts. Volumes sind eine Art Behälter für die Daten, die in den Containern gespeichert werden. Der Vorteil von Volumes ist, dass sie von Podman verwaltet und automatisch auf dem Host-System gespeichert werden.
Du benennst das Volume, Podman erstellt den Behälter für dich und kümmert sich um die Speicherung der Daten auf dem Host-System. Simpel.
In unserem Podman-Befehl haben wir auch zwei Volumes. Das erste haben wir mit dem Namen caddy_data angegeben. Wir mounten es unter /data in den Container. Caddy speichert alle seine Daten, die nicht direkt mit den Konfigurationen zusammenhängen, unter /data. Ein Beispiel sind die TLS-Zertifikate. Mit dem Volume caddy_data haben wir eine persistente Speicherung gewährleistet.
Das zweite Volume haben wir mit dem Namen caddy_config angegeben. Wir mounten es unter /config in den Container. Caddy speichert da die aktuell aktive, “autosaved” Konfiguration.
--mount type=volume
Ich möchte nochmals betonen: Bei Volumes wird als source der Name des Volumes angegeben. Also kein Pfad, wie bei Bind Mounts. Anders ist es beim target, dort bleibt es weiterhin der Pfad im Container. Wenn du die --mount-Syntax verwendest, musst du auch noch den type=volume angeben.
--mount type=volume,source=caddy_data,target=/data
--mount type=volume,source=caddy_config,target=/config
-v / --volume
Bei der -v / --volume-Syntax wird der Name des Volumes und der Zielpfad im Container durch Komma getrennt angegeben. Ansonsten gibt es kein Unterscheidungsmerkmal zwischen Volumes und Bind Mounts.
-v caddy_data:/data
-v caddy_config:/config
Das einzige, was also in der -v / --volume-Syntax Volumes von Bind Mounts unterscheidet, ist die Tatsache, dass bei Volumes der Name des Volumes, bei Bind Mounts der Pfad im Host-System angegeben wird. Dies kann unter Umständen bedeuten, dass ein einziger Schrägstrich (/) den Unterschied macht, wie du in folgendem Beispiel sehen kannst:
-v /myapp_data:/data # Bind Mount
-v myapp_data:/data # Volume
podman volume
Podman bietet eine einfache CLI-Möglichkeit, Volumes zu verwalten. Mit podman volume create kannst du Volumes erstellen, mit podman volume ls anzeigen und mit podman volume rm löschen.
Obwohl podman run --mount Volumes direkt erstellt, kann es Vorteile bringen, es zuvor mit podman volume create anzulegen, beispielsweise, wenn das Volume komplexer ist als im obigen Beispiel.
Mit podman volume inspect kannst du die Details des Volumes anzeigen.
Spannend wird es, mit podman volume export , um ein Volume als Tar-Archiv zu exportieren. Mit podman volume import kannst du ein Volume aus einem Tar-Archiv importieren. Das kann beispielsweise für Backups genutzt werden, wenn deine Backup-Software kein Podman unterstützt: Du lässt deine Backup-Software mittels Script den Inhalt aller deiner Volumes exportieren und hast somit einen Snapshot deiner Container-Daten. Nun kann sie dein Host-System sichern und gleichzeitig deine Container-Daten.
Quadlet .volume
Mit Quadlet kannst du Volumes auch in einer .volume-Datei definieren. Diese Datei wird dann verwendet, um das Volume zu erstellen. Bei simplen Volumes wie bei unseren caddy_data- und caddy_config-Volumes bleiben auch die caddy_data.volume- und caddy_config.volume-Dateien simpel:
# caddy_data.volume
[Volume]
VolumeName=caddy_data
# caddy_config.volume
[Volume]
VolumeName=caddy_config
Wann nutze ich Bind Mounts und wann Volumes?
Die Frage, die du dir stellen musst, ist: Wo liegt die Quelle der Wahrheit (Source of Truth) der Daten? Generiert der Container die Daten selbst (z.B. bei den TLS-Zertifikaten), dann solltest du Volumes bevorzugen. Liegt die Quelle ausserhalb des Containers (z.B. beim Caddyfile oder in einer CI/CD-Pipeline), dann solltest du Bind Mounts verwenden.
Die zweite Frage, die du dir stellen kannst: Wie portabel muss dein Container sein? Hast du vielleicht einmal vor, den Host zu wechseln oder auf Kubernetes zu migrieren? Dann sind Volumes die bessere Wahl.
Im Zweifelsfall würde ich Volumes bevorzugen. Einfach, weil Volumes sich einiger der Stolpersteine von Bind Mounts entledigen.
IT Tools und Caddy aufsetzen
Wir setzen jetzt alles um, was wir bisher gelernt haben.
Wir wollen erreichen, dass alle Anfragen an https://it-tools.example.com über Caddy gehen und die IT Tools anzeigen. Alle anderen Anfragen sollen die 404-Seite anzeigen, da im Caddyfile keine entsprechende Konfiguration vorhanden ist.
Dafür müssen wir die DNS-Einträge für it-tools.example.com und test.example.com (um die 404-Seite testen zu können) einrichten.
Der ganze Ablauf ist wie folgt:
- DNS-Einträge für
it-tools.example.comundtest.example.comin die/etc/hosts-Datei schreiben. - Container
it-toolsstarten. - Erreichbarkeit von IT Tools testen.
- Privilegierte Ports neu definieren.
- Verzeichnisse für Caddy anlegen.
- Caddyfile einrichten.
- 404.html Seite schreiben.
- Container
caddymit Podman starten. - Erreichbarkeit der 404-Seite testen.
- Erreichbarkeit der IT Tools via Caddy testen.
Spoiler: Der letzte Test wird nicht klappen, da noch ein Puzzleteil fehlt: Podman-Netzwerke. Aber sieh selbst:
DNS-Einträge
-
Sichere die originale hosts-Datei.
sudo cp /etc/hosts /etc/hosts.backup -
Schreibe einen Eintrag für
it-tools.example.comundtest.example.comin/etc/hosts. (Denke daran,durch deine eigene Domain zu ersetzen, falls du eine hast.) myip=$(ip route get 1.1.1.1 | awk '{print $7; exit}') echo "$myip it-tools.example.com" | sudo tee -a /etc/hosts echo "$myip test.example.com" | sudo tee -a /etc/hosts -
Wenn du mit den Tests fertig bist, solltest du unbedingt die ursprüngliche
hosts-Datei wiederherstellen.sudo mv /etc/hosts.backup /etc/hosts
Wir haben noch einen zusätzlichen test.example.com-Eintrag in die /etc/hosts-Datei geschrieben. Diesen nutzen wir, um die 404-Seite zu testen. Die URL zeigt auf unsere IP-Adresse, ist jedoch keinem Container im Caddyfile zugeordnet.
IT Tools starten
podman run --pull always --restart unless-stopped -p 8080:8080 -d --name it-tools docker.io/sharevb/it-tools:latest
Erreichbarkeit von IT Tools testen
Wir machen zwei Erreichbarkeits-Tests, bevor wir Caddy gestartet haben:
- Versuche die IT Tools wie zuvor über
http://localhost:8080zu erreichen. Das sollte funktionieren. - Versuche die IT Tools über
https://it-tools.example.comzu erreichen. Das sollte nicht funktionieren. Schliesslich würde das über Caddy führen, den wir aber noch nicht gestartet haben. Stattdessen erhalten wir die Fehlermeldung. Bei Firefox lautet die Fehlermeldung: Verbindung fehlgeschlagen. Firefox kann sich nicht mit dem Server auf it-tools.example.com verbinden
Privilegierte Ports neu definieren
# Temporär setzen (bis zum nächsten Reboot)
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
Verzeichnisse für Caddy-Dateien anlegen
mkdir -p $HOME/{caddy,site}
Caddyfile einrichten
Lege die Caddyfile-Datei mit deinem Lieblings-Editor an:
nano $HOME/caddy/Caddyfile
Füge folgenden Inhalt ein:
# it-tools über HTTPS (self-signed Zertifikat)
https://it-tools.example.com {
tls internal
reverse_proxy it-tools:8080
}
# Catch-all für alle anderen/nicht vorhandenen Domains -> eigene 404-Seite
:443 {
tls internal {
on_demand
}
root * /srv
file_server
handle_errors {
@404 expression {http.error.status_code} == 404
rewrite @404 /404.html
file_server
}
}
404.html Seite schreiben
Lege die 404.html-Datei mit deinem Lieblings-Editor an:
nano $HOME/site/404.html
Füge folgenden Inhalt ein:
html>
<html>
<head>
<title>404 - Seite nicht gefundentitle>
head>
<body>
<h1>404 - Seite nicht gefundenh1>
<p>Die angeforderte Seite existiert nicht.p>
body>
html>
Caddy starten
Wir starten Caddy als Container mit dem Befehl, den wir erarbeitet haben.
podman run -p 80:80 -p 443:443 -p 443:443/udp \
--mount type=bind,source=$HOME/site,target=/srv,readonly,relabel=shared \
--mount type=bind,source=$HOME/caddy,target=/etc/caddy,readonly,relabel=shared \
--mount type=volume,source=caddy_data,target=/data \
--mount type=volume,source=caddy_config,target=/config \
--name caddy \
docker.io/caddy
Erreichbarkeit der 404-Seite testen
Wenn wir https://test.example.com aufrufen, kriegen wir als erstes eine Warnung, dass die Verbindung potenziell gefährlich ist. Firefox sagt bei mir: “Seien Sie vorsichtig. Irgendetwas stimmt hier nicht.” Diese Warnung ist zu erwarten, da das genutzte Caddyfile Caddy anweist, selbstsignierte SSL-Zertifikate zu verwenden. Unser Browser vertraut diesen nicht.
Wir müssen dem Browser mitteilen, dass wir die selbstsignierten SSL-Zertifikate akzeptieren möchten. Bei der Warnung kannst du dafür auf “Erweitert” klicken und dann auf “Weiter zu test.example.com” klicken.
Ergebnis: Dir wird die 404-Seite angezeigt! Super! Mit diesem Test wissen wir, dass…
- Caddy grundsätzlich funktioniert.
- Die 404-Seite korrekt gemountet ist.
- Das Caddyfile korrekt gemountet und die 404-Seite korrekt konfiguriert ist.
Erreichbarkeit der IT Tools-Seite via Caddy testen
Oben bei den Zwischentests haben wir die IT Tools über http://localhost:8080 erreicht. Wir wissen also, dass der Container läuft.
Als wir die IT Tools über https://it-tools.example.com aufgerufen haben, erhielten wir die Fehlermeldung von Firefox: Verbindung fehlgeschlagen. Firefox kann sich nicht mit dem Server auf it-tools.example.com verbinden. Dies war zu erwarten, da wir noch keine Caddy-Instanz gestartet haben.
502 Bad Gateway
Nachdem wir jetzt die Caddy-Instanz gestartet haben, erhalten wir eine neue Fehlermeldung beim Aufruf der IT Tools über https://it-tools.example.com. Bei Firefox lautet die Fehlermeldung: Anscheinend gibt es ein Problem mit dieser Website. Der Server auf it-tools.example.com sendete einen Fehler: 502 Bad Gateway. Schauen wir uns die Fehlermeldung genauer an:
-
Die Tatsache, dass wir eine neue Fehlermeldung erhalten, bedeutet, dass die URL
https://it-tools.example.comüber Caddy geleitet wird. -
Wir wissen ausserdem, dass Caddy die Einstellung zur URL
, die wir im Caddyfile konfiguriert haben, erkannt hat. Das wissen wir, weil wir sonst unsere 404-Seite erhalten hätten, die ja immer dann angezeigt wird, wenn die URL nicht konfiguriert ist. -
Der Fehlercode 502 Bad Gateway bedeutet, dass der Server it-tools auf it-tools.example.com nicht erreichbar ist. Das kann drei Gründe haben:
- Der
it-tools-Container läuft nicht. - Der
it-tools-Container läuft zwar, aber die Konfiguration im Caddyfile, wie derit-tools-Container erreicht werden soll, ist nicht korrekt. - Der
it-tools-Container läuft und die Konfiguration im Caddyfile ist korrekt, aber Caddy kann denit-tools-Container trotzdem nicht erreichen.
- Der
-
Wir erreichen IT Tools über
http://localhost:8080, also wissen wir, dass der Container läuft. Grund 1 ist also nicht der Fall. -
Wir überprüfen unser Caddyfile und sind überzeugt davon, dass die Einstellungen korrekt sind. Grund 2 schliessen wir einmal aus.
-
Es muss also Grund 3 sein. Doch wieso sollte Caddy den
it-tools-Container nicht erreichen können?
Spoiler: Der Grund dafür ist, dass Caddy und IT Tools nicht auf demselben Podman-Netzwerk laufen. Diesem Problem nehmen wir uns im nächsten Artikel an.
Fazit und Ausblick
Container sind disposable – und genau das macht Daten zum Problem, sobald sie den Container überleben sollen. Die Lösung: Bind Mounts für Daten, deren Quelle der Wahrheit auf dem Host liegt (unser Caddyfile, die statischen HTML-Dateien), und Volumes für Daten, die der Container selbst erzeugt (Caddys TLS-Zertifikate, seine Konfiguration). Dazu die zwei Syntax-Varianten: -v fürs schnelle Testen, --mount für alles, bei dem Tippfehler wehtun.
Am Ende hast du IT Tools und Caddy erfolgreich mit persistenten Daten aufgesetzt. Alles läuft, ausser dass Caddy den it-tools-Container nicht erreichen kann. Der 502 Bad Gateway zeigt: Ein Container-Name allein reicht nicht, damit Caddy den it-tools-Container auch erreicht. Genau darum geht es im nächsten Teil: Podman-Netzwerke.
TL;DR
Bind Mount (Host-Pfad ist die Quelle der Wahrheit):
-v "$HOME/site:/srv:ro,z"
--mount type=bind,source=$HOME/site,target=/srv,readonly,relabel=shared
Volume (Container verwaltet die Daten selbst):
-v caddy_data:/data
--mount type=volume,source=caddy_data,target=/data
Faustregel: Volumes bevorzugen, ausser du musst regelmässig vom Host aus auf die Daten zugreifen (dann Bind Mount) – und immer Verzeichnisse mounten, nie einzelne Dateien.
Unsere finalen Befehle:
# Mit der --mount Syntax
podman run -p 80:80 -p 443:443 -p 443:443/udp \
--mount type=bind,source=$HOME/site,target=/srv,readonly,relabel=shared \
--mount type=bind,source=$HOME/caddy,target=/etc/caddy,readonly,relabel=shared \
--mount type=volume,source=caddy_data,target=/data \
--mount type=volume,source=caddy_config,target=/config \
--name caddy \
docker.io/caddy
# Mit der -v Syntax
podman run -p 80:80 -p 443:443 -p 443:443/udp \
-v "$HOME/site:/srv:ro,z" \
-v "$HOME/caddy:/etc/caddy:ro,z" \
-v caddy_data:/data \
-v caddy_config:/config \
--name caddy \
docker.io/caddy
Quellen und Dokumentation
- «docker - Podman volume mounts: When to use the :z or :Z suffix? - Unix & Linux Stack Exchange». Zugriff am 15. September 2026. https://unix.stackexchange.com/questions/651198/podman-volume-mounts-when-to-use-the-z-or-z-suffix.
- OneUptime | One Complete Observability Platform. «How to Use the –Mount Flag vs –Volume Flag in Podman». 17. März 2026. https://oneuptime.com/blog/post/2026-03-17-mount-flag-vs-volume-flag-podman/view.
- «podman-run — Podman documentation». Zugriff am 15. September 2026. https://docs.podman.io/en/latest/markdown/podman-run.1.html#mount-type-type-type-specific-option.
- «podman-systemd.unit — Podman documentation». Zugriff am 15. September 2026. https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html#volume-units-volume.
- «podman-volume.unit — Podman documentation». Zugriff am 15. September 2026. https://docs.podman.io/en/latest/markdown/podman-volume.unit.5.html.
