## Introduction La planification des capacités d'un déploiement Kubernetes consiste à estimer et à configurer le CPU, la mémoire et le nombre de réplicas dont vos charges de travail ont besoin pour fonctionner de manière fiable sans gaspiller d'infrastructure. Chaque déploiement que vous créez consomme des ressources du cluster. Si vous définissez des requests et des limits trop basses, les pods peuvent être évincés ou limités en cas de charge. Si vous les définissez trop hautes, vous surprovisionnez, ce qui augmente les coûts et prive d'autres charges de travail de ressources. Une approche structurée sépare l'estimation, la configuration et la vérification, ce qui réduit les conjectures et les retouches. Ce guide présente une méthode pratique avec des commandes et des exemples concrets. Vous apprendrez à inventorier votre cluster, à choisir des valeurs de départ sûres, à observer l'utilisation réelle, à configurer l'autoscaling, à diagnostiquer les pannes et à maintenir une liste de contrôle reproductible. L'approche fonctionne pour les services web sans état, les API et les charges de travail similaires. À la fin, vous serez en mesure de dimensionner les déploiements avec confiance et d'éviter les pannes courantes liées aux ressources. ## Inventaire des versions et de l'environnement Avant de définir des paramètres de capacité, confirmez votre version de Kubernetes et les ressources API disponibles. Les champs liés à la capacité comme `requests`, `limits` et le comportement de l'autoscaling ont évolué au fil des versions. Exécutez ces commandes sur un cluster avec un accès `kubectl` : ```bash kubectl version --short kubectl api-resources | grep -E 'deployments|horizontalpodautoscalers|resourcequotas' ``` La sortie attendue montrera vos versions client et serveur, puis une liste de groupes API pertinents. Par exemple, sur Kubernetes 1.28 : ```text Client Version: v1.28.2 Server Version: v1.28.4 deployments apps/v1 horizontalpodautoscalers autoscaling/v2 resourcequotas v1 ``` Si vous utilisez un service Kubernetes managé, la version peut apparaître dans la console cloud. Notez la version mineure exacte car les champs HPA v2 diffèrent de v1. Vérifiez également que l'API des métriques est disponible si vous prévoyez d'autoscaler sur le CPU ou la mémoire : ```bash kubectl get --raw /apis/metrics.k8s.io/v1beta1 | head -n 5 ``` Vous devriez voir une liste de ressources, pas une erreur 404. Si l'API des métriques est absente, installez le metrics-server ou l'équivalent de votre fournisseur. Pour la planification des capacités, vous devez aussi connaître la capacité des nœuds et la pression existante sur les ressources : ```bash kubectl describe nodes | grep -A 5 'Allocated resources' ``` La sortie montre les requests et limits de CPU et de mémoire en pourcentages. Utilisez cela pour évaluer la marge de manœuvre. Si les nœuds sont déjà demandés à plus de 80 %, évitez d'ajouter de grands déploiements sans étendre le cluster. Documentez ces versions et ces chiffres avant de continuer ; ils influencent la façon dont vous interprétez les métriques et configurez l'autoscaling. ## Chemin de configuration sûr Commencez la planification des capacités avec un seul déploiement et des estimations prudentes. N'essayez pas de dimensionner tous les services à la fois. Un pilote étroit vous permet d'observer l'utilisation réelle et de vous ajuster sans risquer la production. Nous allons créer un déploiement d'application web simple avec des `requests` et des `limits` explicites, puis le faire évoluer manuellement et via HPA. Le responsable de ce dimensionnement initial est le responsable technique du service, qui devra revoir ces valeurs après la première semaine de trafic de production et mensuellement par la suite. ### Étape 1 : Commencer avec un manifeste de base Supposons que vous ayez une application web sans état qui utilise typiquement 100 millicores (0,1 CPU) et 128 Mio de mémoire par instance sous charge légère. Le pic peut tripler cela. Définissez les `requests` initiales sur l'utilisation typique et les `limits` sur le pic attendu. Créez `web-deployment.yaml` : ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: web-app spec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: web image: nginx:1.25 resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "300m" memory: "256Mi" ``` Appliquez-le : ```bash kubectl apply -f web-deployment.yaml ``` Résultat attendu : ```text deployment.apps/web-app created ``` Vérifiez les pods : ```bash kubectl get pods -l app=web ``` Vous devriez voir deux pods en cours d'exécution après quelques secondes. Les requests garantissent que chaque pod obtient au moins les ressources spécifiées. Les limits plafonnent la quantité qu'il peut consommer en pointe. Si le pod dépasse sa limite de mémoire, il est tué par OOM. S'il dépasse sa limite de CPU, il est limité (throttling). C'est pourquoi les limites ne doivent pas être fixées arbitrairement hautes : le throttling peut dégrader la latence avant que vous ne le remarquiez. ### Étape 2 : Observer l'utilisation réelle avant de scaler Laissez le déploiement s'exécuter sous un trafic réaliste pendant quelques heures ou jours. Surveillez la consommation de ressources par pod : ```bash kubectl top pods -l app=web ``` Exemple de sortie : ```text NAME CPU(cores) MEMORY(bytes) web-app-6b4d8c9f5-abcde 45m 102Mi web-app-6b4d8c9f5-fghij 52m 118Mi ``` Ce sont des échantillons d'utilisation réelle. Si l'utilisation typique est bien inférieure aux requests, vous pouvez réduire les requests pour améliorer le bin packing. Si elle approche des limites, augmentez les limites ou le nombre de réplicas. Pour une moyenne rapide sur 5 minutes, utilisez `kubectl top pods --containers` pour un détail par conteneur. Enregistrez ces valeurs ; elles informent l'étape suivante. ### Étape 3 : Configurer l'Horizontal Pod Autoscaler (HPA) L'autoscaling basé sur le CPU ou la mémoire est le principal mécanisme réactif de capacité. Créez un HPA ciblant 60 % d'utilisation CPU moyenne sur les pods : ```bash kubectl autoscale deployment web-app --cpu=60% --min=2 --max=8 ``` Résultat attendu : ```text horizontalpodautoscaler.autoscaling/web-app autoscaled ``` Vérifiez le HPA : ```bash kubectl get hpa web-app ``` Exemple de sortie : ```text NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE web-app Deployment/web-app 10%/60% 2 8 2 5m ``` La colonne `TARGETS` montre l'utilisation actuelle par rapport à la cible. Attendez quelques minutes et répétez s'il n'y a pas de charge. Pour simuler une charge, vous pouvez temporairement exécuter un pod générateur de charge. Cependant, ne vous fiez pas uniquement au HPA ; il réagit après coup. Définissez un nombre minimum de réplicas raisonnable pour la charge de base afin d'éviter les démarrages à froid. ### Étape 4 : Ajuster les requests et limits de manière itérative Une fois que vous avez des métriques, ajustez le manifeste. Supposons que le pod moyen utilise 80m de CPU et 150 Mio de mémoire en pic. Vos limites d'origine étaient trop basses ; augmentez-les à 500m de CPU et 512 Mio de mémoire, mais gardez les requests à 100m et 128 Mio pour éviter de sur-réserver. Mettez à jour le déploiement : ```bash kubectl patch deployment web-app -p '{"spec":{"template":{"spec":{"containers":[{"name":"web","resources":{"limits":{"cpu":"500m","memory":"512Mi"}}}]}}}}' ``` Cela déclenche une mise à jour progressive. Surveillez le déploiement : ```bash kubectl rollout status deployment/web-app ``` Résultat attendu : ```text deployment "web-app" successfully rolled out ``` Revérifiez l'utilisation et le HPA. Cette boucle itérative est au cœur de la planification des capacités. Le responsable technique doit revoir ces paramètres chaque semaine pendant le premier mois, puis mensuellement, ou après tout changement de trafic significatif. ### Étape 5 : Envisager l'affinité de nœud et les Pod Disruption Budgets (optionnel) La planification des capacités inclut aussi la disponibilité. Si votre déploiement ne doit pas avoir tous ses réplicas sur un seul nœud, utilisez l'anti-affinité de pod. Par exemple, pour répartir les pods sur les nœuds, ajoutez ceci à la spécification du pod : ```yaml affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - web topologyKey: kubernetes.io/hostname ``` De plus, définissez un PodDisruptionBudget (PDB) pour limiter les perturbations volontaires pendant la maintenance. Exemple de PDB : ```yaml apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: web-app-pdb spec: minAvailable: 1 selector: matchLabels: app: web ``` Appliquez avec `kubectl apply -f pdb.yaml`. Cela garantit qu'au moins un pod reste disponible pendant les drains de nœuds. L'équipe plateforme possède les politiques de PDB et les revoit trimestriellement. ## Vérification et diagnostics Après la configuration, vérifiez que les paramètres de capacité sont efficaces et que le système se comporte comme prévu sous charge. Utilisez plusieurs signaux d'observabilité. ### Vérifier les requests et limits de ressources ```bash kubectl get deployment web-app -o json | jq '.spec.template.spec.containers[0].resources' ``` Résultat attendu : ```json { "limits": { "cpu": "500m", "memory": "512Mi" }, "requests": { "cpu": "100m", "memory": "128Mi" } } ``` ### Vérifier le statut et les événements du HPA ```bash kubectl describe hpa web-app ``` Cherchez les événements de mise à l'échelle. Extrait d'exemple : ```text Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 10m horizontal-pod-autoscaler New size: 3; reason: cpu resource utilization (percentage of request) above target ``` Si vous voyez des mises à l'échelle rapides et répétées, vérifiez le flapping causé par des seuils trop bas ou des métriques bruitées. Ajustez la cible ou ajoutez des fenêtres de stabilisation comme décrit plus loin. ### Test de charge pour confirmer la mise à l'échelle Générez de la charge à l'aide d'un pod temporaire avec un outil de charge HTTP simple. Par exemple, exécutez `hey` depuis un conteneur de débogage : ```bash kubectl run load-generator --image=williamyeh/hey --rm -it -- -n 10000 -c 10 http://web-app-service/ ``` Surveillez le HPA et le nombre de pods pendant le test : ```bash watch kubectl get hpa, pods ``` Après le test, vérifiez que le nombre de réplicas est redescendu au minimum une fois la charge arrêtée. Cela confirme que le HPA réduit correctement l'échelle. Le propriétaire du service doit exécuter un tel test avant toute version majeure ou événement de trafic. ### Diagnostiquer les problèmes de capacité Si des pods sont en attente, vérifiez les ressources des nœuds : ```bash kubectl describe pod | grep -A 3 Events ``` Un événement courant est `0/2 nodes are available: 2 Insufficient cpu`. Cela indique que le cluster manque de capacité pour le CPU demandé. Vous devez soit réduire les requests, ajouter des nœuds, soit réduire d'autres charges de travail. Si des pods sont tués par OOM, inspectez la raison de terminaison : ```bash kubectl get pod -o json | jq '.status.containerStatuses[0].state.terminated.reason' ``` La sortie `OOMKilled` signifie que la limite de mémoire était trop basse. Augmentez la limite ou corrigez la fuite de l'application. Utilisez `kubectl describe node` pour voir la pression mémoire. Ces étapes de diagnostic doivent être documentées dans votre runbook pour les ingénieurs d'astreinte. ## Modes de défaillance et récupération La planification des capacités peut mal tourner de plusieurs façons. Connaître les défaillances courantes et comment les récupérer est essentiel. Chaque mode de défaillance ci-dessous liste un propriétaire désigné qui doit être alerté et l'action de récupération typique. ### OOMKilled et évictions de pods **Défaillance :** Les pods dépassent les limites de mémoire et sont tués, provoquant des redémarrages et des interruptions potentielles. **Détection :** `kubectl get pods` montre `RESTARTS` qui augmente, et `kubectl describe pod` montre `OOMKilled`. **Récupération :** Augmentez temporairement les limites de mémoire, mais recherchez la cause. Si l'application a besoin de plus de mémoire en pic, ajustez les limites et éventuellement les requests. Par exemple, pour définir la limite de mémoire à 1 Gio : ```bash kubectl set resources deployment web-app --limits=memory=1Gi ``` Vérifiez ensuite avec `kubectl rollout status`. Si l'application a une fuite de mémoire, corriger le code est la solution à long terme. Le développeur de l'application est propriétaire de l'utilisation de la mémoire et doit être alerté dès le premier événement OOMKilled. ### Throttling CPU causant une latence élevée **Défaillance :** Les limites de CPU sont trop basses ; les pods sont limités mais pas tués, ce qui entraîne des réponses lentes. **Détection :** Vérifiez les métriques de conteneur pour `container_cpu_cfs_throttled_seconds_total`, ou corrélez une latence élevée avec les atteintes de limite CPU dans votre tableau de bord de surveillance. **Récupération :** Augmentez les limites de CPU. Par exemple : ```bash kubectl set resources deployment web-app --limits=cpu=1 ``` Surveillez la latence après le changement. Le SRE d'astreinte doit effectuer cette récupération, puis planifier une revue de capacité avec le propriétaire du service. ### Épuisement des ressources du nœud et pods en attente **Défaillance :** Les nœuds manquent de CPU ou de mémoire allouable, de sorte que les nouveaux pods ne peuvent pas être planifiés. **Détection :** `kubectl get pods` montre l'état `Pending` ; `kubectl describe node` montre une pression élevée sur les ressources. **Récupération :** Réduisez les requests de ressources pour les déploiements non critiques, ajoutez des nœuds ou utilisez l'autoscaler de cluster s'il est disponible. Pour réduire temporairement les requests : ```bash kubectl set resources deployment web-app --requests=cpu=50m,memory=64Mi ``` Cela peut affamer les pods en cas de mauvaise utilisation, alors ne le faites que lorsque vous comprenez la charge de travail. L'administrateur du cluster possède la capacité des nœuds et doit être notifié lorsque la pression dépasse 80 %. ### Mauvaise configuration du HPA causant du flapping **Défaillance :** L'utilisation cible du HPA est trop basse ou les métriques sont bruitées, provoquant des mises à l'échelle rapides en montée et en descente, déstabilisant le service. **Détection :** Les événements HPA montrent des `SuccessfulRescale` fréquents avec des tailles alternées. **Récupération :** Ajustez le pourcentage cible ou ajoutez une fenêtre de stabilisation. Par exemple, pour définir la stabilisation de réduction à 5 minutes : ```bash kubectl patch hpa web-app --type='json' -p='[{"op": "replace", "path": "/spec/behavior/scaleDown/stabilizationWindowSeconds", "value": 300}]' ``` Vérifiez avec `kubectl get hpa web-app -o yaml`. Le propriétaire du service doit revoir les paramètres HPA mensuellement et après tout changement de modèle de trafic. ### Rollback d'un mauvais changement de capacité Si un changement cause des problèmes, annulez le déploiement à la révision précédente : ```bash kubectl rollout undo deployment/web-app ``` Cela revient à la dernière configuration connue comme bonne. Vérifiez le statut du déploiement. Pour revenir à une révision spécifique, listez d'abord les révisions : ```bash kubectl rollout history deployment/web-app ``` Puis utilisez `--to-revision=`. Le gestionnaire de version possède les décisions de rollback et doit documenter l'incident. ## Pièges courants et comment les éviter Au-delà des modes de défaillance, plusieurs pratiques piègent fréquemment les équipes. Reconnaître ces pièges tôt permet d'économiser du temps et des ressources. ### Définir des requests et limits trop proches **Pourquoi cela arrive :** Les équipes copient les valeurs de production vers le développement sans ajuster pour un trafic plus faible, ou elles définissent les deux à la même valeur élevée pour éviter le throttling. **Conséquence :** La sur-réservation gaspille la capacité du cluster et conduit à un mauvais bin packing, augmentant les coûts. **Comment éviter :** Basez les requests sur l'utilisation moyenne réelle mesurée avec `kubectl top`, et les limites sur l'utilisation de pointe plus une marge de sécurité de 20 à 30 %. Revoyez mensuellement. ### Ignorer la capacité et la topologie des nœuds **Pourquoi cela arrive :** Les développeurs se concentrent sur les limites au niveau des pods et oublient que les nœuds ont des ressources finies. **Conséquence :** Les pods peuvent être non planifiables même si le cluster semble avoir des ressources libres si les requests sont déséquilibrées. **Comment éviter :** Utilisez régulièrement `kubectl describe nodes` pour vérifier `Allocated resources`. Envisagez l'affinité et l'anti-affinité de nœud pour répartir la charge. Alertez lorsque les requests des nœuds dépassent 70 %. ### Trop compter sur le HPA sans réplicas minimum **Pourquoi cela arrive :** Les équipes supposent que le HPA gérera toute la mise à l'échelle, y compris depuis zéro, mais le HPA ne scale que sur la base de la charge actuelle et peut être lent à réagir aux pics soudains. **Conséquence :** Démarrages à froid et trafic abandonné pendant les pics de trafic. **Comment éviter :** Définissez un nombre minimum de réplicas capable de gérer le trafic de base plus une marge. Utilisez des requests CPU burstable pour permettre des pics sans throttling. Le propriétaire du service doit définir ce minimum. ### Ne pas surveiller l'utilisation réelle après le déploiement **Pourquoi cela arrive :** Après le déploiement avec des estimations initiales, les équipes passent à la tâche suivante. **Conséquence :** Les paramètres de ressources deviennent obsolètes, conduisant à un sur ou sous-provisionnement. **Comment éviter :** Établissez une cadence de revue (mensuelle) et utilisez des tableaux de bord automatisés pour suivre les tendances d'utilisation des ressources. Le responsable d'ingénierie possède ce processus. ### Utiliser les quotas de ressources comme un instrument brutal **Pourquoi cela arrive :** Les administrateurs définissent des quotas serrés pour contrôler les coûts, mais ils restreignent les charges de travail légitimes. **Conséquence :** Les déploiements échouent à se planifier, frustrant les développeurs. **Comment éviter :** Coordonnez les quotas avec les plans de capacité réels. Revoyez l'utilisation des quotas mensuellement et ajustez en fonction de la croissance projetée. L'équipe plateforme possède la politique de quotas. ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle pour revoir la capacité de tout déploiement Kubernetes avant et après les changements. Le propriétaire du service est responsable de chaque élément ; le responsable d'ingénierie revoit la liste complétée mensuellement. | Élément | Commande ou vérification | Résultat attendu | |---------|--------------------------|------------------| | Version du cluster et API des métriques disponible | `kubectl version --short`, `kubectl get --raw /apis/metrics.k8s.io/v1beta1` | Version serveur >= 1.20, le point de terminaison des métriques renvoie une liste de ressources | | Marge de capacité des nœuds | `kubectl describe nodes \| grep -A 5 'Allocated resources'` | Requests CPU et mémoire inférieures à 70 % en moyenne | | Le déploiement a des requests et des limits | `kubectl get deployment -o json \| jq '.spec.template.spec.containers[0].resources'` | Les requests et limits sont définies pour le CPU et la mémoire | | HPA configuré avec min/max et cible raisonnables | `kubectl get hpa ` | Min replicas >= 2, max <= capacité du nœud, cible 50-80 % | | Utilisation réelle dans les limites | `kubectl top pods -l app=