First live end-to-end install on real Unraid hardware (all 8 built
packages installed via upgradepkg, rc.podman started, containers
pulled/run/networked/port-mapped) — surfaced five genuine bugs no
amount of container-based CI testing could have caught, since none of
them exist inside the vbatts/slackware:15.0 build container:
1. rc.podman never created $PODMAN_LOG_DIR before redirecting the
podman system service's output into it, so the service failed to
even start ("No such file or directory"). Added it alongside the
existing PODMAN_RUN_DIR mkdir.
2. config/storage.conf hardcoded a [storage] table, and
podman-config.sh's `sync` step appended a second one at boot with
the real graphroot/runroot — TOML forbids defining the same table
twice. Removed the template's [storage] entirely; sync already
generates the whole thing.
3. config/policy.json had a "_comment" pseudo-field for
documentation, but containers/image's policy parser rejects any
unknown top-level key outright. JSON has no comment syntax; moved
the rationale into docs/ARCHITECTURE.md instead.
4. netavark >= 2.0 dropped its iptables firewall driver entirely
(verified: passing "iptables" is flatly rejected) — nftables or
firewalld are the only remaining options, and firewalld needs
systemd/dbus, which Unraid has neither of. Set firewall_driver =
"nftables" explicitly and documented that Unraid OS doesn't ship
the `nft` binary this needs (a slackware64 nftables package works;
not yet wired into the build/install pipeline — see follow-up).
5. Every container failed with "crun: pivot_root: Invalid argument".
Root cause: Unraid's / is permanently the kernel's initial "rootfs"
pseudo-filesystem (Unraid never pivots to a real one at boot — the
whole OS runs from RAM), and pivot_root(2) unconditionally rejects
that as the old root. This is not new: Docker/runc hits the exact
same kernel restriction on this exact host and silently falls back
to an MS_MOVE-based chroot; crun has no such fallback, only a
--no-pivot flag with no config-file equivalent. Added
plugin/sbin/crun-no-pivot.sh, a thin wrapper that scans crun's full
argument list (podman puts global flags before the subcommand, so
the subcommand isn't reliably $1) and injects --no-pivot right
after create/run, and pointed containers.conf's crun runtime at it.
Also fixed the podman.plg postinstall's chmod glob
(`podman-*.sh` -> `*.sh`), which would have skipped this new
non-podman-prefixed sbin script.
Verified end-to-end on the real host: pull, run, real network
connectivity (wget through the container's bridge), and a published
port actually serving HTTP (curl through -p 8099:80 to nginx) all
work. --no-pivot's security tradeoff (disabling one particular
container-escape mitigation) was explicitly discussed with and
approved by the user before committing, given it must be the default
for any container to start at all on this platform.
Follow-up not yet done: nftables (needed for #4) is not yet a
packages/ component in the reproducible build pipeline — it was only
installed manually on the test host for this verification run.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
38 KiB
unraid-podman — Architekturplanung
Natives Unraid-Plugin zur vollständigen Integration von Podman (rootful, Phase 1) als gleichberechtigte Alternative zu Docker, mit dem langfristigen Ziel, Docker optional abschaltbar zu machen.
Status: Planungsdokument, kein Code. Dient als Grundlage für Implementierungs-Tickets.
0. Ziele & Nicht-Ziele
Ziele (Phase 1 / MVP):
- Podman rootful lauffähig unter Unraid, überlebt Reboots (Config, Images, Container, Volumes, Netzwerke).
- Koexistenz mit Docker ohne Konflikte (Storage, Netzwerk, Ports, iptables-Ketten).
- Start/Stop/Autostart analog zum bestehenden
rc.docker-Muster, ohne systemd. - Sauberer Update-/Rollback-Pfad für das Plugin selbst.
- Grundlegendes Logging & Fehlerdiagnose, das GUI-Meldungen von Unraid nutzt.
- Vorbereitung (nicht Umsetzung) einer WebUI-Anbindung.
Nicht-Ziele (bewusst verschoben):
- Rootless Podman (Phase 2+, andere Storage-/UID-Mapping-Anforderungen).
- Podman Pods / Kubernetes-YAML-Support (Phase 3, siehe Roadmap).
- 1:1-Ersatz der Community-Applications-Vorlagen (erfordert eigenen Übersetzungslayer, separat geplant).
- Abschalten von Docker (erst wenn Podman-Pfad stabil ist, siehe Abschnitt 17).
1. Rahmenbedingungen von Unraid, die die Architektur erzwingen
| Eigenschaft | Konsequenz für das Plugin |
|---|---|
Unraid läuft komplett im RAM (SquashFS + tmpfs-Overlay via unionfs) |
Alles, was /, /etc, /usr, /var betrifft, ist bei jedem Reboot verloren. Nichts darf implizit dort persistiert werden. |
Persistenter Speicher nur unter /boot (USB-Stick, FAT32, klein, langsam, schreibintensiv riskant) und /mnt/* (Array/Cache/Pools) |
Konfiguration klein & textbasiert auf /boot/config/plugins/...; große/volatile Daten (Images, Container-Storage, Logs) auf Array/Cache. |
Kein systemd, sondern BSD-artige /etc/rc.d/rc.*-Skripte, angestoßen über /boot/config/go |
Eigenes rc.podman-Init-Skript im klassischen `start |
Slackware-Basis, Pakete als .txz (pkgtools: installpkg/upgradepkg/removepkg) |
Podman + Abhängigkeiten müssen als Slackware-kompatible .txz gebaut werden, nicht als RPM/DEB. |
Plugins werden über .plg-XML installiert (lädt Pakete, führt <FILE>-Blöcke mit Pre-/Post-Scripts aus) |
Das .plg ist der zentrale Installations-/Update-/Deinstallations-Mechanismus, vergleichbar mit einem deklarativen Installer. |
/mnt/user (shfs/FUSE) hat Einschränkungen für Overlay-Filesysteme (fehlendes d_type in manchen Konstellationen, FUSE-Overhead) |
Podman-Storage (overlay-Driver) nicht direkt auf /mnt/user/... legen, sondern auf ein dediziertes Loopback-Image oder einen direkt gemounteten Pool/Disk-Pfad (Analogie zu docker.img bzw. Docker-„Directory“-Modus seit 6.12). |
Array kann offline sein / erst spät im Boot verfügbar (emhttpd, Array-Start ist ein User-Trigger, kein automatischer Boot-Schritt) |
rc.podman darf nicht blind beim Boot starten, sondern muss auf Array-/Pool-Verfügbarkeit warten bzw. vom dynamix-Event „array started“ getriggert werden, wie es rc.docker heute schon tut. |
Unraid pflegt eigene Firewall-/NAT-Logik (iptables) für Docker-Netzwerke (docker0, custom bridges, macvlan) |
Podman-Netzwerke (netavark) müssen eigene, klar abgegrenzte iptables-Ketten/Chains verwenden, um nicht mit Dockers Regeln zu kollidieren. |
2. Gesamtarchitektur (Überblick)
┌───────────────────────────────────────────┐
│ /boot (USB, FAT32) │
│ config/plugins/podman/ │
│ ├─ podman.cfg (Settings) │
│ ├─ autostart (Flat-File) │
│ ├─ network.json │
│ ├─ containers.conf / storage.conf (Vorlagen)
│ └─ backup/ (vorherige Paketversionen) │
└───────────────────┬─────────────────────────┘
│ beim Boot kopiert nach /etc, /var/lib
▼
┌────────────────────────────────────────────────────────────────────┐
│ RAM-Root (tmpfs/unionfs) │
│ /etc/rc.d/rc.podman (Init-Skript) │
│ /etc/containers/* (aus /boot kopiert) │
│ /usr/bin/podman, conmon, crun, netavark, aardvark-dns, ... │
│ /usr/local/emhttp/plugins/podman/ (WebUI-Stub, PHP) │
└───────────────────────────┬───────────────────────────────────────┘
│ bind-mount / Storage-Root zeigt auf
▼
┌────────────────────────────────────────────────────────────────────┐
│ Persistenter Bereich (Cache-Pool empfohlen) │
│ /mnt/cache/system/podman/ │
│ ├─ podman.img (Loopback, XFS/BTRFS, für overlay-Storage) │
│ │ → gemountet auf /var/lib/containers/storage │
│ ├─ logs/ │
│ └─ networks/ (netavark state, falls nicht im Image) │
└────────────────────────────────────────────────────────────────────┘
Kernprinzip: Trennung von „Konfiguration“ (klein, Text, /boot) und „Nutzdaten“
(groß, binär, Array/Cache) — exakt das bestehende Unraid-Muster, das auch
dynamix.docker.manager verwendet.
3. Pluginstruktur
3.1 Repository-Layout (Build-/Source-Repo, nicht das, was auf Unraid landet)
unraid-podman/
├── podman.plg # Haupt-Plugin-Manifest (XML)
├── packages/ # Slackware .txz Build-Rezepte
│ ├── podman/
│ ├── conmon/
│ ├── crun/
│ ├── netavark/
│ ├── aardvark-dns/
│ ├── containers-common/
│ ├── fuse-overlayfs/
│ └── passt/
├── source/
│ ├── rc.podman # Init-Skript
│ ├── podman-preflight.sh # Startup-Checks
│ ├── podman-autostart.sh
│ ├── podman-backup.sh
│ └── config-templates/
│ ├── containers.conf
│ ├── storage.conf
│ └── registries.conf
├── emhttp/
│ └── plugins/podman/ # WebUI (PHP/JS), Phase 2+
├── scripts/
│ ├── build-packages.sh
│ └── release.sh
└── CHANGELOG.md
3.2 .plg-Manifest — Verantwortlichkeiten
Das .plg ist eine deklarative XML-Datei, die von Unraids plugin-Kommando
interpretiert wird. Verantwortlich für:
- Metadaten:
<plugin name="podman" version="..." pluginURL="..." min="..." />inkl. Mindest-Unraid-Version (Kernel-/glibc-Kompatibilität der Podman-Binaries). - Entity-Variablen (XML-Entities) für Basis-URL, Version, MD5-Summen — ermöglicht Update-Checks über den Plugin-Manager der GUI.
<FILE>-Blöcke:- Download & Installation aller acht
.txz-Pakete (die sieben Komponenten plus das plugin-eigeneunraid-podman-Scaffolding-Paket) einheitlich perupgradepkg --install-new --reinstall— funktioniert unverändert für Erstinstallation und Update (bestätigtes Muster echter Unraid-Plugins, siehe unten). <INLINE>-Postinstall-Skript: Setzen von Berechtigungen, Anlegen der Verzeichnisstruktur unter/boot/config/plugins/podman/(nur beim ersten Install, idempotent; Configs nur kopiert, wenn nicht vorhanden — kein Überschreiben bestehender Nutzerkonfiguration bei Updates), Schreiben der Versions-Manifest-Datei, ersterrc.podman start.
- Download & Installation aller acht
- Array-Start/Stop-Hook: kein Eintrag in
/boot/config/go. Stattdessen der offizielle Unraid-Plugin-Event-Mechanismus:/usr/local/emhttp/plugins/podman/event/disks_mounted(startetrc.podman, sobald Cache-Pools/Disks gemountet sind) und.../event/stopping(stopptrc.podmansynchron als allererster Schritt der Shutdown-Sequenz, bevor Unraid die zugrundeliegende Disk unmountet). Dieses Verzeichnis-Konvention wurde gegen den echten Quellcode etablierter Plugins verifiziert (u. a.unassigned.devices, das exakt dieselbenevent/-Hooks fürdisks_mounted/stopping_svcsverwendet) — kein/boot/config/go-Edit nötig, dadurch auch beim Deinstallieren nichts manuell rückgängig zu machen. <FILE Run="/bin/bash" Method="remove">-Block für Deinstallation: ruft zuerstpodman-uninstall-cleanup.shauf (stopptrc.podman, räumt Laufzeitzustand auf), dannremovepkgfür alle acht Pakete. Lässt Nutzdaten unter/mnt/*und/boot/config/plugins/podman/standardmäßig stehen (explizite Option „Restlose Deinstallation inkl. Daten“ via--purge-data-Flag, kein automatisches Löschen von Nutzdaten).
3.3 Namens- und Versionskonventionen
- Plugin-Name:
podman(Namespace-Kollisionen mit CA-Plugins prüfen). - Paket-Versionierung getrennt von Plugin-Versionierung:
podman.plgträgt eine eigene SemVer (1.2.0), referenziert aber exakte Upstream-Versionen der Binärpakete (podman-5.x.x,netavark-1.x.x, ...) — erlaubt Plugin-Patches (z. B. am Init-Skript) ohne Podman-Versionssprung.
4. Verzeichnislayout (vollständig)
4.1 Auf dem Flash-Device (/boot, persistent, klein)
/boot/config/plugins/podman/
├── podman.cfg # Key=Value, analog docker.cfg (Storage-Pfad, Enable, Optionen)
├── autostart # eine Container-ID/-Name pro Zeile, Reihenfolge = Startreihenfolge
├── autostart-delay # optionale Wartezeiten pro Container (Key=Sekunden)
├── containers.conf # Vorlage, wird nach /etc/containers/ kopiert
├── storage.conf # Vorlage, referenziert podman.img-Pfad
├── registries.conf
├── policy.json
├── networks/ # persistierte netavark-Netzwerkdefinitionen (JSON)
├── backup/
│ ├── packages/<version>/*.txz # vorherige Paketversionen für Rollback
│ └── config/<timestamp>/ # Config-Snapshots vor Updates
└── plugin.log # Install-/Update-Log des Plugins selbst
/boot/config/plugins/podman/ ist bewusst analog zu
/boot/config/plugins/dynamix.docker.manager/ gehalten (Wiedererkennung für
erfahrene Unraid-Nutzer, Support-Vergleichbarkeit).
4.2 Laufzeit (RAM-Root, bei jedem Boot neu aufgebaut)
/etc/rc.d/rc.podman # Init-Skript (Symlink-Ziel oder direkt kopiert)
/etc/containers/{containers,storage,registries}.conf # aus /boot kopiert
/etc/containers/policy.json
/etc/cni/ (falls CNI-Fallback statt netavark benötigt)
/usr/bin/{podman,conmon,crun,fuse-overlayfs,passt,pasta}
/usr/libexec/podman/{netavark,aardvark-dns} # matches upstream's own layout
/usr/local/emhttp/plugins/podman/ # WebUI-Stub (statisch aus Paket)
/var/run/podman/podman.sock # API-Socket (rootful)
/var/log/podman -> /mnt/cache/system/podman/logs # Symlink, siehe Abschnitt 13
4.3 Persistente Nutzdaten (Cache-Pool bevorzugt, Array als Fallback)
/mnt/cache/system/podman/ # analog /mnt/user/system/docker/
├── podman.img # Loopback-Datei, XFS (ftype=1) oder BTRFS
│ # → gemountet auf /var/lib/containers/storage
├── logs/
│ ├── containers/<id>.log
│ └── podman-service.log
└── networks/ # falls netavark-State nicht im Image liegt
Warum Cache-Pool statt /mnt/user: Der overlay-Storage-Driver benötigt native
Dateisystemsemantik (d_type, xattrs, Hardlinks) ohne den FUSE-Layer von shfs. Das
Docker-Vorbild löst das identisch mit docker.img/Directory-Modus auf einem echten
Mountpoint. Nutzer ohne Cache-Pool müssen einen Array-Disk-Pfad (/mnt/diskX/system/podman)
wählen können — mit deutlicher GUI-Warnung bzgl. Performance und Spin-up-Verhalten.
5. Paketmanagement
5.1 Zu paketierende Komponenten
| Paket | Zweck | Bemerkung |
|---|---|---|
podman |
Kern-Binary | Statisch gegen möglichst wenige glibc-Versionen bauen oder gegen Unraid-Slackware-Base kompilieren |
conmon |
Container-Monitor-Prozess | Pflicht |
crun (empfohlen) / runc |
OCI-Runtime | crun bevorzugt (leichter, cgroup v2-freundlich, kompatibel zu Unraids Kernel-Config) |
netavark + aardvark-dns |
Netzwerk-Backend + DNS | Ersetzt CNI-Plugins als Default seit Podman 4.x |
containers-common |
Default-Configs (containers.conf, seccomp.json, registries.conf) |
Wird als Vorlage übernommen, nicht als aktive Config |
fuse-overlayfs |
Fallback-Storage-Driver | Für Rootless-Phase 2 vorbereitet, in Phase 1 optional |
passt/pasta |
Rootless-Networking | Nachfolger von slirp4netns, Phase 2, aber Paket schon mitbauen (geringe Kosten) |
catatonit oder tini |
Init-Prozess in Containern (optional, falls von Templates genutzt) |
5.2 Build-Strategie
- Eigene Build-Pipeline (containerisiert, z. B. in einem Slackware-kompatiblen Build-Container) statt manuellem Cross-Compile auf laufenden Unraid-Systemen.
- Zielarchitektur:
x86_64(Unraid unterstützt aktuell keine anderen Architekturen produktiv) — vereinfacht Matrix erheblich. - Statisch oder minimal dynamisch gelinkt (Go-Binaries von Podman/netavark/aardvark-dns sind ohnehin größtenteils statisch), um Abhängigkeits-Drift gegenüber der jeweils aktuellen Unraid-Slackware-Basis zu minimieren.
- Jedes Paket als eigenständiges
.txzmit Slackware-Standard-Metadaten (slack-desc,doinst.sh), damitremovepkg/upgradepkgkorrekt funktionieren. - Versions-Pinning: Das
.plgreferenziert exakte Paketversionen + MD5, kein „latest“-Pull zur Laufzeit — reproduzierbare Installationen, Voraussetzung für Rollback.
5.3 Abhängigkeitsprüfung
- Preflight-Check im
.plg-Postinstall: Kernel-Version,cgroup v2aktiv, vorhandeneiptables/nftables-Binaries, freier Platz auf Zielpfad fürpodman.img. Bei Nichterfüllung: Installation abbrechen mit klarer GUI-Meldung statt eines halb-funktionsfähigen Zustands.
6. Start-/Stop-Skripte
6.1 rc.podman — Design analog zu rc.docker
Klassisches Slackware-BSD-Init-Skript mit Case-Dispatch:
rc.podman start # Preflight → Storage mounten → API-Service starten → Autostart-Liste abarbeiten
rc.podman stop # Container geordnet stoppen (Timeout) → API-Service stoppen → Storage unmounten
rc.podman restart
rc.podman status # Health-Check-Ausgabe für GUI/CLI
Kernschritte von start (konzeptionell, kein Code):
- Preflight (
podman-preflight.sh): prüft, ob konfigurierter Storage-Pfad (Cache-Pool/Disk) gemountet ist; fallspodman.imgfehlt → anlegen (Erstinstallation) mit konfigurierter Größe; falls vorhanden → per Loopback mounten. - Config-Sync: Kopiert
/boot/config/plugins/podman/*.confnach/etc/containers/(Boot-Config ist „Source of Truth“, Laufzeit-Kopie ist Cache). - Socket-Service starten:
podman system serviceim Hintergrund (rootful Unix-Socket unter/var/run/podman/podman.sock), damit spätere WebUI/API-Konsumenten und CLI dieselbe Instanz sehen (statt pro Aufruf neuer Podman-Fork-Prozesse ohne gemeinsamen State — State liegt zwar in/var/lib/containers, ein Service vereinfacht aber Health-Checks, Event-Streaming und spätere WebUI-Anbindung). - Netzwerke wiederherstellen: netavark-Netzwerkdefinitionen aus
/boot/config/plugins/podman/networks/nach/etc/containers/networks/synchronisieren. - Autostart (
podman-autostart.sh, siehe Abschnitt 10). - Statusdatei schreiben (für GUI-Polling), Event ins Unraid-Log (
logger).
stop in umgekehrter Reihenfolge, mit konfigurierbarem Stop-Timeout pro Container
(analog Dockers „Stop timeout“-Einstellung), danach podman system service beenden,
zuletzt Loopback-Storage sauber unmounten (verhindert Dateisystemfehler im podman.img).
6.2 Boot-Integration
-
Offizieller Unraid-Plugin-Event-Mechanismus, kein
/boot/config/go-Edit: Unraidsemhttpdführt bei jedem Array-/Boot-Event automatisch jedes ausführbare Skript unter/usr/local/emhttp/plugins/<name>/event/<eventname>aus, sofern vorhanden. Dieses Verhalten wurde gegen den echten Quellcode etablierter Plugins verifiziert (unassigned.devicesnutzt exakt dieselbe Konvention für seinedisks_mounted/started/stopping_svcs-Hooks). unraid-podman nutzt zwei Events:event/disks_mounted— feuert, sobald Array-Disks und Cache-Pools gemountet sind (Unraids Event-Reihenfolge:starting→array_started→disks_mounted→svcs_restarted→docker_started→libvirt_started→started). Ruftrc.podman startim Hintergrund auf (& disown), damit der Array-Start nicht blockiert.event/stopping— der erste Schritt der Shutdown-Sequenz (vorstopping_docker,stopping_svcs,unmounting_disks,stopping_array). Ruftrc.podman stopsynchron auf, damit Container gestoppt undpodman.imgsauber unmountet sind, bevor Unraid die zugrundeliegende Disk/den Cache-Pool unmountet.
Dadurch kein Start vor Verfügbarkeit von Cache/Array, und beim Deinstallieren ist nichts manuell rückgängig zu machen — die Hook-Skripte verschwinden automatisch mit
removepkgdesunraid-podman-Pakets (siehe Abschnitt 3.2).
7. Persistenz-Strategie (Zusammenfassung der Prinzipien)
| Datenkategorie | Ablageort | Synchronisationsrichtung |
|---|---|---|
| Plugin-Settings (Storage-Pfad, Feature-Flags) | /boot/config/plugins/podman/podman.cfg |
Boot → Laufzeit (read-only Kopie) |
| Container-/Netzwerk-/Registry-Config | /boot/config/plugins/podman/*.conf |
Boot → Laufzeit bei jedem Start |
| Autostart-Liste & Reihenfolge | /boot/config/plugins/podman/autostart |
Boot → Laufzeit; GUI schreibt zurück nach /boot |
| Images, Container, named Volumes, Layer-Cache | podman.img auf Cache-Pool |
Laufzeit-only, Backup optional via Snapshot |
| Logs | Cache-Pool logs/ |
Laufzeit-only, Rotation |
| Netzwerk-Definitionen (netavark JSON) | Boot-Kopie + Laufzeit-Kopie | bidirektional bei Änderung über GUI/CLI (Watcher oder expliziter „Apply“-Schritt) |
Grundregel: Jede Änderung, die ein Nutzer über CLI/GUI an persistenzrelevanten
Objekten vornimmt (neues Netzwerk, geänderte Autostart-Reihenfolge), muss explizit
oder per Watcher nach /boot/config/plugins/podman/ zurückgeschrieben werden —
sonst geht sie beim nächsten Reboot verloren. Das ist der Kernunterschied zu
Standard-Linux-Distributionen und der häufigste Fehlerquell-Kandidat bei Docker-artigen
Unraid-Plugins.
8. Netzwerke
- Backend:
netavark+aardvark-dns(Podman-Default seit 4.x), kein CNI in Phase 1. - Firewall-Treiber:
netavark>= 2.0 hat seineniptables-Treiber ersatzlos entfernt — nur nochnftablesoderfirewalld(Letzteres braucht systemd/dbus, hat Unraid nicht).nftablesist also zwingend, aber Unraid OS bringt dasnft-Binary selbst nicht mit (nur das ältereiptables/iptables-nft) — muss vom Plugin bereitgestellt werden (verifiziert per Live-Test:podman runmit Port-Publishing scheitert ohnenftmit „Must provide a valid firewall backend“). - Default-Bridge: eigene Bridge
podman0(nichtdocker0), eigener privater Adressraum (konfigurierbar, Default-Vorschlag außerhalb von Dockers Default-Range, um Kollisionen bei Parallelbetrieb zu vermeiden). - Custom Networks: analog Docker-für-Unraid „Custom Networks“-Feature — GUI-Verwaltung in Phase 2, Config-Persistenz-Mechanismus aber bereits in Phase 1 vorsehen (Abschnitt 7).
- macvlan/ipvlan: gleiche Kernel-Voraussetzungen wie bei Docker; bekannte Unraid-Falle „macvlan call trap“ (Kernel-Panic bei bestimmten NIC-Treibern) muss dokumentiert und im Preflight als Warnung ausgegeben werden, wenn macvlan-Netzwerke angelegt werden.
- iptables/nftables-Koexistenz mit Docker: netavark legt eigene Chains an
(
NETAVARK-*Präfix); explizit verifizieren, dass diese nicht mit DockersDOCKER-Chains oder Unraids eigenen Firewall-Regeln interferieren. Firewall-Reload durch Docker (bei dessen Start/Stop) darf Podman-Regeln nicht löschen und umgekehrt — ggf. eigenesiptables-restore-Hook nach jedemrc.podman start. - DNS:
aardvark-dnsfür Container-zu-Container-Namensauflösung innerhalb benutzerdefinierter Netzwerke, analog Dockers eingebettetem DNS-Server. - Port-Publishing: Kollisionsprüfung mit bereits von Docker/anderen Diensten
belegten Ports als GUI-seitige Validierung (spätere Phase), technisch bereits
durch Kernel/
iptablesohnehin erzwungen.
9. Volumes
- Named Volumes: liegen innerhalb von
podman.imgunter.../storage/volumes/, damit sie vom selben Backup-/Rollback-Mechanismus wie Images erfasst werden. - Bind-Mounts auf Unraid-Shares (
/mnt/user/appdata/...): empfohlener Standardweg für Nutzerdaten (analog Dockers „Path“-Mappings in Community-Applications-Templates), da/mnt/user/appdatabereits vom Nutzer im Backup-/Mover-/Cache-Konzept berücksichtigt wird. Bind-Mounts direkt gegen/mnt/user(FUSE) sind für Applikationsdaten unkritisch (kein Overlay-Storage-Anspruch), nur der Storage-Graph selbst braucht den echten Mount. - Permissions/UID-Mapping: Phase 1 rootful → Container laufen mit denselben UID/GID-Semantiken wie Docker rootful heute; keine zusätzliche User-Namespace-Remapping- Komplexität. Wird in Phase 2 (rootless) relevant.
- Migration-Hilfe (spätere Phase, nicht MVP): Werkzeug zum Referenzieren bestehender Docker-Bind-Mount-Pfade beim Anlegen äquivalenter Podman-Container, um Parallelbetrieb mit denselben Appdata-Verzeichnissen zu erleichtern (mit klarer Warnung vor gleichzeitigem Schreibzugriff durch zwei Runtimes).
10. Images
- Storage-Driver:
overlay(native, keinfuse-overlayfs) auf dem gemountetenpodman.img— Performance-Parität mit Dockers Standard-Setup. - Registries: Default
registries.confmit Docker Hub + ggf.ghcr.io,quay.iovorkonfiguriert, kurz-Namen-Auflösung (unqualified-search-registries) explizit gesetzt statt interaktivem Prompt (der in einer daemonless/Skript-Umgebung nicht funktioniert). - Pull/Push: Standard-Podman-CLI-Semantik, keine Besonderheiten; Fortschrittsanzeige später über API-Service-Events für die WebUI nutzbar.
- Image-Größenmanagement:
podman.imgist eine feste/dynamisch wachsende Loopback-Datei — GUI muss Füllstand anzeigen und Vergrößern anbieten (analog Dockers „docker.img full“-Problem, das in der Community bekannt und schmerzhaft ist; hier von Anfang an mit klarer Fehlermeldung statt stillem Fehlschlag lösen, siehe Abschnitt 16). - Community-Applications-Kompatibilität: kein automatischer Import von Docker-Templates in Phase 1 (eigenes, separates Vorhaben); Podman-Images werden zunächst über CLI/eigene, minimale Template-Definition verwaltet.
- Signatur-Policy (
config/policy.json):insecureAcceptAnythingals Default — akzeptiert Images ohne Signaturprüfung, entspricht Dockers heutigem Standard-Vertrauensmodell auf Unraid. Vor einem 1.0-Release erneut bewerten, falls signierte Images ein Ziel werden. Die Datei selbst darf keine Kommentarfelder enthalten (containers/images Policy-Parser lehnt unbekannte Top-Level-Keys wie_commentstrikt ab) — Begründung lebt deshalb hier, nicht in der Datei.
11. Container (Lifecycle-Management)
- Lifecycle-Operationen (
create,start,stop,restart,remove,exec,logs,inspect) laufen über den in Abschnitt 6.1 gestarteten Podman-API-Service, nicht über Ad-hoc-CLI-Aufrufe aus der GUI heraus — ein gemeinsamer Service reduziert Race Conditions und ermöglicht Event-Streaming. - Labels für GUI-Integration: eigenes Label-Schema (z. B.
net.unraid.podman.icon,net.unraid.podman.webui), angelehnt an, aber getrennt von Dockersnet.unraid.docker.*-Konventionen, um spätere GUI-Icons/WebUI-Links analog zur Docker-Tab-Darstellung zu ermöglichen, ohne Namensraum-Kollisionen. - Update-Strategie für Container-Images: „Check for Updates“-Mechanismus
(Digest-Vergleich gegen Registry) als spätere GUI-Funktion, technisch schon in
Phase 1 per
podman image inspect/skopeo-Vergleich vorbereitbar.
12. Autostart
Da kein systemd existiert, wird Autostart explizit vom Plugin verwaltet, nicht von Podman selbst (Podman hat kein natives „restart on boot“ ohne generierte Unit-Files):
- Flache Datei
/boot/config/plugins/podman/autostart, eine Zeile pro Container (Name oder ID), Reihenfolge = Zeilen-Reihenfolge = Startreihenfolge — direktes Äquivalent zu Dockers/boot/config/plugins/dynamix.docker.manager/docker-autostartbzw. der DB-gestützten Nachfolgelösung. - Optionale, separate Delay-Datei für Wartezeiten zwischen Starts (Abhängigkeiten zwischen Containern, z. B. DB vor App).
rc.podman startliest die Liste sequenziell, startet jeden Container über den API-Service, protokolliert Erfolg/Fehler pro Eintrag, bricht bei Einzelfehlern nicht die gesamte Kette ab (ein defekter Container darf nicht alle anderen blockieren).- GUI-Checkbox „Autostart“ pro Container (spätere Phase) schreibt direkt in diese Datei zurück — kein separates DB-Layer in Phase 1, um Komplexität niedrig zu halten (kann bei Bedarf später durch strukturierteres Format, z. B. JSON, ersetzt werden).
13. Updates
13.1 Plugin-Update (Podman-Version, Init-Skripte)
- Über den regulären Unraid-Plugin-Update-Mechanismus:
.plgmit neuer Version + neuen Paket-URLs/MD5s wird erneut ausgeführt. - Vor jedem Update: automatisches Backup (siehe Abschnitt 14) der aktuellen
.txz-Pakete und Config-Dateien. - Container laufen während des Plugin-Updates weiter, sofern nur Binaries
ausgetauscht werden (laufende
conmon/Container-Prozesse sind vom Dateisystem-Austausch unter/usr/binisoliert, solange der Prozess nicht neu exec't wird) — erst ein nachfolgenderrc.podman restartübernimmt die neue Podman-Version für den API-Service. Klar kommunizieren: Update ≠ sofortiger Container-Neustart. - Config-Migrationen (z. B. neues Feld in
containers.conf) über ein Versions-gestempeltes Migrationsskript, das beim Postinstall geprüft wird (podman.cfgenthältCONFIG_SCHEMA_VERSION).
13.2 Container-Image-Updates
- Getrennt vom Plugin-Update zu betrachten — reine Podman-Funktionalität
(
podman pull+ Recreate), GUI-Komfortfunktion für Phase 2.
14. Rollback
- Paket-Rollback: Vor jedem Update werden die aktuell installierten
.txznach/boot/config/plugins/podman/backup/packages/<alte-version>/kopiert. Ein „Rollback“-Kommando (Postinstall-Skript, später GUI-Button) installiert diese Pakete erneut perupgradepkg --reinstall. - Config-Rollback: Vor jeder strukturellen Config-Änderung (Plugin-Update mit
Schema-Migration) wird ein Snapshot nach
/boot/config/plugins/podman/backup/config/<timestamp>/geschrieben; Rollback kopiert diesen Snapshot zurück und setztCONFIG_SCHEMA_VERSIONentsprechend zurück. - Storage-Rollback (Images/Container) ist explizit außerhalb des automatischen
Rollbacks:
podman.imgwird nicht bei jedem Plugin-Update gesichert (zu groß, zu I/O-intensiv). Stattdessen: dokumentierte, manuell auslösbare Snapshot-Funktion (z. B.cp --reflinkauf BTRFS/ZFS-Cache-Pools, wo Reflinks verfügbar sind) als optionales Feature, kein Zwang. - Rollback-Historie begrenzen (z. B. letzte 3 Versionen), um den knappen Flash-Speicher nicht zu erschöpfen.
15. Logging
- Problem:
/var/logliegt im RAM und ist bei Reboot weg;journaldexistiert nicht, daher kann Podmansjournald-Log-Driver nicht Default sein. - Lösung: Default-Log-Driver
k8s-file(JSON-per-Zeile, Podman-nativ) mit Zielverzeichnis unter/mnt/cache/system/podman/logs/containers/, per Symlink von/var/log/podmandorthin erreichbar (einheitlicher Pfad für Tools, die/var/logerwarten, ohne RAM-Verlust). - Log-Rotation: eigener Cron-Eintrag (Unraid nutzt
cronbereits für andere Plugins über/boot/config/plugins/dynamix/-Muster bzw./etc/cron.d) mitlogrotate-Konfiguration oder einfachem Größen-/Alter-basiertem Skript, da Flash/Cache-Platz begrenzt ist. - Service-Log (
podman system service,rc.podman-Ausführung) getrennt von Container-Logs, ebenfalls auf Cache-Pool, zusätzlich Kurzfassung wichtiger Ereignisse (Start/Stop/Fehler) überloggerin Unraids zentrales Syslog, damit sie in der Standard-„System Log“-GUI sichtbar sind. - GUI-Zugriff (spätere Phase): Log-Viewer analog Dockers Container-Log-Fenster,
liest direkt aus den
k8s-file-Logs bzw. streamt über den API-Service.
16. Fehlerbehandlung
16.1 Startup-Robustheit
- Preflight-Checks vor jedem
rc.podman start(siehe 6.1): Storage-Mount, Speicherplatz aufpodman.img, Kernel-Voraussetzungen, Socket-Verfügbarkeit (kein verwaister Socket von vorherigem Absturz). - Storage-Korruption: Falls
podman.imgbeim Mount-Versuch Dateisystemfehler zeigt (xfs_repair/btrfs checkschlägt fehl oder wird nicht automatisch ausgeführt) → Start abbrechen, klare GUI-Fehlermeldung mit Handlungsempfehlung (Recovery-Tool ausführen, Backup einspielen), kein automatisches Neuanlegen/Formatieren ohne Nutzerbestätigung (Datenverlustrisiko). - Autostart-Fehler pro Container: einzelner fehlgeschlagener Container wird geloggt und übersprungen, blockiert nicht die restliche Kette (siehe Abschnitt 12); nach N gescheiterten Autostart-Versuchen in Folge wird der Container automatisch aus der Autostart-Kette pausiert („Safe-Mode“ pro Container) mit GUI-Hinweis, um Boot-Loops/Ressourcenverschwendung zu vermeiden.
16.2 Laufzeitfehler
- Health-Check des API-Service:
rc.podman statusprüft Socket-Erreichbarkeit und meldet Diskrepanzen (Prozess läuft, Socket tot o. ä.) verständlich. - Firewall-/Netzwerk-Konflikte: bei bekannten Fehlerbildern (z. B. Chain-Konflikt
mit Docker, Port bereits belegt) definierte, für Menschen lesbare Fehlermeldungen
statt roher
iptables/Go-Stacktraces — Fehlerkatalog mit Klartext-Ursache + nächstem Schritt. - Ressourcenerschöpfung (
podman.imgvoll): aktive Prüfung im Preflight und periodisch (Cron), GUI-Warnung bei > 85 % Füllstand, klare Anleitung zum Vergrößern des Loopback-Images (bekannte Docker-für-Unraid-Schwachstelle, hier von Anfang an proaktiv statt reaktiv lösen). - Unraid-Benachrichtigungssystem: kritische Fehler (Storage-Mount fehlgeschlagen,
Autostart-Kette größtenteils fehlgeschlagen,
podman.img> Schwellwert) werden über Unraids Standard-Notify-Mechanismus (/usr/local/emhttp/webGui/scripts/notify) ausgelöst, damit sie in GUI-Toasts, optional E-Mail/Pushover (falls vom Nutzer konfiguriert) erscheinen — kein Parallel-Notify-System erfinden.
17. Docker-Parallelbetrieb & spätere Deaktivierung
Phase 1 — Parallelbetrieb (Pflicht)
- Getrennte Storage-Roots (
docker.imgvs.podman.img), getrennte Default-Bridges, getrennte iptables-Chain-Präfixe, getrennte Log-Verzeichnisse — keine gemeinsam genutzten mutable Ressourcen außer read-only Kernel-Features (cgroups, netfilter). - Ressourcen-Konkurrenz (CPU/RAM/Disk-IO) ist erwartet und wird nicht technisch verhindert, aber in der GUI/Doku transparent gemacht.
- Beide Runtimes dürfen gleichzeitig laufen, ohne dass Start/Stop des einen den anderen beeinflusst (insbesondere Firewall-Reloads, siehe Abschnitt 8).
Phase 2+ — Docker optional deaktivierbar
- Neuer Schalter (z. B. in den bestehenden Docker-Settings oder einem neuen „Container Engine“-Auswahlbereich): „Docker aktiviert / Podman aktiviert / beide“.
- Deaktivierung von Docker bedeutet:
rc.docker stop+ Entfernen des Autostart-Hooks aus/boot/config/gofür Docker, kein Deinstallieren des Docker-Plugins selbst (reversibel, Datenerhalt). - Voraussetzung für diese Phase: Podman-Pfad muss funktional äquivalent zu den von Nutzern tatsächlich genutzten Docker-Features sein (mind. Custom Networks, Autostart, Log-Viewer, Update-Check) — technisch als Gate, nicht nur als Empfehlung, im Freigabeprozess verankern.
- CA-Kompatibilität (Community Applications erwartet aktuell Docker) ist der wahrscheinlich größte Blocker für „Docker komplett aus“ und sollte als eigenes Arbeitspaket (Template-Übersetzung Docker→Podman) vor Freigabe dieser Option behandelt werden.
18. Zukünftige WebUI
18.1 Architektur (Zielbild, Umsetzung nach MVP)
- Eigene GUI-Seite unter
/usr/local/emhttp/plugins/podman/, PHP + JS im bestehenden Unraid-„Dynamix“-Stil (Konsistenz mit restlicher GUI, wiederverwendbare CSS-/JS-Assets), analog zur Docker-Tab-Struktur (dynamix.docker.manager). - Backend-Kommunikation nicht über Shell-Exec von
podman-CLI-Aufrufen aus PHP (fragil, schwer zu parallelisieren), sondern über den in Abschnitt 6.1 laufenden Podman-API-Service (Unix-Socket, REST, Docker-kompatible Teilmenge der API) — ermöglicht später auch Wiederverwendung bestehender Docker-API-kompatibler Frontend-Bibliotheken. - Echtzeit-Updates (Container-Status, Logs) über Server-Sent Events oder Polling gegen den API-Service, kein WebSocket-Zwang in Phase 1 der WebUI (geringerer Implementierungsaufwand, ausreichend für Status-Refresh im Sekundenbereich).
18.2 Funktionsumfang, gestaffelt
- Stufe 1: Read-only Übersicht (laufende Container, Images, Netzwerke), Start/Stop/Restart einzelner Container.
- Stufe 2: Container-Erstellung über einfache Formulare (Image, Ports, Volumes, Env, Labels), Autostart-Verwaltung direkt in GUI (schreibt in Abschnitt-12-Datei).
- Stufe 3: Log-Viewer, Netzwerk-Verwaltung (Custom Networks/macvlan-Anlage), Update-Check pro Container.
- Stufe 4: Community-Applications-Anbindung/Template-Import (separates Vorhaben).
18.3 Sicherheitsaspekt der WebUI
- API-Service-Socket nur lokal (
/var/run/podman/podman.sock), keine TCP-Exposition nach außen ohne explizite, abgesicherte Opt-in-Konfiguration (TLS + Auth), da rootful Podman-API faktisch Root-Äquivalent ist — gleiche Vorsicht wie beim Docker-Socket.
19. Sicherheitsbetrachtungen (Phase 1, rootful)
- Rootful Podman-API-Socket ist funktional gleichwertig zu
docker.sockbzgl. Angriffsfläche (Zugriff = Root auf dem Host) — Berechtigungen auf den Socket (0660, Gruppe analogdocker-Gruppe, z. B. neue Gruppepodman) restriktiv setzen. Achtung Docker Sock: root Äquivalenz, daher keine ungeprüfte Gruppenmitgliedschaft für WebUI-Prozesse vergeben, die nicht ohnehin schon rootäquivalent laufen (emhttpdläuft unter Unraid ohnehin als root, insofern kein zusätzliches Risiko gegenüber Docker heute — aber explizit dokumentieren, nicht stillschweigend voraussetzen). - Keine automatische, ungefragte Netzwerk-Exposition von Container-Ports über die Standard-Bridge hinaus.
- Rollback-/Backup-Mechanismus darf keine Zugangsdaten (Registry-Logins in
auth.json) ungesichert auf dem FAT32-Flash ablegen, ohne dass sich der Nutzer dessen bewusst ist (Flash ist physisch leicht auslesbar) — ggf. Hinweis, sensible Registry-Credentials bevorzugt nicht dauerhaft dort zu speichern, oder Ablage ausschließlich auf dem Cache-Pool statt/boot.
20. Phasenplan
| Phase | Inhalt |
|---|---|
| MVP (Phase 1) | Plugin-Grundgerüst, Pakete, rc.podman, Storage auf Cache-Pool, Autostart-Datei, Basis-Logging, Preflight/Fehlerbehandlung, Rollback für Pakete/Config, keine WebUI (CLI-only, podman direkt nutzbar) |
| Phase 2 | WebUI Stufe 1–2, Custom-Networks-Verwaltung, Log-Viewer, Storage-Snapshot-Feature |
| Phase 3 | Rootless-Option, Docker-Deaktivierungs-Schalter, CA-Template-Kompatibilitätsschicht |
| Phase 4 | Pods/Quadlet-artige Konzepte (ohne systemd nur eingeschränkt sinnvoll — ggf. eigenes Skript-Äquivalent statt echter Quadlet/systemd-Generatoren) |
21. Offene Fragen / Risiken (zur Klärung vor Implementierungsstart)
- Ziel-Podman-Version und Update-Kadenz (Tracking von Upstream-CVEs erfordert Paket-Update-Prozess, nicht nur Erstrelease).
- Cache-Pool-Pflicht vs. Array-Fallback für
podman.img— Nutzer ohne Cache-Pool sind bei Docker heute ebenfalls im Nachteil; gleiche Community-Erwartungshaltung übernehmen oder verbessern? 2a. Verhalten bei mehreren Cache-Pools (Unraid 6.9+ unterstützt mehrere benannte Pools) — welchen Pool per Default vorschlagen, wie in GUI wählbar machen. podman system serviceals Dauerprozess vs. Socket-Activation-artiges On-Demand-Start (ohne systemd nur eingeschränkt nachbaubar) — Dauerprozess ist der pragmatischere Start, sollte aber gegen Ressourcenverbrauch im Idle evaluiert werden.- Genaues Verhalten bei gleichzeitigem Boot von Docker und Podman bzgl.
iptables-Reihenfolge/Locking (
iptables-Aufrufe sind nicht atomar über mehrere Prozesse hinweg) — ggf. Locking-Strategie (xtables_lock) explizit prüfen. - Lizenz-/Signatur-Anforderungen für Community-Verbreitung des Plugins
(Unraid-Plugin-Repository-Richtlinien, Signierung der
.plg/Pakete).