## Introduction

Les services Kubernetes fournissent une abstraction stable pour exposer vos applications exécutées sous forme de pods. Ils offrent une adresse IP cohérente, un nom DNS et un équilibrage de charge entre les pods sains. Mais lorsqu'un service est mal configuré, vous pouvez rencontrer des erreurs frustrantes : connexion refusée, aucun point de terminaison disponible, échecs de résolution DNS ou conflits avec des adresses IP ClusterIP existantes. Ce guide passe en revue les messages d'erreur les plus courants des services Kubernetes, explique pourquoi ils surviennent, comment les diagnostiquer avec des commandes pratiques et comment les corriger en toute sécurité. Vous apprendrez à identifier les incohérences de sélecteur, à résoudre les problèmes de points de terminaison manquants, à résoudre les conflits ClusterIP et à déboguer les problèmes DNS. Chaque section comprend des exemples de commandes concrets, les sorties attendues et les étapes de retour en arrière. À la fin, vous disposerez d'un processus reproductible pour maintenir vos services en bonne santé.

## Inventaire des versions et de l'environnement

Avant de commencer le dépannage, rassemblez des informations sur votre cluster Kubernetes et le service concerné. Connaître la version vous aide à identifier les bogues connus ou les changements de comportement. Exécutez `kubectl version` pour voir les versions du client et du serveur.

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

Vérifiez les détails du service avec `kubectl get svc <nom-du-service> -o yaml` et inspectez le sélecteur, les ports et le type. Par exemple :

```yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: default
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP
```

Vérifiez également que les pods ont des étiquettes correspondantes en utilisant `kubectl get pods --show-labels`. Si le sélecteur ne correspond à aucune étiquette de pod, le service n'aura aucun point de terminaison. C'est une cause fréquente d'erreurs.

```text
NAME                     READY   STATUS    RESTARTS   AGE   LABELS
my-app-6d4b7c9f5-abcde   1/1     Running   0          10m   app=my-app,version=v1
my-app-6d4b7c9f5-fghij   1/1     Running   0          10m   app=my-app,version=v1
```

Notez que les étiquettes sur les pods incluent la paire clé-valeur `app=my-app` attendue par le sélecteur du service. Si votre sélecteur utilise `app: my-app` mais que les pods ont seulement `app: myapp` ou aucune étiquette `app`, vous vous retrouverez sans points de terminaison.

## Chemin de configuration sûr

Commencez avec une configuration de service minimale et validez-la avant d'apporter des modifications. Utilisez `kubectl apply --dry-run=client` pour tester la syntaxe sans rien appliquer au cluster.

```bash
kubectl apply -f service.yaml --dry-run=client
```

Sortie attendue :

```text
service/my-service created (dry run)
```

Lors de la modification d'un service existant, enregistrez d'abord une sauvegarde de la configuration actuelle :

```bash
kubectl get svc my-service -o yaml > service-backup.yaml
```

Appliquez les modifications de manière limitée, par exemple dans un espace de noms de test d'abord. Créez un espace de noms avec `kubectl create namespace test`, puis appliquez le YAML du service là-bas en utilisant `kubectl apply -f service.yaml -n test` pour observer le comportement avant de toucher à la production.

Une bonne pratique consiste à utiliser des sélecteurs explicites et à toujours spécifier clairement `targetPort`. Évitez d'utiliser `targetPort` comme un nom de chaîne qui pourrait ne pas correspondre au nom du port du conteneur. Par exemple, si votre conteneur expose un port nommé `http` sur 8080, votre service doit référencer `targetPort: http` ou `targetPort: 8080`. Si vous utilisez `targetPort: 8081` mais que le conteneur écoute sur 8080, vous obtiendrez une connexion refusée.

## Vérification et diagnostics

Après avoir appliqué un service, vérifiez son état et ses points de terminaison. Exécutez `kubectl describe svc my-service` pour voir les événements et les points de terminaison. Exemple de sortie :

```text
Name:              my-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=my-app
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.0.100
IPs:               10.96.0.100
Port:              <unset>  80/TCP
TargetPort:        8080/TCP
Endpoints:         172.17.0.5:8080,172.17.0.6:8080
Session Affinity:  None
Events:            <none>
```

Si `Endpoints` est vide, le sélecteur est peut-être incorrect. Vérifiez avec `kubectl get endpoints my-service`.

```text
NAME         ENDPOINTS                     AGE
my-service   172.17.0.5:8080,172.17.0.6:8080   10m
```

Si vous voyez `<none>` sous ENDPOINTS, cela indique qu'aucun pod n'est sélectionné. Vérifiez le sélecteur et les étiquettes des pods comme décrit ci-dessus.

Testez la connectivité depuis un autre pod en utilisant `kubectl run -it --rm debug --image=busybox -- sh` puis exécutez `wget -qO- http://my-service`. Pour le DNS, utilisez `nslookup my-service` à l'intérieur du pod de débogage.

```bash
kubectl run -it --rm debug --image=busybox -- sh
# À l'intérieur du pod de débogage :
wget -qO- http://my-service
nslookup my-service
```

Si le service est dans un espace de noms différent de celui du pod, utilisez le nom de domaine pleinement qualifié (FQDN) comme `my-service.default.svc.cluster.local`. Par exemple, depuis un pod dans l'espace de noms `test`, vous utiliseriez `wget -qO- http://my-service.default.svc.cluster.local`.

## Modes d'échec et récupération

### Aucun point de terminaison disponible

La cause la plus courante de l'erreur « aucun point de terminaison disponible » est une incohérence de sélecteur entre le service et les pods. Par exemple, si votre sélecteur de service est `app: my-app` mais que vos pods sont étiquetés `app: myapp` ou `tier: frontend`, le service ne sélectionnera aucun pod et ses points de terminaison seront vides. Pour corriger cela, corrigez le sélecteur dans le YAML du service pour qu'il corresponde exactement aux étiquettes des pods.

```yaml
spec:
  selector:
    app: my-app
    # Assurez-vous que cela correspond à vos étiquettes de pod ; par exemple, si les pods ont aussi version=v1, vous n'en avez peut-être pas besoin.
```

Après la mise à jour, vérifiez avec `kubectl get endpoints my-service`. Si vous devez revenir en arrière, réappliquez la configuration de sauvegarde avec `kubectl apply -f service-backup.yaml`.

Une autre cause d'absence de points de terminaison est le fait que les pods ne sont pas prêts. Vérifiez l'état des pods avec `kubectl get pods -l app=my-app`. Si les pods sont en `CrashLoopBackOff` ou ne sont pas prêts, le service ne leur acheminera pas le trafic. Examinez les journaux des pods avec `kubectl logs <nom-du-pod>`.

### Conflit de ClusterIP

Si un service est créé avec une `clusterIP` spécifique qui existe déjà, vous obtenez une erreur du type « l'IP fournie est déjà allouée ». Pour éviter cela, supprimez le champ `clusterIP` de votre YAML de service et laissez Kubernetes allouer automatiquement une nouvelle IP, ou supprimez le service en conflit.

Exemple d'erreur :

```text
Error from server (AlreadyExists): services "my-service" already exists
```

Si vous voyez une erreur plus spécifique concernant l'allocation d'IP lors de la création, assurez-vous que le champ `clusterIP` n'est pas défini ou choisissez une autre IP dans le CIDR de service. Vous pouvez vérifier les ClusterIP allouées avec `kubectl get svc --all-namespaces -o wide`.

Pour résoudre :

1. Modifiez le service : `kubectl edit svc my-service` et supprimez la ligne `clusterIP`, puis enregistrez. Kubernetes allouera une nouvelle IP.
2. Sinon, supprimez et recréez le service sans spécifier `clusterIP` :

```bash
kubectl delete svc my-service
kubectl apply -f service.yaml  # service.yaml sans clusterIP
```

### Échec de résolution DNS

Si le nom du service ne peut pas être résolu, vérifiez que CoreDNS est en cours d'exécution et que le service est dans le bon espace de noms. Le nom DNS complet est `<nom-du-service>.<espace-de-noms>.svc.cluster.local`. Depuis l'intérieur d'un pod, exécutez `nslookup my-service`. Si cela échoue, vérifiez les pods CoreDNS :

```bash
kubectl get pods -n kube-system -l k8s-app=kube-dns
```

La sortie attendue inclut des pods CoreDNS en état Running. Vérifiez également que le service existe dans l'espace de noms prévu : `kubectl get svc -n <espace-de-noms>`.

Si le DNS échoue uniquement pour les noms externes, vérifiez la configuration de CoreDNS pour les redirecteurs. Pour les services internes, assurez-vous que le service est de type ClusterIP ou Headless, pas ExternalName (qui nécessite un comportement DNS différent).

### Connexion refusée

« Connexion refusée » signifie généralement que le port cible n'écoute pas. Assurez-vous que le conteneur écoute sur le `targetPort` et que les politiques réseau autorisent le trafic. Utilisez `kubectl get svc my-service -o yaml` pour confirmer que `targetPort` correspond au port du conteneur.

Par exemple, si votre conteneur écoute sur le port 8080 mais que le `targetPort` du service est 8081, vous verrez une connexion refusée. Corrigez le `targetPort` à 8080. Vérifiez également que le processus du conteneur est réellement en cours d'exécution et lié à la bonne interface (0.0.0.0, pas localhost). Utilisez `kubectl exec <nom-du-pod> -- netstat -tulpn` (si disponible) pour voir les ports en écoute.

Les politiques réseau peuvent également bloquer le trafic. Si vous avez une NetworkPolicy qui n'autorise pas l'entrée vers les pods sur le port cible, vous pouvez obtenir une connexion refusée ou un délai d'attente. Passez en revue les politiques réseau dans l'espace de noms avec `kubectl get networkpolicies`.

## Liste de vérification des opérations

Utilisez cette liste de vérification avant et après avoir apporté des modifications au service. Remplacez les espaces réservés par votre nom de service et votre espace de noms spécifiques.

| Tâche | Commande | Résultat attendu |
|---|---|---|
| Vérifier la version du cluster | `kubectl version` | Versions du client et du serveur affichées |
| Inspecter le YAML actuel du service | `kubectl get svc my-service -o yaml` | YAML avec sélecteur et ports |
| Lister les pods avec étiquettes | `kubectl get pods -n default --show-labels` | Les étiquettes des pods correspondent au sélecteur du service |
| Appliquer en mode simulation | `kubectl apply -f service.yaml --dry-run=client` | Aucune erreur : `service/my-service created (dry run)` |
| Décrire le service | `kubectl describe svc my-service` | La section Endpoints liste des paires IP:port de pods |
| Vérifier les points de terminaison | `kubectl get endpoints my-service` | La colonne ENDPOINTS montre au moins une IP:port |
| Tester la résolution DNS | `kubectl run -it --rm debug --image=busybox -- nslookup my-service` | La sortie montre l'IP ClusterIP pour my-service.default.svc.cluster.local |
| Tester la connectivité HTTP | `kubectl run -it --rm debug --image=busybox -- wget -qO- http://my-service` | Renvoie le corps de réponse HTTP attendu |
| Vérifier l'état de CoreDNS (si le DNS échoue) | `kubectl get pods -n kube-system -l k8s-app=kube-dns` | Les pods CoreDNS sont Running et Ready |
| Revenir en arrière si nécessaire | `kubectl apply -f service-backup.yaml` | Le service revient à l'état de fonctionnement précédent |

Passez régulièrement en revue les services pour détecter les entrées inutilisées ou mal configurées. Utilisez `kubectl get svc --all-namespaces` pour lister tous les services et rechercher ceux qui n'ont aucun point de terminaison ou des problèmes de sélecteur. Nettoyez les services obsolètes pour éviter toute confusion et les conflits potentiels.

## Conclusion

Les erreurs des services Kubernetes peuvent être déboguées efficacement en vérifiant méthodiquement la définition du service, les étiquettes du sélecteur, les points de terminaison et le DNS. Commencez toujours par une configuration minimale, utilisez la simulation pour la validation et conservez des sauvegardes pour le retour en arrière. Utilisez les commandes de vérification de ce guide pour confirmer que votre service fonctionne comme prévu. En suivant la liste de vérification des opérations, vous pouvez maintenir des services sains et éviter les pièges courants tels que les incohérences de sélecteur, les conflits ClusterIP et les échecs DNS. Avec ce processus reproductible, vous réduirez les temps d'arrêt et garderez vos applications exposées de manière fiable au sein de votre cluster.