
Podman est un moteur de conteneurs sans démon obligatoire (daemonless), pensé pour une utilisation Linux native : rootless par défaut, intégration propre à systemd via Quadlet, et support des pods façon Kubernetes. Sur macOS et Windows, il s'appuie sur Podman Machine (une VM Linux). Ce guide couvre la version stable 5.8 et signale les changements de Podman 6.
Le modèle mental Podman
Section intitulée « Le modèle mental Podman »Trois décisions d'architecture expliquent l'essentiel des différences que vous constaterez avec Docker, et donc l'essentiel des surprises. Elles ne sont pas indépendantes : c'est parce que Podman n'a pas de démon qu'un conteneur peut appartenir à votre session utilisateur, et c'est parce qu'il appartient à votre session que systemd peut en prendre la charge comme de n'importe quel autre processus. Gardez cet enchaînement en tête, il rend prévisible le comportement de l'outil.
- Rootless : les conteneurs tournent avec les droits de votre utilisateur, via les user namespaces.
- Daemonless : pas de service central permanent pour gérer vos conteneurs au quotidien.
- Systemd-first : avec Quadlet, un conteneur devient un service propre (restart, logs, dépendances).
- Bonus, pods et kube play : regrouper des conteneurs façon Kubernetes et lancer des manifests sans cluster.
Pour le « pourquoi » et les détails d'architecture, voir les concepts Podman.
Démarrer en 5 minutes
Section intitulée « Démarrer en 5 minutes »Objectif : valider que Podman tourne, savoir exposer un port, lire des logs, monter un volume, puis nettoyer.
Deux détails de cette séquence n'ont pas d'équivalent sous Docker. Le nom d'image est complet (docker.io/library/nginx:alpine) parce que Podman ne préfixe pas silencieusement les noms courts : il vous demandera de choisir un registre si vous écrivez seulement nginx. Et le suffixe :Z sur le volume demande à Podman de réétiqueter le répertoire pour SELinux ; sans lui, sur Fedora ou RHEL, le conteneur lira un permission denied alors que les droits Unix sont corrects.
# Vérifier la versionpodman version
# Lancer un conteneur nginxpodman run -d --name web -p 8080:80 docker.io/library/nginx:alpine
# Vérifier qu'il tournecurl http://localhost:8080
# Voir les logspodman logs web
# Tester un volume (SELinux : :Z)podman run -d --name web2 -v ~/html:/usr/share/nginx/html:Z -p 8081:80 docker.io/library/nginx:alpine
# Nettoyerpodman rm -f web web2Podman vs Docker : choisir sans se mentir
Section intitulée « Podman vs Docker : choisir sans se mentir »L'objectif n'est pas une comparaison exhaustive, mais de vous aider à décider vite, puis de vous envoyer vers les guides.
Choisissez Podman si…
Section intitulée « Choisissez Podman si… »Ces quatre situations ont un point commun : elles portent sur l'exploitation de la machine, pas sur le développement de l'application. Podman se distingue quand vous devez rendre des comptes sur qui exécute quoi, sur un serveur que vous administrez.
- Vous voulez rootless par défaut (multi-utilisateurs, postes partagés, moindre risque).
- Vous voulez des services systemd propres (serveur, self-hosting, edge).
- Vous voulez rester proche de Kubernetes (pods,
kube play,kube generate). - Vous voulez éviter un daemon central obligatoire sur la machine.
Restez sur Docker si…
Section intitulée « Restez sur Docker si… »À l'inverse, deux contextes rendent la migration plus coûteuse que le bénéfice attendu. Dans les deux cas, l'obstacle n'est pas technique mais lié à l'outillage autour : podman compose délègue à docker-compose ou à podman-compose selon ce qui est installé, et les comportements divergent sur les fichiers Compose élaborés.
- Votre quotidien dépend d'un Docker Compose complexe et d'intégrations « Docker-only ».
- Vous êtes dans un contexte où l'écosystème Docker Desktop est imposé.
Pilier 1, rootless en pratique
Section intitulée « Pilier 1, rootless en pratique »Le mode rootless est le gros avantage de Podman, mais il a des implications concrètes.
Ce qui se passe réellement
Section intitulée « Ce qui se passe réellement »Podman utilise les user namespaces pour mapper les identités du conteneur vers des UID/GID non privilégiés sur l'hôte :
Hôte Conteneur─────────────────────────────────────────────UID 1000 (vous) UID 0 (root)UID 100000-165535 (subuid) UID 1-65535Les trois frictions les plus courantes
Section intitulée « Les trois frictions les plus courantes »Ces trois frictions découlent toutes du même fait : votre conteneur croit être root, l'hôte sait qu'il ne l'est pas. Lisez la colonne Symptôme en premier, c'est le message d'erreur exact que vous verrez. La plus fréquente en pratique est celle des volumes : un fichier créé dans le conteneur par l'UID 0 apparaît sur l'hôte avec l'UID de base de votre plage subuid, souvent 100000, donc illisible par votre propre compte tant que vous n'avez pas ajouté --userns=keep-id.
| Friction | Symptôme | Réflexe |
|---|---|---|
| Ports bas | bind: permission denied sur 80/443 | utiliser ≥1024 ou sysctl net.ipv4.ip_unprivileged_port_start |
| Volumes | fichiers root:root ou permission denied | --userns=keep-id ou options de volume |
| Réseau | DNS ou perf surprenants | réseau dédié + backend adapté |
Pilier 2, réseau : pasta, netavark et DNS
Section intitulée « Pilier 2, réseau : pasta, netavark et DNS »En rootless, c'est souvent le réseau qui surprend. L'objectif : un réseau où les conteneurs se résolvent par nom avec une perf correcte. Depuis Podman 5, le backend par défaut est Netavark (avec Aardvark pour le DNS) et la pile réseau rootless par défaut est Pasta.
# Créer un réseau applicatif (résolution DNS par nom)podman network create app-network
# Un conteneur "db" et un client qui le joint par son nompodman run -d --network app-network --name db docker.io/library/postgres:16-alpinepodman run --rm --network app-network docker.io/library/alpine ping -c 1 dbPilier 3, systemd : Quadlet (recommandé)
Section intitulée « Pilier 3, systemd : Quadlet (recommandé) »Pour du « prod-like » sur un serveur Linux, Quadlet est le point d'inflexion : un conteneur devient un service (journalctl, restart, dépendances). C'est la voie recommandée par l'écosystème Podman ; l'ancien podman generate systemd est déprécié (toujours utilisable, mais ce n'est plus la direction).
Exemple minimal : nginx.container
Section intitulée « Exemple minimal : nginx.container »Un fichier .container est une unité systemd enrichie : systemd le lit, génère à la volée le service correspondant, et vous manipulez ensuite ce service avec les commandes habituelles. La section [Container] remplace les arguments de podman run, la section [Service] reste du systemd standard. Sur une machine que vous exploitez réellement, remplacez le tag alpine par un digest @sha256:... : c'est le seul moyen de garantir qu'un redémarrage du service ne change pas l'image sous vos pieds.
[Container]Image=docker.io/library/nginx:alpinePublishPort=8080:80Volume=/data/nginx:/usr/share/nginx/html:ro,Z
[Service]Restart=always
[Install]WantedBy=default.targetActivation en rootless :
mkdir -p ~/.config/containers/systemd# placer nginx.container dans ce dossier
systemctl --user daemon-reloadsystemctl --user start nginxsystemctl --user enable nginxjournalctl --user -u nginx -fBonus, pods et intégration Kubernetes (sans cluster)
Section intitulée « Bonus, pods et intégration Kubernetes (sans cluster) »Quand vous avez besoin d'un modèle mental « mini-Kubernetes » sans déployer de cluster, les pods Podman sont parfaits.
Pod : web + base de données
Section intitulée « Pod : web + base de données »Le point à comprendre est la publication des ports. Elle se déclare une seule fois, sur le pod, jamais sur les conteneurs qui le rejoignent : ces derniers partagent la même pile réseau et se joignent entre eux par localhost. C'est exactement le comportement d'un Pod Kubernetes, et c'est ce qui explique pourquoi la chaîne de connexion de l'application pointe sur localhost:5432 alors que la base tourne dans un autre conteneur.
Le mot de passe est lu depuis une variable du shell plutôt qu'écrit dans la commande : sans cette précaution, il finit dans l'historique du shell et dans la sortie de podman inspect. Pour un usage durable, préférez podman secret create et --secret.
export PGPASS="$(openssl rand -base64 24)"
podman pod create --name webapp -p 8080:80
podman run -d --pod webapp --name db \ -e POSTGRES_PASSWORD="$PGPASS" docker.io/library/postgres:16-alpine
podman run -d --pod webapp --name app \ -e DATABASE_URL="postgres://postgres:$PGPASS@localhost:5432" \ mon-app:latestpodman kube play : exécuter un manifest sans cluster
Section intitulée « podman kube play : exécuter un manifest sans cluster »# Lancer un manifest Kubernetes localementpodman kube play deployment.yaml
# Arrêter et supprimerpodman kube play deployment.yaml --down
# Exporter un pod existant vers un manifest Kubernetespodman kube generate webapp > webapp.yamlLes commandes historiques podman play kube et podman generate kube restent des alias, mais la forme moderne est podman kube play / podman kube generate.
macOS / Windows : Podman Machine
Section intitulée « macOS / Windows : Podman Machine »Sur macOS et Windows, les conteneurs Linux nécessitent une VM, car ils dépendent du kernel Linux. Podman Machine la gère pour vous.
podman machine initpodman machine startpodman run -d -p 8080:80 docker.io/library/nginx:alpinepodman machine sshParcours recommandé
Section intitulée « Parcours recommandé »Choisissez votre point d'entrée, puis avancez module par module. Les quatre premières lignes forment le socle et se lisent dans l'ordre ; les suivantes sont indépendantes et se prennent au besoin. Une seule contrainte d'enchaînement compte : Quadlet suppose acquis le contenu de Réseaux et de Volumes, puisqu'une unité systemd déclare les deux sans possibilité de tâtonner en ligne de commande.
| Module | Objectif |
|---|---|
| Installation | être opérationnel (Linux/macOS/Windows) |
| Concepts | rootless, daemonless, pods, architecture |
| Commandes de base | run, ps, exec, logs, images, nettoyage |
| Run avancé | rootless, namespaces, sécurité, options |
| Volumes | persistance et permissions |
| Réseaux | DNS, ports, isolation, multi-tier |
| Build | Containerfile, multi-stage, optimisation |
| Pods | pods, infra container, mapping Kubernetes |
| kube play | déployer des manifests sans cluster |
| Quadlet | conteneurs comme services systemd |
| Manifests multi-arch | images multi-architecture |
Versions et distributions
Section intitulée « Versions et distributions »Podman évolue vite et chaque distribution embarque une version différente. La branche stable de référence pour ce guide est la 5.8 (dernière 5.x : 5.8.5, publiée le 8 juillet 2026). La 6.0.0 est sortie le 24 juin 2026, suivie de la 6.0.2 le 22 juillet ; elle arrive d'abord sur les distributions rolling et via Homebrew.
Ce tableau sert à répondre à une seule question avant de suivre un guide : la commande que vous lisez existe-t-elle dans votre version ? L'écart est considérable, plus de trois ans séparent la 4.3 de Debian 12 de la 6.0 d'Arch, et des pans entiers de la documentation amont ne s'appliquent pas aux versions 4.x, à commencer par Quadlet, absent avant la 4.4.
| Base | Version Podman |
|---|---|
| Arch Linux, Homebrew (macOS) | 6.0 |
| Amont (dernières) | 5.8.5 (5.x) / 6.0.2 |
| Fedora 43 (à jour) | 5.8 |
| Debian 13, Ubuntu 25.10 | 5.4 |
| Fedora 42 | 5.4 |
| Ubuntu 24.04 LTS | 4.9 |
| Debian 12 | 4.3 |
Pour un environnement critique, épinglez la version et testez les comportements par défaut, qui changent d'une majeure à l'autre (réseau, volumes, cgroups).
Podman 6 : ce qui change
Section intitulée « Podman 6 : ce qui change »Sortie le 24 juin 2026, Podman 6 finalise plusieurs suppressions entamées en 5.x. Elle exige des composants compagnons alignés : Buildah 1.44, Skopeo 1.23, Netavark/Aardvark 2.0. Le dépôt a par ailleurs rejoint l'organisation CNCF podman-container-tools.
La CVE-2026-57231 est souvent citée comme argument de migration, à tort. Cette fuite de variables d'environnement de l'hôte vers le conteneur, déclenchée par une image contenant une variable sans valeur, touche toutes les versions de la 1.8.1 à la 5.8.3 incluse et pèse 7.5 sur l'échelle CVSS v3.1. Elle est corrigée à la fois dans la 5.8.4 et dans la 6.0.0 : rester sur la branche 5.x à jour suffit à s'en protéger, la montée en 6 se décide sur d'autres critères.
Ruptures qui cassent des setups
Section intitulée « Ruptures qui cassent des setups »Ces suppressions ne sont pas des surprises : chacune concerne un composant déjà remplacé par défaut depuis Podman 4 ou 5, et déjà signalé comme déprécié. Le risque porte donc sur les machines qui ont été configurées explicitement pour l'ancien composant, typiquement un /etc/containers/containers.conf qui force network_backend = "cni". Vérifiez ce fichier avant toute montée de version, ainsi que vos scripts : la dernière ligne de la liste, sur le changement de logique des filtres, casse silencieusement un podman ps --filter qui en cumulait plusieurs.
- CNI supprimé au profit de Netavark (le backend réseau par défaut depuis Podman 5).
- slirp4netns supprimé au profit de Pasta pour le réseau rootless.
- cgroups v1 et iptables supprimés (passez à cgroups v2 et nftables).
- BoltDB supprimé : migration automatique vers SQLite au premier démarrage.
- Intel Mac et Windows 10 ne sont plus supportés.
podman volume prunene supprime plus que les volumes anonymes par défaut ; utilisez--allpour l'ancien comportement.- Quadlet range désormais chaque unité et ses fichiers dans un sous-répertoire au lieu du fichier
.app. - Filtres multiples : ils se combinent maintenant en ET et non plus en OU, ce qui restreint les résultats d'un
--filtercumulé.
Nouveautés utiles
Section intitulée « Nouveautés utiles »Ces ajouts répondent tous à des frustrations connues de la 5.x. Les deux premiers rendent le nettoyage prévisible, ce qui manquait cruellement : jusqu'ici, podman volume prune supprimait sans prévisualisation possible. Le troisième donne enfin une vue directe des unités Quadlet, qu'il fallait auparavant reconstituer en listant les fichiers et les services systemd séparément.
podman volume prune --dry-runet--allpour un nettoyage maîtrisé.podman quadlet ls(nouvel alias) avec une colonne Pod.podman infoexpose les répertoires CDI et les périphériques découverts.--gpuscompatible AMD, adresses IP statiques multiples, routesblackhole/unreachable.podman machine os updateet gestion multi-provider des VM.
Autour de Podman
Section intitulée « Autour de Podman »Podman ne construit pas d'images et ne parle pas aux registres tout seul : ces fonctions vivent dans des binaires distincts, qui partagent la même bibliothèque de stockage et les mêmes fichiers de configuration. Vous pouvez donc construire une image avec Buildah, la copier avec Skopeo et l'exécuter avec Podman sans jamais la pousser sur un registre intermédiaire.
Mettre en pratique
Section intitulée « Mettre en pratique »Avant de dérouler le parcours, validez le geste de base : ce lab vous fait lancer un conteneur en mode détaché avec Podman, contrôler son état et consulter ses logs sur une VM, sans rien installer sur votre poste.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Cgroups : Les limites de CPU, de mémoire et d'entrées/sorties que Podman applique à chaque conteneur.
- Namespaces : Les espaces de noms utilisateur dont dépend directement le mode rootless.
- Capabilities : Les privilèges unitaires qu'un conteneur conserve ou perd, la base de
--cap-drop.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions rassemblées ici sont celles que pose une équipe qui vient de Docker : équivalences de commandes, sort de Compose, et comportement du mode rootless sur les ports privilégiés. Chaque réponse tient en quelques lignes et renvoie vers le guide détaillé quand le sujet le mérite.
Une alternative daemonless et rootless à Docker
Podman (POD MANager) est un moteur de conteneurs open source conforme à OCI, créé par Red Hat et désormais hébergé par la CNCF. Il exécute des conteneurs et des pods, avec deux différences clés face à Docker :- Daemonless : pas de démon central, chaque commande lance directement le conteneur.
- Rootless : les conteneurs tournent avec vos droits utilisateur, sans root.
alias docker=podman fonctionne dans la majorité des cas). Il ajoute l'intégration systemd via Quadlet et le support des pods façon Kubernetes.podman run -d -p 8080:80 docker.io/library/nginx:alpine
Une majeure surtout faite de suppressions
Podman 6 est sortie fin juin 2026. Elle finalise des retraits entamés en 5.x :| Supprimé | Remplacé par |
|---|---|
| CNI | Netavark |
| slirp4netns | Pasta |
| cgroups v1 | cgroups v2 |
| iptables | nftables |
| BoltDB | SQLite (migration auto) |
podman volume prune ne supprime plus que les volumes anonymes par défaut (--all pour tout), Quadlet range ses fichiers en sous-répertoires, et les compagnons doivent être alignés (Buildah 1.44, Skopeo 1.23, Netavark/Aardvark 2.0).Aujourd'hui, seuls Arch et Homebrew livrent la 6.0 ; Fedora et Debian restent en 5.x.dockerd.Comparaison architecturale
Docker : Client → dockerd (root) → containerd → runc → conteneur
Podman : Client → conmon (user) → runc → conteneur
Avantages du daemonless
| Aspect | Docker (daemon) | Podman (daemonless) |
|---|---|---|
| Point de défaillance | dockerd = SPOF | Pas de SPOF |
| Redémarrage service | Tue tous les conteneurs | Conteneurs indépendants |
| Surface d'attaque | Daemon root exposé | Pas de daemon |
| Ressources | Daemon permanent | Processus à la demande |
En pratique
# Pas de service à démarrer
podman run -d nginx # Crée directement le processus
# Chaque conteneur est un processus indépendant
ps aux | grep conmon
# user 1234 conmon --cid abc123...
# user 5678 conmon --cid def456...
→ Concepts PodmanPrincipe de fonctionnement
┌─────────────────────────────────────────────────────────┐
│ HÔTE │
│ Utilisateur bob (UID 1000) │
│ └── Plage subuid : 100000-165535 │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ CONTENEUR │ │
│ │ root (UID 0) → mappé sur UID 100000 (hôte) │ │
│ │ user (UID 1000) → mappé sur UID 101000 (hôte) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Configuration
# Vérifier les plages subuid/subgid
cat /etc/subuid
# bob:100000:65536
# Initialiser le user namespace
podman system migrate
# Lancer un conteneur rootless
podman run -d nginx
Sécurité
| Scénario | Impact rootless |
|---|---|
| Évasion du conteneur | Attaquant = UID 100000 (non privilégié) |
| Accès au socket | Pas de socket root exposé |
| Montage /etc/passwd | Impossible sans droits |
Ce que partagent les conteneurs d'un pod
| Ressource | Partagée ? | Implication |
|---|---|---|
| Namespace réseau | ✅ Oui | Tous les conteneurs utilisent localhost |
| Namespace IPC | ✅ Oui | Mémoire partagée possible |
| Namespace UTS | ✅ Oui | Même hostname |
| Volumes | ⚙️ Configurable | Partage de données |
| Namespace PID | ❌ Non | Processus isolés |
Exemple pratique
# Créer un pod avec un port exposé
podman pod create --name webapp -p 8080:80
# Ajouter une BDD (accessible via localhost dans le pod)
podman run -d --pod webapp \
--name db \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine
# Ajouter l'app (accède à la BDD via localhost:5432)
podman run -d --pod webapp \
--name app \
-e DATABASE_HOST=localhost \
mon-app:latest
Étape 1 : Installer Podman
# Ubuntu/Debian
sudo apt install podman
# Fedora
sudo dnf install podman
Étape 2 : Créer l'alias
# Dans ~/.bashrc ou ~/.zshrc
alias docker=podman
Étape 3 : Migrer les commandes
| Docker | Podman | Notes |
|---|---|---|
docker run |
podman run |
✅ Identique |
docker build |
podman build |
✅ Identique |
docker-compose |
podman-compose |
Installer via pip |
Dockerfile |
Containerfile |
Les deux acceptés |
Étape 4 : Docker Compose
# Option 1 : podman-compose
pip install podman-compose
podman-compose up -d
# Option 2 : podman compose (4.x+)
podman compose up -d
Ce qui fonctionne directement
- ✅ Images Docker Hub
- ✅ Dockerfile/Containerfile
- ✅ Volumes et réseaux
- ✅ Variables d'environnement
Différences mineures
- Registres multiples par défaut (pas seulement Docker Hub)
- Socket différent (
/run/podman/podman.sock) - Mode rootless par défaut
Ports ≥ 1024 (fonctionnent directement)
# Aucune configuration spéciale
podman run -d -p 8080:80 nginx
curl http://localhost:8080
Ports < 1024 (nécessitent configuration)
# Par défaut, erreur :
podman run -d -p 80:80 nginx
# Error: rootlessport cannot expose privileged port 80
Solution 1 : Modifier sysctl# Autoriser les ports à partir de 80
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
# Rendre permanent
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/podman-ports.conf
Solution 2 : Utiliser rootlesskit# Dans ~/.config/containers/containers.conf
[network]
rootless_networking = "pasta"
Tableau récapitulatif
| Port | Mode rootless | Solution |
|---|---|---|
| ≥ 1024 | ✅ Direct | -p 8080:80 |
| < 1024 | ⚠️ Bloqué | sysctl ou rootlesskit |
| 443 (HTTPS) | ⚠️ Bloqué | sysctl ou reverse proxy |
podman build utilise Buildah en interne pour la construction d'images.Architecture de build
podman build ─────┐
▼
Buildah (bibliothèque)
│
▼
Image OCI
Différences d'usage
| Outil | Usage | Commande type |
|---|---|---|
| podman build | Build via Containerfile | podman build -t app . |
| buildah | Build interactif ou scripté | buildah from, buildah run, buildah commit |
Exemple Buildah interactif
# Créer un conteneur de travail
ctr=$(buildah from alpine:3.21)
# Exécuter des commandes
buildah run $ctr apk add --no-cache curl jq
# Configurer l'image
buildah config --entrypoint '["curl"]' $ctr
# Committer l'image
buildah commit $ctr mon-curl:1.0
Quand utiliser Buildah directement ?
- Scripts de build complexes sans Dockerfile
- Modification d'images existantes
- Pipelines CI/CD avec contrôle fin
- Images minimales construites instruction par instruction
Diagnostic
# Vérifier les permissions
podman run --rm -v ~/data:/data alpine ls -la /data
# Permission denied → problème d'UID ou SELinux
Solution 1 : Option :U (ajustement UID)
# :U ajuste automatiquement le propriétaire pour le mapping rootless
podman run -v ~/data:/data:U mon-app
Solution 2 : SELinux avec :Z ou :z
# :Z = label privé (un seul conteneur)
podman run -v ~/data:/data:Z mon-app
# :z = label partagé (plusieurs conteneurs)
podman run -v ~/shared:/shared:z mon-app
Solution 3 : keep-id
# Votre UID (1000) devient l'UID 1000 dans le conteneur
podman run --userns=keep-id -v ~/data:/data mon-app
Tableau des options
| Option | Problème résolu | Effet |
|---|---|---|
:U |
UID rootless | Chown récursif |
:Z |
SELinux | Label privé |
:z |
SELinux partagé | Label partagé |
--userns=keep-id |
Mapping UID | Conserve votre UID |
:ro |
Sécurité | Lecture seule |
Générer un manifest depuis un conteneur/pod
# Depuis un conteneur unique
podman run -d --name web -p 8080:80 nginx
podman generate kube web > web-pod.yaml
# Depuis un pod complet
podman pod create --name webapp -p 8080:80
podman run -d --pod webapp --name db postgres:16
podman run -d --pod webapp --name app mon-app
podman generate kube webapp > webapp.yaml
Exemple de manifest généré
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
containers:
- name: db
image: postgres:16
- name: app
image: mon-app:latest
Exécuter un manifest Kubernetes localement
# Déployer un manifest existant
podman play kube webapp.yaml
# Avec un ConfigMap
podman play kube webapp.yaml --configmap config.yaml
# Arrêter et supprimer
podman play kube webapp.yaml --down
Workflow dev → prod
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Dev local │ ──▶ │ generate │ ──▶ │ Kubernetes │
│ (podman) │ │ kube │ │ (prod) │
└─────────────┘ └─────────────┘ └─────────────┘
→ Concepts podsLimiter la mémoire
# Limite à 512 Mo de RAM
podman run -d --memory 512m nginx
# Limite RAM + swap
podman run -d --memory 512m --memory-swap 1g nginx
Limiter le CPU
# Limite à 1.5 cœurs CPU
podman run -d --cpus 1.5 nginx
# Limite en millicores (comme Kubernetes)
podman run -d --cpus 0.5 nginx # 500m
# Limiter à certains cœurs spécifiques
podman run -d --cpuset-cpus 0,1 nginx
Limiter les processus
# Maximum 100 processus
podman run -d --pids-limit 100 nginx
Vérifier les limites
# Statistiques en temps réel
podman stats
# Inspecter les limites configurées
podman inspect nginx --format '{{.HostConfig.Memory}}'
Tableau récapitulatif
| Option | Effet | Exemple |
|---|---|---|
--memory |
Limite RAM | --memory 256m |
--memory-swap |
Limite RAM+swap | --memory-swap 512m |
--cpus |
Limite cœurs | --cpus 2 |
--cpuset-cpus |
Cœurs spécifiques | --cpuset-cpus 0,2 |
--pids-limit |
Limite processus | --pids-limit 50 |
Réseau par défaut : pas de DNS
# Le réseau 'podman' par défaut n'a pas de DNS
podman run -d --name db postgres:16
podman run --rm alpine ping db
# ping: bad address 'db' ← Échec !
Réseau personnalisé : DNS activé
# Créer un réseau avec DNS intégré
podman network create mon-reseau
# Lancer les conteneurs sur ce réseau
podman run -d --network mon-reseau --name db postgres:16
podman run --rm --network mon-reseau alpine ping db
# PING db (10.89.0.2): 56 data bytes ← Succès !
Alias DNS
# Ajouter des alias pour un conteneur
podman run -d --network mon-reseau \
--name postgres \
--network-alias db \
--network-alias database \
postgres:16
# Accessible via 'postgres', 'db' ou 'database'
Tableau récapitulatif
| Réseau | DNS | Isolation |
|---|---|---|
podman (défaut) |
❌ Non | Minimale |
| Personnalisé | ✅ Oui | Par réseau |
host |
Hôte | Aucune |
none |
❌ Non | Totale |
podman generate systemd qui est déprécié.Créer un fichier Quadlet
# Rootless : ~/.config/containers/systemd/
# Rootful : /etc/containers/systemd/
mkdir -p ~/.config/containers/systemd
Exemple minimal : nginx.container
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=/data/nginx:/usr/share/nginx/html:ro,Z
[Service]
Restart=always
[Install]
WantedBy=default.target
Activer le service
# Recharger systemd pour détecter le fichier
systemctl --user daemon-reload
# Démarrer le conteneur
systemctl --user start nginx.service
# Activer au boot
systemctl --user enable nginx.service
Avantages de Quadlet
| Aspect | generate systemd | Quadlet |
|---|---|---|
| Maintenance | Régénérer si config change | Fichier déclaratif |
| Statut | Déprécié | Recommandé |
| Logs | podman logs |
journalctl |
| Restart | Configurable | Natif systemd |
Architecture Podman Machine
macOS/Windows VM Podman Machine
┌─────────────────┐ ┌─────────────────┐
│ podman CLI │ ◄─────────▶ │ Kernel Linux │
│ (commandes) │ socket │ + Podman │
│ │ │ + Conteneurs │
└─────────────────┘ └─────────────────┘
Commandes de base
# Initialiser la VM (télécharge l'image Fedora CoreOS)
podman machine init
# Démarrer la VM
podman machine start
# Vérifier le statut
podman machine list
# Se connecter à la VM
podman machine ssh
Options de virtualisation
| Plateforme | Backend par défaut | Alternative |
|---|---|---|
| macOS Intel | QEMU | HyperKit |
| macOS Apple Silicon | QEMU (arm64) | - |
| Windows | WSL 2 | Hyper-V |
Forwarding de ports
Les ports exposés par les conteneurs sont automatiquement accessibles sur localhost grâce au forwarding intégré.→ Installation PodmanArbre de décision
| Critère | → Podman | → Docker |
|---|---|---|
| Sécurité rootless | ✅ Natif | ⚠️ Expérimental |
| Intégration systemd | ✅ Quadlet | ❌ Workarounds |
| Pods Kubernetes | ✅ Natif | ❌ Non supporté |
| Docker Compose | ⚠️ Compat partielle | ✅ Natif |
| Écosystème existant | ⚠️ Migration | ✅ Déjà en place |
| Support enterprise | Red Hat | Docker Inc |
Recommandations
Choisir Podman si :- Environnement RHEL/Fedora/CentOS
- Sécurité rootless requise
- Services systemd (self-hosting)
- Préparation vers Kubernetes
- Équipe formée Docker Compose
- Intégrations tierces Docker-only
- Pas de contrainte rootless
En pratique
Beaucoup d'équipes utilisent les deux : Docker Desktop pour le dev, Podman pour la prod sur serveurs Linux.→ Comparaison DockerProblème 1 : Ports < 1024
# Erreur typique
podman run -p 80:80 nginx
# Error: rootlessport cannot expose privileged port 80
Solution :sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
Problème 2 : DNS entre conteneurs
# Le réseau par défaut n'a pas de DNS
podman run --rm alpine ping other-container
# ping: bad address 'other-container'
Solution : créer un réseau personnalisépodman network create mon-reseau
podman run -d --network mon-reseau --name db postgres
podman run --rm --network mon-reseau alpine ping db # ✅ fonctionne
Problème 3 : Performance réseau
slirp4netns est plus lent que le bridge kernel.Solution : utiliser pasta (Podman 4.x+)# ~/.config/containers/containers.conf
[network]
default_rootless_network_cmd = "pasta"
Tableau des backends réseau rootless
| Backend | Perf | DNS | Disponibilité |
|---|---|---|---|
| slirp4netns | Lente | ❌ | Partout |
| pasta | Rapide | ✅ | Podman 4.4+ |
podman play kube permet de déployer des manifests Kubernetes localement sans avoir besoin d'un cluster.Cas d'usage
- Test local avant déploiement en prod
- Machines edge sans Kubernetes
- CI/CD pour valider les manifests
- Développement avec les mêmes fichiers que la prod
Exemple pratique
# webapp.yaml
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
containers:
- name: web
image: nginx:alpine
ports:
- containerPort: 80
hostPort: 8080
# Déployer le manifest
podman play kube webapp.yaml
# Vérifier
podman pod ps
podman ps
curl http://localhost:8080
# Arrêter et supprimer
podman play kube webapp.yaml --down
Ressources Kubernetes supportées
| Ressource | Support |
|---|---|
| Pod | ✅ Complet |
| Deployment | ✅ Complet |
| ConfigMap | ✅ Complet |
| Secret | ✅ Complet |
| Service | ⚠️ Partiel |
| PersistentVolume | ⚠️ Limité |