Salta al contenuto
openplate

L'app

Podman

Eseguire questi file compose e i container con Podman invece di Docker: la distinzione tra podman compose e podman-compose, e le note sulla modalità rootless

Questa pagina è tradotta automaticamente dalla documentazione in inglese.

Ogni comando docker compose e docker run in questa documentazione funziona anche con Podman. Sostituisci docker con podman. Questa pagina spiega una volta sola la trappola dei nomi e le differenze in modalità rootless. Gli altri documenti rimandano qui direttamente invece di ripeterle.

podman compose non è podman-compose

Sono due strumenti diversi. Quello sbagliato esegue un'implementazione meno compatibile senza alcun avviso.

  • podman compose (uno spazio) è un sottocomando integrato in Podman. È un wrapper sottile. Cerca un provider compose esterno sulla macchina, docker-compose o podman-compose, e gli passa il comando. Se hai installato docker-compose, Podman usa prima quello. È l'implementazione originale della specifica Compose. Esegui podman compose version per visualizzare il provider stampato in un banner.
  • podman-compose (un trattino) è un'implementazione separata, basata su Python, della specifica Compose. Funziona da sola senza Docker. Supporta una porzione inferiore della specifica. Il supporto per depends_on: condition: service_healthy è più debole, e assegna nomi diversi alle reti come impostazione predefinita.

Senza un provider, podman compose non fa nulla. Un'installazione pulita di Ubuntu 24.04 con solo podman risponde a ogni comando podman compose con Error: looking up compose provider failed. Installa prima un provider:

bash
sudo apt install podman podman-compose
podman compose version     # names /usr/bin/podman-compose, version 1.0.6

Su quella macchina, podman compose e podman-compose eseguono lo stesso programma. Gli healthcheck in questi file compose funzionano al suo interno. compose.yml e compose.core.yml riportavano healthy con podman 4.9.3 e podman-compose 1.0.6, inclusa l'attesa di Postgres. Per questo motivo gli healthcheck usano una singola riga di shell semplice (wget -q -O /dev/null http://127.0.0.1:3000/...). La vecchia sintassi node -e "fetch(...)" arrivava a podman-compose 1.0.6 come una riga di shell non valida. podman ps segnalava quindi unhealthy di continuo mentre l'app rispondeva.

Ogni file compose che avvia Postgres (compose.core.yml, compose.full.yml e la guida rapida di openplate-core compose.yml) usa depends_on: condition: service_healthy per vincolare un servizio all'healthcheck di Postgres. Se usi un provider diverso, verifica che supporti questa condizione.

Note sulla modalità rootless

Podman funziona in modalità rootless come impostazione predefinita. I container girano con il tuo utente, non come root. Questo offre una sicurezza migliore. Introduce anche tre differenze rispetto a Docker da conoscere prima di fare Self-hosting.

Etichette di volume per SELinux. Su un host con SELinux in modalità enforcing, predefinita su Fedora, un container non può leggere o scrivere in una directory dell'host montata tramite bind senza un'etichetta di accesso per container. Aggiungi :Z al mount se lo usa un solo container. Aggiungi :z se lo condividono più container, ad esempio -v ./pg-data:/var/lib/postgresql:Z. Nessuno dei file compose in questi tre repository monta directory dell'host con bind mount. Tutti usano volumi con nome, che Podman etichetta automaticamente. Questa nota si applica solo se modifichi una voce volumes: per usare un percorso dell'host. La modifica interessa i livelli di sincronizzazione 2 e 4 per Postgres, e il livello di inferenza 3 per i pesi del modello.

Porte inferiori a 1024. Un container rootless non può fare il bind di una porta dell'host inferiore a 1024 senza autorizzazione, ad esempio tramite sudo sysctl net.ipv4.ip_unprivileged_port_start=80. Nessuna delle porte predefinite in questi file compose (3000, 3001, 8300) ne ha bisogno. Il problema si presenta solo se rimappi una porta sulla 80 o sulla 443 per aggirare un reverse proxy. Poiché ogni livello pubblica almeno una porta, questo può riguardare ciascuno dei 4 livelli.

Postgres rootless. Il container di Postgres gira come utente non root. Quell'utente deve possedere la propria directory dei dati. Un volume con nome risolve il problema automaticamente, e apps/core/docker/compose.yml, compose.core.yml e compose.full.yml lo usano già. Podman crea il volume con nome assegnando la proprietà corretta. Se passi a una directory dell'host con bind mount, imposta prima la proprietà dall'host con podman unshare chown -R 70:70 ./pg-data. L'ID utente 70 corrisponde all'utente postgres nell'immagine bloccata postgres:18-alpine; le immagini Debian usano 999. Senza questo passaggio, il container fallisce all'avvio con un errore di permessi. Questo interessa i livelli 2 e 4.

Unit Quadlet

Quadlet non usa né podman compose né podman-compose: systemd avvia ciascun container direttamente con podman. Se ti interessa solo Quadlet, salta l'installazione del provider descritta sopra.

Tutti i file compose menzionati sopra sono distribuiti anche come unità systemd rootless. Vengono generate da scripts/quadlet.sh e salvate in docker/quadlet/. Un set di unità resta attivo tra i riavvii sotto systemctl --user senza un processo compose attivo. Ciascuna directory include un README con i passaggi di installazione, i file env letti da ogni unità e i log delle esecuzioni di prova:

Scegli una sola strada: compose o Quadlet, mai entrambe. Un'unità systemd personalizzata che esegue podman compose up e un set di unità Quadlet svolgono lo stesso compito. Se le installi entrambe, entrano in conflitto all'avvio sulla porta 3000. Rimuovi il servizio esistente prima di passare a Quadlet. Per rimuovere Quadlet, segui i passaggi di disinstallazione nel README dello scenario.

Due cose da sapere prima di iniziare, su qualsiasi installazione di Podman:

  • Non c'è alcun passaggio systemctl --user enable. Il generatore di Podman crea i servizi. Non puoi abilitare unità generate. Se esegui quel comando ottieni Failed to enable unit: Unit /run/user/1000/systemd/generator/app.service is transient or generated. Questo è il comportamento previsto. L'avvio automatico si basa sulla riga [Install] WantedBy=default.target in ciascuna unità, insieme a loginctl enable-linger "$USER". Quel comando avvia l'istanza systemd del tuo utente al boot invece che al primo login.
  • Ogni impostazione va in <unit>.env, mai nell'unità. Ciascuna unità legge due file env dalla propria directory: <unit>.defaults.env, distribuito con le unità, che contiene i valori predefiniti di compose, poi <unit>.env, che è il tuo. Podman li legge in quest'ordine, quindi una riga nel tuo file ha la precedenza. Il tuo file deve esistere, anche se vuoto, altrimenti il container non parte. Un aggiornamento sovrascrive le unità e i file predefiniti, lasciando intatto il tuo file. Il README dello scenario elenca i valori che di solito si modificano.

Podman 4.9, la versione di Ubuntu 24.04, differisce da Podman 5 per due aspetti:

  • Ignora Notify=healthy, che richiede Podman 5.0 o superiore. Di conseguenza, systemctl --user start termina circa un secondo dopo l'avvio del container, prima che l'healthcheck sia completato. Un'unità con Requires= non attende lo stato di salute dei servizi dipendenti. Verifica lo stato del container manualmente:
    bash
    until [ "$(podman inspect --format '{{.State.Health.Status}}' systemd-app)" = healthy ]; do sleep 5; done
  • Non legge alcuna directory drop-in (app.container.d/*.conf). I file inseriti lì non producono alcun effetto. Le unità non ne hanno bisogno: ogni valore che puoi modificare viene letto da <unit>.env.

Modifica questa pagina su GitHub