Retour au cours

infra / kubernetes

Services : ClusterIP, NodePort, LoadBalancer

Leçon 51 exercice

Explication

Ce que vous allez apprendre

  • Expliquer pourquoi les Pods ont besoin d'une adresse stable via un Service, leur IP n'étant jamais fiable
  • Décrire comment un Service découvre dynamiquement ses Pods cibles via labels/selector, comme un Deployment
  • Distinguer les trois types de Service (ClusterIP, NodePort, LoadBalancer) et choisir le bon selon le besoin d'exposition
  • Diagnostiquer un Service qui ne route aucun trafic en vérifiant ses endpoints
  • Relier le fonctionnement d'un Service à celui de kube-proxy vu à la leçon 1

Dans quel contexte ?

Une équipe backend déploie un microservice de paiement derrière un Service ClusterIP, appelé par le frontend via son nom DNS interne payment-service. Après une mise à jour qui recrée tous les Pods du service de paiement, le frontend continue de fonctionner sans aucune modification de configuration : le Service a automatiquement mis à jour la liste de ses endpoints vers les nouveaux Pods, et le nom DNS n'a jamais changé. C'est exactement ce découplage entre "où sont les Pods" et "comment les joindre" qui rend Kubernetes utilisable en production.

Le problème posé par une IP qui change

D'abord, un fait à connaître : un Pod recréé (après un crash, une mise à jour, un déplacement) obtient une NOUVELLE adresse IP à chaque fois.

Prérequis

Cette leçon suppose acquis le mécanisme de labels/selector vu avec les Deployments (leçon 4) : un Service l'utilise exactement de la même façon pour trouver ses Pods.

Ce que ça casserait sans solution

Si ton frontend appelait directement l'IP d'un Pod backend, il perdrait la connexion à chaque redémarrage de ce Pod. Il faut un point d'accès qui ne change jamais, même quand les Pods derrière lui vont et viennent.

La solution : un objet dédié à la stabilité

C'est exactement le rôle du Service. Comme le Deployment, il utilise un selector basé sur des labels pour trouver ses Pods, plutôt que de connaître leurs noms un par un.

Un mécanisme totalement automatique

Tous les Pods portant le bon label sont ajoutés ou retirés dynamiquement de la liste des cibles (les "endpoints") au fur et à mesure qu'ils apparaissent ou disparaissent. Le Service n'a même pas besoin de savoir comment ces Pods ont été créés.

Trois portées à bien distinguer

Une fois ce mécanisme compris, il reste à choisir la bonne portée. ClusterIP, le type par défaut, n'est joignable que depuis l'intérieur du cluster : c'est le bon choix pour la communication entre microservices internes.

Type de ServicePortéeCas d'usage
ClusterIP (défaut)Interne au cluster uniquementCommunication entre microservices
NodePortPort fixe ouvert sur chaque nodeTest, démo, rarement en production
LoadBalancerIP publique via le fournisseur cloudExposition externe en production

Deux autres portées pour sortir du cluster

NodePort ouvre un port fixe sur chaque machine du cluster, pratique pour du test ou une démo, mais rarement utilisé tel quel en production. LoadBalancer demande au fournisseur cloud de provisionner un vrai équilibreur de charge avec une IP publique : c'est la solution d'exposition externe classique en production.

Le piège à vérifier systématiquement

Le piège le plus fréquent est un selector qui ne correspond à aucun Pod, à cause d'une faute de frappe dans un label. Le Service existe, semble fonctionner, mais ne route de trafic vers personne.

Piège fréquent

Un selector qui ne correspond à aucun Pod, souvent à cause d'une faute de frappe dans un label, crée un Service qui existe et semble fonctionner mais ne route de trafic vers personne. kubectl get endpoints <service> révèle immédiatement le problème : une liste vide signale un selector défaillant.

Le réflexe pour éviter ce piège

Vérifie toujours concrètement quels Pods sont réellement ciblés avec kubectl get endpoints, plutôt que de faire confiance uniquement à la définition du manifeste.

Maintenant que le réseau est stable, la leçon suivante s'attaque à un autre problème classique : séparer le code de sa configuration, avec les ConfigMaps.

Commandes & code

Services

Les Pods ont des IP éphémères. Un Service donne un point d'accès stable devant un groupe de Pods (via selector).

yaml
# service-clusterip.yaml - accessible uniquement DEPUIS le cluster (défaut)
apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  type: ClusterIP
  selector:
    app: api             # cible tous les Pods portant ce label
  ports:
    - port: 80            # port exposé par le Service
      targetPort: 3000     # port réel du conteneur
yaml
# service-nodeport.yaml - accessible depuis l'extérieur via <IP_NODE>:<nodePort>
apiVersion: v1
kind: Service
metadata:
  name: api-nodeport
spec:
  type: NodePort
  selector:
    app: api
  ports:
    - port: 80
      targetPort: 3000
      nodePort: 30080      # doit être dans la plage 30000-32767
yaml
# service-loadbalancer.yaml - provisionne un load balancer chez le cloud provider
apiVersion: v1
kind: Service
metadata:
  name: api-lb
spec:
  type: LoadBalancer
  selector:
    app: api
  ports:
    - port: 443
      targetPort: 3000
bash
kubectl apply -f service-clusterip.yaml
kubectl get svc
kubectl describe svc api-service

# Résolution DNS interne : "api-service.<namespace>.svc.cluster.local"
kubectl run debug --image=busybox -it --rm -- nslookup api-service

# Vérifier quels Pods sont réellement ciblés par le Service
kubectl get endpoints api-service
TypePortéeCas d'usage
ClusterIPInterne au cluster (défaut)Communication service-à-service
NodePortIP de chaque node + port fixeDev/démo, sans load balancer cloud
LoadBalancerIP publique externeExposition prod (nécessite un cloud provider)
ExternalNameAlias DNS vers un service externeIntégrer une base de données externe

Résumé

  • Un Service route le trafic vers les Pods via selector, jamais vers une IP de Pod en dur.
  • ClusterIP = interne, NodePort = accès externe simple, LoadBalancer = prod cloud.
  • kubectl get endpoints révèle vite un selector mal configuré (0 endpoint = 0 Pod ciblé).
  • Le DNS interne suit <service>.<namespace>.svc.cluster.local.

Exercices pratiques

1 disponible
1

Mission : le service de paiement injoignable

Objectif : Diagnostiquer un Service qui existe mais ne route aucun trafic, en vérifiant ses endpoints réels plutôt que sa seule définition YAML.

Contexte

Le frontend appelle payment-service via son nom DNS interne et reçoit systématiquement une erreur de connexion, alors que kubectl get svc montre que le Service existe bel et bien avec une ClusterIP assignée. Les Pods du Deployment payment-deployment portent le label app: payment, mais quelqu'un a écrit le Service il y a plusieurs semaines, avant un renommage d'équipe.

Résoudre l’exercice →