
Les conteneurs sont éphémères : supprimer un conteneur supprime ses données internes. Le stockage se gère donc avec 3 mécanismes : volume nommé, bind mount, tmpfs. Ce cours vous apprend à les utiliser dans des contextes réels — dev, prod, temporaire — et à résoudre les problèmes de permissions qui bloquent 80% des débutants.
Choisir le bon type de stockage
Section intitulée « Choisir le bon type de stockage »Avant de foncer sur les commandes, posez-vous la question : quel est mon contexte ?
| Contexte | Type recommandé | Pourquoi |
|---|---|---|
| Dev : je modifie du code sur l’hôte, je veux voir le résultat immédiatement | Bind mount | Lien direct hôte ↔ conteneur |
| Prod : je veux persister des données (DB, uploads, logs) | Volume nommé | Géré par Podman, portable, sauvegardable |
| Temporaire : cache, sessions, fichiers de build | tmpfs | Rapide (RAM), disparaît à l’arrêt |
Recette 1 — Développement : bind mount
Section intitulée « Recette 1 — Développement : bind mount »Objectif
Section intitulée « Objectif »Monter un répertoire de votre machine dans le conteneur. Vous éditez les fichiers sur l’hôte, le conteneur les voit instantanément.
Mise en place
Section intitulée « Mise en place »-
Créez un répertoire de travail
Fenêtre de terminal mkdir -p ~/dev-projetecho "<h1>Hello depuis l'hôte</h1>" > ~/dev-projet/index.html -
Lancez nginx avec un bind mount
Fenêtre de terminal podman run -d --name dev-nginx -p 8080:80 \-v ~/dev-projet:/usr/share/nginx/html:Z \docker.io/library/nginx:alpine -
Vérifiez dans le navigateur
Ouvrez http://localhost:8080 — vous voyez “Hello depuis l’hôte”.
-
Modifiez le fichier sur l’hôte
Fenêtre de terminal echo "<h1>Modification en direct !</h1>" > ~/dev-projet/index.html -
Rafraîchissez le navigateur
Le changement est visible immédiatement — pas de rebuild, pas de redémarrage.
Vérification de l’écriture bidirectionnelle
Section intitulée « Vérification de l’écriture bidirectionnelle »Le conteneur peut aussi écrire sur l’hôte :
podman exec dev-nginx sh -c "echo 'Log du conteneur' > /usr/share/nginx/html/log.txt"cat ~/dev-projet/log.txtLog du conteneurNettoyage
Section intitulée « Nettoyage »podman rm -f dev-nginxRecette 2 — Production : volume nommé + base de données
Section intitulée « Recette 2 — Production : volume nommé + base de données »Objectif
Section intitulée « Objectif »Persister les données d’une base PostgreSQL indépendamment du conteneur. Supprimer et recréer le conteneur ne perd pas les données.
Mise en place
Section intitulée « Mise en place »-
Créez le volume
Fenêtre de terminal podman volume create postgres-data -
Lancez PostgreSQL avec ce volume
Fenêtre de terminal podman run -d --name postgres-prod \-e POSTGRES_PASSWORD=secret \-v postgres-data:/var/lib/postgresql/data \docker.io/library/postgres:16-alpine -
Créez une table de test
Fenêtre de terminal sleep 5 # Attendre le démarragepodman exec -it postgres-prod psql -U postgres -c \"CREATE TABLE test (id serial, message text); INSERT INTO test (message) VALUES ('Données persistantes');" -
Supprimez le conteneur
Fenêtre de terminal podman rm -f postgres-prod -
Recréez un conteneur avec le même volume
Fenêtre de terminal podman run -d --name postgres-prod \-e POSTGRES_PASSWORD=secret \-v postgres-data:/var/lib/postgresql/data \docker.io/library/postgres:16-alpine -
Vérifiez que les données sont toujours là
Fenêtre de terminal sleep 3podman exec -it postgres-prod psql -U postgres -c "SELECT * FROM test;"Résultat attendu id | message----+---------------------1 | Données persistantes
Où sont stockées les données ?
Section intitulée « Où sont stockées les données ? »Ne mémorisez pas un chemin fixe — demandez-le à Podman :
podman volume inspect postgres-data --format '{{.Mountpoint}}'Le chemin dépend du mode (rootless vs rootful) et de la configuration storage.
Nettoyage
Section intitulée « Nettoyage »podman rm -f postgres-prod# Le volume existe toujours — supprimez-le seulement si vous voulez perdre les données :# podman volume rm postgres-dataRecette 3 — Temporaire : tmpfs pour le cache
Section intitulée « Recette 3 — Temporaire : tmpfs pour le cache »Objectif
Section intitulée « Objectif »Stocker des données temporaires en RAM. Rapide, volatile, parfait pour les caches ou les sessions.
Mise en place
Section intitulée « Mise en place »podman run --rm --mount type=tmpfs,destination=/cache,tmpfs-size=64M \ docker.io/library/alpine:3.20 sh -c " echo 'Données temporaires' > /cache/session.txt df -h /cache cat /cache/session.txt "Filesystem Size Used Available Use% Mounted ontmpfs 64.0M 0 64.0M 0% /cacheDonnées temporairesQuand le conteneur s’arrête, tout disparaît.
Cas d’usage typique : conteneur read-only avec tmpfs
Section intitulée « Cas d’usage typique : conteneur read-only avec tmpfs »Pour durcir un conteneur, montez le système de fichiers en lecture seule mais
autorisez /tmp en tmpfs :
podman run --rm --read-only \ --mount type=tmpfs,destination=/tmp \ docker.io/library/alpine:3.20 sh -c "echo test > /tmp/ok.txt && cat /tmp/ok.txt"Recette 4 — Partager un volume entre conteneurs
Section intitulée « Recette 4 — Partager un volume entre conteneurs »Objectif
Section intitulée « Objectif »Deux conteneurs accèdent au même volume — un écrivain, un lecteur.
-
Créez le volume partagé
Fenêtre de terminal podman volume create shared-logs -
Lancez le conteneur écrivain
Fenêtre de terminal podman run -d --name writer -v shared-logs:/logs docker.io/library/alpine:3.20 \sh -c "while true; do date >> /logs/events.log; sleep 2; done" -
Lisez depuis un autre conteneur
Fenêtre de terminal sleep 5podman run --rm -v shared-logs:/logs:ro docker.io/library/alpine:3.20 \tail -5 /logs/events.logRésultat Thu Feb 13 10:15:02 UTC 2026Thu Feb 13 10:15:04 UTC 2026Thu Feb 13 10:15:06 UTC 2026
Nettoyage
Section intitulée « Nettoyage »podman rm -f writerpodman volume rm shared-logsDépannage : les vrais problèmes
Section intitulée « Dépannage : les vrais problèmes »En Podman, 80% des problèmes de volumes viennent de deux sources : permissions rootless et SELinux. Voici comment les résoudre.
Problème 1 : “Permission denied” sur un bind mount
Section intitulée « Problème 1 : “Permission denied” sur un bind mount »Symptôme :
/bin/sh: can't create /app/file.txt: Permission deniedCauses possibles :
| Cause | Solution |
|---|---|
| SELinux bloque l’accès | Ajoutez :Z ou :z au montage |
| UID mismatch rootless | Utilisez --userns=keep-id + :U |
| Permissions UNIX du dossier | chmod 777 ~/mon-dossier (test) ou ajustez les ACL |
Diagnostic rapide :
# Vérifiez si SELinux est actifgetenforce
# Vérifiez les permissions du dossierls -laZ ~/mon-dossierSolution SELinux :
# :Z = privé (un seul conteneur)podman run -v ~/mon-dossier:/app:Z ...
# :z = partagé (plusieurs conteneurs)podman run -v ~/mon-dossier:/app:z ...Problème 2 : fichiers créés en “root:root”
Section intitulée « Problème 2 : fichiers créés en “root:root” »Symptôme : les fichiers créés par le conteneur appartiennent à root sur l’hôte, vous ne pouvez pas les modifier.
Cause : en rootless, l’UID dans le conteneur est mappé différemment.
Solution : --userns=keep-id conserve votre UID, et :U ajuste le volume.
podman run --rm --userns=keep-id -v ~/mon-dossier:/app:U \ docker.io/library/alpine:3.20 touch /app/mon-fichier.txt
ls -la ~/mon-dossier/mon-fichier.txt-rw-r--r-- 1 bob bob 0 Feb 13 10:30 mon-fichier.txtLe fichier vous appartient.
Problème 3 : “volume in use” lors de la suppression
Section intitulée « Problème 3 : “volume in use” lors de la suppression »Symptôme :
Error: volume "mon-volume" is being used by the following container(s): abc123Solution : supprimez d’abord le conteneur (même arrêté) :
podman rm abc123podman volume rm mon-volumeProblème 4 : données perdues après podman machine reset
Section intitulée « Problème 4 : données perdues après podman machine reset »Symptôme (macOS/Windows) : après un podman machine rm, tous les volumes
ont disparu.
Cause : les volumes sont stockés dans la VM. Supprimer la VM = supprimer les volumes.
Solution : sauvegardez vos volumes avant de toucher à la machine :
# Backuppodman run --rm -v mon-volume:/source:ro -v ~/backups:/backup \ alpine tar cvf /backup/mon-volume.tar -C /source .Backup et restore
Section intitulée « Backup et restore »Sauvegarder un volume
Section intitulée « Sauvegarder un volume »podman run --rm \ -v postgres-data:/source:ro \ -v ~/backups:/backup \ docker.io/library/alpine:3.20 \ tar cvf /backup/postgres-data-$(date +%Y%m%d).tar -C /source .Restaurer dans un nouveau volume
Section intitulée « Restaurer dans un nouveau volume »podman volume create postgres-data-restored
podman run --rm \ -v postgres-data-restored:/dest \ -v ~/backups:/backup \ docker.io/library/alpine:3.20 \ tar xvf /backup/postgres-data-20260213.tar -C /destVérifier la restauration
Section intitulée « Vérifier la restauration »Toujours vérifier avant de remettre en prod :
podman run --rm -v postgres-data-restored:/data docker.io/library/alpine:3.20 \ ls -la /dataGouvernance : labels et nettoyage
Section intitulée « Gouvernance : labels et nettoyage »Organiser avec des labels
Section intitulée « Organiser avec des labels »podman volume create --label env=dev --label app=web dev-web-datapodman volume create --label env=prod --label app=db prod-db-data
# Filtrerpodman volume ls --filter label=env=prodNettoyer les volumes orphelins
Section intitulée « Nettoyer les volumes orphelins »# Voir les volumes non utiliséspodman volume ls -f dangling=true
# Supprimer (avec confirmation)podman volume pruneExercice pratique : environnement complet
Section intitulée « Exercice pratique : environnement complet »Mettez en pratique ce que vous avez appris :
-
Créez un volume pour une app
Fenêtre de terminal podman volume create --label app=exercice exercice-data -
Lancez un conteneur qui écrit dedans
Fenêtre de terminal podman run --rm -v exercice-data:/data docker.io/library/alpine:3.20 \sh -c "echo 'Test exercice' > /data/test.txt" -
Sauvegardez le volume
Fenêtre de terminal mkdir -p ~/backupspodman run --rm -v exercice-data:/source:ro -v ~/backups:/backup \docker.io/library/alpine:3.20 tar cvf /backup/exercice.tar -C /source . -
Supprimez le volume
Fenêtre de terminal podman volume rm exercice-data -
Restaurez et vérifiez
Fenêtre de terminal podman volume create exercice-data-restoredpodman run --rm -v exercice-data-restored:/dest -v ~/backups:/backup \docker.io/library/alpine:3.20 tar xvf /backup/exercice.tar -C /destpodman run --rm -v exercice-data-restored:/data docker.io/library/alpine:3.20 \cat /data/test.txtVous devez voir :
Test exercice
À retenir
Section intitulée « À retenir »Types de stockage
- Bind mount : dev, hot-reload, accès direct aux fichiers hôte
- Volume nommé : prod, persistance, portable
- tmpfs : cache, sessions, données volatiles
Résoudre les permissions
- SELinux : ajoutez
:Z(privé) ou:z(partagé) - Rootless : utilisez
--userns=keep-id+:U - Fichiers root:root : combinez keep-id et :U
Aide-mémoire des options
Section intitulée « Aide-mémoire des options »| Option | Description | Exemple |
|---|---|---|
-v nom:/chemin | Volume nommé | -v app-data:/var/lib/app |
-v /hôte:/chemin | Bind mount | -v ~/code:/app |
:ro | Lecture seule | -v config:/etc/app:ro |
:Z | SELinux privé | -v ~/data:/data:Z |
:z | SELinux partagé | -v ~/shared:/shared:z |
:U | Ajuster UID (rootless) | -v vol:/data:U |
--mount type=tmpfs | RAM temporaire | --mount type=tmpfs,dst=/cache |