La containerizzazione ha rivoluzionato il modo in cui sviluppatori, sysadmin e appassionati di self-hosting distribuiscono applicazioni. Tra gli strumenti che hanno reso possibile questa trasformazione, Docker è diventato un nome quasi sinonimo stesso di “container”: un progetto nato nel 2013 da Docker Inc., che ha portato un approccio semplice, uniforme e immediato alla creazione e gestione dei container. È l’opzione scelta dalla maggior parte degli utenti perché “funziona subito”, con un ecosistema maturo e una documentazione onnipresente.
Ma Docker non è l’unica strada. Nel 2019 Red Hat ha introdotto Podman, un runtime compatibile con Docker ma progettato con una filosofia diversa: sicurezza by-design, gestione daemon-less, supporto nativo ai pod (in stile Kubernetes) e un’integrazione più pulita con il mondo Linux.
I pod sono un insieme di container che lavorano come se fossero un’unica unità: container che condividono lo stesso namespace di rete (quindi stesso indirizzo IP e porte interne) e possono comunicare tra loro come se fossero processi sulla stessa macchina.
Se Podman è tecnicamente solido, moderno e compatibile con Docker… perché la community continua a preferire Docker? Capire questa dinamica significa comprendere non solo le differenze tecniche tra i due strumenti, ma anche come l’esperienza dell’utente, la documentazione, gli strumenti intorno ai container e la cultura della comunità influenzino la scelta finale.
Il peso della documentazione e della community
Docker ha una massa critica enorme. Tutti i tutorial, guide di installazione e gli script sono pensati per Docker. Per un self-hoster, adottare Docker significa usare una strada già ben battuta: se qualcosa non funziona, è molto più facile trovare aiuto o una soluzione online. In confronto, Podman è ancora meno presente nei tutorial. Questo gap nella documentazione rappresenta una barriera reale per chi non vuole perdere tempo a reinventare la ruota.
Sicurezza sì, ma la comodità vince spesso
Podman è apprezzato per i suoi vantaggi in termini di sicurezza:
- Rootless: permette di eseguire container senza privilegi di root, riducendo il rischio di escalation di privilegi.
- Daemonless: non c’è un processo centrale sempre attivo (come
dockerd), e ogni container è un processo del proprio utente. - Integrazione con systemd: grazie a Podman, molti usano file di unità systemd per gestire i container (avvio, logging, auto-update).
Dove non ci sono scenari multi-utente complessi, la differenza in termini di rischi percepiti (tra un Docker rootful e un Podman rootless) può non giustificare il passaggio da Docker a Podman. Quest’ultimo, tuttavia, è particolarmente apprezzato da chi predilige un ambiente server più “pulito”, senza processi residenti come il Docker daemon, e da chi cerca un’alternativa più conforme agli standard di containerizzazione.
Motivazioni culturali: Docker regna
Per molti self-hoster, usare Docker è quasi un’impostazione di default culturale. È lo strumento con cui hanno iniziato, quello che hanno visto usare nei forum e nei tutorial. Abbandonarlo significa investire tempo a capire un flusso diverso, anche se più sicuro e versatile.
Docker eccelle nell’esperienza out-of-the-box e nell’ampiezza dell’ecosistema; Podman punta su sicurezza, compatibilità e aderenza alle specifiche OCI, risultando più vicino al mondo enterprise e ai workflow dei sistemi Linux moderni.
Come già sottolineato, Docker ha dalla sua un ecosistema enorme: archivi di immagini (Docker Hub), strumenti CI/CD, integrazioni varie. Anche se Podman supporta le immagini Docker (grazie alla compatibilità OCI), molti strumenti già pronti spesso assumono che il runtime usato sia comunque Docker.
Compatibilità e convenienza di “alias”
L’idea di iniziare la migrazione da Docker a Podman con un semplice alias su Linux (alias docker=podman) è una tentazione comprensibile.
Podman, infatti, è compatibile con la CLI (command-line interface) di Docker e per molti comandi basilari il trucco dell’alias funziona davvero. Tuttavia, usare questo alias come unica strategia di migrazione crea l’illusione che i due strumenti siano intercambiabili al 100%, quando in realtà hanno differenze strutturali che emergono appena si esce dallo scenario del “container singolo”.
Docker Compose vs Podman + Quadlet: due mondi diversi
Uno degli ostacoli maggiori è che Docker Compose non è parte del mondo Podman. Quest’ultimo ha provato a supportarlo tramite podman-compose, un progetto della comunità, che però non è mantenuto allo stesso livello di Docker Compose, non copre tutte le funzionalità e può generare comportamenti diversi con network, volumi e dipendenze.
Podman ha quindi introdotto Quadlet, un approccio completamente diverso basato su file .container, .pod, .image, .volume integrati in systemd. Docker Compose gestisce stack complessi con YAML; Quadlet trasforma container e pod in servizi systemd. È un approccio potente, ma richiede un cambio di mentalità non indifferente.
Porte privilegiate e rootless: Podman è più sicuro… ma meno permissivo
Docker usa un daemon root che abilita molte operazioni senza pensarci troppo. Con Podman, per impostazione predefinita, l’utente è rootless: ciò significa che non è possibile aprire porte di comunicazione < 1024 senza configurazioni aggiuntive; i volumi hanno mapping dell’UID basato su user namespaces; l’accesso alla rete è più vincolato.
Se in Docker la creazione di un server Web nginx funziona subito con docker run -p 80:80 nginx, in Podman rootless è necessario usare una porta alta per non incorrere in errori: podman run -p 8080:80 nginx.
In alternativa, si deve intervenire su un file di configurazione come sysctl/capabilities/authbind/Slirp4netns per abilitare l’uso delle porte < 1024 con Podman. Cosa certamente più complessa e non immediata per attività di self-hosting semplice.
API: Docker ha un daemon; Podman ha un servizio opzionale
Molti strumenti esterni si basano su Docker Engine API. Podman non ha un daemon sempre attivo; per compatibilità è necessario creare una API rootless tramite l’istruzione systemctl --user start podman.socket.
Tuttavia, non tutti gli strumenti che parlano con Docker funzionano con Podman (i.e. Portainer, alcuni plugin CI/CD, buildkit avanzato, ecc.).
Come installare e provare Docker
Per installare Docker sulle distribuzioni Linux principali (Ubuntu/Debian), è possibile ricorrere ai seguenti comandi (validi anche su WSL, Windows Subsystem for Linux):
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable docker --now
Per verificare che tutto funzioni, si può ad esempio digitare quanto segue:
sudo docker run hello-world
Docker richiede il daemon dockerd attivo. Per usare Docker senza impartire ogni volta il comando sudo, si può aggiungere manualmente il nome dell’utente al gruppo docker:
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world
Installazione di Podman: ancora più semplice e veloce
Funzionando senza daemon e configurato di default in modalità rootless, Podman risulta ancora più immediato da installare e utilizzare. Su Ubuntu/Debian (ma anche su WSL, in Windows, installando una distro derivata da Debian) basta impartire i seguenti comandi:
sudo apt update
sudo apt install podman -y
podman run hello-world
Esempio pratico: eseguire il server Web nginx
Come spiegato in precedenza, per caricare un container con il server Web nginx e porlo in ascolto sulla porta 80, basta digitare il comando seguente con Docker:
sudo docker run -d -p 80:80 --name webserver nginx
sudo docker ps
Con Podman rootless, si possono impartire le seguenti istruzioni:
podman run -d -p 8080:80 --name webserver nginx
podman ps
Digitando, rispettivamente, localhost e localhost:8080 nella barra degli indirizzi del browser Web preferito, si ottiene risposta da parte del server Web nginx locale, ospitato nel container Docker o Podman. In 80:80 e 8080:80 il primo numero corrisponde alla porta esposta, il secondo alla porta utilizzata dal container per rispondere alle richieste in arrivo.
In entrambi i casi, webserver è il nome arbitrario assegnato al container con nginx.
Nel caso in cui, con Podman, si ricevesse l’errore “nginx did not resolve to an alias and no unqualified-search registries are defined in …./registries.conf“, è possibile usare il comando seguente:
podman run -d -p 8080:80 --name webserver docker.io/library/nginx:latest
In alternativa si può aggiungere docker.io ai registri di ricerca utilizzati da Podman:
sudo bash -c 'grep -q "unqualified-search-registries" /etc/containers/registries.conf || echo "unqualified-search-registries = [\"docker.io\"]" >> /etc/containers/registries.conf'
Esempi rapidi di comandi utili
Fermare/riavviare/rimuovere i container:
docker stop webserver
docker start webserver
docker rm -f webserver
podman stop webserver
podman start webserver
podman rm -f webserver
Verificare il contenuto dei log:
docker logs -f webserver
podman logs -f webserver
Al posto di webserver va ovviamente specificato il nome corretto del container. È possibile verificarlo digitando i comandi docker ps e podman ps quindi facendo riferimento alla colonna Names (l’ultima a destra).
Qual è il modo canonico per gestire il contenuto di un container?
Il modello alla base del funzionamento dei container — sia Docker che Podman — si basa su immutabilità + configurazione esterna. Ciò significa che, di norma, il container non si modifica mai dall’interno: piuttosto, si montano file dall’host oppure si ricrea un’immagine aggiornata secondo le proprie necessità.
Prendiamo come esempio un container nginx: come si passa al server Web la configurazione da gestire? Il metodo standard consiste nel fare in modo che nginx legga la configurazione gestita sul sistema host. Esempio con Podman:
podman run -d -p 8080:80 --name webserver \
-v ./conf:/etc/nginx/conf.d:Z \
-v ./html:/usr/share/nginx/html:Z \
docker.io/library/nginx:latest
Questo approccio permette di gestire la configurazione dal sistema host, con editor e strumenti software abituali. La configurazione può essere ad esempio “versionata” con Git.
Così facendo, il container è veramente stateless: aggiornare Nginx significa solo ricreare il container.
Creare un’immagine personalizzata
Quanto descritto in precedenza, è ciò che si fa di norma negli ambienti di produzione. Tuttavia, una valida alternativa consiste nel creare una nuova immagine che contiene la configurazione desiderata, in questo caso per nginx (salvarla come Podmanfile o Dockerfile):
FROM docker.io/library/nginx:latest
COPY conf/ /etc/nginx/conf.d/
COPY html/ /usr/share/nginx/html/
A questo punto si può passare al comando di build dell’immagine del container. Ad esempio, sempre con Podman:
podman build -t my-nginx .
Alla fine, si può avviare normalmente il container personalizzato:
podman run -d -p 8080:80 --name webserver my-nginx
In questo caso, il vantaggio è che tutto è ripetibile e versionato; risulta semplice fare deploy identici su più host; non vi è alcuna dipendenza dai file dell’host; è il metodo “a prova di DevOps” per usare i container.
Conclusioni
Docker e Podman rappresentano due approcci complementari al mondo dei container: Docker con la sua diffusione capillare e l’ecosistema consolidato, Podman con la sua filosofia rootless, la compatibilità con i pod e un focus particolare su sicurezza e flessibilità.
Per chi si avvicina al self-hosting, la scelta tra i due non è dettata solo da funzionalità tecniche, ma anche dal tipo di workflow, dall’esperienza pregressa e dalle necessità di integrazione con strumenti esistenti. L’alias docker=podman può essere un punto di partenza utile, ma comprendere le differenze profonde, come la gestione delle configurazioni, delle porte privilegiate e dei pod, permette di sfruttare appieno le potenzialità di ciascuna piattaforma.