De Docker Compose à Kubernetes : architecture complète, distributions (K8s, K3s, K0s, MicroK8s), objets fondamentaux, networking, Ingress, scaling automatique et déploiement en production.
Les variables d'environnement hardcodées dans les manifestes sont un antipattern. Kubernetes offre des mécanismes dédiés : ConfigMaps pour les données de configuration, Secrets pour les données sensibles, et PersistentVolumes pour le stockage persistant.
Un ConfigMap stocke des paires clé/valeur ou des fichiers entiers. Utile pour les URLs de service, les feature flags, les configurations Nginx, les fichiers de config YAML.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
NODE_ENV: production
LOG_LEVEL: info
API_URL: https://api.example.com
nginx.conf: |
server {
listen 80;
location / {
proxy_pass http://localhost:3000;
}
}Via variables d'environnement :
spec:
containers:
- name: app
env:
- name: NODE_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: NODE_ENV
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
# Ou injecter toutes les clés d'un coup
envFrom:
- configMapRef:
name: app-configVia volume (pour les fichiers de config) :
spec:
volumes:
- name: nginx-config
configMap:
name: app-config
items:
- key: nginx.conf
path: nginx.conf
containers:
- name: nginx
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/
readOnly: trueMise à jour : quand vous mettez à jour un ConfigMap monté en volume, K8s synchronise les fichiers automatiquement (délai ~1 min). Pour les variables d'environnement, il faut redémarrer les pods (kubectl rollout restart deployment/mon-app).
Les Secrets fonctionnent comme des ConfigMaps mais les valeurs sont encodées en base64 et, avec les bonnes configurations, chiffrées au repos dans etcd.
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: production
type: Opaque
stringData:
# stringData accepte les valeurs en clair (K8s encode en base64 automatiquement)
database-url: postgresql://user:password@postgres:5432/mydb
jwt-secret: mon-secret-tres-long-et-aleatoire
redis-password: autre-secretkubectl apply -f secret.yaml
# Voir les secrets (base64)
kubectl get secret app-secrets -o yaml
# Décoder une valeur
kubectl get secret app-secrets -o jsonpath='{.data.jwt-secret}' | base64 -dNe committez jamais un fichier Secret dans Git. Utilisez des outils comme Sealed Secrets, External Secrets Operator, ou Vault pour gérer les secrets K8s en sécurité.
spec:
containers:
- name: app
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: app-secrets
key: jwt-secret
envFrom:
- secretRef:
name: app-secrets # toutes les clés comme variables d'env| Type | Usage |
|---|---|
Opaque | Données génériques (défaut) |
kubernetes.io/tls | Certificats TLS (cert.pem + key.pem) |
kubernetes.io/dockerconfigjson | Credentials registry Docker |
kubernetes.io/service-account-token | Token de service account |
Secret pour un registry Docker privé :
kubectl create secret docker-registry registry-credentials \
--docker-server=registry.example.com \
--docker-username=mon-user \
--docker-password=mon-token \
-n productionspec:
imagePullSecrets:
- name: registry-credentials
containers:
- name: app
image: registry.example.com/mon-app:1.0.0Le stockage des Pods est éphémère par défaut — quand un pod est supprimé, ses données disparaissent. Les PersistentVolumes (PV) permettent de découpler le cycle de vie du stockage de celui du pod.
Définit la classe de stockage disponible. K3s inclut une StorageClass local-path par défaut.
kubectl get storageclass
# NAME PROVISIONER
# local-path (default) rancher.io/local-pathVous demandez du stockage via un PVC. K8s provisionne un PV correspondant automatiquement (provisionnement dynamique).
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: production
spec:
accessModes:
- ReadWriteOnce # monté en lecture/écriture sur un seul nœud
storageClassName: local-path
resources:
requests:
storage: 20GiModes d'accès :
| Mode | Signification |
|---|---|
ReadWriteOnce (RWO) | Lecture/écriture par un seul nœud |
ReadOnlyMany (ROX) | Lecture seule par plusieurs nœuds |
ReadWriteMany (RWX) | Lecture/écriture par plusieurs nœuds (NFS, CephFS) |
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: production
spec:
replicas: 1 # RWO = un seul pod peut écrire
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16-alpine
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres-datakubectl get pvc -n production
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# postgres-data Bound pvc-abc123... 20Gi RWOBound = le PVC est associé à un PV. Pending = pas de stockage disponible correspondant.
spec:
volumes:
- name: cache
emptyDir: {}
containers:
- name: app
volumeMounts:
- name: cache
mountPath: /tmp/cache
- name: sidecar
volumeMounts:
- name: cache
mountPath: /cacheemptyDir est créé vide au démarrage du pod et supprimé quand le pod est supprimé. Utile pour partager des fichiers entre conteneurs d'un même pod (logs, cache temporaire).
Configuration et stockage maîtrisés. Le chapitre suivant couvre le networking avancé : types de Services, Ingress NGINX, cert-manager pour le TLS automatique.