## Introduction

La planification de capacité dans Kubernetes consiste à traduire la demande réelle en un mélange adapté de requêtes (requests), limites (limits), répliques et nœuds, puis à valider le résultat par des mesures. Ce guide propose un workflow pratique, piloté par l'exemple, que vous pouvez appliquer à un service unique dès aujourd'hui et étendre à l'ensemble d'un cluster.

Vous apprendrez à :

- Définir des SLO (Service Level Objectives — objectifs de niveau de service) et une charge de référence.

- Dimensionner les requêtes et limites CPU et mémoire à partir de mesures.

- Choisir les signaux de scaling pour le HPA (Horizontal Pod Autoscaler) et utiliser le VPA (Vertical Pod Autoscaler) en toute sécurité.

- Planifier les types de nœuds et la densité de pods avec des marges de sécurité.

- Intégrer le stockage et le réseau dans vos calculs.

- Construire des tableaux de bord Prometheus liés aux risques.

Sujets connexes utilisés dans les exemples : images Docker, valeurs Helm, pics GitLab CI/CD, Nginx Ingress, stockage Ceph, et métriques Prometheus.

## Vue d'ensemble du workflow

Utilisez cette séquence reproductible pour chaque charge de travail :

- Définir les SLO et prévoir la demande.

- Mesurer une ligne de base sur une réplique.

- Convertir les mesures en requêtes et limites.

- Choisir les répliques et les signaux HPA ; activer le VPA en mode recommandation seule.

- Planifier les nœuds et la densité de pods ; garantir du headroom (marge de manœuvre).

- Inclure les budgets stockage et réseau.

- Ajouter tableaux de bord et alertes liés aux SLO et à la saturation.

- Exécuter un pilote, examiner les résultats, puis élargir le périmètre.

Chaque étape produit des artefacts que vous pouvez versionner dans Git : values.yaml, Deployment, HPA, et configurations de tableaux de bord.

## Définir les SLO et les lignes de base

Choisissez des cibles concrètes et des entrées sur lesquelles vous dimensionnerez :

- SLO disponibilité : 99,9 % mensuel pour le service.

- SLO latence : p95 latence HTTP <= 200 ms en pointe.

- Trafic : prévision QPS de pointe, tailles de payload, et jobs d'arrière-plan.

- Fenêtres batch : pics GitLab CI/CD en début d'heure ; jobs de données nocturnes.

Mesurez une réplique unique sous une charge réaliste :

- CPU par requête (ms CPU par requête sur une base 1 vCPU).

- Working set mémoire (MiB) en régime permanent et pendant les pics (GC, compactions).

- I/O : requêtes par seconde et octets pour le stockage et le réseau.

Commandes rapides d'exemple :

kubectl top pods -n app
kubectl describe node <nodeName> | grep -E "capacity|allocatable|pods" 
 Si vous placez le service derrière Nginx Ingress, activez les access logs et exportez QPS et histogrammes de latence vers Prometheus.

## Dimensionnement des requêtes et limites

Traduisez les mesures en spécifications de ressources Kubernetes. L'objectif est d'éviter le throttling CPU et les OOMKills tout en préservant l'efficacité du bin packing.

Supposons une API stateless derrière Nginx avec ces mesures de référence sur une réplique :

- QPS de pointe : 200

- CPU par requête : 2 ms sur une base 1 vCPU

- Working set mémoire stable : 350 MiB, p95 pic : 500 MiB

Calcul CPU :

- CPU nécessaire = QPS × CPU_par_requête = 200 × 0,002 = 0,4 vCPU

- Ajouter 20 % de marge pour jitter et bibliothèques : 0,48 vCPU

- Arrondir requests.cpu à 600m ; fixer limits.cpu à 1200m pour autoriser le burst sans starvation

Calcul mémoire :

- Request = working set p95 × 1,2 = 500 MiB × 1,2 = 600 MiB

- Limit = Request × 1,5 = 900 MiB (laisse de la place avant OOM tout en surfuyant les fuites)

Exemple valeurs Helm (values.yaml) :

resources:
 requests:
 cpu: "600m"
 memory: "600Mi"
 limits:
 cpu: "1200m"
 memory: "900Mi" 
 Extrait Deployment :

apiVersion: apps/v1
kind: Deployment
metadata:
 name: api
spec:
 replicas: 2
 template:
 spec:
 containers:
 - name: api
 image: registry.local/api:1.2.3
 resources:
 requests:
 cpu: "600m"
 memory: "600Mi"
 limits:
 cpu: "1200m"
 memory: "900Mi" 
 Règles pratiques défendables :

- Démarrer les requests près de l'usage p95 observé ; garder les limits entre 1,5x et 2x les requests pour les services CPU-bound.

- Pour la mémoire, fixer les limits prudemment. Trop serrées causent des OOMKills. Trop larges cachent les fuites. Surveillez les redémarrages.

- Recalculez après chaque release modifiant les caractéristiques de performance.

## Répliques et Autoscaling

Choisissez les répliques initiales pour la disponibilité, puis ajoutez l'autoscaling.

Répliques pour la disponibilité :

- Minimum 2 répliques par zone pour la HA (High Availability — haute disponibilité).

- Si zone unique : 3 répliques réparties sur plusieurs nœuds pour tolérer le drain d'un nœud.

HPA utilisant l'utilisation CPU :

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
 name: api-hpa
spec:
 scaleTargetRef:
 apiVersion: apps/v1
 kind: Deployment
 name: api
 minReplicas: 2
 maxReplicas: 10
 metrics:
 - type: Resource
 resource:
 name: cpu
 target:
 type: Utilization
 averageUtilization: 70
 behavior:
 scaleUp:
 policies:
 - type: Percent
 value: 100
 periodSeconds: 60
 stabilizationWindowSeconds: 30
 scaleDown:
 stabilizationWindowSeconds: 300 
 Métriques personnalisées (recommandées quand la latence ou la file d'attente importent plus que le CPU) :

- Utiliser le taux de requêtes par réplique, la profondeur de file, ou la latence p90 comme signaux via Prometheus Adapter.

Exemple stanza HPA métrique personnalisée :

- type: Pods
 pods:
 metric:
 name: http_requests_per_second
 target:
 type: AverageValue
 averageValue: "150" 
 VPA en mode recommend-only pour éviter de lutter contre le HPA :

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
 name: api-vpa
spec:
 targetRef:
 apiVersion: "apps/v1"
 kind: Deployment
 name: api
 updatePolicy:
 updateMode: "Off" 
 Lisez les recommandations et ajustez les requests dans Git, puis redéployez.

Scaling fenêtré dans le temps pour pics batch :

- Utiliser un CronJob qui patche les répliques du Deployment avant et après une fenêtre connue.

- Alternativement, fournir une métrique de taille de backlog au HPA pour qu'il réagisse automatiquement.

## Nœuds et Bin Packing

Calculez l'allocatable, plafonnez la densité de pods, et évitez les noisy neighbors (voisins bruyants).

Type de nœud d'exemple :

- Instance : 4 vCPU, 16 GiB RAM

- kube-reserved + system : 0,5 vCPU, 1,5 GiB

- Allocatable : 3,5 vCPU, 14,5 GiB

Avec le pod api dimensionné à 600m CPU et 600Mi request :

- Max pods CPU-bound par nœud par CPU = floor(3,5 / 0,6) = 5

- Par mémoire = floor(14,5 GiB / 0,6 GiB) = 24

- CPU est le goulot, donc planifiez 5 pods api par nœud maximum.

Bonnes pratiques :

- Fixer un cap de pods par nœud sous le maximum théorique (par exemple 30) pour laisser de la place aux DaemonSets et au surge pendant les rollouts.

- Utiliser PodTopologySpread pour répartir les répliques entre nœuds et zones.

- Pour les charges bruyantes (builds, runners GitLab CI), isoler avec taints/tolerations ou pools de nœuds séparés.

## Stockage et Réseau

N'ignorez pas l'I/O ; beaucoup d'incidents viennent de la saturation disques ou liens alors que le CPU semble correct.

Capacité Ceph :

- Facteur de réplication 3 signifie une capacité effective d'environ raw × 0,33 avant métadonnées et overhead. Gardez les pools sous ~70 % pour éviter les falaises de latence.

- Planifiez le trafic de récupération pendant une panne OSD ; gardez de la marge réseau.

Débit et IOPS :

- Mesurez p95 read/write IOPS et MiB/s en régime permanent et pendant les fenêtres de maintenance (backups, compaction, reindexation).

- Pour les services log-intensifs, envisagez du NVMe local avec rétention bornée et expédition asynchrone vers du stockage objet.

Ingress et egress :

- Pour Nginx Ingress, suivez requêtes par seconde, tailles de réponse, et histogrammes de latence upstream. Dimensionnez le CPU pour la terminaison TLS et le gzip.

- Budgétisez l'egress inter-zone et inter-cluster ; placez les services bavards dans la même zone quand possible.

## Observabilité

Lie les tableaux de bord et alertes aux SLO et à la saturation, pas seulement aux métriques hôtes.

Requêtes Prometheus pour démarrer :

- CPU par pod :

rate(container_cpu_usage_seconds_total{container!="",pod=~"api-.*"}[5m]) 

- Working set mémoire par pod :

 container_memory_working_set_bytes{container!="",pod=~"api-.*"} 

- Taux requêtes et latence Nginx (en supposant métriques exportées) :

 sum(rate(nginx_ingress_controller_requests[1m])) by (ingress)
histogram_quantile(0.95, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket[5m])) by (le, ingress)) 

- Profondeur de file ou backlog métrique personnalisée de l'app pour décisions HPA.

 Alertes :

- Burn rate contre SLO latence.

- Allocatable CPU nœud > 80 % pendant 10 min.

- Compteur OOMKill pod > 0 en 5 min.

- Remplissage pool Ceph > 70 % et OSD nearfull.

## Marges de sécurité et Coût

Visez la résilience sans gaspillage.

- Maintenez l'utilisation CPU et mémoire cluster-wide sous 70 % en régime permanent pour absorber pics et disruptions.

- Pour services critiques, maintenez une capacité N+1 nœud dans chaque domaine de panne.

- Suivez le coût par requête : somme coûts nœud, stockage, egress divisée par requêtes réussies. Utilisez-le pour affiner requests et limites dans le temps.

- Revisitez le dimensionnement après changements majeurs de code ou mises à jour de dépendances.

## Plan de Pilote Local

Démarrez petit, mesurez, et étendez.

Périmètre pilote :

- Une API stateless derrière Nginx Ingress.

- Ajouter requests/limits, un HPA sur CPU à 70 % cible, et VPA en mode recommend-only.

- Tableaux de bord pour CPU, mémoire, QPS, latence p95, et taux d'erreur.

Étapes :

- Ajouter requests/limits ressources et déployer dans un namespace de staging.

- Exécuter un test de charge contrôlé vers le QPS cible de pointe.

- Enregistrer CPU/requête et working set mémoire ; recalculer requests si nécessaire.

- Activer HPA et vérifier comportement de scaling et stabilisation.

- Valider le headroom : garder nœuds sous 70 % CPU en pointe.

- Documenter résultats et déployer en production dans une région ou un cluster.

Critères d'acceptation :

- Latence p95 <= SLO à la pointe cible.

- Aucun OOMKill ni avertissement throttling.

- HPA scale dans les 2 minutes d'une augmentation par palier.

- Taux d'éviction nœud et pod proche de zéro pendant le test.

Plan de rollback :

- Conserver la révision Deployment précédente et le manifeste HPA désactivé prêts.

- Si alertes se déclenchent, ramener les répliques à la dernière valeur connue bonne et augmenter les requests.

## Conclusion

Un plan de capacité pratique dans Kubernetes commence par les SLO, transforme les mesures en requests et limites, choisit des signaux de scaling reflétant la charge réelle, et garde assez de headroom pour absorber pannes et bursts. Lancez un petit pilote sur un service, validez contre des critères d'acceptation clairs, et étendez itérativement. Au fur et à mesure que vos charges et trafic évoluent, revisitez les hypothèses, gardez les tableaux de bord honnêtes, et ajustez requests, limites, et pools de nœuds avec des preuves.