Zum Inhalt

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.

Container:    nginx + eigene index.html
              ↓ podman rm
              eigene index.html: 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 :z oder :Z anhängen. :z für geteilten Zugriff, :Z fü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 /home/teilnehmer01/webroot/
# drwxr-x--- 2 teilnehmer01 teilnehmer01 4096
# → nginx (UID 101) kann nicht lesen!

"Ein UID-Mismatch im Container ist wie ein falsch gesetzter chown nach einem Restore – der Prozess startet, aber kommt nicht an seine eigenen Dateien ran."

Lösung

# Option 1: Berechtigungen anpassen
chmod o+rx /home/teilnehmer01/webroot/
chmod o+r  /home/teilnehmer01/webroot/*

# Option 2: Besitzer anpassen (auf die UID im Container)
chown -R 101:101 /home/teilnehmer01/webroot/

# Option 3: Bei rootless Podman – UID-Mapping verstehen
# Der Container-Prozess läuft als UID 101 innerhalb des Containers
# Auf dem Host wird diese UID gemappt auf eine sub-UID des Users
# Mehr dazu in Block 7

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 nginx
# teilnehm+   1234   nginx: master process
# → 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):

export USER_NAME=$(whoami)
export PORT=8100   # deinen Port anpassen

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 (nginx-User), aber ~/webroot/ gehört deinem User. Lösung:

chmod o+rx ~/webroot/
chmod o+r  ~/webroot/index.html
# Container neu starten
podman restart mein-nginx
curl http://localhost:${PORT}
Mehr zu UID/GID-Problemen in Abschnitt 3.5.

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!

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