TL;DR — Kurzzusammenfassung
Podman Compose für rootlose Container-Orchestrierung. Installieren, konfigurieren und von Docker Compose migrieren mit systemd, Quadlet und Buildah.
Podman Compose bringt den vertrauten Docker Compose-Workflow zur daemonlosen, rootlosen Podman-Container-Engine. Wenn Sie nach einer Docker-Alternative suchen, die keinen privilegierten Hintergrund-Daemon benötigt, keine Root-Angriffsfläche freilegt und sich nativ in systemd integriert, ist dieser Leitfaden genau das Richtige. Sie lernen, Podman und podman-compose zu installieren, rootlose Benutzer-Namespaces zu konfigurieren, bestehende Docker Compose-Projekte zu migrieren, Pods zu verwalten und den automatischen Start über Quadlet zu aktivieren.
Voraussetzungen
Stellen Sie sicher, dass Sie Folgendes haben:
- Ein Linux-System: Ubuntu 22.04/24.04, Fedora 39+ oder RHEL/Rocky Linux 9
- Ein normales Benutzerkonto (Root ist für den täglichen Betrieb nicht erforderlich)
- Grundkenntnisse der Docker Compose YAML-Syntax
sudo-Zugriff nur für die Erstinstallation
Warum Podman Statt Docker?
Dockers Architektur basiert auf einem privilegierten Daemon (dockerd), der als Root läuft. Jeder docker CLI-Aufruf geht über einen Unix-Socket, der Root gehört. Das bedeutet, dass jeder Prozess, der auf den Docker-Socket zugreifen kann, effektiv Root auf dem Host hat.
Podman verfolgt einen grundlegend anderen Ansatz:
| Aspekt | Docker | Podman |
|---|---|---|
| Architektur | Client-Server-Daemon | Fork/exec, daemonlos |
| Standardberechtigung | Läuft als Root | Rootlos standardmäßig |
| Compose-Unterstützung | docker compose Plugin | podman-compose oder podman compose |
| Image-Format | OCI (Docker-kompatibel) | OCI (Docker-kompatibel) |
| Socket-Anforderung | /var/run/docker.sock (Root) | Optionaler Benutzer-Socket |
| systemd-Integration | Externe Unit-Dateien | Nativer Quadlet-Support |
| CLI-Kompatibilität | Referenzimplementierung | Drop-in (alias docker=podman) |
Installation
Ubuntu 22.04 / 24.04
sudo apt update
sudo apt install -y podman
podman --version
Für Podman 5.x auf Ubuntu 22.04, fügen Sie das offizielle Kubic-Repository hinzu:
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${VERSION_ID}/ /" \
| sudo tee /etc/apt/sources.list.d/kubic-podman.list
curl -fsSL "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${VERSION_ID}/Release.key" \
| sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/kubic-podman.gpg
sudo apt update && sudo apt install -y podman
Fedora / RHEL / Rocky Linux
sudo dnf install -y podman # Fedora
sudo dnf install -y container-tools # RHEL 9 / Rocky Linux 9
Drop-in Alias für Docker
sudo apt install -y podman-docker # Ubuntu
sudo dnf install -y podman-docker # Fedora/RHEL
Konfiguration Rootloser Container
Der rootlose Betrieb hängt von Linux-Benutzer-Namespaces und UID/GID-Zuordnungen ab, die in /etc/subuid und /etc/subgid definiert sind.
grep "^$(whoami)" /etc/subuid /etc/subgid
Falls die Einträge fehlen:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)
podman system migrate
podman run --rm hello-world
Für Ports unter 1024:
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-unprivileged-ports.conf
sudo sysctl --system
Installation von podman-compose
# Via pip (alle Distributionen)
pip install --user podman-compose
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Fedora / RHEL
sudo dnf install -y podman-compose
# Ubuntu
sudo apt install -y podman-compose
Podman 4.4+ enthält einen eingebauten podman compose-Unterbefehl, der automatisch an podman-compose oder docker-compose delegiert:
podman compose version
Erstellen einer compose.yaml für Podman
Podman Compose unterstützt die Compose-Spezifikation (v2/v3-Syntax). Ihre bestehenden docker-compose.yml-Dateien funktionieren ohne Änderungen in den meisten Fällen.
Vollständiges Produktions-Stack-Beispiel — Node.js-API mit PostgreSQL und Redis:
# compose.yaml
name: myapp
services:
api:
build:
context: ./api
dockerfile: Containerfile
image: myapp-api:latest
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: "postgresql://appuser:${DB_PASSWORD}@db:5432/appdb"
REDIS_URL: "redis://redis:6379"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
volumes:
- ./api/logs:/app/logs:Z
networks:
- backend
restart: unless-stopped
db:
image: docker.io/library/postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD: "${DB_PASSWORD}"
volumes:
- pgdata:/var/lib/postgresql/data:Z
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- backend
restart: unless-stopped
redis:
image: docker.io/library/redis:7-alpine
command: redis-server --save 60 1 --loglevel warning
volumes:
- redis-data:/data:Z
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
networks:
- backend
restart: unless-stopped
networks:
backend:
driver: bridge
volumes:
pgdata:
redis-data:
Podman-spezifische Hinweise:
docker.io/library/-Präfix: Podman fügt Docker Hub nicht als implizites Registry hinzu. Verwenden Sie immer vollständig qualifizierte Image-Referenzen.:Z-Volume-Label: Auf SELinux-fähigen Systemen (Fedora, RHEL, Rocky) kennzeichnet das Suffix:Zdas Volume neu, damit der Container-Prozess darauf zugreifen kann.
Starten Sie den Stack:
podman-compose up -d
podman pod ps
podman ps
podman-compose logs -f api
Pod-Verwaltung
Wenn podman-compose einen Multi-Service-Stack startet, erstellt es einen Podman-Pod, der die Container gruppiert und einen Netzwerk-Namespace teilt:
podman pod ps
podman pod inspect myapp_default
podman pod stats myapp_default
podman-compose down
podman-compose down -v
Images mit Buildah und Containerfiles erstellen
# Containerfile
FROM docker.io/library/node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
FROM docker.io/library/node:22-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
RUN adduser -D -u 1001 appuser
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
podman build -t myapp-api:latest -f Containerfile ./api
systemd-Integration: Quadlet
Quadlet ist die moderne Methode, Podman-Container als systemd-Dienste auszuführen, ohne Unit-Dateien manuell schreiben zu müssen. Es ist ab Podman 4.4+ enthalten.
Erstellen Sie ~/.config/containers/systemd/myapp-db.container:
[Unit]
Description=MyApp Datenbank
[Container]
Image=docker.io/library/postgres:16-alpine
Environment=POSTGRES_DB=appdb
Environment=POSTGRES_USER=appuser
EnvironmentFile=%h/.config/myapp/db.env
Volume=%h/.local/share/myapp/pgdata:/var/lib/postgresql/data:Z
HealthCmd=pg_isready -U appuser -d appdb
HealthInterval=10s
[Service]
Restart=always
[Install]
WantedBy=default.target
Aktivieren:
systemctl --user daemon-reload
systemctl --user enable --now myapp-db
journalctl --user -u myapp-db -f
loginctl enable-linger $(whoami)
Vergleich: Compose-Orchestrierungstools
| Tool | Rootlos | Daemon | systemd-Integration | Compose Spec | Kubernetes-Export |
|---|---|---|---|---|---|
| Docker Compose | Nein (rootful) | Ja (dockerd) | Nur extern | Vollständig | Nein |
| podman-compose | Ja | Nein | Via Quadlet | v2/v3 | Nein |
podman compose | Ja | Nein | Via Quadlet | v2/v3 | Nein |
| Nerdctl + containerd | Teilweise | Ja (containerd) | Begrenzt | Vollständig | Nein |
| Podman Quadlet | Ja | Nein | Nativ | Deklarativ | Via podman kube generate |
| Kubernetes (k3s) | Teilweise | Ja | Extern | Via Kompose | Ja (nativ) |
Migration von Docker Compose
# Schritt 1 — Alias docker auf podman
alias docker=podman
alias docker-compose=podman-compose
echo "alias docker=podman" >> ~/.bashrc
echo "alias docker-compose=podman-compose" >> ~/.bashrc
Image-Referenzen aktualisieren:
# Vorher (Docker)
image: postgres:16-alpine
# Nachher (Podman Best Practice)
image: docker.io/library/postgres:16-alpine
Fügen Sie SELinux-Volume-Labels auf RHEL/Fedora-Systemen hinzu und entfernen Sie privileged: true wo möglich.
Besonderheiten und Fallstricke
Netzwerkunterschiede: Der rootlose Podman-Modus verwendet pasta/slirp4netns statt Kernel-Bridge-Netzwerke. Macvlan- und ipvlan-Netzwerke erfordern den Root-Modus.
Ports unter 1024: Rootlose Container können standardmäßig keine Host-Ports unter 1024 binden. Konfigurieren Sie net.ipv4.ip_unprivileged_port_start=80 oder verwenden Sie einen Reverse-Proxy.
docker.sock-Kompatibilität: Tools wie Portainer benötigen den Docker-Socket. Podman stellt einen kompatiblen Socket über podman system service bereit. Starten Sie mit systemctl --user start podman.socket.
SELinux-Verweigerungen: Wenn ein Volume-Mount auf RHEL/Fedora fehlschlägt, fügen Sie das :Z-Label hinzu. Deaktivieren Sie SELinux niemals.
Fehlerbehebung
“short-name resolution”-Fehler: Podman erfordert vollständig qualifizierte Image-Namen. Fügen Sie unqualified-search-registries = ["docker.io"] zu /etc/containers/registries.conf hinzu.
“newuidmap/newgidmap not found”: Installieren Sie das uidmap-Paket (sudo apt install uidmap).
Container erreicht das Internet nicht: Installieren Sie slirp4netns (sudo apt install slirp4netns) oder passt auf Ubuntu 24.04 (sudo apt install passt).
Zusammenfassung
- Podman ist eine daemonlose, standardmäßig rootlose Container-Engine, die OCI-kompatibel und ein Drop-in für die Docker CLI ist
- podman-compose unterstützt Compose Spec v2/v3 und führt Multi-Service-Stacks ohne Root-Rechte aus
- Konfigurieren Sie
/etc/subuidund/etc/subgidfür rootlose UID-Zuordnung vor dem Ausführen von Multi-Container-Workloads - Verwenden Sie immer vollständig qualifizierte Image-Referenzen und fügen Sie
:Z-Volume-Labels auf SELinux-Systemen hinzu - Quadlet bietet native systemd-Integration für automatischen Start und Journal-Protokollierung containerisierter Dienste
- Für Produktions-Workloads bevorzugen Sie Quadlet gegenüber
podman generate systemdfür deklarative, wartbare Dienstdefinitionen