Zum Inhalt

Block 2 – Grundbefehle & täglicher Betrieb

Dauer: ca. 50 Minuten
Ziel: Überblick verschaffen, Container analysieren, sicher navigieren – die wichtigsten Werkzeuge für den Alltag.

💡 Roter Faden: Wir arbeiten weiter mit dem nginx-Container aus Block 1.


Kursvariablen setzen

Bevor wir starten – setze diese zwei Variablen in deiner Session. Alle Befehle in diesem Kurs verwenden sie, damit du nichts manuell ersetzen musst:

# Deinen Username (wird automatisch gesetzt)
export USER_NAME=$(whoami)

# Deinen Port (steht in deiner ~/.kurs-info)
export PORT=8100        # teilnehmer01
# export PORT=8200      # teilnehmer02
# export PORT=8300      # teilnehmer03

# Prüfen
echo "User: ${USER_NAME}  |  Port: ${PORT}"

⚠️ Wichtig: Diese Variablen gelten nur für die aktuelle SSH-Session. Nach einem neuen Login müssen sie neu gesetzt werden. Tipp: in ~/.bashrc eintragen damit sie automatisch gesetzt werden:

echo "export PORT=8100" >> ~/.bashrc


2.1 Unbekannter Server – was läuft hier überhaupt?

Bevor du podman ps tippst: Auf einem unbekannten Server musst du zuerst klären was für Container-Technologie überhaupt installiert und aktiv ist. Die Möglichkeiten sind vielfältiger als man denkt:

Mögliche Container-Technologien auf einem Server:
├── Podman          (rootful oder rootless)
├── Docker          (mit dockerd-Daemon)
├── Kubernetes      (kubectl + kubelet)
├── k3s             (leichtgewichtiges Kubernetes)
└── Kombinationen davon
# Schritt 1 – Was ist installiert?
which docker podman kubectl k3s 2>/dev/null

# Schritt 2 – Welche Dienste laufen?
systemctl is-active docker          # Docker aktiv?
systemctl is-active podman.socket   # Podman Socket aktiv?
systemctl is-active kubelet         # Kubernetes Node-Agent?
systemctl is-active k3s             # k3s aktiv?

# Schritt 3 – Kubernetes/k3s läuft?
kubectl get nodes 2>/dev/null       # Kubernetes Cluster erreichbar?
k3s kubectl get pods 2>/dev/null    # k3s Pods

# Schritt 4 – Rootful Container (root-Ebene)
sudo docker ps 2>/dev/null          # Docker Container
sudo podman ps 2>/dev/null          # Podman root Container

# Schritt 5 – Rootless Container irgendwo?
ps aux | grep conmon                # conmon = läuft hinter jedem Podman-Container
ps aux | grep containerd            # containerd = Laufzeit für Docker und k8s
ps aux | grep kubelet               # Kubernetes Node-Agent

# Schritt 6 – Welche User haben Container?
ls /home/                           # Welche User gibt es?
sudo -u teilnehmer01 podman ps      # Container eines bestimmten Users

"Auf einem unbekannten Server immer zuerst klären womit du es zu tun hast. ps aux | grep -E 'conmon|containerd|kubelet' gibt dir in einer Zeile einen Überblick ob und was für Container-Technologie aktiv ist."

Die Technologien und ihre Werkzeuge

Technologie Erkennung Befehle
Podman which podman podman ps, podman ps -a
Docker systemctl is-active docker docker ps, docker ps -a
Kubernetes systemctl is-active kubelet kubectl get pods -A
k3s systemctl is-active k3s k3s kubectl get pods -A

"Bei Kubernetes und k3s fragst du nicht nach Containern – du fragst nach Pods. Die Container darin werden von Kubernetes verwaltet, nicht direkt von dir."

Wichtig: podman ps zeigt nur deine Container

teilnehmer01:  podman ps  →  nur Container von teilnehmer01
teilnehmer02:  podman ps  →  nur Container von teilnehmer02
root:          podman ps  →  nur root-Container (NICHT die rootless User!)

Root sieht also auch nicht alle Container automatisch. Rootless Container laufen im User-Namespace – selbst root bekommt keinen automatischen Überblick.

# Schnellster Überblick über ALLE laufenden Container-Prozesse
ps aux | grep -E 'conmon|containerd|kubelet'
# → Zeigt alle Container-Technologien die aktiv sind

2.2 Überblick verschaffen – "Was läuft hier?"

Wenn du weisst womit du es zu tun hast, ist das dein erster Griff:

# Nur laufende Container
podman ps

# Alle Container – auch gestoppte
podman ps -a

# Kompaktere Ausgabe mit mehr Details
podman ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}\t{{.Image}}"

"podman ps ist dein ps aux für Container – der erste Blick auf das System."

Was sagt mir die Ausgabe?

CONTAINER ID  IMAGE                          COMMAND     CREATED      STATUS            PORTS                 NAMES
a1b2c3d4e5f6  docker.io/library/nginx:latest             2 hours ago  Up 2 hours        0.0.0.0:8100->80/tcp  mein-nginx
b2c3d4e5f6a1  docker.io/library/nginx:latest             1 hour ago   Exited (1) 5 min                        crashed-nginx
Feld Bedeutung
STATUS Up = läuft, Exited (0) = sauber beendet, Exited (1) = Fehler
PORTS 0.0.0.0:8100->80/tcp = Host-Port 8100 → Container-Port 80
NAMES Vergibst du mit --name, sonst zufällig generiert

2.3 Details zu einem Container

# Vollständige Informationen (JSON)
podman inspect mein-nginx

# Gezielt einzelne Felder herausfiltern
podman inspect --format '{{.State.Status}}'   mein-nginx   # Status
podman inspect --format '{{.NetworkSettings.IPAddress}}' mein-nginx   # IP
podman inspect --format '{{.Mounts}}'         mein-nginx   # Mounts
podman inspect --format '{{.Config.Env}}'     mein-nginx   # Umgebungsvariablen

# Ports anzeigen
podman port mein-nginx

"podman inspect ist wie cat /proc/<pid>/status – alles was du über den Container wissen willst, auf einen Blick. Nur etwas gesprächiger."

Ressourcenverbrauch live

# Live-Statistiken (wie top, aber für Container)
podman stats

# Nur bestimmte Container
podman stats mein-nginx

# Einmalige Ausgabe ohne Live-Update
podman stats --no-stream

Prozesse im Container sehen

# Was läuft im Container?
podman top mein-nginx

# Mit Feldern wie ps aux
podman top mein-nginx pid,user,comm,args

2.4 Logs lesen

# Alle Logs
podman logs mein-nginx

# Letzte 20 Zeilen
podman logs --tail 20 mein-nginx

# Live mitlesen (wie tail -f)
podman logs -f mein-nginx

# Mit Zeitstempel
podman logs -t mein-nginx

# Seit einem bestimmten Zeitpunkt
podman logs --since 30m mein-nginx
podman logs --since "2024-01-15T10:00:00" mein-nginx

"podman logs ist dein journalctl für Container. Ohne Logs kein Troubleshooting."


2.5 In einen Container einsteigen – podman exec

podman exec ist eines der wichtigsten Werkzeuge im Alltag. Es führt einen Befehl in einem laufenden Container aus – ohne den Container neu zu starten.

"podman exec ist wie SSH in eine VM – nur ohne Netzwerk, ohne SSH-Daemon, direkt in den Prozess-Namespace."

# Interaktive Shell im Container
podman exec -it mein-nginx bash

# Oder sh wenn bash nicht vorhanden
podman exec -it mein-nginx sh

# Einzelnen Befehl ausführen ohne Shell
podman exec mein-nginx cat /etc/nginx/nginx.conf
podman exec mein-nginx nginx -t          # nginx Config testen
podman exec mein-nginx id                # Welcher User läuft?
podman exec mein-nginx env               # Umgebungsvariablen
podman exec mein-nginx ps aux            # Prozesse im Container

Typische Anwendungsfälle

Situation Befehl
nginx-Config prüfen podman exec mein-nginx nginx -t
Welcher User läuft im Container? podman exec mein-nginx id
Netzwerk-Verbindung testen podman exec mein-nginx curl http://andere-app
Log-Datei direkt lesen podman exec mein-nginx cat /var/log/nginx/error.log
Paket nachinstallieren (temporär!) podman exec mein-nginx dnf install -y curl

⚠️ Wichtig: Alles was du via exec änderst, liegt in der R/W-Schicht und ist beim nächsten Start weg. Für temporäre Analysen ideal – für dauerhafte Änderungen nicht geeignet.

exec vs. attach

# exec → neuer Prozess im Container (empfohlen)
podman exec -it mein-nginx bash

# attach → an den Hauptprozess anhängen (Vorsicht!)
podman attach mein-nginx
# → CTRL+C beendet hier den Hauptprozess = Container stoppt!

"Verwende immer exec, nie attach. Mit attach hängst du dich direkt an den Hauptprozess – ein versehentliches CTRL+C und der Container ist weg."


2.6 Was hat sich verändert? – podman diff

# Zeigt alle Dateisystem-Änderungen seit Container-Start
podman diff mein-nginx

# A = Added, C = Changed, D = Deleted
# A /tmp/testfile
# C /var/log/nginx/access.log

"podman diff ist wie git status für deinen Container – du siehst genau was sich in der R/W-Schicht verändert hat, ohne reinzugehen."


2.7 Container-Lifecycle

# Starten / Stoppen / Neustarten
podman start mein-nginx
podman stop mein-nginx          # Graceful (SIGTERM, wartet 10s)
podman stop -t 30 mein-nginx    # 30 Sekunden warten
podman restart mein-nginx

# Sofort beenden (SIGKILL – nur wenn stop nicht funktioniert)
podman kill mein-nginx

# Container entfernen
podman rm mein-nginx                    # Nur wenn gestoppt
podman rm -f mein-nginx                 # Erzwingen (auch laufend)

# Beim Start automatisch entfernen (ideal für Tests)
podman run --rm nginx echo "hallo"      # Container weg nach Beendigung

⚠️ Produktions-Warnung:

"Niemals podman rm -f auf einem unbekannten Container in Produktion – ohne vorher zu wissen was drin läuft und ob Daten verloren gehen."


2.8 Image-Management

# Lokale Images anzeigen
podman images
podman images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"

# Image pullen
podman pull docker.io/library/nginx:latest
podman pull docker.io/library/nginx:1.24   # Spezifische Version

# Image entfernen
podman rmi docker.io/library/nginx:latest

# Alle nicht verwendeten Images löschen
podman image prune

# Layer-Aufbau anzeigen
podman history docker.io/library/nginx:latest

# Detailinfo zum Image
podman inspect docker.io/library/nginx:latest

2.9 Storage-Verzeichnisse – was wo liegt

Das ist wichtig für Disk-Management, Backup-Planung und Monitoring. Container-Technologien füllen Verzeichnisse die man kennen muss.

Podman – alle Varianten

┌─────────────────────────────────────────────────────────────────────┐
│                    PODMAN STORAGE-ÜBERSICHT                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ROOTFUL (sudo podman)                                              │
│  /var/lib/containers/storage/         ← Images, Container, Volumes  │
│  /var/lib/containers/storage/volumes/ ← Named Volumes               │
│  /run/containers/                     ← Laufzeit-Daten (tmpfs)      │
│                                                                      │
│  ROOTLESS (podman als User)                                         │
│  ~/.local/share/containers/storage/         ← Images, Container     │
│  ~/.local/share/containers/storage/volumes/ ← Named Volumes         │
│  /run/user/<UID>/containers/                ← Laufzeit-Daten        │
│                                                                      │
│  PRO USER – jeder User hat seinen eigenen Store!                    │
│  /home/user1/.local/share/containers/storage/                       │
│  /home/user2/.local/share/containers/storage/                       │
│  /home/user3/.local/share/containers/storage/                       │
└─────────────────────────────────────────────────────────────────────┘

Docker – Verzeichnisse

┌─────────────────────────────────────────────────────────────────────┐
│                    DOCKER STORAGE-ÜBERSICHT                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ROOTFUL (immer – Docker kennt kein rootless)                       │
│  /var/lib/docker/                     ← Alles: Images, Container    │
│  /var/lib/docker/volumes/             ← Named Volumes               │
│  /var/lib/docker/overlay2/            ← Image-Layer (grösster Teil) │
│  /var/run/docker.sock                 ← Docker-Socket               │
│                                                                      │
│  Docker hat KEINEN User-Store – alles liegt zentral unter root.     │
└─────────────────────────────────────────────────────────────────────┘

Was wirklich Platz braucht

# Podman rootful – Übersicht
sudo du -sh /var/lib/containers/storage/
sudo podman system df

# Podman rootless – eigener Store
du -sh ~/.local/share/containers/storage/
podman system df

# Podman rootless – alle User auf dem System (als root)
du -sh /home/*/.local/share/containers/storage/ 2>/dev/null

# Docker
sudo du -sh /var/lib/docker/
sudo docker system df

"Wenn die Disk voll ist, ist /var/lib/containers oder /var/lib/docker sehr oft der Schuldige. Und bei vielen rootless Usern kann es in /home versteckt sein – das übersieht man leicht."

Verzeichnisse im Blick behalten

# Schnelle Übersicht welche Container-Verzeichnisse Platz belegen
du -sh /var/lib/containers/ 2>/dev/null
du -sh /var/lib/docker/ 2>/dev/null
du -sh /home/*/.local/share/containers/ 2>/dev/null
du -sh /run/containers/ 2>/dev/null

# Genauere Aufschlüsselung mit podman
podman system df           # eigener Store
sudo podman system df      # root Store

Was muss ins Backup?

Was Pfad Backup nötig?
Podman Images (root) /var/lib/containers/storage/ ⚠️ nur wenn selbst gebaut
Podman Images (User) ~/.local/share/containers/storage/ ⚠️ nur wenn selbst gebaut
Podman Volumes (root) /var/lib/containers/storage/volumes/ ✅ ja – Anwendungsdaten
Podman Volumes (User) ~/.local/share/containers/storage/volumes/ ✅ ja – Anwendungsdaten
Bind Mounts beliebiger Host-Pfad ✅ ja – liegt wo du es hingelegt hast
Docker Images /var/lib/docker/ ⚠️ nur wenn selbst gebaut
Docker Volumes /var/lib/docker/volumes/ ✅ ja – Anwendungsdaten

"Images müssen nicht gesichert werden wenn sie aus einer Registry gepullt werden können. Was wirklich gesichert werden muss sind Volumes und Bind-Mount-Pfade – dort liegen die Anwendungsdaten."

Root-Store vs. User-Store – das Problem

# Als root gepullt
sudo podman pull nginx

# Als teilnehmer01 eingeloggt
podman images
# → LEER. nginx ist nicht sichtbar.

Root und User sehen nicht dieselben Images. Was root pullt, ist für normale User unsichtbar – und umgekehrt.

Wo liegen die Stores genau?

# Deinen Store anzeigen
podman info | grep -A3 "graphRoot"

# Root-Store (nur mit sudo)
sudo podman info | grep -A3 "graphRoot"

Images zwischen Stores kopieren

# Image von root zu einem User kopieren
sudo podman image scp docker.io/library/nginx:latest teilnehmer01@::

# Image von User zu root kopieren (selten nötig)
podman image scp docker.io/library/nginx:latest root@::

"Das ist wie cp zwischen /root und /home/user – Podman kopiert die Layer rüber ohne erneuten Download."


2.10 Monitoring-Tools

podman stats

Ohne zusätzliche Tools direkt verfügbar:

podman stats --no-stream
# NAME         CPU %   MEM USAGE / LIMIT   MEM %   NET IO    BLOCK IO
# mein-nginx   0.00%   6.2MB / 7.5GB       0.08%   0B / 0B   0B / 0B

Orientierungstabelle – "Was will ich wissen?"

Frage Befehl
Was läuft? podman ps
Was läuft auch gestoppt? podman ps -a
Wo sind die Logs? podman logs <name>
Welcher User läuft im Container? podman exec <name> id
Welche Ports? podman port <name>
Welche Mounts? podman inspect --format '{{.Mounts}}' <name>
Wie viel RAM/CPU? podman stats --no-stream
Was hat sich verändert? podman diff <name>
Welche Umgebungsvariablen? podman inspect --format '{{.Config.Env}}' <name>
Welche IP hat der Container? podman inspect --format '{{.NetworkSettings.IPAddress}}' <name>

Übung 2 – nginx analysieren

🔴 Roter Faden: Wir analysieren unseren laufenden nginx aus Block 1.

Stelle sicher dass dein nginx läuft:

podman ps | grep mein-nginx
# Falls nicht: podman start mein-nginx

Aufgabe 2a – Überblick verschaffen

# Status, Ports, Image anzeigen
podman ps
podman inspect --format '{{.State.Status}}' mein-nginx
podman port mein-nginx

Fragen: 1. Welchen Status hat der Container? 2. Auf welchem Port ist nginx erreichbar?

Aufgabe 2b – In den Container einsteigen

podman exec -it mein-nginx bash

# Im Container:
id                          # Welcher User bin ich?
ps aux                      # Was läuft alles?
cat /etc/nginx/nginx.conf   # nginx-Config anschauen
nginx -t                    # Config-Test
exit

Aufgabe 2c – Logs und Änderungen

# Etwas generieren – Seite aufrufen
curl http://localhost:${PORT}

# Logs anschauen
podman logs mein-nginx
podman logs --tail 5 mein-nginx

# Was hat sich verändert?
podman diff mein-nginx

Aufgabe 2d – Image-Store verstehen

# Deinen Store anzeigen
podman images

# Was liegt im Root-Store?
sudo podman images

# Sind die gleichen Images sichtbar?

Musterlösung Übung 2

2a

podman port mein-nginx
# 80/tcp -> 0.0.0.0:8100

podman inspect --format '{{.State.Status}}' mein-nginx
# running

2b

podman exec -it mein-nginx bash

id
# uid=0(root) gid=0(root)  ← nginx läuft standardmässig als root im Container
# (In Block 7 schauen wir wie das mit rootless besser wird)

ps aux
# PID   USER     COMMAND
# 1     root     nginx: master process nginx -g daemon off;
# 29    nginx    nginx: worker process

nginx -t
# nginx: configuration file /etc/nginx/nginx.conf test is successful

2c

podman diff mein-nginx
# C /run
# C /var/cache/nginx
# A /var/cache/nginx/client_temp
# ...
# → nginx hat beim Start Verzeichnisse und PID-Files angelegt

2d

podman images
# docker.io/library/nginx   latest   ...   187MB

sudo podman images
# Möglicherweise andere Images oder gleiche – aber getrennte Stores
# → Root und User sehen nicht dieselbe Welt

Thema Link
podman-ps Manpage docs.podman.io/en/latest/markdown/podman-ps.1.html
podman-exec Manpage docs.podman.io/en/latest/markdown/podman-exec.1.html
podman-inspect Manpage docs.podman.io/en/latest/markdown/podman-inspect.1.html
Red Hat – Container untersuchen access.redhat.com – Investigating and debugging containers