Die App
Podman
Diese Compose-Dateien und Container unter Podman statt Docker ausführen: der Unterschied zwischen podman compose und podman-compose sowie die Hinweise zum Rootless-Betrieb
Diese Seite wurde maschinell aus der englischen Dokumentation übersetzt.
Jeder Befehl für docker compose und docker run in dieser Dokumentation funktioniert auch mit Podman. Tausche docker gegen podman aus. Diese Seite dokumentiert die Namensfalle und Rootless-Unterschiede einmalig. Andere Dokumente verlinken direkt hierher, anstatt sie zu wiederholen.
podman compose ist nicht podman-compose
Dies sind zwei verschiedene Werkzeuge. Das falsche führt ohne Warnung eine weniger kompatible Implementierung aus.
podman compose(ein Leerzeichen) ist ein in Podman integrierter Unterbefehl. Es ist ein schlanker Wrapper. Er sucht einen externen Compose-Provider auf deiner Maschine, entwederdocker-composeoderpodman-compose, und übergibt den Befehl an ihn. Wenn dudocker-composeinstalliert hast, nutzt Podman dies zuerst. Es ist die ursprüngliche Implementierung der Compose-Spezifikation. Führepodman compose versionaus, um den Provider in einem Banner ausgegeben zu sehen.podman-compose(ein Bindestrich) ist eine separate, Python-basierte Implementierung der Compose-Spezifikation. Sie läuft eigenständig ohne Docker. Sie unterstützt weniger von der Spezifikation. Ihre Unterstützung fürdepends_on: condition: service_healthyist schwächer, und sie benennt Netzwerke standardmäßig anders.
Ohne Provider tut podman compose nichts. Eine saubere Ubuntu-24.04-Installation mit nur podman beantwortet jeden podman compose-Befehl mit Error: looking up compose provider failed. Installiere zuerst einen Provider:
sudo apt install podman podman-compose
podman compose version # names /usr/bin/podman-compose, version 1.0.6Auf dieser Maschine führen podman compose und podman-compose dasselbe Programm aus. Die Healthchecks in diesen Compose-Dateien funktionieren darunter. compose.yml und compose.core.yml meldeten healthy mit podman 4.9.3 und podman-compose 1.0.6, einschließlich des Wartens auf Postgres. Die Healthchecks verwenden aus diesem Grund eine einfache Shell-Zeile (wget -q -O /dev/null http://127.0.0.1:3000/...). Die ältere Syntax node -e "fetch(...)" kam bei podman-compose 1.0.6 als fehlerhafte Shell-Zeile an. podman ps meldete dann durchgehend unhealthy, während die App antwortete.
Jede Compose-Datei, die Postgres startet (compose.core.yml, compose.full.yml und das Quickstart compose.yml von openplate-core), verwendet depends_on: condition: service_healthy, um einen Dienst an den Postgres-Healthcheck zu binden. Wenn du einen anderen Provider nutzt, überprüfe, ob er diese Bedingung unterstützt.
Hinweise zum Rootless-Betrieb
Podman läuft standardmäßig rootless. Container laufen als dein eigener Benutzer, nicht als root. Das bietet bessere Sicherheit. Es bringt auch drei Unterschiede zu Docker mit sich, die man vor dem Self-Hosting kennen sollte.
SELinux-Volume-Labels. Auf einem Host mit aktivem SELinux, was auf Fedora Standard ist, kann ein Container ein per Bind-Mount eingebundenes Host-Verzeichnis ohne Container-Zugriffslabel weder lesen noch schreiben. Füge dem Mount :Z hinzu, wenn nur ein Container ihn nutzt. Füge :z hinzu, wenn mehrere Container ihn teilen, zum Beispiel -v ./pg-data:/var/lib/postgresql:Z. Keine der Compose-Dateien in diesen drei Repositories bindet ein Host-Verzeichnis per Bind-Mount ein. Alle verwenden benannte Volumes, die Podman automatisch labelt. Dieser Hinweis gilt nur, wenn du einen volumes:-Eintrag so bearbeitest, dass er einen Host-Pfad verwendet. Diese Änderung betrifft die Sync-Stufen 2 und 4 für Postgres sowie die Inferenz-Stufe 3 für Modellgewichte.
Ports unter 1024. Ein Rootless-Container kann einen Host-Port unter 1024 nicht ohne Berechtigung binden, etwa über sudo sysctl net.ipv4.ip_unprivileged_port_start=80. Keiner der Standardports in diesen Compose-Dateien (3000, 3001, 8300) benötigt dies. Dieses Problem tritt nur auf, wenn du einen Port auf 80 oder 443 umlegst, um einen Reverse Proxy zu umgehen. Da jede Stufe mindestens einen Port veröffentlicht, kann dies jede der 4 Stufen betreffen.
Rootless Postgres. Der Postgres-Container läuft als Nicht-Root-Benutzer. Dieser Benutzer muss Eigentümer seines Datenverzeichnisses sein. Ein benanntes Volume löst dies automatisch, was apps/core/docker/compose.yml, compose.core.yml und compose.full.yml bereits nutzen. Podman erstellt das benannte Volume mit den korrekten Eigentumsrechten. Wenn du zu einem per Bind-Mount eingebundenen Host-Verzeichnis wechselst, setze die Eigentumsrechte vom Host aus zuerst mit podman unshare chown -R 70:70 ./pg-data. Die Benutzer-ID 70 entspricht dem Benutzer postgres im festgepinnten Image postgres:18-alpine; Debian-Images nutzen 999. Ohne diesen Schritt schlägt der Container beim Start mit einem Berechtigungsfehler fehl. Dies betrifft die Stufen 2 und 4.
Quadlet-Units
Quadlet nutzt weder podman compose noch podman-compose: systemd startet jeden Container mit podman selbst. Wenn du nur Quadlet möchtest, überspringe die obige Provider-Installation.
Jede obige Compose-Datei wird auch als Rootless-systemd-Units ausgeliefert. Sie werden von scripts/quadlet.sh generiert und in docker/quadlet/ gespeichert. Ein Unit-Satz bleibt über Neustarts hinweg unter systemctl --user ohne aktiven Compose-Prozess erhalten. Jedes Verzeichnis enthält eine README mit Installationsschritten, den Env-Dateien, die jede Unit liest, und Testlauf-Logs:
- app: Stufe 1, die App allein
- core: Stufe 2, Postgres, die App und openplate-core
- inference: Stufe 3, openplate-inference und die App
- full: Stufe 4, alle vier
- openplate-core: der Core-Server allein
- openplate-inference: der Inferenz-Endpunkt allein
Wähle einen Weg: Compose oder Quadlet, niemals beides. Eine eigene systemd-Unit, die podman compose up ausführt, und ein Quadlet-Unit-Satz erledigen dieselbe Aufgabe. Wenn du beide installierst, geraten sie beim Booten über Port 3000 in Konflikt. Entferne den bestehenden Dienst vor dem Wechsel zu Quadlet. Um Quadlet zu entfernen, befolge die Deinstallationsschritte in der README des Szenarios.
Zwei Dinge, die du vor dem Start wissen solltest, auf jedem Podman:
- Es gibt keinen
systemctl --user enable-Schritt. Der Generator von Podman erstellt die Dienste. Du kannst generierte Units nicht aktivieren. Das Ausführen dieses Befehls liefertFailed to enable unit: Unit /run/user/1000/systemd/generator/app.service is transient or generated.Dies ist normales Verhalten. Der automatische Start stützt sich auf die Zeile[Install] WantedBy=default.targetin jeder Unit, zusammen mitloginctl enable-linger "$USER". Dieser Befehl startet deine Benutzer-systemd-Instanz beim Booten statt beim ersten Login. - Jede Einstellung gehört in
<unit>.env, niemals in die Unit. Jede Unit liest zwei Env-Dateien aus ihrem eigenen Verzeichnis:<unit>.defaults.env, die mit den Units ausgeliefert wird und die Compose-Standardwerte enthält, danach<unit>.env, die deine ist. Podman liest sie in dieser Reihenfolge, eine Zeile in deiner gewinnt also. Deine Datei muss existieren, selbst wenn sie leer ist, sonst startet der Container nicht. Ein Update kopiert die Units und die Standardwert-Dateien erneut und lässt deine Datei unberührt. Die README des Szenarios listet die Werte auf, die geändert werden.
Podman 4.9, die Version von Ubuntu 24.04, unterscheidet sich in zwei Punkten von Podman 5:
- Es ignoriert
Notify=healthy, was Podman 5.0 oder neuer erfordert. Infolgedessen beendet sichsystemctl --user startetwa eine Sekunde nach dem Container-Start, bevor der Healthcheck abgeschlossen ist. Eine Unit mitRequires=wartet nicht auf den Health-Status von Abhängigkeiten. Teste den Container-Status manuell:bashuntil [ "$(podman inspect --format '{{.State.Health.Status}}' systemd-app)" = healthy ]; do sleep 5; done
- Es liest kein Drop-in-Verzeichnis (
app.container.d/*.conf). Dateien, die dort abgelegt werden, bewirken nichts. Die Units brauchen keine: Jeder Wert, den du ändern kannst, wird aus<unit>.envgelesen.