Meilleures pratiques pour optimiser les performances d'un cluster Kubernetes
Optimisez les performances de Kubernetes avec des ressources adaptées, l'autoscaling, un réseau efficace, des choix de stockage et une observabilité constante.
Meilleures pratiques pour optimiser les performances d'un cluster Kubernetes
Les problèmes de performance d'un cluster Kubernetes se manifestent généralement par des déploiements lents, des Pods en attente, des voisins bruyants ou des factures cloud surprises. La solution n'est rarement un seul paramètre magique ; vous avez besoin d'un dimensionnement précis des ressources, de règles de mise à l'échelle adaptées à la demande, et d'une observabilité suffisante pour identifier où la pression commence.
Utilisez cette liste de contrôle pour optimiser votre cluster sans tâtonner.
Commencez par les demandes et les limites
Le planificateur utilise les requests de CPU et de mémoire pour décider où placer les Pods. Si les demandes sont trop faibles, les nœuds semblent plus vides qu'ils ne le sont et les charges de travail se disputent les ressources. Si les demandes sont trop élevées, le planificateur gaspille de la capacité et les Pods peuvent rester en attente.
Définissez les demandes à partir de données d'utilisation réelles. Par exemple, si un conteneur API utilise environ 300 millicores en trafic normal et atteint près de 700 millicores lors du réchauffement du déploiement, vous pourriez commencer par :
resources:
requests:
cpu: "300m"
memory: "512Mi"
limits:
memory: "1Gi"
Soyez prudent avec les limites CPU. Une limite CPU stricte peut limiter les services sensibles à la latence même lorsque le nœud dispose de CPU de réserve. Les limites de mémoire sont toujours utiles car un conteneur qui dépasse sa limite de mémoire peut être tué avant de pousser tout le nœud en pression mémoire.
Utilisez l'autoscaling avec des signaux clairs
Le Horizontal Pod Autoscaler fonctionne bien lorsque votre métrique suit la demande des utilisateurs. Le CPU peut suffire pour des services sans état simples, mais la profondeur de file d'attente, le taux de requêtes ou des métriques d'application personnalisées sont souvent de meilleurs signaux de mise à l'échelle.
kubectl autoscale deployment api \
--cpu-percent=70 \
--min=3 \
--max=20
Le Cluster Autoscaler, Karpenter ou la couche d'autoscaling de nœuds de votre fournisseur cloud doivent avoir de la marge pour ajouter des nœuds avant que les Pods ne restent en attente pendant de longues périodes. Vérifiez que les groupes de nœuds couvrent les tailles d'instance, les zones, les exigences GPU ou les taints dont vos charges de travail ont besoin.
Gardez un ordonnancement prévisible
Les performances chutent lorsque des Pods critiques atterrissent sur des nœuds surchargés ou inadaptés. Utilisez des contraintes de répartition topologique pour les services à fort trafic, l'affinité de nœud pour les charges de travail spécifiques au matériel, et les taints pour les nœuds qui ne doivent exécuter qu'une classe étroite de Pods.
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: api
Cela empêche les répliques de s'accumuler sur un seul nœud lorsque le cluster a de meilleures options de placement.
Optimisez le réseau là où ça fait vraiment mal
La plupart des clusters n'ont pas besoin d'optimisations réseau exotiques. Commencez par identifier le chemin lent : temps de résolution DNS, surcharge du service mesh, trafic inter-zones, ingress surchargé, ou latence Pod-base de données.
Les vérifications utiles incluent :
kubectl top pods -A
kubectl get endpointslices -A
kubectl describe ingress <nom>
kubectl logs -n kube-system -l k8s-app=kube-dns
Pour les services bavards, gardez les Pods et leurs dépendances principales dans la même région et, si possible, la même zone. Si vous utilisez un service mesh, mesurez la latence p95 et p99 avec et sans injection de sidecar pour une charge de travail avant de déployer largement les modifications du mesh.
Adaptez le stockage à la charge de travail
Les choix de stockage peuvent dominer les performances pour les bases de données, les files d'attente et les charges de travail CI. Choisissez des volumes en fonction de la latence, des IOPS, du débit et du comportement en cas d'échec, pas seulement de la capacité.
Par exemple, un Pod PostgreSQL a besoin d'une classe de volume persistant avec une latence prévisible et un comportement de sauvegarde clair. Un cache de build peut se soucier davantage du débit et peut tolérer des reconstructions. Un service web sans état devrait éviter complètement les volumes persistants sauf s'il a une raison réelle.
Surveillez ces symptômes :
- Pods bloqués en
ContainerCreatingcar les volumes s'attachent lentement. - Latence de l'application qui augmente tandis que le CPU reste normal.
- Pression disque du nœud évincant des Pods.
- StatefulSets bloqués car un volume est lié à une seule zone.
Observez le cluster avant de le modifier
L'optimisation sans métriques de base n'est que du churn. Au minimum, suivez le CPU, la mémoire, les redémarrages, les Pods en attente, les conditions de pression des nœuds, la latence du serveur API et la latence p95 des charges de travail.
kubectl get nodes
kubectl describe node <nom-du-nœud>
kubectl get pods -A --field-selector=status.phase=Pending
kubectl top nodes
Si vous utilisez Prometheus, ajoutez des alertes pour la pression soutenue des nœuds, les taux de redémarrage élevés, le HPA au maximum de répliques et les répliques indisponibles sur les déploiements critiques.
À retenir
Optimisez Kubernetes de la charge de travail vers l'extérieur. Dimensionnez correctement les demandes, évitez les limitations CPU inutiles, mettez à l'échelle à partir des signaux de demande, maintenez les répliques réparties et choisissez un stockage adapté à la charge de travail. Ensuite, mesurez après chaque changement pour savoir si le cluster est devenu plus rapide, moins cher ou simplement différent.