Introduction
Lorsqu'un pod utilisant un compte de service Kubernetes ne parvient pas à joindre un service interne, la cause première est rarement le code de l'application. Il s'agit plus souvent d'une mauvaise configuration réseau impliquant les autorisations du compte de service, la résolution DNS ou les politiques réseau. Ce guide propose une approche de dépannage systématique pour les problèmes réseau liés aux comptes de service Kubernetes, avec des exemples pratiques et des commandes que vous pouvez exécuter dans votre propre cluster.
Nous nous concentrons sur le chemin réseau allant d'un pod associé à un compte de service spécifique vers un service Kubernetes. Nous verrons comment vérifier que le compte de service existe, que le pod l'utilise correctement, que le DNS résout le nom du service, que les politiques réseau autorisent le trafic et que les endpoints du service sont joignables. À la fin, vous disposerez d'un processus reproductible pour diagnostiquer et corriger les problèmes réseau courants liés aux comptes de service.
Inventaire des versions et de l'environnement
Avant de commencer le dépannage, documentez votre environnement. Cela garantit que vous testez sur le bon cluster et que vous comprenez les composants impliqués.
1. Noter les versions de Kubernetes et du client
kubectl version --short
Sortie attendue (exemple) :
Client Version: v1.24.3
Server Version: v1.24.3
Si les versions du client et du serveur diffèrent considérablement, certaines commandes ou ressources d'API peuvent se comporter différemment. Notez les versions pour référence.
2. Confirmer le contexte du cluster et l'espace de noms
Assurez-vous d'opérer dans le bon cluster et le bon espace de noms.
kubectl config current-context
kubectl get namespaces
Vérifiez l'espace de noms où se trouvent votre pod et votre service. Pour ce guide, nous supposons un espace de noms appelé app-ns.
3. Identifier le pod et son compte de service
Listez les pods avec leurs comptes de service :
kubectl get pods -n app-ns -o custom-columns=POD:.metadata.name,SERVICE_ACCOUNT:.spec.serviceAccountName
Sortie attendue (exemple) :
POD SERVICE_ACCOUNT
web-5b7c9d6f8-abcde web-sa
api-7f8d9c6b5-fghij api-sa
Notez le nom du compte de service pour le pod que vous dépannez. Dans cet exemple, nous utiliserons web-sa.
4. Vérifier l'existence et les détails du compte de service
Vérifiez que le compte de service existe et notez ses secrets (le cas échéant) et les rôles associés.
kubectl get serviceaccount web-sa -n app-ns -o yaml
Recherchez les champs secrets et imagePullSecrets. Si le compte de service n'a aucun secret listé, c'est normal dans Kubernetes 1.24+ où les secrets de jeton ne sont pas automatiquement créés. Le pod peut toujours s'authentifier à l'aide de jetons projetés.
5. Vérifier la topologie réseau
Comprenez comment les pods communiquent. Les plugins CNI courants (Calico, Flannel, Cilium) ont des comportements par défaut différents. Vérifiez les ressources NetworkPolicy dans l'espace de noms :
kubectl get networkpolicies -n app-ns
S'il en existe, elles peuvent bloquer le trafic. Nous les examinerons plus tard.
Prérequis pour le dépannage
Vous avez besoin d'un accès kubectl au cluster et, idéalement, de la permission d'exécuter des commandes dans les pods. Vous devez également avoir une compréhension de base des services Kubernetes, des endpoints et du DNS.
Chemin de configuration sûr
Pour illustrer le dépannage, nous avons besoin d'une configuration fonctionnelle. Nous allons créer un exemple minimal : un compte de service, un déploiement utilisant ce compte de service et un service que le pod doit joindre.
1. Créer un compte de service
Définissez un compte de service dans sa.yaml :
apiVersion: v1
kind: ServiceAccount
metadata:
name: web-sa
namespace: app-ns
Appliquez-le :
kubectl apply -f sa.yaml
Sortie attendue :
serviceaccount/web-sa created
2. Créer un déploiement utilisant le compte de service
Créez deploy.yaml :
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: app-ns
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
serviceAccountName: web-sa
containers:
- name: web
image: nginx:alpine
ports:
- containerPort: 80
Appliquez :
kubectl apply -f deploy.yaml
Vérifiez que le pod est en cours d'exécution :
kubectl get pods -n app-ns -l app=web
Sortie attendue :
NAME READY STATUS RESTARTS AGE
web-5b7c9d6f8-abcde 1/1 Running 0 30s
3. Créer un service
Définissez service.yaml pour un service interne auquel le pod web doit accéder. Nous utilisons un simple service ClusterIP :
apiVersion: v1
kind: Service
metadata:
name: api
namespace: app-ns
spec:
selector:
app: api
ports:
- port: 80
targetPort: 8080
Appliquez-le :
kubectl apply -f service.yaml
Vérifiez :
kubectl get services -n app-ns
Sortie attendue :
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api ClusterIP 10.96.100.50 <none> 80/TCP 10s
4. Créer un pod backend pour le service
Pour que le service ait des endpoints, créez un déploiement backend simple :
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: app-ns
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: hashicorp/http-echo:latest
args:
- "-text=API is up"
- "-listen=:8080"
ports:
- containerPort: 8080
Appliquez et attendez qu'il soit prêt.
Cette configuration nous donne un environnement contrôlé pour tester la connectivité. Le pod web utilise le compte de service web-sa. Nous n'avons pas encore configuré de politiques réseau, donc par défaut tout le trafic est autorisé.
Vérification et diagnostics
Nous allons maintenant vérifier systématiquement chaque couche du chemin réseau.
1. Confirmer que le pod utilise le bon compte de service
Vérifiez la spécification du pod :
kubectl get pod -n app-ns -l app=web -o jsonpath='{.items[0].spec.serviceAccountName}'
Sortie attendue :
web-sa
Si la sortie est vide, le pod utilise le compte de service default de l'espace de noms.
2. Vérifier le jeton du compte de service monté dans le pod
Kubernetes projette un jeton de compte de service dans le pod à l'emplacement /var/run/secrets/kubernetes.io/serviceaccount. Vérifiez qu'il existe :
kubectl exec -n app-ns <nom-du-pod-web> -- ls /var/run/secrets/kubernetes.io/serviceaccount
Sortie attendue :
ca.crt namespace token
Si ces fichiers sont absents, le pod peut ne pas être en mesure de s'authentifier auprès de l'API server, ce qui peut affecter certaines fonctionnalités réseau (mais pas le trafic direct de service à service).
3. Résolution DNS à l'intérieur du pod
Depuis le pod web, tentez de résoudre le nom DNS du service. Le nom DNS complet d'un service dans le même espace de noms est <service>.<espace-de-noms>.svc.cluster.local. Pour un espace de noms différent, c'est également <service>.<espace-de-noms>.svc.cluster.local, mais le nom court <service> fonctionne dans le même espace de noms.
kubectl exec -n app-ns <nom-du-pod-web> -- nslookup api
Sortie attendue (exemple) :
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: api.app-ns.svc.cluster.local
Address: 10.96.100.50
Si nslookup n'est pas disponible, utilisez getent hosts api ou cat /etc/resolv.conf pour vérifier la configuration DNS.
Vérifiez resolv.conf :
kubectl exec -n app-ns <nom-du-pod-web> -- cat /etc/resolv.conf
Sortie attendue (exemple) :
nameserver 10.96.0.10
search app-ns.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Le serveur de noms doit être l'adresse IP du service DNS du cluster (généralement kube-dns). Si le DNS échoue, l'adresse IP du service peut ne pas être renvoyée.
4. Tester la connectivité vers l'IP et le port du service
Utilisez curl ou wget depuis le pod pour accéder au service. Comme notre backend renvoie un message, nous pouvons nous attendre à une réponse.
kubectl exec -n app-ns <nom-du-pod-web> -- curl -s http://api
Sortie attendue :
API is up
Si curl n'est pas disponible, utilisez nc -zv api 80 ou telnet api 80 pour tester la connectivité TCP.
Si cela échoue, vérifiez les endpoints du service :
kubectl get endpoints -n app-ns api
Sortie attendue (exemple) :
NAME ENDPOINTS AGE
api 10.244.1.5:8080 5m
Si les endpoints sont vides, le sélecteur du service ne correspond à aucun pod. Vérifiez les libellés des pods backend :
kubectl get pods -n app-ns -l app=api --show-labels
5. Vérifier les politiques réseau (NetworkPolicy)
Si des NetworkPolicies existent, elles peuvent bloquer le trafic. Listez-les :
kubectl get networkpolicies -n app-ns
Si elles sont présentes, inspectez-les. Par exemple, une politique peut refuser tout le trafic entrant vers les pods portant le libellé app=api sauf depuis des sources spécifiques. Vous pouvez tester en créant temporairement une politique autorisant tout (uniquement dans un environnement de test) :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
namespace: app-ns
spec:
podSelector: {}
ingress:
- {}
egress:
- {}
policyTypes:
- Ingress
- Egress
Appliquez-la, retestez la connectivité, puis supprimez-la. Si la connectivité fonctionne avec cette politique, vous savez que les politiques précédentes étaient la cause.
6. Vérifier les autorisations du compte de service (RBAC) pour l'accès à l'API
Parfois, le pod doit appeler l'API Kubernetes (par exemple, pour lister les services). Cela nécessite des rôles RBAC liés au compte de service. Vérifiez si le compte de service a une liaison de rôle :
kubectl get rolebindings,clusterrolebindings -n app-ns -o json | jq '.items[] | select(.subjects[]?.name=="web-sa")'
Si aucune liaison n'existe, le pod ne peut pas effectuer d'appels API. Pour tester l'accès API, exécutez :
kubectl exec -n app-ns <nom-du-pod-web> -- curl -s -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/api/v1/namespaces/app-ns/services
Si vous obtenez une erreur 403 Forbidden, le compte de service n'a pas les autorisations RBAC nécessaires. Notez que le trafic de service à service ne nécessite pas l'accès à l'API, mais certaines applications en dépendent.
7. Inspecter kube-proxy et les règles de service
Sur le nœud (si vous y avez accès), vérifiez les règles iptables pour l'IP du service :
sudo iptables-save | grep 10.96.100.50
Cela montre les règles DNAT qui acheminent le trafic vers l'IP du pod. Si les règles sont absentes, kube-proxy peut être défaillant.
Modes de défaillance et récupération
Modes de défaillance courants et comment s'en remettre.
Défaillance 1 : Faute de frappe ou absence du nom du compte de service
Si la spécification du pod fait référence à un compte de service inexistant, le pod ne démarrera pas avec une erreur du type :
Error creating: pods "web-..." is forbidden: error looking up service account app-ns/web-sa: serviceaccount "web-sa" not found
Récupération : Créez le compte de service ou corrigez le nom dans le déploiement. Appliquez le changement et le pod redémarrera automatiquement.
Défaillance 2 : Échec de la résolution DNS
Symptômes : nslookup renvoie server can't find api: NXDOMAIN ou expire.
Causes possibles :
- Les pods CoreDNS ne sont pas en cours d'exécution : vérifiez
kubectl get pods -n kube-system -l k8s-app=kube-dns. - Problèmes de configuration CoreDNS : vérifiez les journaux
kubectl logs -n kube-system -l k8s-app=kube-dns. - Le fichier
resolv.confdu pod est incorrect en raison d'undnsPolicyoudnsConfigpersonnalisé.
Récupération : Assurez-vous que CoreDNS est sain. Si les paramètres DNS du pod sont incorrects, ajustez la spécification du pod. Pour un test rapide, vous pouvez temporairement utiliser directement l'IP ClusterIP du service : curl http://10.96.100.50.
Défaillance 3 : Politique réseau bloquant le trafic
Si les NetworkPolicies refusent le trafic, les pods ne peuvent pas se connecter. Vérifiez en examinant les politiques et leurs sélecteurs. Souvent, une politique est destinée à n'autoriser que des espaces de noms ou des pods spécifiques.
Récupération : Modifiez la NetworkPolicy pour autoriser le trafic provenant des libellés ou de l'espace de noms du pod web. Par exemple, pour autoriser le trafic depuis les pods portant le libellé app=web :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-to-api
namespace: app-ns
spec:
podSelector:
matchLabels:
app: api
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- port: 8080
Appliquez et retestez.
Défaillance 4 : Endpoints du service vides
Si kubectl get endpoints ne montre aucun endpoint, le sélecteur du service ne correspond à aucun pod en cours d'exécution. Vérifiez que les pods backend ont les bons libellés et sont dans l'état Ready.
Récupération : Corrigez les libellés ou assurez-vous que les pods backend sont en cours d'exécution. Par exemple, si les pods backend ont le libellé app=api-v2 mais que le service sélectionne app=api, mettez à jour le sélecteur du service.
Défaillance 5 : Restrictions RBAC sur les appels API
Si le pod doit accéder à l'API Kubernetes et obtient des erreurs 403, créez un rôle et une liaison de rôle appropriés.
Exemple de rôle pour autoriser la lecture des services :
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: app-ns
name: service-reader
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
Liaison de rôle :
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: app-ns
name: web-sa-service-reader
subjects:
- kind: ServiceAccount
name: web-sa
namespace: app-ns
roleRef:
kind: Role
name: service-reader
apiGroup: rbac.authorization.k8s.io
Appliquez et retestez l'accès API.
Stratégies de retour en arrière
Conservez toujours une sauvegarde des fichiers YAML d'origine avant d'apporter des modifications. Si un changement casse la connectivité, revenez à la version précédente en utilisant kubectl apply -f previous.yaml. Pour les NetworkPolicies, vous pouvez supprimer la politique fautive et réappliquer celle qui est connue comme bonne.
Vérifications de récupération
Après tout changement, exécutez la séquence de vérification suivante :
kubectl get pods -n app-ns- assurez-vous que les pods sont en cours d'exécution et prêts.kubectl get endpoints -n app-ns api- assurez-vous que les endpoints sont renseignés.kubectl exec -n app-ns <pod-web> -- curl -s http://api- attendez la réponse du backend.kubectl exec -n app-ns <pod-web> -- nslookup api- attendez la bonne IP.
Liste de contrôle des opérations
Utilisez cette liste de contrôle pour un dépannage et une maintenance reproductibles.
| Étape | Action | Commande | Résultat attendu |
|---|---|---|---|
| 1 | Vérifier l'existence du compte de service | kubectl get sa web-sa -n app-ns | Compte de service listé |
| 2 | Confirmer que le pod utilise le bon SA | kubectl get pod <pod> -n app-ns -o jsonpath='{.spec.serviceAccountName}' | Affiche web-sa |
| 3 | Vérifier les fichiers de jeton du pod | kubectl exec <pod> -n app-ns -- ls /var/run/secrets/kubernetes.io/serviceaccount | Liste ca.crt, namespace, token |
| 4 | Tester la résolution DNS | kubectl exec <pod> -n app-ns -- nslookup api | Renvoie l'IP du service |
| 5 | Tester la connectivité au service | kubectl exec <pod> -n app-ns -- curl -s http://api | Renvoie la réponse attendue |
| 6 | Vérifier les endpoints | kubectl get endpoints api -n app-ns | Endpoints non vides |
| 7 | Vérifier les politiques réseau | kubectl get networkpolicies -n app-ns | Examiner toute politique |
| 8 | Vérifier les liaisons RBAC | kubectl get rolebindings,clusterrolebindings -n app-ns -o json | jq '.items[] | select(.subjects[]?.name=="web-sa")' | Liaisons si l'accès API est nécessaire |
| 9 | Examiner les journaux CoreDNS | kubectl logs -n kube-system -l k8s-app=kube-dns | Aucune erreur |
Effectuez ces vérifications chaque fois qu'un problème réseau survient, après tout changement de configuration et lors des audits de routine.
Pièges courants et comment les éviter
Même les administrateurs Kubernetes expérimentés peuvent négliger certains détails qui conduisent à des échecs de réseau des comptes de service. Voici les erreurs les plus fréquentes et comment les éviter.
1. Supposer que la politique réseau par défaut autorise tout le trafic
De nombreuses équipes activent une NetworkPolicy de refus par défaut au niveau de l'espace de noms, puis oublient d'ajouter une règle d'autorisation pour leurs charges de travail. Un pod qui fonctionnait hier peut soudainement perdre la connectivité après l'application d'une politique.
Pourquoi cela arrive : Les NetworkPolicies de Kubernetes sont additives : si une politique sélectionne un pod, le pod est isolé et seul le trafic explicitement autorisé par l'union des politiques est permis.
Comment éviter : Documentez toujours les NetworkPolicies et leur effet prévu. Lors du dépannage, vérifiez les politiques qui sélectionnent les pods source ou destination. Utilisez kubectl describe networkpolicy <nom> -n <espace-de-noms> pour voir les règles exactes.
2. Ignorer les domaines de recherche DNS et ndots
L'option ndots:5 dans /etc/resolv.conf amène le résolveur à essayer le nom complet avec les domaines de recherche avant de tenter le nom absolu. Cela peut conduire à des recherches DNS inattendues et à des retards si vous utilisez fréquemment des noms d'hôtes externes sans point final.
Pourquoi cela arrive : Kubernetes injecte les domaines de recherche du cluster dans chaque pod par défaut. Pour un nom comme api, le résolveur essaie d'abord api.app-ns.svc.cluster.local, puis api.svc.cluster.local, etc., avant de revenir au nom absolu.
Comment éviter : Soyez conscient de ce comportement lors du débogage des problèmes DNS. Utilisez des noms de domaine pleinement qualifiés (FQDN) se terminant par un point pour contourner les domaines de recherche, ou ajustez dnsConfig dans la spécification du pod si nécessaire.
3. Oublier que les comptes de service n'affectent pas directement le réseau de service à service
Une idée fausse courante est qu'un compte de service est nécessaire pour qu'un pod atteigne un autre service. En réalité, le trafic de service à service au sein du cluster repose sur le DNS, kube-proxy et les politiques réseau, et non sur le compte de service. Le compte de service n'a d'importance que lorsque le pod doit s'authentifier auprès de l'API Kubernetes ou de systèmes externes à l'aide de son jeton.
Pourquoi cela arrive : La documentation regroupe souvent la configuration du compte de service avec la sécurité générale des pods et le réseau, ce qui prête à confusion.
Comment éviter : Séparez les préoccupations. Si un pod ne peut pas joindre un service, vérifiez d'abord le DNS et les politiques réseau. N'enquêtez sur le RBAC et les jetons de compte de service que si le pod échoue à accéder à l'API Kubernetes ou à des services externes nécessitant une authentification.
4. Utiliser un objet Endpoint obsolète pour le débogage
Après avoir corrigé un sélecteur de service ou les libellés des pods backend, l'objet Endpoints peut ne pas se mettre à jour immédiatement. Vérifier kubectl get endpoints trop tôt peut montrer des endpoints vides même si le service est maintenant correctement configuré.
Pourquoi cela arrive : Le contrôleur Endpoints a une boucle de réconciliation et peut prendre quelques secondes pour se mettre à jour.
Comment éviter : Attendez que le contrôleur se synchronise, ou surveillez l'objet endpoints avec kubectl get endpoints -n app-ns -w pour voir la mise à jour en temps réel.
5. Négliger l'impact des services NodePort ou LoadBalancer sur la communication interne
Lorsqu'un service est exposé en NodePort ou LoadBalancer, il possède toujours une ClusterIP. Les pods internes doivent utiliser la ClusterIP ou le nom DNS ; utiliser le port du nœud depuis un pod peut échouer si le pare-feu du nœud ou la politique réseau bloque ce port.
Pourquoi cela arrive : Les développeurs testent parfois depuis un pod en utilisant l'IP du nœud et le NodePort, qui peuvent ne pas être joignables en raison des politiques réseau ou des règles de pare-feu du nœud.
Comment éviter : Utilisez toujours le nom DNS du service ou la ClusterIP depuis l'intérieur du cluster. Réservez NodePort et LoadBalancer au trafic externe.
Conclusion
Le dépannage du réseau des comptes de service Kubernetes nécessite une approche méthodique. Commencez par vérifier la configuration du compte de service et du pod, puis testez la résolution DNS et la connectivité, et enfin inspectez les politiques réseau et le RBAC. Les commandes pratiques et les exemples de ce guide fournissent un processus reproductible pour identifier et résoudre la plupart des problèmes. En suivant la liste de contrôle des opérations, vous pouvez rapidement diagnostiquer les problèmes et rétablir la communication entre services.
N'oubliez pas de documenter votre environnement et de tester les changements dans un espace de noms sûr et isolé avant de les déployer en production. Avec ces outils, vous pouvez gérer en toute confiance le réseau des comptes de service dans Kubernetes.