Introduction
Les IP virtuelles Kubernetes sont au cœur de la mise en réseau des services. Chaque fois que vous créez un Service, Kubernetes attribue une IP virtuelle stable (l'IP de cluster) qui n'appartient à aucun pod individuel. Au lieu de cela, le plan de contrôle programme chaque nœud pour réécrire le trafic destiné à cette IP virtuelle vers l'un des pods prêts derrière le service. Cette indirection vous offre des points de terminaison stables, un équilibrage de charge et une découverte de services même lorsque les pods sont créés, détruits ou mis à l'échelle.
Cet article est une plongée approfondie destinée aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui comprennent déjà les objets Kubernetes de base et souhaitent exploiter les IP virtuelles en toute confiance. Vous découvrirez les rouages internes de kube-proxy dans ses trois modes principaux - iptables, IPVS et eBPF - et comment chaque mode installe le chemin de données qui transforme une IP virtuelle en trafic vers les pods. Nous renforcerons chaque concept avec des commandes concrètes, des sorties attendues et des signaux de défaillance. En cas de problème, vous saurez quoi inspecter en premier et comment récupérer.
Nous commencerons par établir un inventaire clair de la version et de l'environnement. À partir de là, nous explorerons le chemin de configuration sûr, la vérification et le diagnostic détaillés, les modes de défaillance courants et les procédures de récupération, et enfin une liste de contrôle opérationnelle que vous pourrez réutiliser dans vos propres clusters. Tout au long, l'accent est mis sur la sécurité opérationnelle : observer avant de changer, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets, vérifier le résultat et documenter comment récupérer si l'état attendu n'est pas atteint.
Inventaire des versions et de l'environnement
Avant de modifier une seule ligne de configuration, vous devez savoir exactement ce que vous exécutez. Pour le comportement des IP virtuelles, les composants pertinents sont la version du serveur d'API Kubernetes, la version de kube-proxy et le mode utilisé par kube-proxy. Le mode détermine la manière dont les IP virtuelles sont programmées sur chaque nœud. Un cluster exécutant kube-proxy en mode iptables affichera des commandes de débogage très différentes de celles utilisant IPVS ou le remplacement basé sur eBPF.
Confirmer les versions de Kubernetes et de kube-proxy
Exécutez ces commandes en lecture seule sur un nœud du plan de contrôle ou depuis une machine avec accès kubectl :
kubectl version --short
Sortie attendue (exemple) :
Client Version: v1.28.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.4
Ensuite, identifiez la version de kube-proxy sur un nœud :
kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kube-proxy-8fz6s 1/1 Running 0 10d 10.0.0.4 node-1
kube-proxy-m2v8x 1/1 Running 0 10d 10.0.0.5 node-2
Vérifiez la version de l'image du conteneur :
kubectl get pods -n kube-system -l k8s-app=kube-proxy -o jsonpath='{.items[0].spec.containers[0].image}'
registry.k8s.io/kube-proxy:v1.28.4
Déterminer le mode de kube-proxy
Le mode de kube-proxy est souvent défini via une ConfigMap. Inspectez-la :
kubectl describe configmap kube-proxy -n kube-system
Recherchez une ligne comme mode: ipvs ou mode: iptables. Si la ConfigMap n'indique pas de mode, inspectez les arguments du daemonset kube-proxy :
kubectl describe daemonset kube-proxy -n kube-system
Dans le modèle de pod, localisez le drapeau --proxy-mode. S'il est absent, le mode par défaut est iptables sur la plupart des distributions Linux.
Sur un nœud, vous pouvez également lire le mode actuel à partir des journaux de kube-proxy :
kubectl logs -n kube-system kube-proxy-8fz6s | head -20
Extrait de journal attendu :
I1205 10:00:01.123456 1 server_others.go:72] "Using iptables Proxier"
ou
I1205 10:00:01.223456 1 server_others.go:72] "Using ipvs Proxier"
Vérifier les prérequis pour chaque mode
Chaque mode de kube-proxy a des prérequis :
- iptables : nécessite l'outil utilisateur
iptableset les modules du noyauip_tables,iptable_nat,iptable_filter. Sur la plupart des distributions modernes, ils sont présents par défaut. - IPVS : nécessite les modules du noyau
ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_shetnf_conntrack. Pour les charger sur un nœud systemd, exécutez :
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack
Vérifiez qu'ils sont chargés :
lsmod | grep ip_vs
ip_vs_sh 16384 0
ip_vs_wrr 16384 0
ip_vs_rr 16384 0
ip_vs 172032 6 ip_vs_sh,ip_vs_wrr,ip_vs_rr
nf_conntrack 155648 7 ip_vs,nf_nat,nf_conntrack_netlink
- Mode eBPF (par exemple, Cilium, Calico eBPF) : nécessite un noyau avec BPF et BPF JIT activés, et souvent des capacités spécifiques. Pour Cilium, vous pouvez vérifier son statut :
kubectl -n kube-system exec ds/cilium -- cilium status
Établir une base de référence en lecture seule
Capturez un instantané de la programmation actuelle des IP virtuelles. Pour le mode iptables, listez les règles NAT pour les services :
sudo iptables-save -t nat | grep -i 'KUBE-SERVICES' | head -20
Pour le mode IPVS, listez les services virtuels :
sudo ipvsadm -L -n
Exemple de sortie pour un service avec ClusterIP 10.96.0.10 :
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.10:443 rr
-> 10.244.1.5:8443 Masq 1 0 0
-> 10.244.2.3:8443 Masq 1 0 0
Stockez ces instantanés avec des horodatages et des noms de nœuds afin de pouvoir comparer avant et après tout changement.
Chemin de configuration sûr
Lorsque vous devez modifier le comportement des IP virtuelles, l'approche la plus sûre consiste à introduire le changement dans un espace de noms de test ou un service unique d'abord, à valider le chemin de données, puis à le déployer. Ne modifiez jamais les paramètres kube-proxy d'un service de production sur tous les nœuds simultanément sans un test canari.
Exemple : basculer un service de la gestion iptables vers IPVS
Supposons que vous souhaitiez tester IPVS pour un service spécifique, même si le kube-proxy du cluster est en mode iptables. Vous ne pouvez pas basculer un seul service ; le mode est global au cluster par nœud. Cependant, vous pouvez tester un nouveau mode de kube-proxy sur un seul nœud en cordonnant ce nœud et en exécutant kube-proxy avec le nouveau mode en tant que processus séparé.
Tout d'abord, cordonnez le nœud et videz-le des charges de travail à l'exception des daemonsets :
kubectl cordon node-2
kubectl drain node-2 --ignore-daemonsets --delete-emptydir-data
Sur le nœud-2, arrêtez le kube-proxy existant (en supposant qu'il s'exécute comme un pod statique ou un service systemd). Pour un pod statique, retirez temporairement le manifeste. Ensuite, exécutez kube-proxy manuellement avec le mode IPVS :
sudo kube-proxy \
--kubeconfig=/etc/kubernetes/kube-proxy.conf \
--proxy-mode=ipvs \
--v=2
Attendez que la table des services virtuels IPVS se remplisse :
sudo ipvsadm -L -n
Vous devriez voir des entrées pour tous les services après quelques secondes.
Valider avec un déploiement de test
Créez un espace de noms de test simple et un déploiement :
apiVersion: v1
kind: Namespace
metadata:
name: vip-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: vip-test
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: vip-test
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
Appliquez et vérifiez que le service a une IP de cluster :
kubectl apply -f test.yaml
kubectl get svc -n vip-test nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.104.12.33 <none> 80/TCP 10s
Depuis le nœud-2, faites un curl vers l'IP virtuelle :
curl -s http://10.104.12.33
Vous devriez voir la page d'accueil de nginx. En même temps, surveillez les connexions IPVS :
sudo ipvsadm -L -n --stats | grep 10.104.12.33
Si le trafic fonctionne, enregistrez la configuration et continuez à tester davantage de services. Sinon, revenez en arrière en redémarrant le kube-proxy d'origine et en décordonnant le nœud.
Liste de contrôle pour une configuration sûre
- Faites toujours une sauvegarde de la ConfigMap de kube-proxy ou de la configuration du nœud avant les modifications :
kubectl get configmap kube-proxy -n kube-system -o yaml > kube-proxy-backup.yaml - Utilisez un nœud ou un espace de noms canari.
- Vérifiez avec des commandes en lecture seule avant et après.
- Ayez un plan de retour en arrière : restaurez la sauvegarde et redémarrez kube-proxy.
- Pour les équilibreurs de charge cloud ou les ingress, testez d'abord avec un
port-forwardlocal pour isoler les problèmes d'application des problèmes de réseau :kubectl -n vip-test port-forward svc/nginx 8080:80.
Vérification et diagnostics
Une fois que vous avez une configuration stable, vous avez besoin d'une vérification continue et de la capacité de diagnostiquer rapidement les pannes. Cette section couvre les commandes et les signaux pour chaque mode de kube-proxy.
Vérifier l'accessibilité de l'IP virtuelle
Le contrôle le plus simple est depuis un pod sur le même nœud et un pod sur un nœud différent. Exécutez un pod temporaire avec curl :
kubectl run tmp --rm -it --image=curlimages/curl -- /bin/sh
Dans le pod, testez le service par nom et par IP :
curl http://nginx.vip-test.svc.cluster.local
curl http://10.104.12.33
Si les deux fonctionnent, l'IP virtuelle est correctement programmée sur au moins un nœud. Pour vérifier tous les nœuds, exécutez un pod sur chaque nœud en utilisant un daemonset ou un pod avec nodeSelector.
Inspecter les règles iptables
Pour le mode iptables, listez la chaîne qui gère le trafic des services :
sudo iptables -t nat -L KUBE-SERVICES -n -v | head -30
Recherchez une règle correspondant à l'IP de cluster et au port de votre service. Exemple :
Chain KUBE-SERVICES (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-2IRACUALRELARSND tcp -- * * 0.0.0.0/0 10.104.12.33 /* vip-test/nginx cluster IP */ tcp dpt:80
Suivez la chaîne cible pour voir les points de terminaison :
sudo iptables -t nat -L KUBE-SVC-2IRACUALRELARSND -n -v
Chain KUBE-SVC-2IRACUALRELARSND (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-AJ5Q5TXBVHZIL7ZI all -- * * 0.0.0.0/0 0.0.0.0/0 statistic mode random probability 0.33333333349
0 0 KUBE-SEP-BL5Q5TXBVHZIL8ZI all -- * * 0.0.0.0/0 0.0.0.0/0 statistic mode random probability 0.50000000000
0 0 KUBE-SEP-CJ5Q5TXBVHZIL9ZI all -- * * 0.0.0.0/0 0.0.0.0/0
Chaque chaîne KUBE-SEP-xxx pointe vers une IP de pod. Vérifiez que les IP des points de terminaison correspondent aux pods prêts :
kubectl get endpoints -n vip-test nginx
NAME ENDPOINTS AGE
nginx 10.244.1.5:80,10.244.2.3:80,10.244.3.8:80 10m
Si les règles iptables ne correspondent pas aux points de terminaison, kube-proxy n'a pas mis à jour le nœud. Vérifiez les journaux de kube-proxy pour les erreurs.
Inspecter les règles IPVS
Pour le mode IPVS, utilisez ipvsadm :
sudo ipvsadm -L -n | grep -A5 10.104.12.33
Sortie attendue :
TCP 10.104.12.33:80 rr
-> 10.244.1.5:80 Masq 1 0 0
-> 10.244.2.3:80 Masq 1 0 0
-> 10.244.3.8:80 Masq 1 0 0
L'ordonnanceur (rr pour round-robin) est choisi par la configuration de kube-proxy. Vérifiez l'état des serveurs réels :
sudo ipvsadm -L -n --stats | grep -A5 10.104.12.33
Cela montre les connexions actives et les erreurs par backend. Si un backend affiche de nombreux InActConn ou un Weight nul, il peut être marqué comme indisponible.
Vérification en mode eBPF
Pour les clusters utilisant Cilium ou une gestion de services basée sur eBPF similaire, utilisez la CLI cilium :
kubectl -n kube-system exec ds/cilium -- cilium service list
Trouvez votre service :
ID Frontend Service Type Backend
2 10.104.12.33:80 ClusterIP 1 => 10.244.1.5:80
2 => 10.244.2.3:80
3 => 10.244.3.8:80
Pour tracer un paquet, utilisez cilium monitor :
kubectl -n kube-system exec ds/cilium -- cilium monitor --type drop
Recherchez les abandons liés à l'IP de votre service.
Résumé des commandes de diagnostic
| Mode | Commande pour inspecter la programmation IP virtuelle | Ce qu'il faut rechercher |
|---|---|---|
| iptables | iptables -t nat -L KUBE-SERVICES | Chaînes cibles et IP des points de terminaison |
| IPVS | ipvsadm -L -n | Serveur virtuel et liste des serveurs réels |
| eBPF | cilium service list | Mappages frontend-backend |
Pour tout mode, inspectez également les journaux de kube-proxy :
kubectl logs -n kube-system kube-proxy-8fz6s --tail=50
Augmentez temporairement la verbosité si nécessaire en modifiant les arguments du daemonset pour inclure --v=4, puis redémarrez.
Modes de défaillance et récupération
Les défaillances des IP virtuelles peuvent se manifester par des délais de connexion, des erreurs 504 intermittentes ou un trafic dirigé vers le mauvais pod. Nous couvrirons les modes de défaillance les plus courants et la récupération étape par étape.
Défaillance : aucun point de terminaison derrière le service
Si le sélecteur d'un service ne correspond à aucun pod, l'IP virtuelle est toujours attribuée, mais kube-proxy ne crée aucune règle de transfert. Les clients se connectant à l'IP virtuelle seront bloqués ou recevront un refus de connexion (selon le mode).
Diagnostic :
kubectl get endpoints -n vip-test nginx
Si la colonne ENDPOINTS est vide ou affiche <none>, le sélecteur est incorrect ou les pods ne sont pas prêts.
Vérifiez les étiquettes des pods et l'état de préparation :
kubectl get pods -n vip-test -l app=nginx -o wide
kubectl describe pod -n vip-test <pod-name>
Récupération :
- Corrigez le sélecteur du service pour qu'il corresponde aux étiquettes des pods.
- Assurez-vous que les pods passent les sondes de préparation. Si aucune sonde de préparation n'est définie, le pod est prêt dès qu'il démarre, mais il peut ne pas accepter de connexions ; ajoutez une sonde de préparation appropriée.
- Si vous utilisez un service sans tête (clusterIP: None), le comportement de l'IP virtuelle est différent ; vous devez utiliser la découverte basée sur le DNS.
Défaillance : kube-proxy ne fonctionne pas ou a planté
Si les pods de kube-proxy ne fonctionnent pas sur un nœud, ce nœud n'aura aucune programmation d'IP virtuelle. Les pods de ce nœud ne peuvent pas joindre les services via l'IP de cluster.
Diagnostic :
kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide
Recherchez les états CrashLoopBackOff ou Error.
Vérifiez les journaux d'un pod planté :
kubectl logs -n kube-system kube-proxy-8fz6s --previous
Causes courantes :
- Modules noyau manquants pour le mode (par exemple, modules IPVS non chargés).
- Kubeconfig invalide ou autorisations RBAC manquantes pour le compte de service kube-proxy.
- Pression sur les ressources du nœud.
Récupération :
- Chargez les modules noyau requis comme indiqué précédemment.
- Vérifiez le compte de service kube-proxy et la liaison de rôle de cluster :
kubectl get clusterrolebinding kube-proxy. - Si tout le reste échoue, redémarrez le pod en le supprimant :
kubectl delete pod -n kube-system kube-proxy-8fz6s(le daemonset le recréera).
Défaillance : IP virtuelle accessible mais lente ou déséquilibrée
Cela peut se produire en mode IPVS si l'ordonnanceur n'est pas adapté à la charge de travail, ou si un pod backend est surchargé. Cela peut également se produire en mode iptables lorsqu'il y a trop de règles et que le parcours des paquets est lent.
Diagnostic :
- Vérifiez les statistiques par backend avec
ipvsadm -L -n --stats. - Recherchez un
InActConnélevé sur un seul backend. - Vérifiez l'utilisation CPU de kube-proxy :
kubectl top pod -n kube-system kube-proxy-8fz6s. - En mode iptables, comptez le nombre de règles :
iptables -t nat -L KUBE-SERVICES -n | wc -l; des nombres élevés (>1000) peuvent causer des problèmes de performance.
Récupération :
- Si vous utilisez IPVS, passez l'ordonnanceur à
lc(least-connection) ouwlc(weighted least-connection) pour un meilleur équilibrage dynamique. Modifiez le champschedulerde la ConfigMap kube-proxy et redémarrez kube-proxy. - Pour iptables, envisagez de migrer vers le mode IPVS ou eBPF si le cluster est grand.
- Mettez à l'échelle les pods backend pour répartir la charge.
Défaillance : le trafic externe vers NodePort ou LoadBalancer n'atteint pas l'IP virtuelle
Cela se produit souvent lorsque la plage NodePort est bloquée par des règles de pare-feu ou que le groupe de sécurité du fournisseur cloud n'ouvre pas les ports des nœuds.
Diagnostic :
kubectl get svc -n vip-test nginx -o wide
Notez le NodePort, par exemple 30345. Ensuite, depuis une machine distante, testez la connectivité vers n'importe quelle IP de nœud sur ce port :
curl http://<node-public-ip>:30345
En cas de délai, vérifiez les règles de pare-feu sur le nœud et les groupes de sécurité cloud. Vérifiez également que kube-proxy écoute sur le port du nœud :
sudo netstat -tlnp | grep 30345
Récupération :
- Ouvrez la plage NodePort dans votre pare-feu ou groupe de sécurité.
- Si vous utilisez un équilibreur de charge cloud, assurez-vous que le groupe cible de l'équilibreur inclut tous les nœuds et que les contrôles de santé réussissent.
Vérification de la récupération
Après toute action de récupération, revérifiez toujours l'IP virtuelle depuis un pod client :
kubectl run curl-test --rm -it --image=curlimages/curl -- sh
curl -v http://nginx.vip-test.svc.cluster.local
La sortie attendue doit afficher HTTP/1.1 200 OK.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle avant et après tout changement de configuration d'IP virtuelle dans un cluster de production.
Avant le changement :
- [ ] Enregistrez les versions du cluster et de kube-proxy :
kubectl version --short - [ ] Déterminez le mode de kube-proxy : vérifiez la ConfigMap ou les journaux
- [ ] Capturez la programmation actuelle des IP virtuelles : sortie iptables, ipvsadm ou cilium
- [ ] Identifiez le rayon d'impact : quels nœuds et services seront affectés ?
- [ ] Préparez le plan de retour en arrière : sauvegardez la ConfigMap et la configuration du nœud
- [ ] Planifiez une fenêtre de maintenance si nécessaire
Pendant le changement :
- [ ] Appliquez le changement à un nœud ou un espace de noms canari d'abord
- [ ] Surveillez les journaux de kube-proxy pour les erreurs
- [ ] Vérifiez la programmation de l'IP virtuelle sur le canari :
iptables -t nat -L KUBE-SERVICESouipvsadm -L -n - [ ] Testez la connectivité du service depuis un pod sur le nœud canari
Après le changement :
- [ ] Vérifiez que les points de terminaison correspondent aux pods :
kubectl get endpoints - [ ] Exécutez un test de connectivité depuis un pod sur chaque nœud
- [ ] Vérifiez les pics de CPU/mémoire dans les pods de kube-proxy
- [ ] Documentez le changement et toute nouvelle métrique ou base de référence
- [ ] En cas d'échec, exécutez le plan de retour en arrière et vérifiez la restauration
Vérification continue :
- [ ] Surveillez l'état des pods kube-proxy dans
kube-system - [ ] Examinez périodiquement
ipvsadm -L -n --statspour la distribution des connexions - [ ] Définissez des alertes pour les baisses du nombre de points de terminaison de service (utilisez les métriques Prometheus
kube_endpoint_address_available) - [ ] Gardez la version de kube-proxy synchronisée avec le plan de contrôle
Conclusion
Les IP virtuelles Kubernetes sont une abstraction puissante, mais elles dépendent du bon fonctionnement des instances de kube-proxy sur chaque nœud. En comprenant les mécanismes sous-jacents - qu'il s'agisse d'iptables, d'IPVS ou d'eBPF - vous pouvez diagnostiquer et corriger des problèmes qui ne sont pas évidents à partir des seuls journaux d'application.
Dans cet article, nous sommes passés de l'inventaire de l'environnement à la configuration sûre, à la vérification et à la récupération. Nous avons fourni des commandes concrètes et des sorties attendues pour chaque mode. Le point clé à retenir est de toujours observer l'état actuel avant d'apporter des modifications, de limiter les changements à un canari et d'avoir un plan de retour en arrière.
Comme prochaine étape, choisissez une vérification à faible risque dans votre propre cluster : enregistrez le mode de kube-proxy, capturez la programmation de l'IP virtuelle pour un service et testez la connectivité depuis un pod sur un nœud différent. Comparez les résultats avec le comportement attendu décrit ici. Si quelque chose diffère, enquêtez à l'aide des commandes de diagnostic. Cette pratique vous permettra d'approfondir votre compréhension et de vous préparer à des incidents réels.