
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 »La colonne à lire en premier est Cycle de vie pratique : elle dit ce qui reste quand le Pod disparaît. Aucun de ces six types ne survit à une replanification sur un autre nœud, y compris hostPath, qui pointe pourtant vers un disque réel. Les quatre types marqués « projeté » ne stockent d'ailleurs rien : le kubelet reconstruit leur contenu à partir d'un objet de l'API à chaque démarrage de conteneur, ce qui explique qu'ils soient toujours considérés comme des sources en lecture.
| 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 »Le manifeste ci-dessous déclare un seul volume et le monte dans deux conteneurs au même chemin /cache. C'est la clé du mécanisme : le nom cache-volume apparaît trois fois, une fois dans volumes et une fois dans chaque volumeMounts. Le sleep 5 du conteneur reader évite une course au démarrage, puisque rien ne garantit l'ordre de lancement des conteneurs d'un Pod. En production, on remplace cette temporisation par une boucle d'attente ou un init container.
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 »La ligne qui compte est la dernière. Les trois premiers cas ont un point commun : la perte des données est sans conséquence, l'application sait les régénérer. Dès que ce n'est plus vrai, emptyDir devient un piège, parce qu'il fonctionne parfaitement en test et perd tout au premier redémarrage de Pod, événement banal lors d'une mise à jour de Deployment ou d'un drain de nœud.
| 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 »Chaque clé de la section data deviendra un fichier portant ce nom, et sa valeur en constituera le contenu. Le pipe | du YAML préserve les retours à la ligne, ce qui permet de coller un fichier de configuration complet sans le transformer. Choisissez donc des clés qui ressemblent à des noms de fichiers valides (config.json, settings.ini) : une clé contenant un / est refusée par l'API.
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 »Le montage remplace entièrement le contenu du répertoire mountPath : si /etc/config existait déjà dans l'image, ses fichiers deviennent invisibles tant que le volume est monté. C'est la cause la plus fréquente d'applications qui ne démarrent plus après l'ajout d'un ConfigMap sur un répertoire système. Le readOnly: true n'est pas décoratif ici : sans lui, un processus peut tenter d'écrire dans le volume et échouer de façon obscure, puisque la source projetée refuse l'écriture.
apiVersion: v1kind: Podmetadata: name: configmap-volume-demospec: containers: - name: app image: busybox:1.36@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662 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é »La section items restreint la projection aux clés listées et permet au passage de renommer le fichier dans le conteneur. Cette sélection est utile quand un même ConfigMap sert plusieurs applications : chacune ne voit que ce qui la concerne. Attention au comportement par défaut, contre-intuitif : dès que items est présent, toutes les clés non listées disparaissent du volume.
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.
Une exception annule complètement ce mécanisme : le montage par subPath. Dans ce cas, le fichier est copié une fois et n'est plus jamais actualisé, même si le ConfigMap change. La section Sous-chemins détaille cette limitation et les contournements possibles.
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 »Le montage est identique à celui d'un ConfigMap, à deux réglages près qui doivent devenir des réflexes : readOnly: true sur le volumeMounts et defaultMode: 0400 sur la source. Le second fixe les permissions POSIX des fichiers projetés, ici lecture seule pour le propriétaire uniquement. Sans ce réglage, Kubernetes applique 0644 et n'importe quel processus du conteneur peut lire le mot de passe, y compris un shell de debug lancé par un tiers.
apiVersion: v1kind: Podmetadata: name: secret-volume-demospec: containers: - name: app image: busybox:1.36@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662 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 »Un Secret monté en volume est nettement plus sûr qu'une variable d'environnement : le fichier peut être relu après rotation, il n'apparaît pas dans kubectl describe pod, et il n'est pas hérité par les processus enfants ni exposé dans un dump de crash. Cela ne règle pas pour autant la question du stockage : la protection au repos se joue au niveau du cluster, pas du manifeste.
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 »Un point critique avant de lire ce tableau : seuls les champs metadata.* sont utilisables dans un volume downwardAPI. Les entrées spec.nodeName, spec.serviceAccountName et status.podIP existent bien dans la Downward API, mais uniquement sous forme de variables d'environnement (env avec valueFrom.fieldRef) ; les déclarer dans un volume fait rejeter le Pod par l'API. Notez enfin que les limites de ressources n'utilisent pas fieldRef mais resourceFieldRef, avec le nom du conteneur cible en paramètre.
| 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. Variable d'environnement uniquement, rejeté dans un volume |
spec.serviceAccountName | ServiceAccount. Variable d'environnement uniquement |
status.podIP | IP du Pod. Variable d'environnement uniquement |
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@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662 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)image : monter une image OCI comme volume (GA en 1.36)
Section intitulée « image : monter une image OCI comme volume (GA en 1.36) »Depuis Kubernetes 1.36, le type de volume image est passé GA (KEP-4639, « OCI Volume Source », alpha en 1.31 et bêta en 1.33). Il permet de monter le contenu d'une image OCI directement dans un Pod, en lecture seule. Les cas d'usage typiques : injecter une configuration versionnée, livrer un dataset ou un modèle ML packagé en image, fournir des outils CLI à un sidecar (debug, audit) sans gonfler l'image principale.
Exemple : monter des outils dans un sidecar
Section intitulée « Exemple : monter des outils dans un sidecar »Le champ reference accepte la même syntaxe qu'un image: de conteneur, donc aussi bien un tag qu'un digest @sha256, forme recommandée puisqu'elle rend le contenu du volume reproductible. Deux prérequis conditionnent le fonctionnement : une version de Kubernetes 1.31 ou supérieure, et un runtime de conteneur qui implémente la fonctionnalité côté CRI. Sur un cluster dont le runtime ne la supporte pas, le Pod reste bloqué en création au lieu de renvoyer une erreur de validation à kubectl apply.
Depuis la version 1.33, l'option subPath du volumeMounts fonctionne aussi sur un volume image et permet de ne monter qu'un sous-répertoire de l'image. Si ce sous-répertoire n'existe pas, la création du conteneur échoue et le message remonte dans les événements du kubelet, visibles avec kubectl describe pod.
apiVersion: v1kind: Podmetadata: name: imagevol-demospec: containers: - name: app image: alpine:3.20 command: ['sleep', '300'] volumeMounts: - name: tools mountPath: /opt/tools readOnly: true volumes: - name: tools image: reference: registry.k8s.io/e2e-test-images/agnhost:2.40 pullPolicy: IfNotPresentLe contenu de l'image cible (binaire agnhost, bin/, certificats…) apparaît dans /opt/tools/. Toute écriture est refusée :
kubectl exec imagevol-demo -- ls /opt/tools# agnhost agnhost-2 bin coredns ...
kubectl exec imagevol-demo -- touch /opt/tools/foo# touch: /opt/tools/foo: Read-only file systemChamps supportés
Section intitulée « Champs supportés »La source image n'expose que deux champs, ce qui la rend simple mais rigide : ni sélection de fichiers façon items, ni réglage de permissions façon defaultMode. Le contenu monté est exactement le système de fichiers de l'image, tel quel. Privilégiez la forme repo/image@sha256:... dans la colonne des valeurs : avec un tag mutable, un pullPolicy: Always peut changer le contenu du volume d'un redémarrage à l'autre sans qu'aucun manifeste n'ait bougé.
| Champ | Rôle | Valeurs |
|---|---|---|
reference | Référence OCI complète de l'image | repo/image:tag ou repo/image@sha256:... |
pullPolicy | Politique de tirage | Always, IfNotPresent, Never |
Quand préférer image à un autre volume
Section intitulée « Quand préférer image à un autre volume »Le critère de choix n'est pas la taille des données mais qui les modifie et à quelle fréquence. Un ConfigMap se change depuis le cluster en une commande, une image OCI impose de reconstruire et republier : cette lourdeur est précisément l'intérêt du volume image pour un dataset ou un modèle, puisqu'elle rend toute modification traçable et signable. À l'inverse, elle disqualifie ce type de volume pour une configuration qu'une équipe ajuste plusieurs fois par semaine.
| Besoin | Type recommandé |
|---|---|
| Configuration ou dataset versionnés et signés (Cosign) | image, l'image OCI est immuable et auditable |
| Configuration éditable depuis le cluster | ConfigMap |
| Données sensibles | Secret |
| Données partagées entre conteneurs d'un Pod | emptyDir |
| Données persistantes au-delà de la vie du Pod | PVC + StorageClass (voir Storage) |
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 un fichier du nœud hôte directement dans le Pod, sans aucune couche d'abstraction. Le Pod voit alors le système de fichiers de la machine avec les mêmes droits que le processus conteneurisé. Ce type de volume existe pour les agents d'infrastructure qui doivent lire les journaux ou les métriques du nœud ; hors de ce cas, il crée plus de problèmes qu'il n'en résout.
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 »Le champ type est votre seul garde-fou, et il est vide par défaut. Dans ce cas, Kubernetes n'effectue aucune vérification avant le montage : un chemin mal orthographié ne provoque pas d'erreur au démarrage du Pod, et l'application se retrouve à travailler sur un emplacement vide. Renseignez systématiquement Directory ou File pour obtenir un échec immédiat et lisible plutôt qu'un comportement dégradé qu'il faudra diagnostiquer en production. Les variantes OrCreate ne conviennent qu'aux DaemonSets qui doivent initialiser leur propre arborescence sur le nœud.
| 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 »fsGroup se déclare au niveau du Pod, pas du conteneur, et agit sur les volumes montés : le kubelet applique récursivement ce GID aux fichiers du volume et ajoute le groupe au processus. C'est le réglage qui résout la plupart des permission denied quand un conteneur tourne avec un utilisateur non root. Le trio fsGroup, runAsUser et runAsGroup va généralement de pair : le premier donne l'accès au volume, les deux autres déterminent l'identité qui exécute le processus.
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@sha256:73aaf090f3d85aa34ee199857f03fa3a95c8ede2ffd4cc2cdb5b94e566b11662 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 »defaultMode s'applique aux volumes projetés (configMap, secret, downwardAPI, projected) et vaut 0644 par défaut, une valeur trop permissive pour un secret. La notation reste octale : en YAML, 0400 est bien interprété comme les droits r--------, mais si vous écrivez le manifeste en JSON, la valeur doit être donnée en décimal (256), sinon les permissions obtenues n'auront rien à voir avec celles attendues.
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) »subPath répond à un besoin précis : injecter un seul fichier dans un répertoire qui contient déjà d'autres fichiers de l'image. Sans lui, monter un ConfigMap sur /etc/nginx/ masquerait tout le contenu d'origine du répertoire. Avec lui, seul nginx.conf est remplacé et le reste survit. Ce confort se paie par une limitation qu'il faut connaître avant de l'adopter.
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 »Le manifeste ci-dessous représente le cas courant en production : une configuration en lecture seule, des certificats TLS en lecture seule avec permissions restreintes, et un cache inscriptible. Le fsGroup: 101 correspond au groupe nginx de l'image officielle Alpine et donne au processus non root le droit d'écrire dans /var/cache/nginx. Repérez la logique : seul le volume sur lequel l'application doit écrire n'a pas de readOnly: true.
apiVersion: v1kind: Podmetadata: name: multi-volumespec: securityContext: fsGroup: 101 # Groupe nginx containers: - name: app image: nginx:1.30-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 »Ce tableau condense les choix vus jusqu'ici. Parcourez-le par la colonne Besoin et non par le type de volume : dans la pratique, l'erreur vient presque toujours de la démarche inverse, quand on choisit hostPath ou emptyDir parce qu'ils sont faciles à écrire avant de vérifier qu'ils correspondent au besoin. La dernière ligne est la frontière du guide : dès qu'une donnée doit survivre au Pod, on quitte les volumes applicatifs pour le domaine des PersistentVolumeClaims.
| 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 »Ces sept erreurs ont un point commun : elles fonctionnent en environnement de test. Un hostPath marche parfaitement sur un cluster à un nœud, un emptyDir conserve ses données tant qu'on ne redéploie pas, et un ConfigMap monté par subPath semble à jour tant que personne ne le modifie. Elles se manifestent au moment le moins choisi : la montée en charge, la mise à jour ou la panne de nœud.
| 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 »Presque tous les incidents de volume se lisent dans les événements du Pod, pas dans les logs applicatifs : commencez donc toujours par kubectl describe pod. Un Pod bloqué en ContainerCreating signale un problème de montage, alors qu'un Pod en Running qui se plaint de permissions relève du securityContext. Cette distinction oriente le diagnostic bien plus vite que la lecture du manifeste.
| 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 »Ces cinq commandes se lancent dans l'ordre, du manifeste vers le système de fichiers réel. Le point de bascule est la troisième : si kubectl exec ... ls montre les fichiers attendus, le problème est applicatif ; s'il ne montre rien, le montage a échoué et la dernière commande, sur les événements, en donnera la raison. Notez que la première nécessite jq sur votre poste, pas dans le cluster.
# 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 »L'examen CKAD est chronométré et n'accorde aucun point pour un YAML élégant. Les cinq réflexes ci-dessous visent le gain de temps : générer une base plutôt que l'écrire, vérifier en une commande plutôt qu'en trois, et connaître par cœur le piège qui coûte le plus de points, la correspondance entre volumes.name et volumeMounts.name.
-
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
Testez vos connaissances
Section intitulée « Testez vos connaissances »Dix questions pour vérifier que les distinctions du guide sont acquises : volume éphémère contre volume projeté, effet de subPath sur la propagation, rôle respectif de fsGroup et de defaultMode. Une réponse hésitante sur l'une d'elles pointe la section à relire.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Les StatefulSets : Le volume propre à chaque replica, pour les applications à état.
- Introduction au stockage : Les PersistentVolume et PersistentVolumeClaim, au-delà des volumes éphémères.
- StorageClass : Le provisionnement dynamique qui évite de créer les volumes à la main.