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.
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 :
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.
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.
kubectl apply -f service.yaml --dry-run=client
Sortie attendue :
service/my-service created (dry run)
Lors de la modification d'un service existant, enregistrez d'abord une sauvegarde de la configuration actuelle :
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 :
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.
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.
kubectl debug -it <pod-name> --image=busybox
# À 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.
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 :
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 :
- Modifiez le service :
kubectl edit svc my-serviceet supprimez la ligneclusterIP, puis enregistrez. Kubernetes allouera une nouvelle IP. - Sinon, supprimez et recréez le service sans spécifier
clusterIP:
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 :
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.