Exercice 02 : Services Kubernetes - ClusterIP, NodePort et LoadBalancer
🎯 Objectifs
À la fin de cet exercice, vous serez capable de :
- ✅ Créer un Service ClusterIP pour la communication interne
- ✅ Créer un Service NodePort pour accéder à l'application depuis l'hôte
- ✅ Comprendre comment Kubernetes utilise les labels comme sélecteurs
- ✅ Tester la découverte de service par DNS (
mon-service.mon-namespace.svc.cluster.local) - ✅ Utiliser
minikube servicepour accéder à un service NodePort
Durée estimée : 25 minutes
Difficulté : ⭐⭐☆☆☆ (Intermédiaire)
Prérequis : Exercice 01 complété, Deployment nginx-app en cours d'exécution
📖 Contexte
Les pods ont des adresses IP éphémères - elles changent à chaque redémarrage. Un Service est une abstraction stable : il garde la même IP et le même nom DNS, même si les pods derrière lui sont remplacés. C'est le Service qui répartit le trafic (load balancing simple) entre les pods correspondant à son sélecteur.
📋 Énoncé
Exposez le Deployment nginx-app avec différents types de Services et testez la communication.
🧭 Déroulement de l'exercice
Tâche 1 : Service ClusterIP (communication interne)
# nginx-service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-clusterip
namespace: intermediaire
spec:
type: ClusterIP # Accessible uniquement depuis l'intérieur du cluster
selector:
app: nginx-app # Sélectionne tous les pods avec ce label
ports:
- name: http
port: 80 # Port du Service (DNS interne)
targetPort: 80 # Port du conteneur
protocol: TCPkubectl apply -f nginx-service-clusterip.yaml
# Voir le Service et son ClusterIP
kubectl get service nginx-clusterip -n intermediaireTest depuis un pod :
# Lancer un pod temporaire pour tester la connectivité interne
kubectl run test-client --image=busybox:latest --restart=Never -n intermediaire \
--rm -it -- sh
# Dans le pod busybox :
# DNS interne court
wget -qO- http://nginx-clusterip:80
# DNS interne complet
wget -qO- http://nginx-clusterip.intermediaire.svc.cluster.local
# Via ClusterIP directement
wget -qO- http://$(kubectl get svc nginx-clusterip -n intermediaire -o jsonpath='{.spec.clusterIP}')Indice : Kubernetes injecte automatiquement un serveur DNS dans chaque pod. Le format DNS d'un Service est
<service>.<namespace>.svc.cluster.local. La forme courte<service>fonctionne si le pod appelant est dans le même namespace.
Tâche 2 : Service NodePort (accès depuis l'hôte)
# nginx-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
namespace: intermediaire
spec:
type: NodePort
selector:
app: nginx-app
ports:
- port: 80 # Port interne du Service
targetPort: 80 # Port du conteneur
nodePort: 30080 # Port sur le nœud (30000-32767)kubectl apply -f nginx-service-nodeport.yaml
# Voir le NodePort
kubectl get service nginx-nodeport -n intermediaireAccéder depuis l'hôte :
# Sur minikube, obtenir l'URL directement
minikube service nginx-nodeport -n intermediaire --url
# Ou tester manuellement
NODE_IP=$(minikube ip)
curl http://$NODE_IP:30080
# Si minikube tunneling est nécessaire
minikube service nginx-nodeport -n intermediaireTâche 3 : Comprendre les Endpoints
Les Endpoints sont la liste des IPs et ports des pods que le Service cible :
# Voir les Endpoints (IPs des pods)
kubectl get endpoints nginx-clusterip -n intermediaire
# Comparer avec les IPs des pods
kubectl get pods -n intermediaire -l app=nginx-app -o wideIndice : Si vous scalez le Deployment (ex:
kubectl scale deployment nginx-app --replicas=3), la liste des Endpoints s'agrandit automatiquement. Le Service sélectionne tous les pods prêts (Ready) avec le label correspondant.
Tester le load balancing :
# Scaler à 3 replicas
kubectl scale deployment nginx-app --replicas=3 -n intermediaire
# Vérifier que les Endpoints reflètent les 3 pods
kubectl get endpoints nginx-clusterip -n intermediaireTâche 4 : Déboguer un Service qui ne répond pas
Apprenez à diagnostiquer un Service qui ne fonctionne pas :
# Créer un Service avec un mauvais sélecteur (erreur volontaire)
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: nginx-broken
namespace: intermediaire
spec:
type: ClusterIP
selector:
app: inexistant # ❌ Aucun pod avec ce label
ports:
- port: 80
targetPort: 80
EOF
# Constater que les Endpoints sont vides
kubectl get endpoints nginx-broken -n intermediaire
# → "nginx-broken <none> ..."
# Vérifier les labels des pods
kubectl get pods -n intermediaire --show-labels
# Corriger le sélecteur
kubectl patch service nginx-broken -n intermediaire \
-p '{"spec":{"selector":{"app":"nginx-app"}}}'
# Vérifier que les Endpoints sont maintenant remplis
kubectl get endpoints nginx-broken -n intermediaire✅ Vérification du résultat
kubectl get service -n intermediaireliste les 2 Services créés- Le pod busybox peut contacter
nginx-clusterip:80depuis l'intérieur curl http://$(minikube ip):30080retourne la page Nginxkubectl get endpoints nginx-clusterip -n intermediaireliste les IPs des pods
💡 À retenir
| Type | Accessible depuis | Cas d'usage |
|---|---|---|
| ClusterIP | Cluster seulement | Communication entre services |
| NodePort | Hôte + Cluster | Dev/tests, accès externe simple |
| LoadBalancer | Internet (via cloud) | Production sur AWS/GCP/Azure |
DNS Kubernetes : <service>.<namespace>.svc.cluster.local
Découverte par labels : Un Service trouve ses pods par leurs labels - si un label change, le Service ne sert plus ce pod.
✨ Solution Complète
# ClusterIP
apiVersion: v1
kind: Service
metadata:
name: mon-service
spec:
selector:
app: mon-app # Doit correspondre aux labels des pods
ports:
- port: 80
targetPort: 3000 # Port sur lequel le conteneur écoute