Block 3 – Storage: Volumes & Mounts
Dauer: ca. 30 Minuten
Ziel: Verstehen wie Daten persistent gemacht werden – und das Aha-Erlebnis live erleben.
💡 Roter Faden: Wir geben unserem nginx eine eigene Webseite – mit einer Datei vom Host.
3.1 Das Problem: Daten sind flüchtig
Aus Block 1 wissen wir: Alles was im Container verändert wird, liegt in der R/W-Schicht und ist beim nächsten Start weg.
Für den Sysadmin-Alltag bedeutet das: - Logfiles im Container → beim Neustart weg - Konfigurationsänderungen direkt im Container → beim Neustart weg - Datenbank-Daten ohne Volume → beim Neustart weg
Die Lösung: Storage von aussen einbinden.
3.2 Drei Arten von Storage
┌─────────────────────────────────────────────────────────────┐
│ HOST │
│ │
│ /home/user/webroot/ podman volume tmpfs (RAM) │
│ │ │ │ │
│ │ Bind Mount │ Volume │ tmpfs Mount │
│ ↓ ↓ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ CONTAINER │ │
│ │ /usr/share/nginx/html /data /tmp/cache │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
| Typ | Beschreibung | Analogie | Wann verwenden |
|---|---|---|---|
| Bind Mount | Host-Pfad direkt in Container | Symlink auf einen Ordner | Configs, Entwicklung, direkter Zugriff nötig |
| Volume | Von Podman verwalteter Speicher | NFS-Mount – der Container geht, die Daten bleiben | Datenbanken, persistente App-Daten |
| tmpfs | Nur im RAM, flüchtig | Ramdisk | Temporäre Dateien, Secrets, Performance |
3.3 Bind Mount – Das Aha-Erlebnis
Ein Bind Mount verbindet einen Host-Pfad direkt mit einem Container-Pfad.
"Ein Bind Mount ist wie ein Symlink auf einen Ordner – du siehst direkt was auf dem Host liegt. Änderung auf dem Host = sofort im Container sichtbar."
# Syntax
podman run -v /host/pfad:/container/pfad image
# Beispiel: eigenen Webroot einbinden
podman run -d \
--name mein-nginx \
-p ${PORT}:80 \
-v /home/teilnehmer01/webroot:/usr/share/nginx/html:ro \
nginx
Mount-Optionen
-v /host/pfad:/container/pfad:ro → read-only (Container kann nicht schreiben)
-v /host/pfad:/container/pfad:rw → read-write (Standard)
-v /host/pfad:/container/pfad:z → SELinux-Label setzen (shared)
-v /host/pfad:/container/pfad:Z → SELinux-Label setzen (private)
💡 SELinux-Hinweis (RHEL): Auf RHEL mit aktivem SELinux kann es beim Bind Mount zu "Permission denied" kommen, obwohl die Linux-Berechtigungen stimmen. In diesem Fall
:zoder:Zanhängen.:zfür geteilten Zugriff,:Zfür exklusiven Zugriff durch diesen Container.
3.4 Volumes – Persistente Daten
Ein Volume wird von Podman verwaltet und überlebt den Container.
"Ein Volume ist wie ein NFS-Mount – der Container geht, die Daten bleiben. Podman kümmert sich darum wo die Daten liegen."
# Volume erstellen
podman volume create meine-daten
# Volume anzeigen
podman volume ls
# Volume inspizieren (wo liegt es wirklich?)
podman volume inspect meine-daten
# → Mountpoint: /home/user/.local/share/containers/storage/volumes/meine-daten/_data
# Container mit Volume starten
podman run -d \
--name mein-nginx \
-v meine-daten:/usr/share/nginx/html \
nginx
# Volume entfernen (nur wenn nicht verwendet)
podman volume rm meine-daten
# Alle unbenutzten Volumes entfernen
podman volume prune
Bind Mount vs. Volume – wann was?
| Bind Mount | Volume | |
|---|---|---|
| Pfad bekannt? | Ja – du gibst ihn an | Nein – Podman verwaltet |
| Direkter Host-Zugriff? | Ja | Nur via podman volume inspect |
| Portabilität | Pfad muss auf jedem Host gleich sein | Überall gleich |
| Typischer Einsatz | Configs, Webroot, Logs | Datenbank-Daten, App-State |
3.5 Dateiberechtigungen und UID/GID
Das ist eine häufige Fehlerquelle im Alltag. Container-Prozesse laufen mit einer bestimmten UID – und die muss zu den Berechtigungen der gemounteten Dateien passen.
# Welche UID läuft im Container?
podman exec mein-nginx id
# uid=101(nginx) gid=101(nginx)
# Welche Berechtigungen hat der Host-Ordner?
ls -la ~/webroot/
# drwxr-x--- 2 teilnehmer01 teilnehmer01 4096
# → nginx (UID 101) kann nicht lesen!
"Ein UID-Mismatch im Container ist wie ein falsch gesetzter
chownnach einem Restore – der Prozess startet, aber kommt nicht an seine eigenen Dateien ran."
Lösung – Host-Dateien im Container lesbar machen
# Option 1: other-Berechtigung setzen (einfachste Lösung)
chmod o+rx ~/webroot/
chmod o+r ~/webroot/*
# Option 2: --user Flag – Container-Prozess als dein User starten
podman run -d --name mein-nginx \
--user 1000:1000 \
-v ~/webroot:/usr/share/nginx/html:ro \
nginx
# → nginx läuft als UID 1000 = dein User → kann deine Dateien direkt lesen
⚠️
--userfunktioniert nicht mit allen ImagesViele Applikationen wie nginx wechseln intern UIDs:
Mitnginx master process → startet als root (braucht Port-Binding) nginx worker process → wechselt zu UID 101 (nginx)--user 1000:1000kann nginx diese UIDs nicht mehr wechseln (setuidfehlt) und startet entweder gar nicht oder ohne Worker-Prozesse.Was dann passiert wenn mehrere UIDs schreiben:
# Ohne --user – jede UID schreibt mit ihrem eigenen Mapping nginx (UID 101) schreibt → Host sieht UID ~100101 ← schwer zugänglich root (UID 0) schreibt → Host sieht UID 1000 ← direkt zugänglich # Mit --user 1000 – alles läuft als UID 1000 nginx schreibt → Host sieht UID 1000 ← direkt zugänglich exec -u root → auch UID 1000 auf Host (Namespace-Mapping)Für nginx speziell:
--userweglassen und stattdessen: -chmod o+rxfür Lesezugriff vom Host -podman unshare chown 0:0wenn Container Dateien erstellt hat die du brauchst - Oderdocker.io/nginxinc/nginx-unprivilegedverwenden – dieses Image ist für rootless ausgelegt
Empfehlung nach Situation:
| Situation | Beste Lösung |
|---|---|
| Container soll Host-Dateien lesen | chmod o+rx auf Host-Ordner |
App unterstützt --user (z.B. einfache Scripts) |
--user $(id -u):$(id -g) |
| nginx schreibt Logs, du willst Zugriff | podman unshare chown 0:0 <datei> |
| Mehrere UIDs schreiben | Kein --user, podman unshare für Zugriff |
3.5b Dateien die im Container erstellt werden
Das ist die umgekehrte Richtung – und häufig eine Überraschung.
Was passiert auf dem Host wenn nginx eine Datei erstellt?
┌─────────────────────────────────────────────────────────────┐
│ rootless Podman – UID-Mapping bei Bind Mounts │
│ │
│ Im Container Auf dem Host │
│ UID 0 (root) → UID 1000 (dein User) ← direkt zugänglich
│ UID 101 (nginx) → UID ~100101 (sub-uid) ← kaum zugänglich
│ UID 1000 → UID ~101000 (sub-uid) ← kaum zugänglich
└─────────────────────────────────────────────────────────────┘
# nginx erstellt eine Log-Datei im gemounteten Verzeichnis
podman exec mein-nginx touch /usr/share/nginx/html/test.txt
# Auf dem Host anschauen
ls -la ~/webroot/
# -rw-r--r-- 100101 100101 test.txt ← gehört UID 100101 – nicht dir!
# Du kannst sie nicht löschen
rm ~/webroot/test.txt
# rm: cannot remove 'test.txt': Permission denied
Was passiert bei Volumes?
# nginx (UID 101) erstellt Datei im Volume
# Volume liegt unter ~/.local/share/containers/storage/volumes/
ls -la ~/.local/share/containers/storage/volumes/nginx-logs/_data/
# 100101 100101 access.log ← sub-uid, kaum zugänglich
# root im Container erstellt Datei im Volume
# UID 0 im Container → UID 1000 (dein User) auf dem Host
# -rw-r--r-- teilnehmer01 teilnehmer01 datei.txt ← direkt zugänglich
"Bei rootless Podman ist UID 0 im Container die einzige UID die direkt auf deinen Host-User gemappt wird. Alle anderen UIDs landen in der sub-uid Range."
Zugriff auf Container-erstellte Dateien
# Option 1: podman unshare – in den Namespace springen
podman unshare ls -la ~/webroot/
# → zeigt Dateien mit Container-UIDs korrekt
# Besitzer im Namespace ändern (UID 0 im NS = dein User auf Host)
podman unshare chown 0:0 ~/webroot/test.txt
ls -la ~/webroot/test.txt
# → gehört jetzt teilnehmer01 ✅
# Option 2: --user Flag – verhindert das Problem von Anfang an
podman run --user 1000:1000 ...
# → alle Dateien die der Container erstellt gehören dir direkt
# Option 3: rootful für Volume-Zugriff
sudo ls -la ~/.local/share/containers/storage/volumes/nginx-logs/_data/
Übersichtstabelle
| Wer erstellt die Datei | Container-UID | Host-UID (rootless) | Direkt zugänglich |
|---|---|---|---|
| root im Container | 0 | 1000 (dein User) | ✅ ja |
| nginx im Container | 101 | ~100101 (sub-uid) | ❌ nein |
--user 1000 |
1000 | 1000 (dein User) | ✅ ja |
Welche UID sieht der Host?
# Im Container
podman exec mein-nginx id
# uid=0(root)
# Auf dem Host – was sieht der Host wirklich?
ps aux | grep [c]onmon
# teilnehm+ 1234 ...
# → Als User-Prozess des Teilnehmers, nicht als root
# Das ist Rootless Podman in Aktion – mehr in Block 7
3.6 Mounts inspizieren
# Welche Mounts hat ein Container?
podman inspect --format '{{.Mounts}}' mein-nginx
# Besser lesbar
podman inspect mein-nginx | grep -A20 '"Mounts"'
# Oder direkt im laufenden Container
podman exec mein-nginx df -h
podman exec mein-nginx mount | grep -v "proc\|sys\|dev"
Übung 3 – Eigene Webseite in nginx
🔴 Roter Faden: Wir geben unserem nginx eine eigene Startseite – direkt vom Host gemountet.
💡 Variablen setzen falls noch nicht geschehen (aus Block 2):
Aufgabe 3a – Das Aha-Erlebnis: Bind Mount
# 1. Eigenen Webroot erstellen
mkdir -p ~/webroot
# 2. Eigene index.html erstellen
cat > ~/webroot/index.html << EOF
<html>
<head><title>Mein Container</title></head>
<body>
<h1>Hallo vom Host</h1>
<p>Diese Datei liegt auf dem Host unter ~/webroot/</p>
<p>User: ${USER_NAME}</p>
</body>
</html>
EOF
# 3. Alten Container entfernen
podman stop mein-nginx && podman rm mein-nginx
# 4. Neuen Container mit Bind Mount starten
podman run -d \
--name mein-nginx \
-p ${PORT}:80 \
-v ~/webroot:/usr/share/nginx/html:ro \
docker.io/library/nginx:latest
# 5. Testen
curl http://localhost:${PORT}
⚠️ Permission denied? Das ist normal und erwartet. nginx läuft im Container als UID 101 (
Mehr zu UID/GID-Problemen in Abschnitt 3.5.nginx-User), aber~/webroot/gehört deinem User. Lösung:
Fragen: 1. Siehst du deine eigene HTML-Seite? 2. Was passiert wenn du die Datei auf dem Host änderst?
# Datei auf dem Host ändern
echo "<h1>Ich wurde geaendert</h1>" > ~/webroot/index.html
# Sofort im Container sichtbar?
curl http://localhost:${PORT}
Aufgabe 3b – Volume erstellen und verwenden
# Volume erstellen
podman volume create nginx-logs
# nginx mit Log-Volume starten
podman stop mein-nginx && podman rm mein-nginx
podman run -d \
--name mein-nginx \
-p ${PORT}:80 \
-v ~/webroot:/usr/share/nginx/html:ro \
-v nginx-logs:/var/log/nginx \
docker.io/library/nginx:latest
# Logs generieren
curl http://localhost:${PORT}
curl http://localhost:${PORT}/nichtvorhanden
# Volume inspizieren
podman volume inspect nginx-logs
# Logs direkt auf dem Host lesen (Pfad aus inspect)
ls -la ~/.local/share/containers/storage/volumes/nginx-logs/_data/
Aufgabe 3c – Was passiert beim Container löschen?
# Container löschen
podman rm -f mein-nginx
# Volume noch vorhanden?
podman volume ls
# → nginx-logs ist noch da!
# Neuen Container mit gleichem Volume starten
podman run -d \
--name mein-nginx \
-p ${PORT}:80 \
-v ~/webroot:/usr/share/nginx/html:ro \
-v nginx-logs:/var/log/nginx \
docker.io/library/nginx:latest
# Alte Logs noch vorhanden?
podman exec mein-nginx cat /var/log/nginx/access.log
Musterlösung Übung 3
3a
curl http://localhost:${PORT}
# <html><head><title>Mein Container</title></head>...
# → Eigene Seite wird angezeigt!
echo "<h1>Ich wurde geaendert</h1>" > ~/webroot/index.html
curl http://localhost:${PORT}
# <h1>Ich wurde geändert!</h1>
# → Sofort sichtbar – kein Container-Neustart nötig!
Das ist das Aha-Erlebnis: Die Datei liegt auf dem Host – der Container sieht sie direkt. Keine Kopie, kein Sync, keine Verzögerung.
3b
podman volume inspect nginx-logs
# [
# {
# "Name": "nginx-logs",
# "Mountpoint": "/home/teilnehmer01/.local/share/containers/storage/volumes/nginx-logs/_data",
# ...
# }
# ]
ls ~/.local/share/containers/storage/volumes/nginx-logs/_data/
# access.log error.log
3c
podman volume ls
# DRIVER VOLUME NAME
# local nginx-logs
# → Volume überlebt den Container
podman exec mein-nginx cat /var/log/nginx/access.log
# → Alte Log-Einträge noch vorhanden!
Weiterführende Links
| Thema | Link |
|---|---|
| Podman Volumes | docs.podman.io – podman-volume |
| Red Hat – Storage in Containern | access.redhat.com – Using storage |
| SELinux und Container | access.redhat.com – SELinux Container security |