
Podman kube permet de tester des manifests Kubernetes localement, sans cluster. Vous pouvez aussi générer des YAML depuis vos conteneurs existants. C'est idéal pour valider vos manifests avant de les déployer sur un vrai cluster.
À la fin de ce guide, vous saurez :
- Lancer des pods depuis des YAML Kubernetes
- Générer des manifests depuis des conteneurs existants
- Itérer rapidement : generate → edit → play
- Nettoyer proprement avec
kube down
Droit au but
Section intitulée « Droit au but »Les quatre raccourcis ci-dessous couvrent le cycle de vie complet : kube play crée les ressources depuis un manifest, kube generate fait le chemin inverse à partir de conteneurs déjà lancés, et kube down défait le tout. Si votre besoin se limite à vérifier qu'un YAML démarre, le premier lien suffit.
Pourquoi utiliser kube play ?
Section intitulée « Pourquoi utiliser kube play ? »Deux besoins reviennent quand on écrit des manifests : vérifier qu'un YAML démarre réellement, et récupérer un manifest depuis des conteneurs déjà en place. Podman traite les deux sans control plane, en traduisant les objets Kubernetes en pods et conteneurs locaux.
Le problème : tester un YAML sans cluster
Section intitulée « Le problème : tester un YAML sans cluster »Vous avez un manifest Kubernetes et vous voulez le tester :
- Sans installer Minikube ou Kind
- Sans déployer sur un cluster de dev
- Rapidement, pour valider la syntaxe et le comportement
La solution : podman kube play
Section intitulée « La solution : podman kube play »podman kube play lit un fichier YAML Kubernetes et crée les ressources localement avec Podman.
Ce qui est supporté
Section intitulée « Ce qui est supporté »Podman ne simule pas un cluster Kubernetes complet, il se concentre sur les ressources que vous pouvez tester localement sans orchestrateur. Les ressources de type "réseau" (Services, Ingress) ne sont pas supportées car elles dépendent d'un control plane Kubernetes.
| Ressource | Supporté | Notes |
|---|---|---|
| Pod | ✅ | Complet |
| Deployment | ✅ | Crée les pods |
| DaemonSet | ✅ | Crée un pod |
| ConfigMap | ✅ | Monté comme fichiers ou envvars |
| Secret | ✅ | Monté comme fichiers ou envvars |
| PersistentVolumeClaim | ✅ | Crée un volume Podman |
| Service | ❌ | Utilisez les ports du pod |
| Ingress | ❌ | Non supporté |
| NetworkPolicy | ❌ | Non supporté |
kube play : lancer un YAML
Section intitulée « kube play : lancer un YAML »Podman lit le document de haut en bas et crée les objets dans l'ordre où il les rencontre. Un Pod donne un pod Podman, un Deployment donne autant de pods que de replicas, et les ConfigMap ou Secret doivent apparaître avant l'objet qui les référence.
Syntaxe de base
Section intitulée « Syntaxe de base »La commande prend le chemin d'un fichier YAML. Podman crée les ressources puis démarre les conteneurs dans la foulée : sauf option contraire, un kube play qui rend la main a déjà lancé le pod.
podman kube play <fichier.yaml>Premier exemple
Section intitulée « Premier exemple »Ce manifest décrit un Pod nginx avec un hostPort, seul moyen d'atteindre le conteneur depuis l'hôte puisque les Services ne sont pas gérés. À l'étape de vérification, le compteur de conteneurs affiche 2 : votre conteneur nginx, plus le conteneur d'infrastructure que Podman ajoute à chaque pod pour tenir les espaces de noms.
-
Créer un manifest simple
nginx-pod.yaml apiVersion: v1kind: Podmetadata:name: nginx-weblabels:app: nginxspec:containers:- name: nginximage: docker.io/library/nginx:1.31.3-alpineports:- containerPort: 80hostPort: 8080 -
Lancer avec kube play
Fenêtre de terminal podman kube play nginx-pod.yamlRésultat Pod:nginx-webContainer:nginx-web-nginx -
Vérifier
Fenêtre de terminal podman pod psRésultat POD ID NAME STATUS CREATED # OF CONTAINERSabc123def456 nginx-web Running 10 seconds ago 2 -
Tester
Fenêtre de terminal curl http://localhost:8080
Exemple avec Deployment
Section intitulée « Exemple avec Deployment »Podman lit le champ replicas et instancie autant de pods indépendants à partir du template. Aucun controller ne les surveille ensuite : si l'un s'arrête, rien ne le recrée, contrairement au comportement d'un Deployment sur un vrai cluster.
apiVersion: apps/v1kind: Deploymentmetadata: name: web-appspec: replicas: 2 # Crée 2 pods selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: web image: docker.io/library/nginx:1.31.3-alpine ports: - containerPort: 80podman kube play deployment.yamlOptions utiles de kube play
Section intitulée « Options utiles de kube play »Les options les plus utiles permettent de contrôler le réseau, de charger des ConfigMaps externes, et surtout d'itérer rapidement avec --replace.
| Option | Description | Exemple |
|---|---|---|
--network | Réseau à utiliser | --network my-net |
--configmap | Charger un ConfigMap externe | --configmap cm.yaml |
--start | Démarrer les pods (défaut: true) | --start=false |
--replace | Remplacer les pods existants | --replace |
--down | Alias pour kube down | (voir section dédiée) |
kube generate : créer un YAML
Section intitulée « kube generate : créer un YAML »podman kube generate lit l'état d'un conteneur ou d'un pod existant et le transcrit en manifest Kubernetes. L'image, les ports publiés, les volumes et les variables d'environnement sont repris ; les réglages propres à Podman sans équivalent Kubernetes sont laissés de côté.
Le cas d'usage
Section intitulée « Le cas d'usage »Vous avez des conteneurs qui fonctionnent avec podman run. Vous voulez les "exporter" en YAML Kubernetes pour :
- Les versionner dans Git
- Les déployer ailleurs
- Les transformer en vraies ressources Kubernetes
La commande écrit sur la sortie standard, d'où la redirection vers un fichier. Elle accepte le nom d'un conteneur seul ou celui d'un pod : dans le second cas, tous les conteneurs du pod se retrouvent dans le même manifest.
# Depuis un conteneurpodman kube generate <container-name> > pod.yaml
# Depuis un podpodman kube generate <pod-name> > pod.yamlExemple : conteneur simple
Section intitulée « Exemple : conteneur simple »Un conteneur isolé produit malgré tout un objet Pod, avec le suffixe -pod ajouté au nom. Le mapping -p 8080:80 devient le couple containerPort / hostPort, et l'image est réécrite en nom pleinement qualifié docker.io/library/nginx:alpine.
# Créer un conteneurpodman run -d --name my-nginx -p 8080:80 nginx:alpine
# Générer le YAMLpodman kube generate my-nginxapiVersion: v1kind: Podmetadata: name: my-nginx-pod labels: app: my-nginx-podspec: containers: - name: my-nginx image: docker.io/library/nginx:1.31.3-alpine ports: - containerPort: 80 hostPort: 8080Exemple : pod complet
Section intitulée « Exemple : pod complet »Le pod api-stack regroupe deux conteneurs qui partagent déjà le même espace réseau. Le manifest généré les place dans la liste containers d'un seul objet Pod, et reprend la publication de port définie à la création du pod, pas celle des conteneurs.
# Créer un pod avec plusieurs conteneurspodman pod create --name api-stack -p 8080:80podman run -d --pod api-stack --name nginx nginx:alpinepodman run -d --pod api-stack --name redis redis:alpine
# Générer le YAMLpodman kube generate api-stack > api-stack.yamlLe YAML généré contient les deux conteneurs dans le même pod.
Options de kube generate
Section intitulée « Options de kube generate »Deux options principales : écrire directement dans un fichier (-f) ou générer aussi un Service Kubernetes (-s) pour faciliter la transition vers un vrai cluster.
| Option | Description | Exemple |
|---|---|---|
-f, --filename | Écrire dans un fichier | -f pod.yaml |
-s, --service | Générer aussi un Service | -s |
# Générer Pod + Servicepodman kube generate my-nginx -sWorkflow d'itération
Section intitulée « Workflow d'itération »Le workflow typique est :
Prototyper en ligne de commande coûte moins cher qu'écrire un manifest à l'aveugle : vous ajustez les options de podman run jusqu'à ce que la stack réponde, puis vous figez le résultat en YAML. Les allers-retours suivants se font sur le fichier, que kube play rejoue à chaque modification.
Démonstration
Section intitulée « Démonstration »Les six étapes appliquent ce cycle à un pod nginx : création manuelle, génération du manifest, ajout d'un bloc resources et d'une variable d'environnement, puis relance. La dernière commande relit la configuration du conteneur avec podman inspect pour confirmer que la valeur ENV=production a bien été prise en compte.
-
Prototyper avec le CLI
Fenêtre de terminal # Créer le pod manuellementpodman pod create --name demo -p 8080:80podman run -d --pod demo --name app nginx:alpine -
Générer le YAML
Fenêtre de terminal podman kube generate demo > demo.yaml -
Éditer le YAML
Ajoutez des ressources, des variables d'environnement, etc.
demo.yaml (édité) apiVersion: v1kind: Podmetadata:name: demospec:containers:- name: appimage: docker.io/library/nginx:1.31.3-alpineports:- containerPort: 80hostPort: 8080resources:limits:memory: "128Mi"cpu: "500m"env:- name: ENVvalue: "production" -
Supprimer l'ancien pod
Fenêtre de terminal podman pod rm -f demo -
Relancer avec le YAML modifié
Fenêtre de terminal podman kube play demo.yaml -
Vérifier les changements
Fenêtre de terminal podman inspect demo-app --format '{{.Config.Env}}'# [ENV=production ...]
L'option --replace
Section intitulée « L'option --replace »--replace condense les étapes 4 et 5 en une seule commande : Podman repère le pod portant le nom déclaré dans le manifest, le supprime, puis le recrée à partir du YAML courant.
Pour éviter de supprimer manuellement le pod :
# Première foispodman kube play demo.yaml
# Modifications...
# Remplacer directementpodman kube play --replace demo.yamlkube down : nettoyer proprement
Section intitulée « kube down : nettoyer proprement »kube down prend le même manifest que kube play et défait ce qu'il avait créé. Podman ne tient aucun inventaire de déploiements : c'est le fichier YAML qui sert de référence, il doit donc rester disponible pour pouvoir nettoyer.
Le fichier passé en argument doit décrire les mêmes objets qu'au moment du play. Si le nom du pod a changé dans le YAML entre-temps, kube down ne retrouve pas le pod d'origine et le laisse tourner.
podman kube down <fichier.yaml>Ce que kube down supprime
Section intitulée « Ce que kube down supprime »kube down est conservateur par défaut : il supprime les pods et conteneurs, mais préserve les volumes pour éviter toute perte de données accidentelle. Utilisez --force uniquement si vous voulez un nettoyage complet.
| Ressource | Supprimée ? | Notes |
|---|---|---|
| Pods | ✅ | Toujours |
| Conteneurs | ✅ | Tous les conteneurs du pod |
| Volumes créés par le YAML | ⚠️ | Seulement avec --force |
| Réseaux | ❌ | Non supprimés |
Le cycle complet tient en trois commandes : créer, vérifier, supprimer. La sortie sépare deux temps, l'arrêt des pods puis leur suppression, ce qui permet de repérer un conteneur qui refuse de s'arrêter avant que la suppression n'échoue.
# Créerpodman kube play demo.yaml
# Vérifierpodman pod ps
# Supprimerpodman kube down demo.yamlPods stopped:demoPods removed:demoSupprimer les volumes aussi
Section intitulée « Supprimer les volumes aussi »Par défaut, kube down préserve les volumes (pour ne pas perdre de données).
# Supprimer pods + volumespodman kube down --force demo.yamlVérifier ce qui reste après kube down
Section intitulée « Vérifier ce qui reste après kube down »Le nettoyage laisse deux traces possibles : les volumes issus d'un PersistentVolumeClaim et les réseaux créés à part. podman volume prune ne supprime que les volumes qu'aucun conteneur ne référence plus, ce qui limite le risque d'effacer des données encore utilisées.
# Vérifier les pods (devrait être vide)podman pod ps
# Vérifier les volumes (peuvent rester)podman volume ls
# Nettoyer manuellement les volumes orphelinspodman volume pruneConfigMaps et Secrets
Section intitulée « ConfigMaps et Secrets »Podman gère ces deux objets dans le même document que le Pod, à condition qu'ils y figurent avant lui. Leur contenu se consomme de deux façons : en volume monté sous forme de fichiers, ou en variable d'environnement via configMapKeyRef et secretKeyRef.
ConfigMap
Section intitulée « ConfigMap »Le manifest ci-dessous combine les deux usages sur la même ConfigMap : la clé app.conf est projetée en fichier /etc/nginx/conf.d/default.conf grâce au bloc items, tandis que LOG_LEVEL devient une variable d'environnement du conteneur.
apiVersion: v1kind: ConfigMapmetadata: name: app-configdata: app.conf: | server { listen 80; } LOG_LEVEL: debug---apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx:1.31.3-alpine volumeMounts: - name: config-volume mountPath: /etc/nginx/conf.d env: - name: LOG_LEVEL valueFrom: configMapKeyRef: name: app-config key: LOG_LEVEL volumes: - name: config-volume configMap: name: app-config items: - key: app.conf path: default.confpodman kube play config.yamlUn objet Secret de type Opaque attend ses valeurs encodées en base64 dans le champ data. Cet encodage n'est pas un chiffrement : quiconque lit le fichier retrouve le mot de passe en une commande, ce manifest n'a donc rien à faire dans un dépôt Git.
apiVersion: v1kind: Secretmetadata: name: db-secrettype: Opaquedata: password: cGFzc3dvcmQxMjM= # base64 encoded---apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx:1.31.3-alpine env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: passwordEncoder un secret en base64 :
echo -n 'password123' | base64# cGFzc3dvcmQxMjM=Lab : workflow complet
Section intitulée « Lab : workflow complet »Objectif : créer une stack API avec nginx + backend, la transformer en YAML, et itérer.
-
Créer la stack avec des commandes
Fenêtre de terminal # Créer le podpodman pod create --name api-demo -p 8080:80# Backend (simule une API)podman run -d --pod api-demo --name backend \python:3.12-alpine python -m http.server 3000# Frontend (nginx)podman run -d --pod api-demo --name frontend \nginx:alpine -
Vérifier que ça fonctionne
Fenêtre de terminal # Étatpodman pod pspodman ps --pod# Testcurl http://localhost:8080 -
Générer le YAML
Fenêtre de terminal podman kube generate api-demo > api-demo.yamlcat api-demo.yaml -
Éditer le YAML
Ajoutez des variables d'environnement, des labels, etc.
-
Supprimer et recréer
Fenêtre de terminal podman pod rm -f api-demopodman kube play api-demo.yaml -
Vérifier
Fenêtre de terminal podman pod pscurl http://localhost:8080 -
Nettoyer
Fenêtre de terminal podman kube down api-demo.yaml
Checklist de validation :
-
podman pod psmontre le pod -
podman ps --podmontre les conteneurs -
curl localhost:8080fonctionne - Après
kube down,podman pod psest vide -
podman volume lsmontre les volumes restants (si PVC)
Dépannage
Section intitulée « Dépannage »Les échecs de kube play se manifestent au moment de la création des ressources, rarement après. Le tableau ci-dessous couvre les messages les plus fréquents ; les commandes qui suivent servent à inspecter ce que Podman a réellement créé avant d'échouer.
Erreurs courantes
Section intitulée « Erreurs courantes »La plupart des erreurs viennent de trois sources : un pod qui existe déjà (nom en conflit), une image mal référencée (oubli du registry), ou un port déjà utilisé.
| Erreur | Cause | Solution |
|---|---|---|
Error: pod already exists | Pod avec ce nom existe | --replace ou supprimer le pod |
image not found | Image avec tag local | Ajouter docker.io/library/ |
hostPort already in use | Port déjà utilisé | Changer le hostPort ou libérer le port |
ConfigMap not found | ConfigMap pas dans le même fichier | Mettre ConfigMap avant Pod dans le YAML |
Commandes de diagnostic
Section intitulée « Commandes de diagnostic »Ces commandes répondent dans l'ordre à trois questions : le pod existe-t-il, ses conteneurs tournent-ils, et que disent leurs logs. La dernière, avec --start=false, crée les ressources sans les démarrer : elle valide la structure du manifest sans rien exécuter.
# Voir ce qui a été créépodman pod pspodman ps --pod
# Logs d'un conteneurpodman logs <container-name>
# Inspecter le podpodman pod inspect <pod-name>
# Vérifier un YAML sans le lancerpodman kube play --start=false <fichier.yaml>Le pod ne démarre pas
Section intitulée « Le pod ne démarre pas »Un pod créé dont les conteneurs sortent aussitôt pointe vers deux causes : une image absente localement et introuvable au pull, ou un hostPort déjà occupé sur la machine. podman logs livre le message de sortie du conteneur, ss -tlnp identifie le processus qui tient le port.
# Vérifier les logspodman kube play my-pod.yamlpodman logs <container-name>
# Problème d'image ?podman pull docker.io/library/nginx:alpine
# Problème de port ?ss -tlnp | grep <port>Bonnes pratiques
Section intitulée « Bonnes pratiques »Un manifest destiné à finir sur un vrai cluster gagne à être organisé dès le départ comme s'il y était déjà. Trois points font la différence à l'usage : l'arborescence des fichiers, l'ordre des objets dans un document multi-ressources, et le nom pleinement qualifié des images.
Organisation des fichiers
Section intitulée « Organisation des fichiers »Séparer une base commune des variantes par environnement prépare le passage à Kustomize ou Helm, qui reposent tous deux sur ce découpage. Tant que vous restez sur Podman, chaque fichier reste jouable seul avec kube play.
Répertoiredeploy/
Répertoirebase/
- pod.yaml
- configmap.yaml
- secret.yaml
Répertoiredev/
- pod-dev.yaml
Répertoireprod/
- pod-prod.yaml
Conventions
Section intitulée « Conventions »Ces quatre règles neutralisent la plupart des erreurs listées au dépannage. L'ordre ConfigMap avant Pod est le plus contraignant : Podman lit le document séquentiellement et échoue si un Pod référence un objet qu'il n'a pas encore créé.
- Un fichier par ressource ou tout dans un fichier avec
---séparateurs - ConfigMap avant Pod : les dépendances d'abord
- Images complètes :
docker.io/library/nginx:alpinepasnginx:alpine - Labels explicites : pour le filtrage et la documentation
Versionner les YAML
Section intitulée « Versionner les YAML »Un manifest généré est un artefact reproductible : mieux vaut le committer que conserver la suite de commandes podman run qui l'a produit. Le suffixe daté sert aux essais jetables, Git prend le relais dès que le fichier devient la source de vérité.
# Générer avec datepodman kube generate my-pod > pod-$(date +%Y%m%d).yaml
# Ou utiliser Gitgit add pod.yamlgit commit -m "feat: add resource limits"À retenir
Section intitulée « À retenir »Podman couvre les deux sens du cycle, du manifest vers le pod et du pod vers le manifest, ce qui suffit à valider la syntaxe et le comportement des conteneurs. Le passage sur un vrai cluster reste obligatoire dès que le réseau Kubernetes entre en jeu.
kube play: lance un YAML Kubernetes localementkube generate: crée un YAML depuis des conteneurs existants--replace: recrée le pod sans suppression manuellekube down: supprime le pod, préserve les volumes (sauf--force)- Workflow : CLI → generate → edit → play → iterate
- Scope limité : pas de Services, Ingress, NetworkPolicy
Prochaines étapes
Section intitulée « Prochaines étapes »Deux directions s'ouvrent ici : industrialiser l'exécution locale avec Quadlet, qui transforme ces manifests en unités systemd, ou basculer sur un cluster réel avec K3s pour retrouver les Services et l'Ingress absents de Podman.