Kubernetes Intermédiaire : Deployments, Services et Volumes
🎯 Objectifs
À la fin de ce module, vous serez capable de :
- ✅ Créer et gérer des Deployments (scaling, mise à jour, rollback)
- ✅ Distinguer et utiliser les types de Services (ClusterIP, NodePort, LoadBalancer)
- ✅ Injecter de la configuration via des variables d'environnement
- ✅ Utiliser emptyDir et PersistentVolumeClaims pour le stockage
- ✅ Configurer les resource requests et limits
- ✅ Déboguer des pods avec
kubectl describeetkubectl logs
📋 Prérequis
- Module Découvrir Kubernetes complété
- Cluster local fonctionnel (Minikube ou kind)
kubectlconfiguré et fonctionnel
🚀 Deployments : gérer les pods à grande échelle
Pourquoi ne pas utiliser des Pods directement ?
Un Pod seul n'est pas restartable. Si le nœud qui l'héberge tombe, le Pod disparaît définitivement. Un Deployment résout ce problème :
- Il garantit qu'un nombre fixe de réplicas tourne en permanence
- Il redémarre automatiquement les pods en échec
- Il permet les mises à jour et les rollbacks contrôlés
Structure d'un Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-app
namespace: default
spec:
replicas: 3 # Combien de pods ?
selector: # Comment identifier "mes" pods ?
matchLabels:
app: mon-app
template: # Le template de chaque pod
metadata:
labels:
app: mon-app
spec:
containers:
- name: app
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256MiCommandes essentielles
# Créer
kubectl apply -f deployment.yaml
# Voir les replicas
kubectl get deployments
kubectl get pods -l app=mon-app
# Scaler
kubectl scale deployment mon-app --replicas=5
# Mettre à jour l'image
kubectl set image deployment/mon-app app=nginx:1.28
# Voir l'historique des rollouts
kubectl rollout history deployment/mon-app
# Annuler la dernière mise à jour
kubectl rollout undo deployment/mon-app🔌 Services : exposer vos applications
Types de Services
Kubernetes propose 4 types de Services :
| Type | Portée | Usage typique |
|---|---|---|
| ClusterIP | Cluster uniquement | Communication inter-pods |
| NodePort | Accessible depuis l'extérieur via port du nœud | Dev, tests |
| LoadBalancer | IP publique via le cloud provider | Production cloud |
| ExternalName | Alias DNS vers un service externe | Intégration services externes |
ClusterIP (défaut)
apiVersion: v1
kind: Service
metadata:
name: mon-app
spec:
type: ClusterIP # Type par défaut
selector:
app: mon-app # Sélectionne les pods avec ce label
ports:
- port: 80 # Port du Service (accessible dans le cluster)
targetPort: 3000 # Port du conteneurNodePort
spec:
type: NodePort
selector:
app: mon-app
ports:
- port: 80
targetPort: 3000
nodePort: 30080 # Port sur chaque nœud (30000-32767)Accès depuis l'extérieur : http://<IP_NODE>:30080
⚙️ Variables d'environnement et ConfigMaps
Injection directe
spec:
containers:
- name: app
image: mon-app:latest
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "3000"Depuis un ConfigMap
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
NODE_ENV: "production"
LOG_LEVEL: "info"
DATABASE_HOST: "postgres-service"# Dans le Deployment : envFrom pour tout injecter
envFrom:
- configMapRef:
name: app-config💾 Stockage dans Kubernetes
emptyDir : partage temporaire entre conteneurs
emptyDir crée un volume temporaire qui vit le temps du pod. Utile pour partager des données entre les conteneurs d'un même pod (sidecar pattern) :
spec:
volumes:
- name: cache-volume
emptyDir: {}
containers:
- name: app
volumeMounts:
- name: cache-volume
mountPath: /tmp/cache
- name: sidecar
volumeMounts:
- name: cache-volume
mountPath: /sharedPersistentVolume et PersistentVolumeClaim
Pour les données qui doivent survivre à la mort d'un pod :
# PersistentVolumeClaim : demande de stockage
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes:
- ReadWriteOnce # Un seul pod peut écrire à la fois
resources:
requests:
storage: 5Gi# Utilisation dans le Deployment
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
containers:
- name: app
volumeMounts:
- name: data
mountPath: /data📊 Resource Requests et Limits
Les resources évitent qu'un pod monopolise toutes les ressources du nœud :
resources:
requests: # Ce que le scheduler réserve pour ce pod
cpu: 100m # 100 millicores = 0.1 vCPU
memory: 128Mi
limits: # Maximum absolu - le pod est tué si dépassé
cpu: 500m
memory: 512MiRègle : Toujours définir requests et limits. Sans requests, le scheduler ne peut pas placer le pod correctement. Sans limits, un pod peut crasher tout le nœud.
🔍 Debugging
# Décrire un pod (events, état des conteneurs)
kubectl describe pod <pod-name>
# Logs d'un conteneur (en temps réel avec -f)
kubectl logs <pod-name> -f
kubectl logs <pod-name> --previous # Logs du container précédent (après crash)
# Shell interactif
kubectl exec -it <pod-name> -- /bin/sh
# Port-forward pour tester sans Service
kubectl port-forward pod/<pod-name> 8080:3000