## Introduction

Les contrôleurs d'admission sont un garde-fou essentiel dans le pipeline de requêtes de l'API Kubernetes. Ils interceptent chaque requête de création, de mise à jour et de suppression, appliquent des politiques et peuvent muter les ressources avant leur persistance. Lorsqu'ils sont mal configurés ou surchargés, ils deviennent un goulot d'étranglement qui ralentit les déploiements, casse les pipelines CI/CD et provoque des délais d'attente mystérieux. Ce guide vous accompagne dans un processus systématique pour régler les performances des contrôleurs d'admission : de l'observation initiale et de l'inventaire des versions aux changements de configuration sûrs, en passant par la vérification, la récupération en cas d'échec et une liste de contrôle opérationnelle. Chaque section comprend des commandes concrètes, les sorties attendues et des exemples pratiques pour les développeurs, les consultants DevOps et les équipes techniques de startups.

Nous nous concentrerons sur deux types principaux de contrôleurs d'admission :

1. **Les contrôleurs d'admission intégrés** (par exemple, ResourceQuota, LimitRanger, PodSecurity) compilés dans le serveur d'API Kubernetes.
2. **Les webhooks d'admission dynamiques** (par exemple, ValidatingWebhookConfiguration, MutatingWebhookConfiguration) qui appellent des services HTTP externes.

Des problèmes de performance peuvent survenir avec l'un ou l'autre type, mais les webhooks dynamiques sont la source de latence la plus courante car ils ajoutent des allers-retours réseau à chaque requête API. Tout au long de cet article, nous utiliserons un scénario typique : une équipe constate que `kubectl apply` prend 10 secondes au lieu d'une seconde, et que les pods restent à l'état `Pending` plus longtemps que prévu.

## Inventaire des versions et de l'environnement

Avant de modifier toute configuration, rassemblez des informations précises sur votre version de Kubernetes, les contrôleurs d'admission actuellement activés et les webhooks installés. Cette base de référence est essentielle pour comparer les performances avant et après, et pour garantir que tout changement est compatible avec votre cluster.

### Vérifier la version de Kubernetes

Exécutez la commande suivante pour obtenir la version du serveur :

```bash
kubectl version --short
```

Sortie attendue (exemple) :

```
Client Version: v1.28.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.3
```

Notez la version du serveur ; pour le réglage des contrôleurs d'admission, les versions 1.24 et ultérieures ont des délais d'attente de webhook cohérents (10 secondes) et prennent en charge `failurePolicy`.

### Lister les contrôleurs d'admission activés

Vous pouvez voir les contrôleurs d'admission activés sur le serveur d'API en vérifiant ses indicateurs. Si vous avez accès aux nœuds du plan de contrôle ou au manifeste `kube-apiserver`, examinez l'indicateur `--enable-admission-plugins`. Par exemple :

```bash
ps aux | grep kube-apiserver | grep enable-admission-plugins
```

Si vous utilisez un service Kubernetes managé (EKS, GKE, AKS), vous n'aurez peut-être pas d'accès direct. À la place, vous pouvez déduire certains plugins en vérifiant des ressources ou des comportements spécifiques. Par exemple, pour voir si `ResourceQuota` est activé, créez un espace de noms et essayez d'appliquer un quota. Cependant, le moyen le plus fiable pour les clusters managés est de consulter la documentation du fournisseur.

Sinon, utilisez `kubectl api-versions` pour voir si certaines API sont disponibles, ce qui peut indiquer les contrôleurs d'admission activés. Par exemple, si `policy/v1` est disponible et que vous pouvez récupérer des `PodDisruptionBudgets`, le contrôleur d'admission `PodDisruptionBudget` est probablement actif.

### Lister les webhooks d'admission configurés

Les webhooks dynamiques sont définis dans les objets `ValidatingWebhookConfiguration` et `MutatingWebhookConfiguration`. Listez-les :

```bash
kubectl get validatingwebhookconfigurations
kubectl get mutatingwebhookconfigurations
```

Exemple de sortie pour les webhooks de validation :

```
NAME                          WEBHOOKS   AGE
gatekeeper-validating-webhook   1         30d
pod-policy.example.com          1         10d
```

Pour chaque webhook, inspectez sa configuration pour voir quelles ressources il intercepte, son délai d'attente et sa politique d'échec :

```bash
kubectl get validatingwebhookconfiguration gatekeeper-validating-webhook -o yaml
```

Les champs cruciaux sont :

- `timeoutSeconds` : temps maximal d'attente du serveur d'API pour une réponse du webhook (10 secondes par défaut).
- `failurePolicy` : soit `Fail` (la requête est rejetée en cas d'échec du webhook) soit `Ignore` (la requête aboutit quand même).
- `rules` : quelles ressources et opérations de l'API déclenchent le webhook.

Exemple d'extrait :

```yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: gatekeeper-validating-webhook
webhooks:
- name: validation.gatekeeper.sh
  timeoutSeconds: 3
  failurePolicy: Fail
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["pods", "deployments"]
```

### Vérifier la santé des points de terminaison des webhooks

Les webhooks sont généralement exposés en tant que services dans le cluster ou sous forme d'URL externes. Vérifiez que les pods sous-jacents sont en cours d'exécution et réactifs. Pour un service dans l'espace de noms `gatekeeper-system` :

```bash
kubectl get pods -n gatekeeper-system -o wide
kubectl logs -n gatekeeper-system <pod-name> --tail=50
```

Si le service webhook dispose d'un point de terminaison de santé, testez-le avec `kubectl port-forward` ou `curl`. Par exemple :

```bash
kubectl port-forward -n gatekeeper-system svc/gatekeeper-webhook-service 8443:443 &
curl -k https://localhost:8443/healthz
```

Sortie attendue : `ok`.

## Chemin de configuration sûr

L'étape suivante consiste à apporter des modifications ciblées pour améliorer les performances tout en minimisant les risques. Commencez toujours par une observation en lecture seule, puis appliquez le plus petit changement qui résout le goulot d'étranglement, et ayez toujours un plan de retour en arrière.

### Identifier le goulot d'étranglement

Le premier diagnostic consiste à mesurer la latence des requêtes API et à déterminer si les webhooks d'admission en sont la cause. Activez la journalisation d'audit ou utilisez les métriques du serveur d'API Kubernetes.

**1. Utiliser les métriques du serveur d'API Kubernetes (si Prometheus est disponible)**

Le serveur d'API expose des métriques à `/metrics`. Métriques clés pour l'admission :

- `apiserver_admission_controller_admission_duration_seconds`
- `apiserver_admission_webhook_admission_duration_seconds`

Interrogez Prometheus pour la latence au 99e percentile :

```promql
histogram_quantile(0.99, rate(apiserver_admission_webhook_admission_duration_seconds_bucket[5m]))
```

Si cette valeur dépasse 1 seconde, les webhooks contribuent probablement aux ralentissements.

**2. Utiliser les journaux d'audit**

Si la journalisation d'audit est activée, recherchez les étapes de requête et les latences. Par exemple, dans le journal d'audit, trouvez les entrées avec `"stage":"ResponseComplete"` et inspectez le champ `"annotations"` pour les latences des webhooks.

**3. Effectuer un test de latence manuel**

Créez un pod de test et chronométrez la requête :

```bash
time kubectl run test-pod --image=nginx --restart=Never
```

Ensuite, supprimez-le :

```bash
kubectl delete pod test-pod --wait=false
```

Comparez le temps avec et sans un webhook particulier (en le désactivant temporairement, si possible).

### Réglage des contrôleurs d'admission intégrés

Les contrôleurs d'admission intégrés sont généralement efficaces, mais certains peuvent entraîner une surcharge. Par exemple, `ResourceQuota` et `LimitRanger` effectuent des recherches et des calculs supplémentaires. Cependant, ils sont rarement le principal goulot d'étranglement des performances. Si vous soupçonnez un contrôleur intégré, vous pouvez mesurer sa durée via les métriques :

```promql
apiserver_admission_controller_admission_duration_seconds{name="ResourceQuota", quantile="0.99"}
```

Si la valeur est élevée, envisagez de réduire le nombre de quotas ou de plages de limites, ou de restreindre la portée du contrôleur (par exemple, appliquer des quotas à moins d'espaces de noms). Mais dans la plupart des cas, le problème vient des webhooks dynamiques.

### Réglage des webhooks dynamiques

Les principaux leviers pour les performances des webhooks sont :

1. **Réduire `timeoutSeconds`** : cela fixe une limite supérieure, mais ne rend pas le webhook plus rapide. Cependant, le réduire (par exemple, de 10 à 3 secondes) peut échouer plus rapidement et éviter de longues attentes lorsque le webhook est en panne. Toutefois, si le webhook est lent mais répond finalement dans les 3 secondes, réduire le délai peut entraîner davantage d'échecs.

2. **Ajuster `failurePolicy` sur `Ignore`** : si un webhook n'est pas critique et subit des échecs intermittents, définir `failurePolicy: Ignore` permet aux requêtes de se poursuivre sans l'approbation du webhook. C'est un compromis entre disponibilité et application des politiques. À utiliser uniquement pour les webhooks consultatifs ou de type audit.

3. **Restreindre la portée du webhook** : plus un webhook intercepte de ressources et d'opérations, plus il traite de requêtes. Limitez les `rules` aux ressources nécessaires. Par exemple, si un webhook valide uniquement les pods, n'incluez pas `deployments` dans les règles (puisque les déploiements créent des pods, la création du pod déclenchera quand même le webhook ; intercepter les déploiements entraînerait des appels en double).

4. **Améliorer les performances du service webhook** : assurez-vous que le backend du webhook dispose de suffisamment de répliques, qu'il est évolutif horizontalement et qu'il a une faible latence interne. Vérifiez l'utilisation du processeur et de la mémoire :

```bash
kubectl top pods -n <webhook-namespace>
```

Si les pods manquent de ressources, augmentez les limites ou le nombre de répliques.

5. **Utiliser des sélecteurs d'objets** : si le webhook ne doit traiter qu'un sous-ensemble d'objets (par exemple, des espaces de noms ou des étiquettes spécifiques), utilisez `namespaceSelector` ou `objectSelector` pour filtrer côté serveur d'API, réduisant ainsi les appels inutiles au webhook.

### Exemple : réglage d'un webhook de validation lent

Supposons que vous ayez un webhook de validation qui vérifie les politiques de sécurité des pods et prend en moyenne 4 secondes par requête. La configuration actuelle ressemble à :

```yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: pod-security-webhook
webhooks:
- name: pod-security.example.com
  timeoutSeconds: 10
  failurePolicy: Fail
  rules:
  - operations: ["CREATE", "UPDATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["pods", "deployments", "statefulsets", "daemonsets", "jobs", "cronjobs"]
  namespaceSelector:
    matchLabels:
      pod-security: enabled
```

Problèmes : le webhook intercepte de nombreux types de ressources et n'a pas de délai d'attente réduit. De plus, le backend est peut-être sous-provisionné.

**Changements sûrs :**

1. Limitez les règles aux seuls `pods` (puisque tous les autres contrôleurs de charge de travail créent des pods, l'événement de création du pod est suffisant) ou utilisez `objectSelector` si possible.
2. Réduisez `timeoutSeconds` à 3 secondes.
3. Faites évoluer le déploiement du webhook avec davantage de répliques.

Appliquez les changements :

```bash
kubectl apply -f updated-webhook.yaml
```

Ensuite, testez avec une création de pod :

```bash
time kubectl run test-pod --image=nginx --restart=Never
```

Observez la nouvelle latence et assurez-vous que le pod est créé avec succès.

## Vérification et diagnostics

Après avoir apporté des modifications, vérifiez que les performances se sont améliorées et que les contrôleurs d'admission fonctionnent correctement. Utilisez une combinaison de métriques, de journaux et de tests réels.

### Vérifier le temps de réponse des webhooks

Utilisez les métriques du serveur d'API pour confirmer que la latence des webhooks a diminué. Si Prometheus n'est pas disponible, vous pouvez activer temporairement la journalisation d'audit ou utiliser l'indicateur `kubectl --v=6` pour voir le chronométrage détaillé des requêtes.

Par exemple, exécutez :

```bash
kubectl get pod test-pod -v=6
```

La sortie comprend le chronométrage de chaque phase, y compris l'admission :

```log
I1015 10:30:00.123456   12345 round_trippers.go:553] GET https://api-server:6443/api/v1/namespaces/default/pods/test-pod 200 OK in 123 milliseconds
```

Le temps total n'est pas décomposé par admission, mais si le temps total est proche de votre paramètre de délai d'attente, les webhooks sont encore lents.

### Vérifier les taux de succès/échec des webhooks

Si le service webhook exporte des métriques, surveillez-les. Sinon, consultez les journaux du service webhook pour détecter des erreurs ou des délais d'attente. Par exemple :

```bash
kubectl logs -n pod-security-webhook -l app=webhook --tail=100 | grep -i error
```

Vérifiez également les journaux du serveur d'API pour les délais d'attente des webhooks. Sur un cluster managé, vous n'y aurez peut-être pas accès, mais sur un cluster auto-géré, consultez les journaux du conteneur kube-apiserver :

```bash
journalctl -u kube-apiserver | grep -i webhook
```

Erreurs attendues comme :

```
E1015 10:35:00.234567   12345 dispatcher.go:173] failed calling webhook "pod-security.example.com": failed to call webhook: Post https://pod-security-webhook.default.svc:443/validate?timeout=3s: context deadline exceeded
```

### Valider que les politiques sont toujours appliquées

Le réglage des performances ne doit pas compromettre l'application des politiques. Testez que le contrôleur d'admission refuse toujours les requêtes invalides. Par exemple, si le webhook impose une exigence d'étiquette, essayez de créer un pod sans l'étiquette requise et attendez-vous à un rejet :

```bash
kubectl run bad-pod --image=nginx --restart=Never
```

La sortie attendue comprend un message d'erreur du webhook :

```
Error from server (Forbidden): admission webhook "pod-security.example.com" denied the request: missing required label 'app'
```

Si la requête est acceptée, le webhook est peut-être mal configuré (par exemple, `failurePolicy: Ignore` l'amenant à ignorer les erreurs) ou les règles ne correspondent plus.

### Test de performance à grande échelle

Pour simuler la charge, utilisez un outil comme `kubectl apply` dans une boucle ou un outil de test de charge. Par exemple, créez 100 pods par lots et mesurez le temps total :

```bash
time for i in $(seq 1 100); do kubectl run test-$i --image=nginx --restart=Never --labels=app=test-$i; done
```

Ensuite, nettoyez :

```bash
kubectl delete pods -l app --selector 'app in (test-1,test-2,...)'
```

Comparez le temps avant et après le réglage. Une réduction significative du temps total indique une amélioration.

## Modes de défaillance et récupération

Même avec un réglage minutieux, les contrôleurs d'admission peuvent tomber en panne et provoquer des pannes généralisées. Comprenez les modes de défaillance courants et comment récupérer rapidement.

### Échecs dus aux délais d'attente des webhooks

Si un webhook dépasse son `timeoutSeconds`, le serveur d'API traite cela comme un échec selon `failurePolicy`. Si `failurePolicy: Fail`, la requête est rejetée avec une erreur comme :

```
Error from server (InternalError): an error on the server ("") has prevented the request from succeeding
```

Cela peut entraîner l'échec de toutes les requêtes correspondantes. Pour récupérer rapidement :

1. **Désactivez temporairement le webhook** en définissant `failurePolicy: Ignore` ou en supprimant la configuration du webhook. Pour une correction temporaire, vous pouvez modifier le webhook :

```bash
kubectl edit validatingwebhookconfiguration pod-security-webhook
```

Changez `failurePolicy` en `Ignore` et enregistrez. Les requêtes se poursuivront alors sans validation.

2. **Faites évoluer le backend du webhook** pour gérer la charge.

3. **Enquêtez sur la cause profonde** (par exemple, problèmes réseau, épuisement des ressources) et corrigez-la.

### Service webhook indisponible

Si les points de terminaison du service webhook ne sont pas prêts (par exemple, les pods sont en boucle de crash), le serveur d'API échouera également les requêtes. Vérifiez les points de terminaison du service :

```bash
kubectl get endpoints -n pod-security-webhook
```

S'il n'y a pas de points de terminaison, le sélecteur de service peut ne pas correspondre aux pods, ou les pods ne sont pas prêts. Vérifiez l'état et les journaux des pods.

### Règles de webhook mal configurées

Un webhook avec des règles trop larges peut intercepter plus de requêtes que prévu, entraînant une dégradation des performances et des refus inattendus. Par exemple, un webhook destiné aux pods mais configuré pour intercepter toutes les ressources (`resources: ["*"]`) sera appelé pour chaque objet. Pour récupérer, restreignez les règles à des ressources spécifiques.

### Problèmes avec les contrôleurs d'admission intégrés

Bien que moins courants, les contrôleurs d'admission intégrés peuvent également causer des problèmes. Par exemple, si le contrôleur `ResourceQuota` est lent, cela peut être dû à un grand nombre de quotas dans le cluster. Dans des cas extrêmes, vous devrez peut-être désactiver temporairement le contrôleur d'admission. Cela nécessite de modifier le manifeste du serveur d'API et n'est pas recommandé en production sans tests approfondis.

### Stratégie de retour en arrière

Conservez toujours une sauvegarde des configurations de webhook d'origine avant d'apporter des modifications. Utilisez `kubectl get <resource> -o yaml > backup.yaml` pour les enregistrer. Si un changement pose problème, restaurez à partir de la sauvegarde :

```bash
kubectl apply -f backup.yaml
```

De plus, versionnez vos configurations à l'aide d'outils GitOps comme Argo CD ou Flux, qui permettent des retours en arrière faciles.

## Liste de contrôle opérationnelle

Utilisez cette liste de contrôle pour vous assurer d'avoir couvert tous les aspects du réglage des performances des contrôleurs d'admission :

- [ ] Identifier la version de Kubernetes et les contrôleurs d'admission activés.
- [ ] Lister toutes les configurations de webhooks de validation et de mutation.
- [ ] Examiner les paramètres `timeoutSeconds` et `failurePolicy` de chaque webhook.
- [ ] Mesurer la latence de base des requêtes API avec et sans les webhooks.
- [ ] Analyser les métriques du serveur d'API pour la durée d'admission, si disponibles.
- [ ] Identifier les webhooks les plus chronophages.
- [ ] Restreindre les règles des webhooks aux ressources et opérations minimales nécessaires.
- [ ] Réduire `timeoutSeconds` à une valeur qui équilibre disponibilité et détection des échecs.
- [ ] Envisager de définir `failurePolicy: Ignore` pour les webhooks non critiques.
- [ ] Utiliser `namespaceSelector` ou `objectSelector` pour filtrer l'invocation des webhooks.
- [ ] Adapter les déploiements du backend des webhooks de manière appropriée.
- [ ] Surveiller l'utilisation des ressources du backend des webhooks (CPU, mémoire) et ajuster les limites.
- [ ] Vérifier que les politiques sont toujours appliquées après le réglage.
- [ ] Effectuer un test de performance sous une charge réaliste.
- [ ] Documenter les modifications et s'assurer que des procédures de retour en arrière sont en place.
- [ ] Mettre en place des alertes sur la latence et les taux d'échec des webhooks si ce n'est pas déjà fait.

## Conclusion

Le réglage des contrôleurs d'admission Kubernetes est un équilibre entre performance et application des politiques. En mesurant systématiquement, en apportant des modifications ciblées et en vérifiant les résultats, vous pouvez éliminer les goulots d'étranglement et prévenir les pannes. N'oubliez pas de toujours avoir un plan de retour en arrière et de surveiller les effets de vos modifications au fil du temps. Grâce aux étapes pratiques de ce guide, vous pouvez vous assurer que les contrôleurs d'admission font leur travail sans ralentir votre cluster.