Dans les environnements cloud natifs, la supervision de l'état des ressources Kubernetes est cruciale. Alors que les outils traditionnels comme cAdvisor se concentrent sur les métriques de performance matérielle (CPU, mémoire), kube-state-metrics (KSM) comble une lacune essentielle : l'exposition de l'état des objets de l'API Kubernetes sous forme de séries chronologiques compatibles avec Prometheus.
Mécanisme de Collecte et Architecture
KSM fonctionne comme un service autonome qui interroge l'API Server de Kubernetes via le mécanisme List-Watch. Il maintient un cache interne des objets et génère dynamiquement des métriques à la demande. Cette approche découplée garantit que la charge de calcul et de formatage des indicateurs n'impacte pas directement le plan de contrôle du cluster.
Couverture des Ressources et Gestion des Labels
Le composant prend en charge nativement plus de cinquante types de ressources. Voici une classification des principales catégories surveillées et leurs indicateurs associés :
| Domaine | Objets Kubernetes | Exemples de Métriques |
|---|---|---|
| Calcul | Pods, Deployments, StatefulSets | kube_pod_status_phase |
| Réseau | Services, Ingresses, Endpoints | kube_service_info |
| Stockage | PersistentVolumes, StorageClasses | kube_persistentvolume_status_phase |
| Sécurité | NetworkPolicies, Roles | kube_networkpolicy_labels |
Pour assurer la compatibilité avec le modèle de données de Prometheus, KSM sanitise les labels Kubernetes. Voici une implémentation alternative illustrant la logique de normalisation des chaînes de caractères et de résolution des conflits :
package main
import (
"crypto/sha256"
"fmt"
"regexp"
"strings"
)
var invalidChars = regexp.MustCompile(`[^a-zA-Z0-9_]`)
func SanitizeLabel(key string) string {
// Remplacement des caractères non alphanumériques par des underscores
normalized := invalidChars.ReplaceAllString(key, "_")
return strings.ToLower(normalized)
}
func ResolveConflict(labelA, labelB string) (string, string) {
// Génération d'un suffixe unique basé sur un hachage SHA-256 en cas de collision
hashA := fmt.Sprintf("%x", sha256.Sum256([]byte(labelA)))[:6]
hashB := fmt.Sprintf("%x", sha256.Sum256([]byte(labelB)))[:6]
return SanitizeLabel(labelA) + "_" + hashA, SanitizeLabel(labelB) + "_" + hashB
}
Déploiement Standard et Configuraton RBAC
L'installation de KSM nécessite des permissions spécifiques pour lire l'état du cluster. Voici une configuration de déploiement restructurée utilisant des labels personnalisés et une exposition de ports modifiée :
apiVersion: apps/v1
kind: Deployment
metadata:
name: ksm-collector
namespace: monitoring
labels:
app.kubernetes.io/component: metrics-exporter
spec:
replicas: 2
selector:
matchLabels:
app: ksm-exporter
template:
metadata:
labels:
app: ksm-exporter
spec:
serviceAccountName: ksm-reader
containers:
- name: metrics-agent
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.1
args:
- --port=9090
- --telemetry-port=9091
- --resources=deployments,pods,nodes,services
ports:
- containerPort: 9090
name: metrics
- containerPort: 9091
name: telemetry
Le rôle RBAC associé doit accorder les verbes de lecture sur les groupes d'API requis :
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ksm-cluster-reader
rules:
- apiGroups: [""]
resources: ["nodes", "pods", "services", "configmaps", "namespaces"]
verbs: ["list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["list", "watch"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["list", "watch"]
Stratégies de Mise à l'Échelle Avancées
Partitionnement Horizontal (Sharding)
Pour les clusters de grande envergure, l'empreinte mémoire de KSM peut devenir problématique. Le sharding permet de diviser la charge entre plusieurs instances. L'algorithme de distribution peut être modélisé comme suit en utilisant une fonction de hachage cryptographique pour une répartition uniforme :
import hashlib
def assign_shard(resource_uid: str, current_shard: int, max_shards: int) -> bool:
"""Détermine si une instance doit traiter un objet basé sur son UID."""
digest = hashlib.sha256(resource_uid.encode('utf-8')).hexdigest()
numeric_val = int(digest, 16)
return (numeric_val % max_shards) == current_shard
Côté configuration Kubernetes, cela se traduit par l'ajout des arguments suivants au conteneur :
args:
- --shard=1
- --total-shards=5
- --use-apiserver-cache=true
Collecte par Nœud via DaemonSet
Une approche alternative pour optimiser la collecte des métrriques liées aux Pods consiste à déployer KSM en tant que DaemonSet, en restreignant chaque instance aux objets hébergés sur son nœud local :
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ksm-node-agent
spec:
selector:
matchLabels:
tier: node-monitoring
template:
metadata:
labels:
tier: node-monitoring
spec:
containers:
- name: ksm
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.1
args:
- --resources=pods
- --node=$(HOST_NODE)
env:
- name: HOST_NODE
valueFrom:
fieldRef:
fieldPath: spec.nodeName
Filtrage des Métriques
Réduire la cardinalité est essentiel pour maîtriser les coûts de stockage TSDB. Les options de filtrage incluent :
- Sélection stricte des ressources :
--resources=deployments,statefulsets - Listes d'autorisation par expression régulière :
--metric-allowlist="kube_pod_status.*" - Restriction par espace de noms :
--namespaces=kube-system,production
Cas d'Usage et Règles d'Alerte Prometheus
Les métriques générées permettent de superviser la conformité de l'état désiré par rapport à l'état réel. Voici des exemples de règles d'alerte ajustées avec des seuils et des sémantiques personnalisées :
groups:
- name: k8s.workload.health
rules:
- alert: PodFrequentRestarts
expr: sum by (namespace, pod) (increase(kube_pod_container_status_restarts_total[2h])) > 10
for: 5m
labels:
priority: high
annotations:
summary: "Redémarrages excessifs détectés sur {{ $labels.pod }}"
description: "Le conteneur dans le pod {{ $labels.pod }} a redémarré plus de 10 fois au cours des 2 dernières heures."
- alert: DeploymentUnavailableReplicas
expr: (kube_deployment_spec_replicas - kube_deployment_status_available_replicas) > 0
for: 15m
labels:
priority: critical
annotations:
summary: "Déficit de réplicas pour le déploiement {{ $labels.deployment }}"
description: "Le déploiement {{ $labels.deployment }} n'arrive pas à maintenir le nombre de réplicas disponibles requis depuis 15 minutes."
Dimensionnement et Dépannage
Le dimensionnement de KSM dépend directement du nombre d'objets présents dans le cluster. Voici des recommandations pour les requêtes de ressources :
| Taille du Cluster | CPU (Request) | Mémoire (Request) | Instances |
|---|---|---|---|
| Petit (moins de 50 nœuds) | 150m | 256Mi | 1 |
| Moyen (50 à 250 nœuds) | 300m | 512Mi | 2 |
| Grand (plus de 250 nœuds) | 1000m | 2Gi | 3+ (avec sharding) |
En cas d'anomalies de collecte, vérifiez systématiquement les points suivants :
- Absence de données : Validez les bindings RBAC et assurez-vous que le type de ressource est explicitement inclus dans le drapeau
--resources. - Latence API : Activez l'option
--use-apiserver-cachepour décharger le serveur etcd et réduire la latence de synchronisation. - Fuites de mémoire : Surveillez la métrique
process_resident_memory_bytes. Un nombre excessif de ConfigMaps ou de Secrets peut saturer le cache interne de l'application.
Extensions et Évolutions Futures
Surveillance des Ressources Personnalisées (CRD)
La fonctionnalité Custom Resource State permet d'étendre KSM pour extraire des métriques à partir de définitions personnalisées. Voici une configuration alternative définissant une jauge basée sur un champ de statut spécifique :
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: app.example.io
version: v1beta1
kind: Microservice
metrics:
- name: microservice_active_connections
help: "Nombre de connexions actives sur le microservice"
each:
type: Gauge
gauge:
path: [status, currentConnections]
labelsFromPath:
service_tier: [metadata, labels, tier]
Les prochaines itérations de l'outil intègrent également une prise en charge native des protocoles OpenTelemetry, facilitant l'exportation des données vers des pipelines d'observabilité unifiés sans nécessiter de proxys de traduction supplémentaires.