Module 4 – Stockage, ConfigMaps et Secrets

Apprenez à gérer la configuration applicative, sécuriser les secrets et provisionner du stockage persistant avec StatefulSets.

Kubernetes est stateless par défaut. Pour faire tourner des applications configurables ou stateful, vous devez maîtriser ConfigMaps, Secrets et le stockage persistant. Ce module vous guide étape par étape.

Objectifs

  • Injecter de la configuration et des secrets dans vos Pods.
  • Provisionner des volumes persistants dynamiques avec StorageClass/PVC.
  • Déployer un StatefulSet avec persistance et vérifier la résilience.

1. ConfigMaps et Secrets

Utilisez un ConfigMap pour stocker des données non sensibles, un Secret pour le sensible (chiffré au repos selon votre solution).

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-cfg
  namespace: staging
data:
  APP_MODE: staging
  FEATURE_FLAG_X: "true"

Secret en clair (Kubernetes se charge d’encoder en base64) :

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: staging
stringData:
  username: reporting
  password: S3cureP@ssw0rd

Injection dans le Pod :

envFrom:
  - configMapRef:
      name: web-cfg
  - secretRef:
      name: db-credentials

Ou montage en volume :

volumes:
  - name: app-config
    configMap:
      name: web-cfg
containers:
  - name: web
    volumeMounts:
      - name: app-config
        mountPath: /app/config

2. Volumes éphémères vs persistants

  • emptyDir : se vide si le Pod est recréé.
  • hostPath : pointe vers le système de fichiers du nœud (à éviter en production).
  • projected : combine ConfigMap + Secret + DownwardAPI.

3. PersistentVolume, PersistentVolumeClaim, StorageClass

Dans la plupart des clusters managés, la création d’un PVC déclenche automatiquement un PV grâce à une StorageClass.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

PersistentVolume (environnement de labo, stockage local) :

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-local
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: fast
  hostPath:
    path: /data/k8s-lab

Claim correspondant :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-web
  namespace: staging
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: fast

Vérifiez l’appairage :

kubectl get pv,pvc -n staging

4. StatefulSet avec volumes

Exemple PostgreSQL à deux réplicas :

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: data
spec:
  serviceName: postgres
  replicas: 2
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:15
          env:
            - name: POSTGRES_DB
              value: analytics
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: username
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi
        storageClassName: fast

N’oubliez pas le Service headless :

apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: data
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
    - name: tcp
      port: 5432

5. Lab guidé

  1. Créer le namespace data, le ConfigMap web-cfg et le Secret db-credentials.
  2. Déployer le StatefulSet PostgreSQL + Service headless.
  3. Créer un Pod utilitaire : kubectl run psql --image=postgres:15 -it --rm -- psql -h postgres-0.postgres.data.svc.cluster.local -U reporting analytics.
  4. Insérer quelques lignes, supprimer le Pod postgres-0 et vérifier que les données persistent.
  5. Monter le PVC en lecture seule dans un Job de backup :
apiVersion: batch/v1
kind: Job
metadata:
  name: pg-backup
  namespace: data
spec:
  template:
    spec:
      restartPolicy: OnFailure
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: data-postgres-0
            readOnly: true
      containers:
        - name: backup
          image: bitnami/kubectl:1.29
          command:
            - /bin/sh
            - -c
            - |
              tar czf /backup/postgres-$(date +%F).tgz -C /var/lib/postgresql/data .
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data

Montez un PVC ou un emptyDir supplémentaire pour stocker l’archive.

Solution détaillée

  1. ConfigMap/Secret montés
    kubectl exec deploy/webapp -n staging -- env | grep APP_MODE → valeur staging.
    kubectl exec deploy/webapp -n staging -- cat /app/config/APP_MODE renvoie the same.
  2. PVC appairé
    kubectl get pvc data-web -n staging doit être Bound au PV pv-local. Vérifiez kubectl get pv pv-local -o jsonpath='{.spec.claimRef.name}'.
  3. StatefulSet
    kubectl get sts postgres -n data → READY 2/2.
    kubectl get pods -n data -l app=postgres -o wide montre postgres-0, postgres-1 avec volumes montés.
  4. Persistance
    Dans le Pod utilitaire, créez une table et insérez une ligne. Supprimez postgres-0, attendez le redémarrage : les données doivent toujours être présentes.

    kubectl delete pod postgres-0 -n data
    kubectl run -n data psql --rm -it --image=postgres:15 -- psql -h postgres-0.postgres.data.svc.cluster.local -U reporting analytics
    analytics=# SELECT * FROM demo;
    
  5. Job de backup
    kubectl get jobs -n datapg-backup Completed. Les logs kubectl logs job/pg-backup -n data confirment la création du tar.

Archiver ces vérifications dans votre journal et conserver les manifestes (ConfigMap, Secret, PVC, StatefulSet) dans votre dépôt de formation.

Pièges fréquents

  • Oublier la clé storageClassName → le PVC reste en Pending.
  • Ajouter des fichiers dans un volume monté sous /etc/config alors que le Pod n’a pas les droits (pensez aux fsGroup).
  • Changer la taille d’un PVC sans que la StorageClass supporte l’expansion.
  • Utiliser des Secrets en clair sans chiffrement de etcd (voir module 5 pour KMS).

Challenge avancé

  • Activer la rotation automatique des Secrets via un CronJob.
  • Tester un opérateur comme Zalando Postgres Operator pour gérer automatiquement les StatefulSets.
  • Comparer Kustomize et Helm pour templater ConfigMaps/Secrets (ex. helm upgrade --install web charts/web --set-file secretFiles.db=secrets.yaml).

Ressources

Checklist

  • ✅ Vos Pods consomment ConfigMaps et Secrets correctement.
  • ✅ Vous savez provisionner un volume persistant et vérifier son appairage.
  • ✅ Vous avez déployé un StatefulSet et validé la persistance après redémarrage.