CKA - Domaine 3 : Services et Réseau (20%)
🎯 Objectifs
À la fin de ce module, tu seras capable de :
- ✅ Expliquer le modèle réseau Kubernetes (chaque Pod a une IP unique)
- ✅ Créer et configurer des Services (ClusterIP, NodePort, LoadBalancer, Headless)
- ✅ Comprendre et utiliser le DNS interne du cluster
- ✅ Configurer un Ingress avec règles de routage et TLS
- ✅ Écrire des NetworkPolicies pour isoler les namespaces et les Pods
- ✅ Diagnostiquer des problèmes réseau dans un cluster
📋 Prérequis
- Module CKA : Workloads et Scheduling lu
- Notions de base réseau : IP, ports, DNS, TCP/UDP
🌐 Le modèle réseau Kubernetes
La règle fondamentale
Kubernetes impose un modèle réseau simple :
- Chaque Pod reçoit une IP unique dans le cluster
- Tous les Pods peuvent se joindre directement sans NAT (peu importe le node)
- Les nodes peuvent joindre tous les Pods sans NAT
C'est le rôle du CNI (Container Network Interface) de mettre en place ce modèle. Flannel, Calico, Weave Net, Cilium sont des implémentations CNI.
# Voir l'IP de chaque pod
kubectl get pods -o wide
# Voir l'IP d'un pod en détail
kubectl describe pod <nom> | grep IP
# Tester la connectivité directement entre pods
kubectl exec -it pod-a -- curl http://<IP-de-pod-b>💡 À l'examen, si un Pod ne peut pas joindre un autre Pod, vérifie d'abord les NetworkPolicies avant de t'attaquer au CNI.
🔌 Services
Pourquoi les Services ?
Les Pods ont des IPs éphémères - elles changent à chaque redémarrage. Un Service fournit une IP stable et un nom DNS qui redirige le trafic vers les bons Pods via un selector.
ClusterIP (défaut)
Accessible uniquement depuis l'intérieur du cluster.
# Mode impératif
kubectl expose deployment nginx --port=80 --target-port=80
kubectl expose deployment nginx --port=80 --target-port=8080 --name=nginx-svc
# Générer le YAML
kubectl expose deployment nginx --port=80 --dry-run=client -o yaml > svc.yamlapiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx # correspond aux labels des Pods cibles
ports:
- protocol: TCP
port: 80 # port exposé par le Service
targetPort: 8080 # port du conteneur
type: ClusterIPNodePort
Accessible depuis l'extérieur via <NodeIP>:<NodePort>.
kubectl expose deployment nginx --type=NodePort --port=80spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080 # optionnel, entre 30000-32767 (assigné auto sinon)LoadBalancer
Crée un load balancer externe (cloud provider requis).
kubectl expose deployment nginx --type=LoadBalancer --port=80ExternalName
Redirige vers un nom DNS externe (utile pour des services hors cluster).
apiVersion: v1
kind: Service
metadata:
name: ma-db
spec:
type: ExternalName
externalName: db.example.comHeadless Service
Un Service sans IP virtuelle (clusterIP: None). Utilisé avec les StatefulSets pour adresser chaque pod individuellement.
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None # pas d'IP virtuelle
selector:
app: mysql
ports:
- port: 3306Chaque pod devient accessible via : mysql-0.mysql-headless.default.svc.cluster.local
🗺️ DNS interne du cluster
CoreDNS
Kubernetes utilise CoreDNS comme serveur DNS interne. Il est déployé comme un Deployment dans le namespace kube-system.
kubectl get pods -n kube-system | grep coredns
kubectl get configmap coredns -n kube-system -o yamlFormat des noms DNS
# Service
<service>.<namespace>.svc.cluster.local
# → nginx-svc.default.svc.cluster.local
# Pod (moins courant)
<ip-avec-tirets>.<namespace>.pod.cluster.local
# → 10-244-1-5.default.pod.cluster.localRésolution depuis un Pod
# Depuis l'intérieur d'un pod
kubectl exec -it <pod> -- nslookup nginx-svc.default.svc.cluster.local
kubectl exec -it <pod> -- nslookup kubernetes.default.svc.cluster.local
# Forme courte (même namespace)
kubectl exec -it <pod> -- curl http://nginx-svc
# Namespace différent
kubectl exec -it <pod> -- curl http://nginx-svc.production.svc.cluster.local
# Lancer un pod de debug temporaire
kubectl run debug --image=busybox --rm -it --restart=Never -- shRésoudre les problèmes DNS
# CoreDNS fonctionne ?
kubectl get pods -n kube-system -l k8s-app=kube-dns
# Logs CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns
# Tester depuis un pod
kubectl exec -it <pod> -- cat /etc/resolv.conf
# nameserver doit pointer vers l'IP du Service kube-dns (souvent 10.96.0.10)🚦 Ingress
Concept
Un Ingress définit des règles de routage HTTP/HTTPS vers des Services. Il nécessite un Ingress Controller pour fonctionner (nginx-ingress, traefik, HAProxy...).
# Avec Minikube (pour les examens)
minikube addons enable ingress
kubectl get pods -n ingress-nginxRègles de routage
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: monapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80Ingress avec TLS
spec:
tls:
- hosts:
- monapp.example.com
secretName: tls-secret # Secret de type kubernetes.io/tls
rules:
- host: monapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80# Créer le Secret TLS
kubectl create secret tls tls-secret \
--cert=tls.crt \
--key=tls.key
kubectl get ingress
kubectl describe ingress app-ingress🛡️ NetworkPolicy
Pourquoi ?
Par défaut, tous les Pods peuvent communiquer entre eux dans un cluster Kubernetes. Les NetworkPolicies permettent de restreindre ce trafic.
⚠️ Les NetworkPolicies ne fonctionnent que si le CNI installé les supporte (Calico, Cilium, Weave Net - mais pas Flannel seul).
Modèle mental
Une NetworkPolicy s'applique à des Pods (via podSelector). Si un pod est sélectionné par au moins une NetworkPolicy, tout le trafic non explicitement autorisé est refusé.
Exemples fondamentaux
# 1. Refuser TOUT le trafic entrant dans un namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: production
spec:
podSelector: {} # s'applique à TOUS les pods du namespace
policyTypes:
- Ingress
# Pas de règles ingress = tout est refusé# 2. Autoriser uniquement les pods avec app=frontend à joindre app=backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
spec:
podSelector:
matchLabels:
app: backend # s'applique aux pods backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # autorise uniquement les pods frontend
ports:
- protocol: TCP
port: 8080# 3. Autoriser le trafic depuis un autre namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring# 4. Règle Egress : restreindre le trafic sortant
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-egress
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
- ports:
- protocol: UDP
port: 53 # autoriser le DNS !⚠️ Si tu bloques l'Egress, n'oublie pas d'autoriser le port 53 UDP pour le DNS, sinon les pods ne peuvent plus résoudre les noms.
# 5. Combiner podSelector ET namespaceSelector (opérateur AND)
from:
- namespaceSelector:
matchLabels:
env: production
podSelector: # ET (même élément de tableau)
matchLabels:
app: frontend
# Comparaison : opérateur OR (deux éléments séparés)
from:
- namespaceSelector: # OU
matchLabels:
env: production
- podSelector: # OU
matchLabels:
app: frontend🔍 Diagnostiquer les problèmes réseau
Checklist de diagnostic
# 1. Le Service existe et sélectionne les bons pods ?
kubectl get svc <nom>
kubectl describe svc <nom> # vérifier Endpoints
kubectl get endpoints <nom> # doit lister les IPs des pods
# 2. Le pod cible est Running et Ready ?
kubectl get pods -l app=<label> -o wide
# 3. Test de connectivité depuis l'intérieur du cluster
kubectl run debug --image=busybox --rm -it --restart=Never -- sh
# Dans le pod :
wget -qO- http://<service>.<namespace>.svc.cluster.local
nslookup <service>
# 4. Les NetworkPolicies bloquent-elles ?
kubectl get networkpolicies -n <namespace>
kubectl describe networkpolicy <nom>
# 5. kube-proxy tourne ?
kubectl get pods -n kube-system | grep kube-proxy
kubectl logs -n kube-system <kube-proxy-pod>Cas courants
Service accessible mais pods pas répondent
# Les Endpoints sont vides = le selector ne correspond à aucun pod
kubectl describe svc mon-svc | grep Endpoints
kubectl get pods --show-labels | grep <label-du-selector>DNS ne résout pas
kubectl run dns-test --image=busybox --rm -it --restart=Never -- nslookup kubernetes.default
# Si ça échoue, CoreDNS a un problème
kubectl get pods -n kube-system | grep coredns
kubectl logs -n kube-system <coredns-pod>Ingress ne route pas
kubectl describe ingress <nom>
kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx <ingress-controller-pod>📊 Récapitulatif des commandes clés
# Services
kubectl expose deployment <name> --port=80 --type=ClusterIP
kubectl get svc -o wide
kubectl get endpoints <svc>
# DNS test
kubectl run debug --image=busybox --rm -it --restart=Never -- nslookup <service>
# Ingress
kubectl get ingress -A
kubectl describe ingress <name>
# NetworkPolicy
kubectl get networkpolicies -A
kubectl describe networkpolicy <name> -n <namespace>
# Connectivité
kubectl exec -it <pod> -- curl http://<service>
kubectl exec -it <pod> -- wget -qO- http://<service>🚀 Prochaines Étapes
- Domaine suivant : CKA : Stockage
- Entraîne-toi : crée une NetworkPolicy deny-all puis autorise progressivement du trafic, vérifie à chaque étape
- Référence : kubernetes.io/docs/concepts/services-networking/