Introduction
Une planification de capacité efficace pour le gestionnaire de contrôleurs Kubernetes (kube-controller-manager) aide les ingénieurs de plateforme à passer d'un dépannage réactif à un dimensionnement proactif. Ce guide fournit des techniques pratiques et concrètes pour mesurer la consommation actuelle des ressources, déterminer les allocations CPU et mémoire appropriées et faire évoluer le gestionnaire de contrôleurs en toute sécurité dans les clusters de production.
Que vous gériez un petit cluster de démarrage ou un grand environnement multi-locataires, la santé du gestionnaire de contrôleurs a un impact direct sur les fonctionnalités fondamentales de Kubernetes : Déploiements, ReplicaSets, StatefulSets, DaemonSets, Jobs, etc. Un sous-provisionnement de ce composant peut entraîner une privation de ressources pour les contrôleurs, une surcharge du serveur d'API et une dégradation des performances du cluster. Un surprovisionnement gaspille des ressources et peut masquer des inefficacités de conception.
Cet article s'adresse aux SRE, aux ingénieurs DevOps et aux équipes de plateforme qui ont besoin d'une approche pratique, pilotée par des commandes, pour la planification de capacité. Nous nous concentrons sur Kubernetes version 1.28 et ultérieures, mais les principes et la plupart des commandes s'appliquent aux versions antérieures avec des ajustements mineurs. Vous apprendrez à :
- Inventorier votre configuration actuelle du gestionnaire de contrôleurs et l'utilisation des ressources
- Analyser les métriques pour identifier les goulots d'étranglement et la marge de manœuvre
- Configurer les demandes et limites de ressources de manière appropriée
- Faire évoluer le gestionnaire de contrôleurs horizontalement ou verticalement si nécessaire
- Diagnostiquer les modes de défaillance courants et s'en remettre
- Mettre en œuvre une liste de contrôle opérationnelle reproductible
À la fin, vous disposerez d'une méthodologie éprouvée avec des exemples concrets et des sorties attendues, vous permettant de prendre des décisions éclairées avec un risque minimal pour la stabilité du cluster.
Inventaire de la version et de l'environnement
Avant de changer quoi que ce soit, établissez une image claire de votre environnement. Cette section explique comment inspecter la version de Kubernetes, la topologie de déploiement du gestionnaire de contrôleurs et les paramètres de ressources actuels.
Vérifier la version de Kubernetes et l'image du gestionnaire de contrôleurs
Tout d'abord, confirmez la version de Kubernetes de votre cluster et l'image du gestionnaire de contrôleurs utilisée. C'est essentiel car les indicateurs et les noms des métriques changent entre les versions.
# Obtenir la version du cluster
kubectl version --short
# Sortie (exemple) :
# Client Version: v1.28.2
# Server Version: v1.28.2
# Si vous utilisez un cluster kubeadm, vérifiez la définition du pod statique pour l'image
sudo grep -A5 'image:' /etc/kubernetes/manifests/kube-controller-manager.yaml
# La sortie peut inclure :
# image: registry.k8s.io/kube-controller-manager:v1.28.2
Pour les services Kubernetes gérés comme EKS, GKE ou AKS, vous ne pouvez pas inspecter directement le plan de contrôle. Vérifiez plutôt le canal de publication ou la version du cluster via l'interface en ligne de commande du fournisseur de cloud, par exemple :
# AWS EKS
eksctl get cluster --name <nom-du-cluster>
# La sortie montre Version: 1.28
# Google GKE
gcloud container clusters describe <nom-du-cluster> --zone <zone> --format='value(currentMasterVersion)'
Notez la version exacte car certains indicateurs liés aux ressources (comme --kube-api-qps et --kube-api-burst) n'ont été ajoutés ou modifiés que dans des versions spécifiques.
Inspecter les demandes et limites de ressources actuelles
Pour les clusters autogérés, le gestionnaire de contrôleurs est généralement un pod statique contrôlé par le kubelet. Ses demandes et limites de ressources sont définies dans le manifeste du pod.
# Lire le manifeste du pod statique
sudo cat /etc/kubernetes/manifests/kube-controller-manager.yaml
Recherchez la section resources dans la spécification du conteneur. Exemple d'extrait :
containers:
- name: kube-controller-manager
image: registry.k8s.io/kube-controller-manager:v1.28.2
resources:
requests:
cpu: 200m
memory: 100Mi
limits:
cpu: 400m
memory: 200Mi
Si aucune ressource n'est spécifiée, le kubelet ne réservera aucune garantie et le gestionnaire de contrôleurs peut être expulsé sous pression. C'est un piège courant.
Pour les plans de contrôle gérés par le cloud, vous ne pouvez pas modifier directement le gestionnaire de contrôleurs. Vous dépendez plutôt du réglage du fournisseur et devrez peut-être ajuster la taille des nœuds du plan de contrôle (par exemple, dans EKS, le plan de contrôle s'exécute sur des nœuds gérés avec des ressources fixes). Ainsi, votre planification de capacité se concentre sur la distribution de la charge de travail et la priorité des API.
Vérifier que le gestionnaire de contrôleurs est en cours d'exécution et sain
Utilisez kubectl pour vérifier l'état du pod (dans les clusters autogérés) ou les points de terminaison de santé du gestionnaire de contrôleurs.
# Pour les clusters autogérés, vérifiez l'état du pod
kubectl get pods -n kube-system -l component=kube-controller-manager
# Sortie :
# NAME READY STATUS RESTARTS AGE
# kube-controller-manager-node1 1/1 Running 0 5d2h
# Vérifiez les points de terminaison de santé (depuis le nœud du plan de contrôle)
curl -s http://localhost:10257/healthz
# Attendu : ok
curl -s http://localhost:10257/healthz/ping
# Attendu : ok
Si le contrôle de santé échoue, enquêtez immédiatement en utilisant journalctl -u kubelet ou les journaux du conteneur.
Chemin de configuration sûr
Lors de la modification du gestionnaire de contrôleurs, suivez toujours un processus sûr : capturez la configuration actuelle, effectuez un changement limité, vérifiez et ayez un plan de retour en arrière. Cette section fournit des étapes concrètes.
Étape 1 : Établir une base de référence des paramètres actuels
Avant tout changement, enregistrez le manifeste ou la configuration actuelle.
Pour les clusters autogérés, copiez le manifeste du pod statique vers un emplacement de sauvegarde :
sudo cp /etc/kubernetes/manifests/kube-controller-manager.yaml /root/kcm-backup-$(date +%Y%m%d).yaml
Enregistrez également les métriques actuelles observées sur une période de référence (au moins 24 heures) pour comparer après les changements. Utilisez metrics-server ou des requêtes Prometheus. Exemple avec kubectl top :
kubectl top pod -n kube-system -l component=kube-controller-manager
# Sortie (exemple) :
# NAME CPU(cores) MEMORY(bytes)
# kube-controller-manager-node1 150m 180Mi
Documentez ces chiffres.
Étape 2 : Décider des changements de ressources en fonction des preuves
Utilisez les métriques historiques pour définir les demandes et les limites. Une approche générale :
- Les demandes doivent couvrir l'utilisation au P99 sur la période de référence plus une marge de sécurité (par exemple, 25 %).
- Les limites doivent être définies plus haut pour permettre des pics mais pas une utilisation incontrôlée. Un ratio courant est limites = 2 x demandes pour le CPU, et limites = 1,5 à 2 x demandes pour la mémoire.
Par exemple, si l'utilisation CPU au P99 est de 180m et la mémoire au P99 de 150Mi, alors définissez :
- demandes : cpu=250m, memory=200Mi
- limites : cpu=500m, memory=400Mi
Mais validez toujours avec des données spécifiques à la charge de travail.
Étape 3 : Appliquer les changements (pod statique autogéré)
Pour un pod statique géré par le kubelet, modifier le fichier manifeste déclenche automatiquement un redémarrage.
# Modifier le manifeste
sudo vi /etc/kubernetes/manifests/kube-controller-manager.yaml
# Ajoutez ou modifiez la section resources selon les besoins
# Enregistrez et quittez ; le kubelet redémarrera le pod. Surveillez avec :
kubectl get pods -n kube-system -w
Vérifiez que le pod fonctionne avec les nouvelles ressources :
kubectl get pod -n kube-system -l component=kube-controller-manager -o json | jq '.items[0].spec.containers[0].resources'
# La sortie montre les nouvelles demandes/limites
Étape 4 : Valider et observer
Après le changement, surveillez l'utilisation des ressources du gestionnaire de contrôleurs et assurez-vous qu'aucune expulsion ou tuerie OOM ne se produit.
# Surveillez les événements dans kube-system
kubectl get events -n kube-system --field-selector involvedObject.name=kube-controller-manager-node1 --watch
# Recherchez les messages OOMKilled ou d'expulsion
Si le gestionnaire de contrôleurs redémarre fréquemment ou est tué, revenez à la sauvegarde :
sudo cp /root/kcm-backup-YYYYMMDD.yaml /etc/kubernetes/manifests/kube-controller-manager.yaml
# Attendez le redémarrage et vérifiez la santé
Étape 5 : Ajuster les indicateurs pour la limitation de débit de l'API (facultatif)
Dans les grands clusters, le gestionnaire de contrôleurs peut submerger le serveur d'API. Réglez --kube-api-qps et --kube-api-burst en fonction de la limitation observée.
Les valeurs par défaut sont qps=20, burst=30. Si vous voyez de nombreuses réponses 429 dans les métriques du serveur d'API, augmentez progressivement.
# Dans le manifeste, ajoutez les indicateurs :
--kube-api-qps=50
--kube-api-burst=100
Validez avec kubectl get --raw /metrics sur le gestionnaire de contrôleurs, en recherchant rest_client_requests_total et les métriques de limitation.
Vérification et diagnostics
Cette section détaille comment utiliser les métriques et les journaux pour vérifier la capacité et diagnostiquer les problèmes.
Métriques essentielles à surveiller
Le gestionnaire de contrôleurs expose des métriques Prometheus sur le port 10257 (HTTPS) à /metrics. Les métriques clés comprennent :
workqueue_depthpour chaque contrôleur (déploiement, replicaset, etc.) - indique l'arriéréworkqueue_adds_total,workqueue_retries_total- taux de traitementprocess_cpu_seconds_total,process_resident_memory_bytes- utilisation des ressourcesrest_client_requests_totalavec les étiquettescode- appels APIleader_election_master_status- indique si cette instance est le leader (dans les configurations HA)
Exemples de requêtes PromQL :
# Taux d'utilisation CPU du gestionnaire de contrôleurs (par seconde)
rate(process_cpu_seconds_total{job="kube-controller-manager"}[5m])
# Utilisation actuelle de la mémoire en octets
process_resident_memory_bytes{job="kube-controller-manager"}
# Top 5 des profondeurs de file d'attente de travail
sort_desc(topk(5, workqueue_depth{job="kube-controller-manager"}))
# Limitation des requêtes API
rate(rest_client_requests_total{job="kube-controller-manager", code="429"}[5m])
Si workqueue_depth pour le contrôleur de déploiement reste élevé (>100) pendant des périodes prolongées, le gestionnaire de contrôleurs peut être sous-dimensionné ou limité par le débit de l'API.
Utilisation de kubectl top et describe
Pour des vérifications rapides, kubectl top donne l'utilisation des ressources en temps réel (si metrics-server est installé) :
kubectl top pod -n kube-system -l component=kube-controller-manager
kubectl describe peut montrer des événements récents comme OOMKilled :
kubectl describe pod -n kube-system kube-controller-manager-node1 | grep -A5 'Events:'
# Exemple d'événement :
# Warning OOMKilled kubelet Container kube-controller-manager was OOMKilled
Analyse des journaux du gestionnaire de contrôleurs
Sur les clusters autogérés, les journaux sont disponibles via journalctl (si systemd est utilisé) ou les journaux du runtime de conteneur.
# Utilisation de crictl (pour containerd)
sudo crictl logs $(sudo crictl ps --name kube-controller-manager -q) --tail=100
# Ou journalctl
journalctl -u kubelet --since "1 hour ago" | grep kube-controller-manager
Recherchez des motifs comme Failed to list *v1.Deployment (indiquant des problèmes d'API), the server has received too many requests (limitation de débit) ou des Back-off restarting failed container répétés (plantages de ressources).
Vérification de l'élection du leader (clusters HA)
Dans une configuration à haute disponibilité avec plusieurs nœuds de plan de contrôle, un seul gestionnaire de contrôleurs est actif. Vérifiez quel pod est le leader :
# Interroger la métrique d'élection du leader (nécessite un accès direct au point de terminaison des métriques)
kubectl exec -n kube-system <pod-actif-kube-controller-manager> -- curl -s https://localhost:10257/metrics | grep leader_election_master_status
# Sortie : leader_election_master_status{name="kube-controller-manager"} 1
Le pod avec la valeur 1 est le leader actuel. Les pods non-leaders doivent avoir 0. Si aucun n'a 1, l'élection du leader est rompue.
Modes de défaillance et récupération
Comprendre les modes de défaillance courants vous aide à réagir rapidement et à prévenir les occurrences futures.
OOMKilled (manque de mémoire)
Cause : Limite de mémoire trop basse pour l'ensemble de travail du gestionnaire de contrôleurs, souvent en raison d'un nombre élevé d'objets ou de grands caches.
Détection : kubectl describe pod montre la raison de terminaison OOMKilled ; le pod redémarre à plusieurs reprises.
Récupération : Augmentez progressivement la limite de mémoire. Par exemple, si la limite actuelle est de 200Mi et qu'un OOM se produit, augmentez à 500Mi, observez, puis ajustez. Envisagez également de réduire la pression mémoire en nettoyant les anciennes ressources ou en diminuant --concurrent-deployment-syncs (par défaut 5) s'il y a trop de réconciliations simultanées.
Prévention : Définissez la limite de mémoire à au moins 2 fois l'utilisation moyenne et assurez-vous que les demandes couvrent le P99.
Famine CPU
Cause : La limitation du CPU empêche le traitement opportun de la file d'attente, provoquant un arriéré et des déploiements retardés.
Détection : La profondeur de la file d'attente de travail augmente, kubectl top montre une utilisation du CPU à ou près de la limite, et les métriques de limitation CPU du conteneur (container_cpu_cfs_throttled_seconds_total) sont élevées.
Récupération : Augmentez la limite CPU ou supprimez-la si le nœud a de la capacité. Alternativement, répartissez la charge du contrôleur en exécutant plusieurs gestionnaires de contrôleurs avec élection de leader (un seul actif) et en utilisant l'anti-affinité de nœud pour la séparation si vous avez des contrôleurs personnalisés.
Prévention : Surveillez la limitation CPU ; définissez la demande CPU égale à l'utilisation observée et la limite à 2-3 fois la demande.
Limitation de débit du serveur d'API
Cause : Trop de requêtes API du gestionnaire de contrôleurs dépassant les limites --kube-api-qps et --kube-api-burst, entraînant des réponses 429 et des nouvelles tentatives.
Détection : Les métriques rest_client_requests_total{code="429"} augmentent ; les journaux montrent des messages "client rate limiter".
Récupération : Augmentez progressivement les paramètres qps et burst. Par exemple, de qps=20, burst=30 à qps=50, burst=100. Surveillez l'effet ; si les problèmes persistent, recherchez la cause première (par exemple, trop d'objets dans un espace de noms).
Prévention : Établissez une base de référence des taux d'appels API en fonctionnement normal ; définissez des limites avec une marge (par exemple, 2 fois le taux de pointe observé).
Échec de l'élection du leader
Cause : Partition réseau entre les nœuds du plan de contrôle, dérive d'horloge ou problèmes etcd entraînant la perte de baux.
Détection : Plusieurs gestionnaires de contrôleurs pensent être leader (split-brain) ou aucun ne l'est ; les journaux montrent des délais d'expiration de l'élection du leader.
Récupération : Assurez la connectivité réseau, synchronisez NTP et redémarrez les pods du gestionnaire de contrôleurs. Forcez un nouveau bail en supprimant l'objet de bail (risqué) :
kubectl delete lease -n kube-system kube-controller-manager
Attendez la réélection ; ne faites pas cela pendant une charge élevée.
Prévention : Exécutez les nœuds du plan de contrôle sur une infrastructure stable, surveillez la dérive d'horloge et disposez d'une redondance etcd.
Manifeste de pod statique mal configuré
Cause : Erreur de syntaxe ou indicateur non valide dans /etc/kubernetes/manifests/kube-controller-manager.yaml après modification, entraînant l'échec de la création du pod.
Détection : Le pod n'apparaît pas dans kubectl get pods ; les journaux du kubelet montrent des erreurs d'analyse du manifeste.
Récupération : Restaurez immédiatement le manifeste de sauvegarde.
Prévention : Validez la syntaxe YAML avant d'enregistrer (yamllint ou kubectl apply --dry-run=client -f sur une ressource factice), testez d'abord les changements sur un cluster de préproduction.
Liste de contrôle opérationnelle
Cette liste résume les étapes clés pour une planification de capacité et une mise à l'échelle sûres du gestionnaire de contrôleurs. Pour chaque élément, nous nommons un propriétaire responsable (rôle typique) et une fréquence d'examen suggérée.
| Élément de la liste | Action à entreprendre | Propriétaire responsable | Fréquence |
|---|---|---|---|
| Inventaire de version | Enregistrer la version du cluster, l'image du gestionnaire de contrôleurs et la topologie de déploiement | Ingénieur plateforme | Mensuelle ou lors d'une mise à niveau |
| Métriques de base | Collecter 7 jours d'utilisation CPU/mémoire, profondeurs de file d'attente, taux d'API | SRE | Continue (examen hebdomadaire) |
| Examen des demandes/limites de ressources | Comparer les demandes/limites actuelles à l'utilisation observée ; ajuster si l'écart > 25 % | Ingénieur plateforme | Mensuelle |
| Vérification de la limitation de débit de l'API | Examiner les métriques 429 ; si > 0,1 % des requêtes, envisager de régler qps/burst | SRE | Hebdomadaire |
| Santé de l'élection du leader | Assurer exactement un leader dans les clusters HA | SRE | Vérification automatisée quotidienne |
| Analyse des erreurs dans les journaux | Rechercher de nouveaux motifs d'erreur dans les journaux du gestionnaire de contrôleurs | Ingénieur DevOps | Hebdomadaire |
| Test du plan de récupération | Simuler OOMKilled ou défaillance du manifeste en préproduction, vérifier le retour en arrière | SRE | Trimestrielle |
| Prévision de capacité | Estimer la croissance des objets et des contrôleurs ; planifier les augmentations de ressources | Responsable plateforme | Mensuelle |
Par exemple, Priya Shah, responsable ingénierie, est propriétaire de la prévision de capacité mensuelle pour le cluster de production. Elle examine les métriques du gestionnaire de contrôleurs ainsi que les projections etcd et du serveur d'API chaque premier lundi du mois. Sa prévision inclut la marge de ressources attendue pour le prochain trimestre, déclenchant des décisions de mise à l'échelle précoces.
Autre exemple : Marcus Chen, SRE, est responsable de la vérification hebdomadaire de la limitation de débit de l'API. Chaque vendredi, il exécute une requête PromQL sur rest_client_requests_total{code="429"} pour le gestionnaire de contrôleurs. Si le taux dépasse 0,1 % (taux moyen sur 5 minutes), il ouvre un ticket pour ajuster --kube-api-qps et --kube-api-burst après avoir examiné les changements récents de charge de travail.
Pour le test du plan de récupération, Aisha Patel, ingénieure DevOps, est la propriétaire. Elle exécute le test sur l'environnement de préproduction chaque trimestre (par exemple, le deuxième mardi de janvier, avril, juillet, octobre). Elle simule un OOMKill en abaissant temporairement les limites de mémoire dans un cluster de test dédié, documente le temps entre la détection et la récupération, et met à jour le runbook si la procédure dérive.
Ces attributions de propriété assurent une responsabilité claire, et les fréquences d'examen maintiennent la planification de capacité proactive.
Pièges courants et comment les éviter
Cette section traite des erreurs fréquentes dans la planification de capacité du gestionnaire de contrôleurs.
1. Ignorer les données de base
Piège : Définir les demandes et limites de ressources arbitrairement (par exemple, copier-coller depuis un autre cluster) sans observer l'utilisation réelle.
Pourquoi cela arrive : Pression temporelle ou manque de configuration de surveillance.
Impact : Le sous-provisionnement entraîne OOMKill ou limitation ; le surprovisionnement gaspille des ressources et peut causer des problèmes de regroupement de nœuds.
Comment éviter : Collectez toujours au moins une semaine de métriques avant de décider. Utilisez kubectl top et les requêtes Prometheus comme indiqué précédemment.
2. Ne pas tenir compte des pics lors des déploiements ou des événements de mise à l'échelle
Piège : Définir les demandes de ressources trop proches de l'utilisation moyenne, ignorant les charges de pointe lors de la recréation massive de pods.
Pourquoi cela arrive : Les développeurs ne regardent que les métriques en régime permanent.
Impact : Lors des mises à jour progressives ou des défaillances de nœuds, le CPU du gestionnaire de contrôleurs augmente, provoquant une réconciliation lente et des délais d'expiration de l'API.
Comment éviter : Examinez l'utilisation au P99 ou maximale sur une période incluant des événements de mise à l'échelle. Ajoutez une marge de 25 à 50 % pour les demandes et des limites plus élevées.
3. Oublier de régler les limites de débit de l'API
Piège : Laisser les valeurs par défaut --kube-api-qps et --kube-api-burst dans les clusters avec un nombre élevé d'objets ou de nombreux contrôleurs.
Pourquoi cela arrive : Ces indicateurs sont cachés dans le manifeste du pod statique et souvent négligés.
Impact : La limitation de l'API provoque des arriérés de contrôleurs et des déploiements retardés.
Comment éviter : Surveillez les métriques 429 ; réglez proactivement en fonction de la taille du cluster. Pour les grands clusters (par exemple, >10 000 pods), envisagez qps=100, burst=200 ou plus, mais testez progressivement.
4. Mal comprendre les implications de l'élection du leader
Piège : Supposer que tous les pods du gestionnaire de contrôleurs traitent le travail simultanément ; en HA, seul le leader est actif, les autres sont en veille.
Pourquoi cela arrive : Méconnaissance de la conception du plan de contrôle Kubernetes.
Impact : La mise à l'échelle horizontale du gestionnaire de contrôleurs au-delà de l'instance de veille n'augmente pas le débit ; seule la mise à l'échelle verticale (plus de ressources au leader) aide.
Comment éviter : Pour l'évolutivité, concentrez-vous sur le dimensionnement des ressources du leader et assurez la préparation au basculement. Si vous avez besoin d'un traitement parallèle, envisagez de créer des contrôleurs personnalisés avec partitionnement, pas le gestionnaire de contrôleurs de base.
5. Ne pas valider les changements YAML
Piège : Modifier /etc/kubernetes/manifests/kube-controller-manager.yaml avec une erreur d'indentation ou un indicateur mal orthographié, ce qui fait que le kubelet ignore le pod ou le fait planter en boucle.
Pourquoi cela arrive : Modification directe sans validation.
Impact : Gestionnaire de contrôleurs hors service, fonctionnalités du cluster altérées.
Comment éviter : Utilisez un linter YAML, testez avec kubelet --config, et ayez toujours une sauvegarde. Envisagez d'utiliser un outil de gestion de configuration comme Ansible pour déployer les changements avec pré-validation.
Conclusion
La planification de capacité pour le gestionnaire de contrôleurs Kubernetes n'est pas une tâche ponctuelle mais un processus continu d'observation, d'ajustement et de vérification. En suivant l'approche structurée décrite dans cet article—inventaire, base de référence, configuration sûre, diagnostics, récupération après défaillance et liste de contrôle—vous pouvez maintenir un plan de contrôle sain qui répond de manière prévisible aux changements de charge de travail.
Commencez par les étapes à faible risque : rassemblez les métriques, comparez-les aux limites actuelles et identifiez les sur- ou sous-provisionnements immédiats. Ensuite, mettez en œuvre des changements progressifs avec des plans de retour en arrière. Documentez vos décisions et revisitez-les mensuellement.
Un flux de travail opérationnel fiable pour le gestionnaire de contrôleurs garantit que les contrôleurs de base de votre cluster peuvent répondre aux demandes de vos applications sans devenir un goulot d'étranglement. Avec les commandes et exemples concrets fournis, vous êtes équipé pour effectuer une planification de capacité efficace dans votre propre environnement.