
Vos conteneurs ont besoin de partager des fichiers entre eux ? D’accéder à une configuration externe ? De recevoir des secrets ? Les volumes applicatifs permettent de monter des données dans vos Pods — qu’il s’agisse de fichiers temporaires, de configurations projetées ou de données sensibles.
Ce guide couvre les volumes utilisés côté développeur. Pour le stockage persistant géré par les administrateurs (PV, PVC, StorageClass), voir Storage Kubernetes.
Prérequis : concepts des Pods et un cluster fonctionnel.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Utiliser emptyDir pour partager des données temporaires entre conteneurs
- Monter un ConfigMap ou un Secret comme fichiers injectés
- Combiner plusieurs sources avec projected
- Comprendre les cycles de vie et limites de chaque type de volume
- Appliquer les bonnes pratiques de sécurité et de permissions
Qu’est-ce qu’un volume Kubernetes ?
Section intitulée « Qu’est-ce qu’un volume Kubernetes ? »Un volume Kubernetes est un espace de stockage monté dans un ou plusieurs conteneurs d’un Pod. Selon son type, il peut être :
- Éphémère : créé avec le Pod, supprimé avec lui (
emptyDir) - Projeté : généré depuis un objet API Kubernetes (
ConfigMap,Secret,downwardAPI) - Lié au nœud : adossé au système de fichiers de la machine hôte (
hostPath)
Pourquoi utiliser des volumes ?
Section intitulée « Pourquoi utiliser des volumes ? »Les données écrites dans le système de fichiers propre au conteneur (writable layer) ne constituent pas une solution fiable pour partager ou conserver des données applicatives. Les volumes Kubernetes fournissent une abstraction dédiée à cet usage :
- Partage : plusieurs conteneurs d’un même Pod peuvent monter le même volume
- Injection : Kubernetes peut pré-remplir le volume avec des configurations ou secrets
- Isolation : le volume existe indépendamment du système de fichiers du conteneur
Types de volumes applicatifs
Section intitulée « Types de volumes applicatifs »| Type | Nature | Cycle de vie pratique |
|---|---|---|
| emptyDir | éphémère | Dure tant que le Pod reste sur le nœud — supprimé si le Pod disparaît |
| configMap | projeté | Reflète un objet ConfigMap — pas du stockage persistant |
| secret | projeté | Reflète un objet Secret — pas du stockage persistant |
| downwardAPI | projeté | Généré à partir des métadonnées du Pod |
| projected | projeté | Combine ConfigMap, Secret, downwardAPI et serviceAccountToken |
| hostPath | nœud local | Dépend du nœud — non portable, non résilient |
emptyDir : partage temporaire entre conteneurs
Section intitulée « emptyDir : partage temporaire entre conteneurs »Un volume emptyDir est créé vide quand le Pod démarre et supprimé quand le Pod disparaît du nœud. Idéal pour partager des données temporaires entre conteneurs du même Pod.
Exemple : deux conteneurs qui partagent des données
Section intitulée « Exemple : deux conteneurs qui partagent des données »apiVersion: v1kind: Podmetadata: name: emptydir-demospec: containers: - name: writer image: busybox:1.36 command: ['sh', '-c', 'echo "Données partagées" > /cache/data.txt && sleep 3600'] volumeMounts: - name: cache-volume mountPath: /cache - name: reader image: busybox:1.36 command: ['sh', '-c', 'sleep 5 && cat /cache/data.txt && sleep 3600'] volumeMounts: - name: cache-volume mountPath: /cache volumes: - name: cache-volume emptyDir: {}kubectl apply -f emptydir-demo.yamlkubectl logs emptydir-demo -c readerSortie :
Données partagéesLe conteneur reader lit bien le fichier écrit par writer — ils partagent le même volume.
emptyDir en mémoire (RAM)
Section intitulée « emptyDir en mémoire (RAM) »Pour des performances maximales (cache, scratch space), utilisez la RAM via tmpfs :
volumes:- name: cache-volume emptyDir: medium: Memory sizeLimit: 100MiQuand utiliser emptyDir
Section intitulée « Quand utiliser emptyDir »| Cas d’usage | Adapté ? |
|---|---|
| Cache applicatif temporaire | ✅ Oui |
| Scratch space pour calculs intermédiaires | ✅ Oui |
| Partage de fichiers entre conteneurs sidecar | ✅ Oui |
| Stockage de données qui doivent survivre au Pod | ❌ Non — utilisez un PVC |
ConfigMap : injecter de la configuration
Section intitulée « ConfigMap : injecter de la configuration »Un ConfigMap monté en volume crée des fichiers — un par clé — dans le répertoire cible. C’est un volume projeté : Kubernetes génère les fichiers à partir d’un objet API.
Créer le ConfigMap
Section intitulée « Créer le ConfigMap »apiVersion: v1kind: ConfigMapmetadata: name: app-configdata: config.json: | { "database": "postgresql", "port": 5432 } settings.ini: | [app] debug = false log_level = infoMonter le ConfigMap
Section intitulée « Monter le ConfigMap »apiVersion: v1kind: Podmetadata: name: configmap-volume-demospec: containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'ls -la /etc/config && cat /etc/config/config.json && sleep 3600'] volumeMounts: - name: config-volume mountPath: /etc/config readOnly: true volumes: - name: config-volume configMap: name: app-configkubectl apply -f configmap-volume.yamlkubectl apply -f pod-configmap-volume.yamlkubectl logs configmap-volume-demoSortie :
total 0lrwxrwxrwx 1 root root 18 Mar 22 10:00 config.json -> ..data/config.jsonlrwxrwxrwx 1 root root 19 Mar 22 10:00 settings.ini -> ..data/settings.ini{ "database": "postgresql", "port": 5432}Chaque clé du ConfigMap devient un fichier (via des liens symboliques pour permettre les mises à jour atomiques).
Monter une seule clé
Section intitulée « Monter une seule clé »Pour ne monter qu’un fichier spécifique :
volumes:- name: config-volume configMap: name: app-config items: - key: config.json path: app-config.json # Nom du fichier dans le conteneurMise à jour automatique (avec délai)
Section intitulée « Mise à jour automatique (avec délai) »Les fichiers sont mis à jour automatiquement quand le ConfigMap change. Cependant, ce n’est pas instantané : le délai dépend du kubelet et de sa stratégie de détection des changements (Watch, TTL, ou accès direct API). Il peut aller jusqu’au délai de synchronisation du kubelet (--sync-frequency, 1 minute par défaut) plus le délai de propagation du cache.
Secret : injecter des données sensibles
Section intitulée « Secret : injecter des données sensibles »Un Secret monté en volume fonctionne comme un ConfigMap, mais pour des données sensibles (credentials, certificats, clés API).
Créer le Secret (avec stringData)
Section intitulée « Créer le Secret (avec stringData) »Utilisez stringData pour écrire les valeurs en clair dans le manifest — Kubernetes les encodera automatiquement en base64 :
apiVersion: v1kind: Secretmetadata: name: db-credentialstype: OpaquestringData: username: admin password: password123Monter le Secret
Section intitulée « Monter le Secret »apiVersion: v1kind: Podmetadata: name: secret-volume-demospec: containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'cat /etc/secrets/username && echo && cat /etc/secrets/password && sleep 3600'] volumeMounts: - name: secret-volume mountPath: /etc/secrets readOnly: true volumes: - name: secret-volume secret: secretName: db-credentials defaultMode: 0400 # Lecture seule pour le propriétairekubectl apply -f secret-volume.yamlkubectl apply -f pod-secret-volume.yamlkubectl logs secret-volume-demoSortie :
adminpassword123Le fichier contient la valeur décodée — pas le base64.
Sécurité des Secrets
Section intitulée « Sécurité des Secrets »Bonnes pratiques :
- Montez toujours les Secrets en
readOnly: true - Définissez des permissions restrictives avec
defaultMode: 0400 - Ne loggez jamais le contenu des fichiers secrets
- Envisagez des solutions comme Sealed Secrets ou External Secrets Operator pour la gestion
downwardAPI : métadonnées du Pod
Section intitulée « downwardAPI : métadonnées du Pod »Le volume downwardAPI expose les métadonnées du Pod comme fichiers. Utile pour que l’application connaisse son contexte sans code spécifique Kubernetes.
apiVersion: v1kind: Podmetadata: name: downward-demo labels: app: myapp version: v1spec: containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'cat /etc/podinfo/labels && echo "---" && cat /etc/podinfo/name && sleep 3600'] volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: true volumes: - name: podinfo downwardAPI: items: - path: labels fieldRef: fieldPath: metadata.labels - path: name fieldRef: fieldPath: metadata.name - path: namespace fieldRef: fieldPath: metadata.namespace - path: cpu-limit resourceFieldRef: containerName: app resource: limits.cpuChamps disponibles
Section intitulée « Champs disponibles »| fieldPath | Contenu |
|---|---|
metadata.name | Nom du Pod |
metadata.namespace | Namespace |
metadata.labels | Labels (format key="value") |
metadata.annotations | Annotations |
metadata.uid | UID du Pod |
spec.nodeName | Nom du nœud |
spec.serviceAccountName | ServiceAccount |
status.podIP | IP du Pod |
projected : combiner plusieurs sources
Section intitulée « projected : combiner plusieurs sources »Un volume projected permet de monter plusieurs sources (ConfigMap, Secret, downwardAPI, serviceAccountToken) dans un seul répertoire. C’est la méthode standard pour agréger des données de sources différentes.
apiVersion: v1kind: Podmetadata: name: projected-demo labels: app: myappspec: containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'ls -la /etc/all-config && sleep 3600'] volumeMounts: - name: all-config mountPath: /etc/all-config readOnly: true volumes: - name: all-config projected: sources: - configMap: name: app-config items: - key: config.json path: config.json - secret: name: db-credentials items: - key: password path: db-password - downwardAPI: items: - path: pod-name fieldRef: fieldPath: metadata.nameRésultat dans /etc/all-config :
config.json (depuis ConfigMap)db-password (depuis Secret)pod-name (depuis downwardAPI)hostPath : accès au système de fichiers du nœud
Section intitulée « hostPath : accès au système de fichiers du nœud »Un volume hostPath monte un répertoire ou fichier du nœud hôte dans le Pod.
apiVersion: v1kind: Podmetadata: name: hostpath-demospec: containers: - name: logger image: busybox:1.36 command: ['sh', '-c', 'ls /var/log && sleep 3600'] volumeMounts: - name: host-logs mountPath: /var/log readOnly: true volumes: - name: host-logs hostPath: path: /var/log type: DirectoryTypes de hostPath
Section intitulée « Types de hostPath »| Type | Comportement |
|---|---|
"" (vide) | Pas de vérification |
DirectoryOrCreate | Crée le répertoire s’il n’existe pas |
Directory | Le répertoire doit exister (échec sinon) |
FileOrCreate | Crée le fichier s’il n’existe pas |
File | Le fichier doit exister (échec sinon) |
Gérer les permissions avec securityContext
Section intitulée « Gérer les permissions avec securityContext »Les problèmes de permissions sont fréquents avec les volumes. Le securityContext permet de les résoudre.
Définir le groupe propriétaire avec fsGroup
Section intitulée « Définir le groupe propriétaire avec fsGroup »apiVersion: v1kind: Podmetadata: name: fsgroup-demospec: securityContext: fsGroup: 1000 # Tous les fichiers montés appartiendront à ce groupe runAsUser: 1000 runAsGroup: 1000 containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'ls -la /data && sleep 3600'] volumeMounts: - name: data mountPath: /data volumes: - name: data emptyDir: {}Définir les permissions des fichiers
Section intitulée « Définir les permissions des fichiers »Pour les volumes ConfigMap et Secret :
volumes:- name: secret-volume secret: secretName: db-credentials defaultMode: 0400 # -r-------- (lecture seule pour le propriétaire)| Mode | Permissions | Usage |
|---|---|---|
0644 | -rw-r--r-- | Fichiers de configuration lisibles par tous |
0600 | -rw------- | Fichiers sensibles, écriture par le propriétaire |
0400 | -r-------- | Secrets, lecture seule |
0755 | -rwxr-xr-x | Scripts exécutables |
Sous-chemins (subPath)
Section intitulée « Sous-chemins (subPath) »Pour monter un fichier spécifique sans écraser le répertoire existant :
volumeMounts:- name: config mountPath: /etc/nginx/nginx.conf subPath: nginx.conf # Ne monte que ce fichierAlternative sans subPath : Montez le ConfigMap dans un sous-répertoire et créez un lien symbolique dans un init container.
Combiner plusieurs volumes
Section intitulée « Combiner plusieurs volumes »Un Pod peut monter plusieurs volumes de types différents :
apiVersion: v1kind: Podmetadata: name: multi-volumespec: securityContext: fsGroup: 101 # Groupe nginx containers: - name: app image: nginx:alpine volumeMounts: - name: config mountPath: /etc/nginx/conf.d readOnly: true - name: secrets mountPath: /etc/nginx/ssl readOnly: true - name: cache mountPath: /var/cache/nginx volumes: - name: config configMap: name: nginx-config - name: secrets secret: secretName: nginx-certs defaultMode: 0400 - name: cache emptyDir: {}Tableau de décision
Section intitulée « Tableau de décision »| Besoin | Volume conseillé | Remarque |
|---|---|---|
| Partager temporairement entre conteneurs | emptyDir | Disparaît avec le Pod |
| Cache haute performance | emptyDir avec medium: Memory | Compte dans la mémoire du Pod |
| Injecter une config sous forme de fichiers | configMap | Volume projeté, mises à jour auto |
| Injecter un secret sous forme de fichiers | secret | Volume projeté, toujours en readOnly |
| Exposer le nom/namespace/labels du Pod | downwardAPI | Volume projeté |
| Combiner config + secret + metadata | projected | Méthode standard d’agrégation |
| Accéder à un chemin du nœud | hostPath | Éviter sauf DaemonSet/debug |
| Stocker des données persistantes | PVC | Pas un volume applicatif |
Anti-patterns à éviter
Section intitulée « Anti-patterns à éviter »| Anti-pattern | Pourquoi c’est problématique | Solution |
|---|---|---|
Utiliser hostPath comme stockage persistant | Non portable, risques de sécurité | Utiliser un PVC |
| Modifier des fichiers depuis un ConfigMap/Secret | Ce sont des sources projetées, pas un espace d’écriture | Copier dans un emptyDir si besoin de modifier |
Oublier que subPath casse la propagation | Les mises à jour ConfigMap ne seront pas reflétées | Monter le répertoire complet ou redémarrer le Pod |
Supposer qu’un emptyDir survit au Pod | Le contenu est perdu si le Pod est supprimé ou reschedulé | Utiliser un PVC pour les données importantes |
Oublier readOnly: true sur les Secrets | Risque de modification accidentelle | Toujours spécifier readOnly: true |
Ignorer les permissions (fsGroup, defaultMode) | Erreurs “permission denied” au runtime | Définir explicitement le contexte de sécurité |
Monter des chemins sensibles via hostPath | Contournement des contrôles de sécurité du cluster | Utiliser les Pod Security Standards pour bloquer |
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
MountVolume.SetUp failed for volume | ConfigMap/Secret introuvable | Vérifier que la ressource existe dans le même namespace |
| Fichiers vides | ConfigMap/Secret vide | kubectl get configmap xxx -o yaml pour vérifier |
Permission denied | Mode trop restrictif ou mauvais user/group | Ajuster defaultMode, fsGroup ou runAsUser |
| Volume non monté | Nom mal référencé | Vérifier que volumeMounts.name correspond exactement à volumes.name |
| Fichier non mis à jour après modification ConfigMap | Utilisation de subPath | Redémarrer le Pod ou ne pas utiliser subPath |
Pod bloqué en ContainerCreating | Volume non disponible | kubectl describe pod pour voir les événements |
Commandes de diagnostic
Section intitulée « Commandes de diagnostic »# Voir les montages déclaréskubectl get pod mon-pod -o jsonpath='{.spec.volumes}' | jq
# Voir les montages effectifs dans le conteneurkubectl describe pod mon-pod | grep -A 20 "Mounts:"
# Lister les fichiers dans un volume montékubectl exec mon-pod -- ls -la /chemin/du/montage
# Vérifier les permissionskubectl exec mon-pod -- stat /chemin/du/fichier
# Voir les événements liés aux volumeskubectl get events --field-selector involvedObject.name=mon-podRéflexes CKAD
Section intitulée « Réflexes CKAD »-
Identifier où déclarer
spec.volumes[]: déclare le volume et sa sourcespec.containers[].volumeMounts[]: monte le volume dans un conteneur- Le
namedoit correspondre exactement entre les deux
-
Créer rapidement un Pod avec volume
Fenêtre de terminal # Générer le YAML de basekubectl run mypod --image=nginx --dry-run=client -o yaml > pod.yaml# Puis ajouter volumes et volumeMounts manuellement -
Vérifier vite le montage
Fenêtre de terminal kubectl describe pod mypod | grep -A 5 "Mounts:"kubectl exec mypod -- ls -la /chemin/montagekubectl exec mypod -- cat /chemin/montage/fichier -
Différencier volume partagé et volume projeté
emptyDir: les conteneurs peuvent lire et écrire — c’est un espace partagéconfigMap,secret,downwardAPI: injectés par Kubernetes — à traiter comme read-only
-
Piège courant à l’examen
Le volume est déclaré mais pas monté, ou le nom ne correspond pas. Toujours vérifier la correspondance
volumes.name↔volumeMounts.name.
Volumes éphémères génériques (aperçu)
Section intitulée « Volumes éphémères génériques (aperçu) »Pour des besoins avancés, Kubernetes propose aussi des ephemeral volumes génériques qui permettent d’utiliser des drivers CSI pour créer des volumes éphémères (par exemple, un disque SSD temporaire provisionné dynamiquement). Ces volumes sont supprimés avec le Pod.
volumes:- name: scratch ephemeral: volumeClaimTemplate: spec: accessModes: ["ReadWriteOnce"] storageClassName: fast-ssd resources: requests: storage: 10GiConsultez la documentation Kubernetes sur les ephemeral volumes pour approfondir.
À retenir
Section intitulée « À retenir »- emptyDir : partage temporaire entre conteneurs — disparaît avec le Pod
- configMap et secret : volumes projetés depuis des objets API — pas du stockage persistant
- projected : combine plusieurs sources dans un seul répertoire — méthode standard d’agrégation
- downwardAPI : expose les métadonnées du Pod comme fichiers
- hostPath : accès au système de fichiers du nœud — risques majeurs, à éviter en production
- Toujours monter ConfigMap et Secret en readOnly: true
- Avec subPath, les mises à jour ne sont pas propagées
- Utilisez securityContext et fsGroup pour gérer les permissions
- Un volume se déclare dans
spec.volumes, se monte avecvolumeMounts— les noms doivent correspondre