Podman et Docker : deux moteurs de conteneurs, deux architectures
Sur un VPS Linux, le réflexe pour lancer un service en conteneur reste Docker : la commande docker run, le fichier Dockerfile, Docker Compose et Docker Hub forment un écosystème que tout administrateur connaît. Mais la recherche « podman vs docker » progresse en France, et ce n'est pas un effet de mode. Podman, le moteur de conteneurs du projet containers soutenu par Red Hat, est devenu le moteur par défaut de Fedora, RHEL et de leurs dérivés, et il arrive désormais en version récente dans les dépôts Debian et Ubuntu. Sa promesse : les mêmes images OCI et la même ligne de commande que Docker, sans démon qui tourne en root.
La différence est architecturale. Docker Engine repose sur un démon, dockerd, qui s'exécute en permanence avec les privilèges root et pilote containerd et le runtime OCI. Le client docker lui parle via le socket Unix /var/run/docker.sock. La documentation Docker le dit sans détour : le démon exige root sauf en mode rootless, et le groupe docker « accorde des privilèges de niveau root à l'utilisateur ». Podman n'a pas de démon : chaque podman run lance le conteneur comme processus enfant de votre shell, par un simple fork/exec, avec un runtime OCI (crun ou runc). Sans démon, il n'y a ni point de défaillance unique, ni socket root à protéger, et un utilisateur ordinaire peut gérer ses conteneurs dans son propre espace de noms.
Au moment d'écrire ce guide, les versions stables sont Podman 6.1.4 (12 octobre 2026) et Docker Engine 29.9.3 (3 novembre 2026). La branche Podman 6, sortie le 24 juin 2026, a tranché plusieurs héritages : fin du support de cgroups v1, d'iptables (nftables obligatoire), du réseau CNI et de slirp4netns, remplacé par pasta. Ce guide compare les deux moteurs sur ce qui compte pour un administrateur de VPS : installation, compatibilité de la CLI et des images, mode rootless, réseau et performances, intégration systemd, Compose et pods. Il complète nos guides installer Docker sur un VPS et Docker Compose sur VPS Linux.
Installation sur Ubuntu et Debian : dépôt officiel contre dépôt de la distribution
Les deux moteurs s'installent en une commande, mais pas depuis la même source. Docker recommande son propre dépôt apt, download.docker.com, qui fournit toujours la dernière version du moteur, de Buildx et du plugin Compose, pour Ubuntu 22.04, 24.04, 26.04 et 26.10. Une fois le dépôt déclaré (la procédure complète est dans notre guide d'installation de Docker), tout tient en une ligne :
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USERSur Debian et Ubuntu, le service docker.service démarre au boot dès l'installation. La dernière ligne évite de taper sudo à chaque commande, au prix d'un accès root équivalent pour cet utilisateur : c'est précisément le compromis que Podman cherche à supprimer.
Podman, lui, est dans les dépôts standard de Debian depuis la version 11 et d'Ubuntu depuis la 20.10. L'installation est donc plus simple, mais la version dépend de la distribution :
| Distribution | Version de Podman dans les dépôts | Réseau rootless par défaut |
|---|---|---|
| Debian 12 (bookworm) | 4.3.1 | slirp4netns |
| Ubuntu 24.04 LTS (noble) | 4.9.3 | slirp4netns |
| Debian 13 (trixie) | 5.4.2 | pasta |
| Ubuntu 26.04 LTS (resolute) | 5.7.0 | pasta |
| Upstream (GitHub containers/podman) | 6.1.4 | pasta (slirp4netns retiré) |
Installez Podman avec ses dépendances rootless, uidmap (qui fournit newuidmap et newgidmap) et passt (qui fournit pasta), puis vérifiez que vous êtes bien en mode rootless :
sudo apt update
sudo apt install -y podman uidmap passt
podman info --format '{{.Host.Security.Rootless}}'
podman run --rm docker.io/library/alpine:3 echo okSur Debian 12 et Ubuntu 24.04, où Podman est en 4.x, ajoutez le paquet slirp4netns : pasta n'est devenu le réseau rootless par défaut qu'avec Podman 5.0, le 19 mars 2024. Si vous avez le choix de l'image système, un VPS Ubuntu 26.04 LTS ou un Debian 13 vous donne un Podman 5 d'emblée, avec Quadlet complet et pasta. Notre guide quelle distribution Linux pour un VPS détaille les cycles de support de chacune.
Compatibilité CLI, images OCI et API Docker
C'est l'argument qui rend la migration réaliste : la ligne de commande de Podman reprend celle de Docker. podman run, podman ps, podman build, podman logs, podman exec, podman volume ou podman network acceptent les mêmes options que leurs équivalents Docker. Le paquet podman-docker, présent dans Debian 13 comme dans Ubuntu 24.04, installe une commande docker qui appelle Podman, pour que vos scripts et vos habitudes continuent de fonctionner. podman build lit un Dockerfile ou un Containerfile et s'appuie sur Buildah ; les images produites sont des images OCI standard, et celles de Docker Hub, GHCR ou Quay se tirent telles quelles.
Deux différences de comportement à connaître. D'abord, Podman préfère les noms d'images pleinement qualifiés : écrivez docker.io/library/nginx:1.27 plutôt que nginx, sinon Podman demande quel registre utiliser ou s'appuie sur la liste de recherche de registries.conf. Ensuite, les données ne sont pas au même endroit : en rootless, images, couches et volumes vivent dans ~/.local/share/containers/storage de chaque utilisateur, au lieu de /var/lib/docker. Le nettoyage régulier décrit dans nettoyer Docker avec prune s'applique avec podman system prune ; notez qu'avec Podman 6, podman volume prune ne supprime plus que les volumes anonymes, comme Docker, sauf avec --all.
Pour les outils qui parlent à l'API Docker (Portainer, Dockge, Traefik, Watchtower, les CI), Podman expose un service d'API compatible : la couche de compatibilité implémente l'API Docker (version 1.44 depuis Podman 6.0) à côté de l'API native libpod. Elle s'active à la demande par socket systemd, sans démon permanent :
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
docker ps # via podman-docker ou le vrai client dockerLe socket rootful est /run/podman/podman.sock, le socket rootless /run/user/UID/podman/podman.sock. La documentation Podman rappelle que cette API « donne un accès complet à toutes les fonctions de Podman » : protégez-la par les permissions du fichier et ne l'exposez jamais en TCP sans TLS mutuel. Le conseil vaut pour docker.sock, qu'un conteneur compromis utilise volontiers pour s'échapper vers l'hôte. Les interfaces comparées dans Portainer, Dockge ou Cosmos dépendent de ce socket, à monter avec discernement.
Mode rootless : natif chez Podman, optionnel chez Docker
Le mode rootless exécute le moteur et les conteneurs dans un espace de noms utilisateur : le root du conteneur est mappé sur un UID non privilégié de l'hôte. Une évasion de conteneur ne donne alors que les droits de votre compte, pas ceux de root. Le mécanisme est le même des deux côtés : des plages d'UID et de GID subordonnés déclarées dans /etc/subuid et /etc/subgid au format utilisateur:début:taille, et les binaires newuidmap/newgidmap pour les appliquer. La différence est dans la position par défaut.
Podman : rootless dès la première commande
Avec Podman, un utilisateur qui lance podman run sans sudo est en rootless, sans configuration supplémentaire dès lors que son compte a une plage dans subuid et subgid (en général créée par useradd sur Debian et Ubuntu ; vérifiez avec la commande grep ci-dessous). Les limites documentées par le projet :
- Ports inférieurs à 1024 : impossibles sans root. Pour servir du HTTP sur le port 80 depuis un conteneur rootless, abaissez le seuil système avec le sysctl
net.ipv4.ip_unprivileged_port_start, ou placez un reverse proxy devant. - Pilotes de stockage : overlay (natif avec un noyau 5.12 et plus, sinon via fuse-overlayfs, plus lent) ou VFS.
- Volumes montés : un fichier appartenant à un UID hors de la plage apparaît avec l'UID de débordement 65534. Pour une image qui tourne avec un
USERnon root, ajoutez--userns=keep-id. - Pas de checkpoint/restore (CRIU exige root), pas de limites de ressources sur cgroups v1, et le répertoire personnel ne doit pas être sur NFS ni monté en noexec.
grep "$USER" /etc/subuid /etc/subgid
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-rootless-ports.conf
sudo sysctl --systemDocker : rootless par un script, avec plus de restrictions
Docker propose le même principe depuis la version 20.10 avec dockerd-rootless-setuptool.sh, fourni par le paquet docker-ce-rootless-extras. Le script crée un service utilisateur systemd qui lance dockerd dans un espace de noms via RootlessKit. Le démon existe toujours, mais il n'est plus root :
sudo apt install -y docker-ce-rootless-extras uidmap
dockerd-rootless-setuptool.sh install
docker info --format '{{.SecurityOptions}}' # doit contenir name=rootless
sudo loginctl enable-linger $USERLes limitations connues listées par Docker sont plus nombreuses : stockage limité à overlay2 (noyau 5.11 et plus), fuse-overlayfs, btrfs ou vfs ; cgroups uniquement avec cgroups v2 et systemd ; pas d'AppArmor, pas de checkpoint, pas de réseau overlay, pas de ports SCTP ; l'adresse IP affichée par docker inspect n'est joignable qu'à l'intérieur de l'espace de noms de RootlessKit ; et docker run -p ne conserve pas l'IP source des clients par défaut. Le mode rootless de Docker fonctionne, mais il reste un mode à part, là où c'est le mode normal de Podman. Pour l'un comme pour l'autre, loginctl enable-linger est indispensable : sans lui, les services utilisateur s'arrêtent à la déconnexion SSH.
Ce choix ne dispense pas de sécuriser l'hôte : clé SSH, pare-feu et Fail2ban restent la base, détaillée dans sécuriser un VPS Ubuntu.
Réseau et performances : netavark, pasta et RootlessKit
Le surcoût CPU et mémoire d'un conteneur est négligeable dans les deux cas : il n'y a pas d'hyperviseur, le processus tourne directement sur le noyau de l'hôte avec des espaces de noms et des cgroups. La vraie question de performance est le réseau, et elle dépend surtout du mode root ou rootless.
En rootful, les deux moteurs utilisent un pont (bridge) dans le noyau et des règles de traduction d'adresses : docker0 et iptables ou nftables côté Docker, netavark côté Podman, avec une adresse IP routable par conteneur. Le débit est celui du noyau, avec une différence mesurable seulement par un benchmark sur votre propre machine.
En rootless, un utilisateur non privilégié ne peut pas créer d'interface réseau dans le noyau : les deux moteurs passent par une pile TCP/IP en espace utilisateur, qui coûte du CPU à chaque paquet. C'est là que les choix diffèrent. Podman a adopté pasta comme pile par défaut en 5.0 « pour de meilleures performances », selon ses notes de version, et a retiré slirp4netns en 6.0. Docker rootless s'appuie sur RootlessKit avec slirp4netns par défaut (gvisor-tap-vsock en son absence) ; sa documentation classe le débit réseau de ces pilotes comme « lent », et propose pasta en option expérimentale, à activer dans un drop-in du service utilisateur :
mkdir -p ~/.config/systemd/user/docker.service.d
printf '[Service]\nEnvironment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=pasta"\nEnvironment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=implicit"\n' > ~/.config/systemd/user/docker.service.d/override.conf
systemctl --user daemon-reload && systemctl --user restart dockerPour un service qui encaisse beaucoup de trafic en rootless, trois leviers : préférer pasta, mesurer avec iperf3 entre le VPS et un conteneur avant de choisir, et, pour un serveur de jeu en UDP, utiliser --network=host, qui contourne la pile utilisateur au prix de l'isolation réseau. Dans tous les cas, les ports publiés doivent être ouverts sur le pare-feu de l'hôte, comme expliqué dans nftables sur VPS Linux. Attention avec Docker rootful : sa documentation précise que le trafic des conteneurs est routé dans la table nat, avant les chaînes INPUT et OUTPUT qu'utilise UFW, ce qui contourne les règles UFW ; Podman rootless avec pasta n'écrit aucune règle de pare-feu sur l'hôte, ce qui simplifie l'audit.
Intégration systemd : Quadlet contre politiques de redémarrage
C'est la différence la plus visible au quotidien. Avec Docker, le démon est le superviseur : vous lancez un conteneur avec --restart unless-stopped ou always, et dockerd le relance après un crash ou un reboot. La documentation Docker recommande ces politiques de redémarrage plutôt qu'un gestionnaire de processus, et déconseille de combiner les deux. Le modèle est simple, mais il vit en dehors de systemd : systemctl status ne sait rien de vos conteneurs, et les dépendances entre un conteneur et un service de l'hôte (une base MariaDB native, un montage réseau) se gèrent à la main.
Podman, sans démon, délègue tout à systemd, et ce depuis la version 4.4 (février 2023) avec Quadlet : un générateur systemd qui transforme un fichier déclaratif .container en unité .service ordinaire. L'ancienne commande podman generate systemd est dépréciée au profit de ce format. Les fichiers vont dans /etc/containers/systemd/ en root, et dans ~/.config/containers/systemd/ en rootless. Exemple pour un Nextcloud rootless :
# ~/.config/containers/systemd/nextcloud.container
[Unit]
Description=Nextcloud en conteneur rootless
[Container]
Image=docker.io/library/nextcloud:stable
ContainerName=nextcloud
PublishPort=8080:80
Volume=nextcloud-data:/var/www/html
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=default.targetsystemctl --user daemon-reload
systemctl --user start nextcloud.service
systemctl --user status nextcloud.service
journalctl --user -u nextcloud.service -f
loginctl enable-linger $USERLe conteneur devient un service systemd comme les autres : journalisation dans journalctl, Restart= géré par systemd, After= et Requires= pour l'ordonnancer après un montage ou une base de données, et démarrage au boot via la cible default.target de la session utilisateur, maintenue vivante par enable-linger. Quadlet gère aussi des fichiers .pod, .network, .volume, .image, .build et .kube, et depuis Podman 6 ses fichiers peuvent être rangés en sous-répertoires. Si vous avez déjà écrit une unité pour un serveur de jeu en suivant créer un service systemd, vous êtes en terrain connu.
La ligne AutoUpdate=registry active podman auto-update : le timer podman-auto-update.timer vérifie chaque nuit si le registre propose un digest plus récent, tire l'image, redémarre l'unité et revient à l'image précédente si le redémarrage échoue. Pour en profiter, le nom d'image doit être pleinement qualifié. C'est l'équivalent intégré de ce que Watchtower fait côté Docker, sans conteneur supplémentaire ni accès au socket. Côté Docker, le modèle équivalent consiste à écrire une unité systemd qui exécute docker compose up avec Restart=, en retirant alors la politique de redémarrage du moteur pour éviter le conflit documenté ; Podman fournit de son côté podman-restart.service pour relancer au boot les conteneurs créés avec --restart hors systemd, mais sa documentation conseille de passer par les unités.
Docker Compose contre pods Podman
Le point fort de Docker reste Docker Compose : un fichier compose.yaml, une commande docker compose up -d, et la quasi-totalité des projets auto-hébergés (Nextcloud, Immich, Vaultwarden, n8n, Jellyfin) publient leur fichier Compose comme méthode d'installation de référence. Le plugin docker-compose-plugin est maintenu par Docker, documenté partout, et c'est ce que nos guides utilisent, par exemple installer Nextcloud avec Docker Compose.
Podman n'implémente pas Compose lui-même. La commande podman compose est un relais vers un fournisseur externe : docker-compose s'il est installé, car c'est l'implémentation de référence de la spécification Compose, sinon podman-compose, un projet communautaire en Python. Podman prépare l'environnement pour que le fournisseur dialogue avec le socket Podman, et affiche un avertissement rappelant qu'il exécute une commande externe. Le fournisseur se force dans containers.conf (compose_providers) ou par la variable PODMAN_COMPOSE_PROVIDER. En pratique, un fichier Compose classique fonctionne, mais les détails (réseaux nommés, dépendances depends_on avec healthcheck, ports privilégiés en rootless) demandent parfois des ajustements que la documentation du projet auto-hébergé ne couvre pas.
sudo apt install -y docker-compose-plugin # ou podman-compose
systemctl --user enable --now podman.socket
podman compose up -dL'alternative native de Podman, ce sont les pods, repris du modèle Kubernetes. Un pod regroupe plusieurs conteneurs qui partagent par défaut les espaces de noms réseau, IPC et UTS, autour d'un conteneur d'infrastructure minimal qui exécute /pause. Les conteneurs d'un pod se joignent en localhost, et les ports se publient au niveau du pod, à sa création, pas conteneur par conteneur :
podman pod create --name blog -p 8080:80
podman run -d --pod blog --name blog-db -e MARIADB_ROOT_PASSWORD=changez-moi docker.io/library/mariadb:11
podman run -d --pod blog --name blog-app -e WORDPRESS_DB_HOST=127.0.0.1 docker.io/library/wordpress:latest
podman pod ps
podman kube generate blog > blog.yamlLa dernière commande exporte le pod en YAML Kubernetes, que podman kube play blog.yaml recrée sur n'importe quelle machine, et qu'un fichier Quadlet .kube peut lancer sous systemd. podman kube play accepte des objets Pod, Deployment, ConfigMap, Secret, PersistentVolumeClaim, DaemonSet et Job : un administrateur qui prépare une migration vers Kubernetes teste ses manifestes sur un simple VPS. Docker n'a pas d'équivalent aux pods ; le partage de réseau se fait au cas par cas avec --network container:nom.
Tableau comparatif Podman vs Docker
| Critère | Docker Engine 29.9 | Podman 6.1 |
|---|---|---|
| Architecture | Démon dockerd (root par défaut) + containerd + runtime OCI | Sans démon, fork/exec par commande, runtime OCI crun ou runc |
| Mode rootless | Optionnel, via dockerd-rootless-setuptool.sh et RootlessKit | Natif, mode normal pour tout utilisateur non root |
| Installation Debian/Ubuntu | Dépôt apt officiel download.docker.com, toujours à jour | Dépôts de la distribution : 4.9.3 sur Ubuntu 24.04, 5.4.2 sur Debian 13, 5.7.0 sur Ubuntu 26.04 |
| CLI et images | Référence | Mêmes commandes et options, images OCI identiques, paquet podman-docker |
| API | Engine API sur /var/run/docker.sock | API compatible Docker 1.44 + libpod, socket activé à la demande |
| Réseau rootful | Bridge docker0, iptables ou nftables | netavark, nftables uniquement depuis 6.0 |
| Réseau rootless | RootlessKit + slirp4netns par défaut, pasta expérimental | pasta par défaut depuis 5.0, slirp4netns retiré en 6.0 |
| Intégration systemd | docker.service + politiques de redémarrage du démon | Quadlet (.container, .pod, .kube), podman auto-update, podman-restart.service |
| Compose | Docker Compose natif (plugin officiel) | podman compose délègue à docker-compose ou podman-compose |
| Pods | Non | Natifs, export et import YAML Kubernetes |
| cgroups v1 | Déprécié en 29.0, maintenu jusqu'en mai 2029 | Retiré en 6.0, cgroups v2 obligatoire |
| Documentation et exemples tiers | Omniprésents, Compose fourni par la plupart des projets | Documentation officielle complète, exemples tiers plus rares |
Quand Docker reste le bon choix, quand Podman l'emporte
Choisissez Docker si votre VPS héberge des applications livrées sous forme de fichier Compose et que vous voulez suivre leur documentation à la lettre ; si vous dépendez d'outils qui montent docker.sock (Portainer, Traefik en découverte automatique, Watchtower) ; si votre CI, vos collègues ou vos images maison supposent Docker ; ou si vous administrez des serveurs de jeu conteneurisés comme dans notre guide FiveM avec Docker, où les images communautaires sont testées sur Docker. Le démon root est un risque maîtrisable : n'ajoutez au groupe docker que des comptes de confiance, ne montez jamais le socket dans un conteneur exposé, et appliquez les mises à jour de sécurité.
Choisissez Podman si la sécurité du VPS prime : conteneurs rootless par défaut, aucun démon root permanent, aucun socket root à protéger, et un périmètre par utilisateur Linux qui isole naturellement les projets d'un même serveur. Choisissez-le aussi si vous voulez que vos conteneurs soient des services systemd à part entière, avec Quadlet, journalctl et auto-update intégrés ; si vous préparez un passage à Kubernetes et voulez manipuler des pods et des manifestes YAML ; ou si vous êtes sur Fedora, Rocky Linux ou AlmaLinux, où Podman est le moteur fourni et maintenu par la distribution.
Les deux peuvent cohabiter sur le même VPS : Docker en rootful pour une pile Compose héritée, Podman rootless pour les nouveaux services, chacun avec son stockage. Et un fichier Compose se convertit progressivement en fichiers Quadlet, un service à la fois, sans tout casser.
Conclusion
Docker et Podman exécutent les mêmes images OCI avec la même ligne de commande ; la différence se joue sur l'architecture et sur ce qui en découle. Docker garde l'avantage de l'écosystème : Compose natif, documentation de chaque projet auto-hébergé, outils tiers branchés sur son socket. Podman l'emporte dès que la question est la surface d'attaque et l'intégration au système : rootless par défaut, sans démon, conteneurs gérés comme des unités systemd par Quadlet, pods et compatibilité Kubernetes. Sur un VPS Debian 13 ou Ubuntu 26.04 LTS, Podman 5 avec pasta et Quadlet est aujourd'hui une option de production sérieuse ; sur Ubuntu 24.04 ou Debian 12, la version 4.x fonctionne mais sans les apports réseau de la branche 5. Quel que soit le moteur, la base reste la même : un hôte à jour, des ports ouverts avec parcimonie et des sauvegardes testées.
FiveM
Minecraft
Rust
RedM
Hytale