Les Pods changent d’adresse à chaque recréation. Le Service met un nom stable devant eux et répartit le trafic. Quand il ne répond rien, la cause est presque toujours la même.
Un Pod a une adresse IP. La tentation est donc de l’utiliser. C’est une mauvaise idée, et Kubernetes est construit pour vous en empêcher.
Ce n’est pas un défaut, c’est le principe de fonctionnement. Kubernetes détruit et recrée des Pods en permanence : lors d’une mise à jour, quand un nœud tombe, quand vous changez le nombre de réplicas, quand une sonde de vivacité échoue.
Pod 1 → 10.1.0.5
Pod 2 → 10.1.0.6 Pod 2 meurt et revient
Pod 3 → 10.1.0.7 ↓
Pod 2 → 10.1.0.18Une adresse notée quelque part est donc une adresse qui sera fausse. Et il n’y a rien à corriger : le comportement est voulu.
Client
↓
SERVICE nom et IP fixes, pour toute sa vie
↓
┌─────────┼─────────┐
↓ ↓ ↓
Pod 1 Pod 2 Pod 3Le Service apporte trois choses d’un coup :
Pas par leur nom : par leurs étiquettes. C’est le mécanisme central, et le seul à vraiment comprendre.
apiVersion: v1
kind: Service
metadata:
name: demo-web
spec:
selector:
app: demo-web # sert tous les Pods portant cette étiquette
ports:
- port: 80 # le port du Service
targetPort: 5000 # le port du conteneur
type: NodePortLe Service ne connaît aucun Pod à l’avance. Il déclare une condition — les Pods étiquetés app: demo-web — et Kubernetes maintient la liste à jour en continu. Un Pod qui apparaît avec la bonne étiquette entre dans la rotation ; un Pod qui disparaît en sort.
Ce diagramme contient déjà les deux seules raisons pour lesquelles un Service ne répond rien, et nous y reviendrons plus bas.
C’est ce couplage souple qui rend le reste possible : passer de 3 à 10 réplicas ne demande aucune modification du Service.
Navigateur
↓
localhost:30080 nodePort ← exposé sur chaque nœud
↓
Service:80 port ← l’entrée du Service
↓
Conteneur:5000 targetPort ← ce que votre application écouteLe seul que votre application impose est targetPort : c’est le port sur lequel elle écoute réellement. Les deux autres sont des choix d’exposition.
Piège fréquent : targetPort doit correspondre au port réel de l’application, pas au containerPort déclaré dans le Deployment. Ce dernier est purement documentaire — Kubernetes ne le vérifie pas et ne s’en sert pas pour router.
| Type | Joignable depuis | Usage |
|---|---|---|
ClusterIP | l’intérieur du cluster seulement | le défaut, et le bon choix pour tout service interne |
NodePort | l’extérieur, sur un port de chaque nœud | apprentissage et cluster local |
LoadBalancer | l’extérieur, via un répartiteur du fournisseur | production dans le nuage |
NodePort ouvre un port dans la plage 30000-32767 sur tous les nœuds. Pratique en local, rarement souhaitable en production : on lui préfère un Ingress ou une passerelle devant un ClusterIP.
À l’intérieur du cluster, un Service est joignable par son nom :
http://demo-web depuis le même namespace
http://demo-web.production depuis un autre namespaceConcrètement, une application qui veut parler à la base de données écrit postgres:5432 dans sa configuration, et ne se soucie jamais de savoir où tourne le Pod. C’est ce qui remplace les fichiers d’adresses et les variables d’environnement recopiées à la main.
C’est la panne la plus fréquente, et elle a presque toujours la même cause. Le diagnostic tient en une commande :
kubectl get endpoints demo-webNAME ENDPOINTS
demo-web <none><none> signifie que le Service ne trouve aucun Pod. Le trafic n’a nulle part à aller, et vous obtenez un délai d’attente ou une connexion refusée.
Deux causes, dans cet ordre :
Le sélecteur ne correspond pas aux étiquettes des Pods. Une majuscule, un tiret, app: demo-web contre app: demoweb. Rien ne vous prévient : Kubernetes accepte un sélecteur qui ne correspond à rien, parce que les Pods pourraient arriver plus tard.
Les Pods ne sont pas prêts. Un Pod dont la sonde de disponibilité échoue est délibérément retiré du Service. Il tourne, il apparaît dans kubectl get pods, et il ne reçoit aucun trafic. C’est le comportement correct, mais il surprend.
kubectl get pods --show-labels # les étiquettes réelles
kubectl describe service demo-web # le sélecteur déclaré
kubectl get pods -o wide # l’état de disponibilitéComparer les deux premières sorties règle la grande majorité des cas.
Parce que la répartition se fait par connexion, pas par requête. Un client qui garde sa connexion ouverte — ce que fait tout client HTTP moderne avec keep-alive — reste sur le même Pod pour toutes ses requêtes.
Sur un test au navigateur, cela donne l’impression que le Service envoie tout sur un seul Pod. Ce n’est pas un défaut du Service ; c’est la couche transport qui fait son travail. Pour observer la répartition, il faut de nouvelles connexions à chaque fois, ou un maillage de services qui répartit au niveau des requêtes.
Le Service est une indirection, et c’est tout son intérêt : il découple qui appelle de ce qui répond. Les Pods peuvent naître, mourir, se multiplier et changer d’adresse sans que personne en amont ne le sache.
Et quand il ne marche pas, commencez par kubectl get endpoints. La réponse est là dans neuf cas sur dix.
Pour la vue d’ensemble, voyez Docker et Kubernetes : qui fait quoi. Pour ce qui fabrique les Pods que ce Service dessert, le Deployment.
Développement et déploiement de solutions de données — les premiers modules sont en accès libre.