CKAD - Services et Networking
🎯 Objectifs
Dans ce module, tu vas :
- ✅ Comprendre les types de Services (ClusterIP, NodePort, LoadBalancer)
- ✅ Créer et configurer des Services
- ✅ Exposer des applications avec Ingress
- ✅ Comprendre le DNS Kubernetes
- ✅ Déboguer la connectivité réseau
- ✅ Maîtriser les Network Policies
📋 Prérequis
- Module Kubernetes - Intermédiaire complété
- Module CKAD - Préparation lu
- Module CKAD - Applications complété
📖 Pourquoi ce module ?
Exposer tes applications aux utilisateurs, c'est faire communiquer tes Pods. Ce module couvre les Services et Networking - 20% de la note CKAD.
Tu dois maîtriser :
- Comment les Pods se trouvent entre eux (DNS)
- Comment les exposer en dehors du cluster (Services)
- Comment router le trafic (Ingress)
🔧 Types de Services
Problème
Les Pods dans Kubernetes ont des IPs, mais ces IPs sont temporaires. Quand un Pod redémarre, il a une nouvelle IP. Comment on peut y accéder de manière stable ?
Solution : Services
ClusterIP (défaut)
Expose l'app seulement à l'intérieur du cluster. Les autres Pods peuvent y accéder par un DNS stable.
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: ClusterIP # Défaut, peut être omis
selector:
app: myapp
ports:
- port: 80 # Port du Service
targetPort: 8080 # Port du PodComment ça marche :
- Le Service obtient une IP stable :
10.96.0.X - Du DNS interne :
myapp.default.svc.cluster.local→10.96.0.X - Les autres Pods contactent :
curl http://myapp:80
NodePort
Expose l'app en dehors du cluster via un port sur chaque Node.
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: NodePort
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
nodePort: 30000 # Port sur le Node (30000-32767)Comment ça marche :
- Le Service reçoit aussi une IP interne (ClusterIP)
- ET elle écoute sur le port 30000 de chaque Node
- De l'extérieur :
curl http://node-ip:30000
LoadBalancer
Expose l'app via un Load Balancer externe (cloud provider : AWS ELB, Google Cloud LB, etc.).
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: LoadBalancer
selector:
app: myapp
ports:
- port: 80
targetPort: 8080Comment ça marche :
- Le cloud provider crée un LB
- Il reçoit une IP publique / DNS
- Le trafic passe par le LB → NodePort → Pod
ExternalName
Redirige vers un service en dehors du cluster.
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.example.com
ports:
- port: 5432De l'intérieur du cluster, curl external-db:5432 va se résoudre en db.example.com:5432.
🚀 Ingress : Routage HTTP/HTTPS
Problème
Les Services créent plein de ports. Pour exposer plusieurs apps, tu dois gérer plusieurs ports... pas pratique.
Solution : Ingress
Ingress fait du routage HTTP/HTTPS :
- URL basée sur le hostname :
app1.example.com→ Service1,app2.example.com→ Service2 - URL basée sur le path :
/app1→ Service1,/app2→ Service2
Créer un Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
- host: api.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080PathType
| Type | Comportement |
|---|---|
Prefix | Routage par préfixe : /app match /app, /app/users, etc. |
Exact | Match exact : /app match que /app |
ImplementationSpecific | Dépend du contrôleur |
HTTPS avec TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
tls:
- hosts:
- myapp.example.com
secretName: tls-secret # Secret de type kubernetes.io/tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80Ingress Controller
Pour que l'Ingress marche, tu dois avoir un Ingress Controller installé dans le cluster :
- NGINX Ingress Controller (le plus courant)
- Ingress fourni par le cloud provider (AWS ALB, Google Cloud LB)
- Traefik
🌐 DNS Kubernetes
Comment ça marche
Chaque Service dans Kubernetes reçoit un DNS :
service-name.namespace.svc.cluster.localExemples :
myapp.default.svc.cluster.localapi.production.svc.cluster.local
Résoudre un Service
De l'intérieur d'un Pod :
# DNS complet
curl http://myapp.default.svc.cluster.local:80
# Depuis le même namespace : pas besoin du namespace
curl http://myapp:80
# Via nslookup
nslookup myapp
nslookup myapp.default.svc.cluster.localDécouverte de Service
Les Pods reçoivent les variables d'environnement du Service automatiquement.
# Pod dans un Deployment
k exec pod/myapp-xyz -- env | grep MYAPP
# Output :
# MYAPP_SERVICE_HOST=10.96.0.50
# MYAPP_SERVICE_PORT=80Ainsi tu peux faire :
curl http://$MYAPP_SERVICE_HOST:$MYAPP_SERVICE_PORT🔧 Déboguer la connectivité
Quand la communication entre Pods ne marche pas :
Vérifier le Service existe
k get services
k describe service myapp
k get service myapp -o yamlVérifier le Selector
Le Service doit avoir un sélecteur qui match les labels des Pods.
# Voir les labels du Pod
k describe pod myapp-xyz
# Chercher : Labels: app=myapp, version=1.0
# Voir les sélecteurs du Service
k describe service myapp
# Chercher : Selector: app=myappSi le Selector ne match pas, il n'y a pas d'Endpoints.
Vérifier les Endpoints
k get endpoints
k get endpoints myapp
# Si tu vois "no endpoints", c'est que le Selector ne match pasTester la connectivité
# DNS
k run debug --image=busybox -it -- nslookup myapp
k run debug --image=busybox -it -- nslookup myapp.default.svc.cluster.local
# HTTP
k run debug --image=curlimages/curl -it -- curl http://myapp:80
# Depuis l'intérieur d'un Pod
k exec pod/client -- curl http://myapp:80
# Vérifier les ports
k exec pod/myapp -- netstat -tuln | grep 8080🛡️ Network Policies
Problème
Par défaut, tous les Pods peuvent communiquer entre eux. C'est un problème de sécurité (tous les pods peuvent parler à tous les autres pods).
Solution : Network Policies
Une Network Policy définit qui peut parler à qui.
Exemple : Isoler un namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
spec:
podSelector: {} # S'applique à TOUS les pods du namespace
policyTypes:
- Ingress # Bloquer l'ingress (par défaut : tout autorisé)Après ça, aucun trafic entrant n'est autorisé.
Autoriser certains trafics
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api
spec:
podSelector:
matchLabels:
app: api # S'applique aux pods "api"
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # Autoriser les pods "frontend"
ports:
- protocol: TCP
port: 8080Ingress vs Egress
| Direction | Signification |
|---|---|
| Ingress | Trafic entrant (vers mon Pod) |
| Egress | Trafic sortant (depuis mon Pod) |
Pour autoriser à la fois l'ingress ET l'egress, dois les déclarer tous les deux.
🔧 Exemple complet : Multi-app avec Ingress
---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
name: production
---
# Frontend App
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: frontend:1.0
ports:
- containerPort: 3000
---
# Frontend Service
apiVersion: v1
kind: Service
metadata:
name: frontend
namespace: production
spec:
type: ClusterIP
selector:
app: frontend
ports:
- port: 80
targetPort: 3000
---
# API App
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: api:2.0
ports:
- containerPort: 8080
---
# API Service
apiVersion: v1
kind: Service
metadata:
name: api
namespace: production
spec:
type: ClusterIP
selector:
app: api
ports:
- port: 80
targetPort: 8080
---
# Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
namespace: production
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api
port:
number: 80
---
# Network Policy : deny-all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
---
# Network Policy : allow frontend to api
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080📊 Résumé
| Service Type | Accès | Utilisation |
|---|---|---|
| ClusterIP | Interne | Communication inter-Pods |
| NodePort | Externe via port | Développement |
| LoadBalancer | Externe via LB | Production (cloud) |
| ExternalName | Service externe | Intégration externe |
| Concept | Utilisation |
|---|---|
| Service | Exposer des Pods |
| Ingress | Routage HTTP/HTTPS |
| DNS | Découverte de service |
| Network Policy | Sécurité réseau |
🚀 Prochaines Étapes
- CKAD : Volumes et Persistance - Stockage et données persistantes