Module 9 : Kubernetes
Prérequis : Module 3 (Docker — containers, images), Module 2 (Réseau — services, ports)
En résumé : Tu passes de “1 serveur avec docker-compose” à un orchestrateur qui gère des dizaines de containers automatiquement. Kubernetes redémarre les containers qui crashent, répartit le traffic et permet de scaler en une commande.
Chemin alternatif : Ce module est optionnel. Le chemin principal du cursus est Modules 0 → 1 → 2 → 3 → 4 → 5 → 6. Kubernetes est une branche parallèle qui part du Module 3 (Docker). Tu n’as pas besoin d’avoir fait les Modules 5-7 pour le suivre. Si tu débutes, concentre-toi sur le chemin principal et reviens ici plus tard.
C’est quoi Kubernetes et pourquoi ça existe ?
Section intitulée « C’est quoi Kubernetes et pourquoi ça existe ? »Le problème : Tu as 1 serveur avec docker-compose, ça marche. Mais si tu as 50 containers sur 10 serveurs ? Qui redémarre un container qui crash à 3h du matin ? Qui répartit le traffic entre les containers ? Qui fait un deployment sans downtime ?
Kubernetes (K8s) est un orchestrateur — un programme qui coordonne et gère automatiquement un grand nombre de containers sur plusieurs machines. Tu lui dis “je veux 3 copies de mon backend qui tournent en permanence”, et il se débrouille : où les placer, les redémarrer si elles crashent (self-healing = auto-réparation), répartir le traffic entre elles.
Les analogies (restaurant) :
- Pod = un cuisinier à son poste
- Deployment = “garde toujours 3 cuisiniers pasta en service”
- Service = le serveur qui route les commandes aux bons cuisiniers
- Node = une cuisine (un serveur physique/virtuel)
- Un cuisinier tombe malade ? Le manager en embauche un nouveau automatiquement.
Architecture (simplifiée)
Section intitulée « Architecture (simplifiée) »┌─── Control Plane (le cerveau) ─────────────────┐│ API Server = le réceptionniste ││ Scheduler = celui qui assigne les tâches ││ etcd = le carnet d'adresses ││ Controller = celui qui vérifie que tout va │└─────────────────────────────────────────────────┘ │ ├── Node 1 (une machine) │ ├── Pod (backend) │ └── Pod (frontend) │ └── Node 2 (une machine) ├── Pod (backend) └── Pod (backend)- Control Plane : décide OÙ placer les pods, surveille tout
- Node : une machine qui fait tourner les pods
- kubelet : l’agent sur chaque node qui communique avec le control plane
Installation (minikube)
Section intitulée « Installation (minikube) »Minikube crée un cluster Kubernetes local (un seul node) pour apprendre.
# Installer kubectl (le client)# -L = suivre les redirections, -O = sauvegarder avec le nom original du fichier# $(...) = exécuter la commande entre parenthèses et utiliser le résultat (récupère la dernière version)curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"# install = copier le fichier avec les bonnes permissions (exécutable par tous)sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectlkubectl version --client# Client Version: v1.x.x
# Installer minikubecurl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Lancer le clusterminikube start# 🎉 minikube v1.x.x# ✅ Using the docker driver# 🏄 Done! kubectl is now configured to use "minikube"
kubectl get nodes# NAME STATUS ROLES AGE VERSION# minikube Ready control-plane 1m v1.x.xLes objets Kubernetes
Section intitulée « Les objets Kubernetes »L’unité de base. Un pod = un ou plusieurs containers qui tournent ensemble. En pratique, 1 pod = 1 container.
Chaque objet Kubernetes est décrit en YAML avec 4 sections :
apiVersion(version de l’API K8s),kind(le type d’objet),metadata(nom et labels),spec(la configuration).
# pod.yml (on n'en crée presque jamais directement — on utilise un Deployment)apiVersion: v1 # Version de l'API Kubernetes (v1 = la plus basique)kind: Pod # Type d'objet : un Podmetadata: name: mon-backend # Le nom du podspec: containers: # Liste des containers dans ce pod (souvent 1 seul) - name: backend image: mon-user/devops-backend:latest ports: - containerPort: 8000 # Le port que le container écouteDeployment
Section intitulée « Deployment »Gère un groupe de pods identiques. Un replica = une copie de ton app. Si tu veux 2 replicas, K8s maintient 2 copies qui tournent en permanence. Si un pod crash → il en recrée un. Si tu veux 3 replicas → il en maintient 3.
apiVersion: apps/v1 # apps/v1 = l'API pour les Deployments (différent de v1 pour les Pods)kind: Deploymentmetadata: name: backendspec: # spec du DEPLOYMENT (combien de replicas, comment les trouver) replicas: 2 # Nombre de copies de ton app à faire tourner selector: matchLabels: app: backend # "Trouve les pods qui ont le label app=backend" # Doit matcher EXACTEMENT les labels dans template ci-dessous template: # Modèle pour créer chaque pod metadata: labels: app: backend # Ce label est utilisé par le selector ci-dessus pour trouver les pods spec: # spec du POD (quels containers, quels ports) # Attention : il y a 2 "spec" — celui du Deployment et celui du Pod containers: - name: backend image: mon-user/devops-backend:latest ports: - containerPort: 8000Expose les pods sur le réseau. Même si les pods meurent et sont recréés (avec de nouvelles IPs), le Service garde une adresse stable.
apiVersion: v1kind: Servicemetadata: name: backend-servicespec: selector: app: backend # Trouve les pods avec le label app=backend (du Deployment ci-dessus) ports: - port: 8000 # Le port pour accéder au Service targetPort: 8000 # Le port du container vers lequel le traffic est redirigé # (souvent les mêmes, mais on pourrait mapper 80 → 8000 par exemple) type: ClusterIP # Accessible uniquement dans le cluster (pas depuis l'extérieur)| Type de Service | C’est quoi |
|---|---|
| ClusterIP | Accessible uniquement dans le cluster (défaut) |
| NodePort | Accessible depuis l’extérieur via un port sur le node |
| LoadBalancer | Crée un load balancer externe (cloud) |
Le concept de load balancer vient du Module 2 (Réseau). Kubernetes Services font la même chose : répartir le traffic entre les pods.
ConfigMap et Secret
Section intitulée « ConfigMap et Secret »# ConfigMap = config non sensibleapiVersion: v1kind: ConfigMapmetadata: name: app-configdata: APP_ENV: "production"
# Secret = config sensible (encodé en base64)apiVersion: v1kind: Secretmetadata: name: app-secrettype: Opaquedata: DB_PASSWORD: bW9ucGFzcw== # base64 de "monpass"Commandes kubectl essentielles
Section intitulée « Commandes kubectl essentielles »# Appliquer un fichier YAMLkubectl apply -f backend-deployment.yml
# Voir les podskubectl get pods# NAME READY STATUS RESTARTS AGE# backend-6d4f5b7c9d-abc12 1/1 Running 0 1m# backend-6d4f5b7c9d-def34 1/1 Running 0 1m
# Voir les deploymentskubectl get deployments
# Voir les serviceskubectl get services
# Détails sur un podkubectl describe pod backend-6d4f5b7c9d-abc12
# Voir les logskubectl logs backend-6d4f5b7c9d-abc12
# Supprimerkubectl delete -f backend-deployment.yml
# Scalerkubectl scale deployment backend --replicas=5Namespaces
Section intitulée « Namespaces »Un namespace isole les ressources dans le cluster (comme des dossiers). Par défaut, tout est dans le namespace default.
kubectl get namespaceskubectl get pods -n kube-system # Voir les pods systèmeProjet pratique : Déployer sur minikube
Section intitulée « Projet pratique : Déployer sur minikube »1. Créer les fichiers
Section intitulée « 1. Créer les fichiers »mkdir -p ~/devops-k8scd ~/devops-k8s2. Backend Deployment + Service
Section intitulée « 2. Backend Deployment + Service »Crée backend.yml :
apiVersion: apps/v1kind: Deploymentmetadata: name: backendspec: replicas: 2 selector: matchLabels: app: backend template: metadata: labels: app: backend spec: containers: - name: backend image: mon-user/devops-backend:latest ports: - containerPort: 8000---apiVersion: v1kind: Servicemetadata: name: backend-servicespec: selector: app: backend ports: - port: 8000 targetPort: 8000 type: NodePort3. Frontend Deployment + Service
Section intitulée « 3. Frontend Deployment + Service »Crée frontend.yml :
apiVersion: apps/v1kind: Deploymentmetadata: name: frontendspec: replicas: 2 selector: matchLabels: app: frontend template: metadata: labels: app: frontend spec: containers: - name: frontend image: mon-user/devops-frontend:latest ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: frontend-servicespec: selector: app: frontend ports: - port: 80 targetPort: 80 type: NodePort4. Charger les images dans minikube
Section intitulée « 4. Charger les images dans minikube »Minikube a son propre registre d’images, séparé de ton Docker local. Si tes images ne sont pas sur Docker Hub, tu dois les charger manuellement :
# Option A : charger des images localesdocker build -t mon-user/devops-backend:latest ~/devops-project/backenddocker build -t mon-user/devops-frontend:latest ~/devops-project/frontendminikube image load mon-user/devops-backend:latestminikube image load mon-user/devops-frontend:latest
# Option B : si tes images sont sur Docker Hub, K8s les télécharge automatiquement# (il faut que le nom dans le YAML corresponde à l'image sur Docker Hub)5. Déployer
Section intitulée « 5. Déployer »kubectl apply -f backend.ymlkubectl apply -f frontend.yml
kubectl get pods# NAME READY STATUS RESTARTS AGE# backend-xxx-abc12 1/1 Running 0 30s# backend-xxx-def34 1/1 Running 0 30s# frontend-xxx-ghi56 1/1 Running 0 25s# frontend-xxx-jkl78 1/1 Running 0 25s
kubectl get services# NAME TYPE CLUSTER-IP PORT(S)# backend-service NodePort 10.96.x.x 8000:3xxxx/TCP# frontend-service NodePort 10.96.x.x 80:3yyyy/TCP6. Accéder à l’app
Section intitulée « 6. Accéder à l’app »minikube service frontend-service --url# http://192.168.49.2:3yyyy# Ouvre cette URL dans ton navigateur7. Scaler et observer
Section intitulée « 7. Scaler et observer »# Passer de 2 à 5 replicaskubectl scale deployment backend --replicas=5kubectl get pods# 5 pods backend !
# Supprimer un pod (K8s en recrée un automatiquement)kubectl delete pod backend-xxx-abc12kubectl get pods# Toujours 5 pods — K8s a recréé le pod manquant
# Rolling update = mise à jour progressive (changer l'image sans downtime)# K8s remplace les pods un par un : il crée un nouveau pod avec la v2,# attend qu'il soit prêt, puis supprime un ancien pod v1, et ainsi de suite.kubectl set image deployment/backend backend=mon-user/devops-backend:v2kubectl rollout status deployment/backend# Waiting for deployment "backend" rollout to finish...# deployment "backend" successfully rolled out8. Nettoyer
Section intitulée « 8. Nettoyer »kubectl delete -f backend.ymlkubectl delete -f frontend.ymlminikube stopExercice debug : Pourquoi le pod ne démarre pas ?
Section intitulée « Exercice debug : Pourquoi le pod ne démarre pas ? »Tu déploies le backend et tu vois ça :
kubectl get pods# NAME READY STATUS RESTARTS AGE# backend-6d4f5b7c9d-abc12 0/1 ImagePullBackOff 0 2mEt quand tu fais kubectl describe pod backend-6d4f5b7c9d-abc12, tu vois :
Events: Warning Failed 2m kubelet Failed to pull image "mon-user/devops-backend:latest": rpc error: code = Unknown desc = Error response from daemon: pull access denied Warning Failed 2m kubelet Error: ImagePullBackOffQue se passe-t-il et comment tu fixes ?
💡 Indice 1
Le message dit “pull access denied”. K8s essaie de télécharger l’image depuis Docker Hub mais n’y arrive pas.
💡 Indice 2
Avec minikube, les images Docker locales ne sont pas automatiquement disponibles dans le cluster.
✅ Solution
Le problème : Kubernetes essaie de télécharger (pull) l’image depuis Docker Hub, mais elle n’existe pas sur Docker Hub (soit le nom est faux, soit le repo est privé, soit l’image est uniquement locale).
3 solutions possibles :
- Charger l’image locale dans minikube (le plus courant en dev) :
minikube image load mon-user/devops-backend:latest- Pousser l’image sur Docker Hub (si tu veux que K8s la télécharge) :
docker push mon-user/devops-backend:latest- Vérifier le nom de l’image dans le YAML — une typo dans
image:cause ce problème.
Après le fix, force K8s à réessayer :
kubectl rollout restart deployment backendCoin entretien
Section intitulée « Coin entretien »Q : C’est quoi Kubernetes ? R : Un orchestrateur de containers. Il gère le deployment, le scaling, et la high availability des applications containerisées sur un cluster de machines.
Q : Différence entre Docker et Kubernetes ? R : Docker fait tourner UN container. Kubernetes orchestre des DIZAINES/CENTAINES de containers sur plusieurs machines (scheduling, scaling, self-healing).
Q : C’est quoi un Pod ? R : L’unité de base dans K8s. Un pod contient un ou plusieurs containers qui partagent le même réseau et stockage. En pratique, 1 pod = 1 container.
Q : C’est quoi un Deployment ? R : Un objet qui gère un groupe de pods identiques. Il maintient le nombre de replicas voulu, gère les updates (rolling update), et recrée les pods qui crashent.
Q : C’est quoi un Service ? R : Un point d’accès réseau stable vers un groupe de pods. Les pods ont des IPs éphémères, le Service a une IP fixe et répartit le traffic.
Q : Comment K8s gère un pod qui crash ? R : Le Controller détecte que le nombre de replicas ne correspond plus au nombre voulu, et recrée automatiquement un pod pour compenser (self-healing).
Q : C’est quoi un Namespace ? R : Un moyen d’isoler les ressources dans un cluster. Utile pour séparer les environnements (dev, staging, prod) ou les équipes.
Bonnes pratiques
Section intitulée « Bonnes pratiques »- Déclare les ressources (CPU/RAM). Sans
resources.requestsetresources.limits, un pod peut consommer tout le node et faire crasher les autres. Toujours définir des limites. - Utilise des health checks.
readinessProbe(le pod est prêt à recevoir du traffic ?) etlivenessProbe(le pod est encore vivant ?). C’est l’endpoint/api/healthqu’on a ajouté dans le Module 3 (Docker). Sans ça, K8s envoie du traffic à des pods qui ne sont pas prêts. - Ne déploie jamais
:latest. Tag tes images avec un hash de commit ou un numéro de version.:latestchange sans prévenir, et tu ne peux pas faire de rollback propre. - Un namespace par environnement.
dev,staging,prod. Ça isole les ressources et évite de supprimer la prod par erreur. - Stocke tes YAML dans Git. Les fichiers de deployment K8s sont du code — ils doivent être versionnés, reviewés en PR, et jamais appliqués à la main en prod.
Erreurs courantes
Section intitulée « Erreurs courantes »- Image pas trouvée → Vérifie le nom de l’image dans le YAML. Si c’est une image locale, utilise
minikube image load. - CrashLoopBackOff → Le container crash en boucle.
kubectl logs PODpour voir l’erreur. - Pending → Pas assez de ressources sur le node. Réduis les replicas ou les resource requests.
- Oublier le selector → Le Service ne trouve pas les pods. Les labels dans le Deployment doivent matcher le selector du Service.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Ingress : routage HTTP — un seul point d’entrée pour plusieurs services, avec des noms de domaine. C’est la première chose que tu configureras pour exposer tes services
- Helm : gestionnaire de packages pour K8s — tu décris ton app dans un “chart” réutilisable au lieu de 10 fichiers YAML séparés
- Horizontal Pod Autoscaler (HPA) : scaler automatiquement le nombre de pods en fonction du CPU/RAM — essentiel en production
- RBAC : contrôle d’accès dans K8s — qui a le droit de faire quoi dans quel namespace. Plus de la gouvernance que du technique
Tu peux passer au module suivant si…
Section intitulée « Tu peux passer au module suivant si… »- Tu sais la différence entre Docker (1 container) et Kubernetes (orchestration de N containers)
- Tu connais les objets de base : Pod, Deployment, Service
- Tu sais utiliser
kubectl get,kubectl apply,kubectl logs,kubectl scale - Tu as déployé le projet sur minikube avec 2 replicas
- Tu as testé le self-healing (supprimer un pod → K8s le recrée)
- Tu as nettoyé avec
minikube stop