Aller au contenu
  1. Blog/

Apprendre Kubernetes : comprendre l'orchestration de conteneurs

·13 mins
Sommaire
Apprendre Kubernetes - Cet article fait partie d'une série.
Partie 1: Cet article

Introduction
#

Vous avez dockerisé vos applications. Vos images tournent en local, vos docker-compose font le job en développement. Mais en production, les questions s’accumulent : comment gérer 50 conteneurs sur 10 machines ? Comment redémarrer automatiquement un conteneur qui plante ? Comment déployer une nouvelle version sans coupure ?

C’est exactement le problème que résout Kubernetes (souvent abrégé K8s). Dans ce premier chapitre, on va comprendre pourquoi cet outil existe, comment il fonctionne sous le capot, et vous allez déployer votre première application sur un cluster local.

Prérequis : connaître les bases de Docker (images, conteneurs, Dockerfile). Avoir un terminal Linux/macOS ou WSL sous Windows.


Pourquoi Kubernetes ?
#

Le problème : gérer des conteneurs à l’échelle
#

Docker a résolu le problème du packaging applicatif : une image, un conteneur, ça tourne partout. Mais Docker seul ne répond pas aux besoins de production :

  • Haute disponibilité — Si un serveur tombe, qui relance les conteneurs ailleurs ?
  • Mise à l’échelle — Le trafic double un vendredi soir, comment ajouter des instances automatiquement ?
  • Déploiement sans coupure — Comment passer de la v1.2 à la v1.3 sans que les utilisateurs voient une erreur 502 ?
  • Découverte de services — Vos 20 microservices doivent se trouver entre eux. Qui gère le DNS interne, le load balancing ?
  • Gestion des secrets et configurations — Où stocker les credentials de base de données sans les mettre en dur dans l’image ?

Avant Kubernetes, on bricolait avec des scripts bash, des outils maison, ou des solutions comme Docker Swarm. Kubernetes a standardisé tout ça.

Ce que Kubernetes apporte
#

Kubernetes est un orchestrateur de conteneurs. Il prend en charge :

BesoinSolution Kubernetes
Haute disponibilitéRedémarrage automatique, répartition sur plusieurs nœuds
ScalingHorizontal Pod Autoscaler, scaling manuel
DéploiementsRolling updates, rollbacks automatiques
Réseau interneServices, DNS intégré (CoreDNS)
ConfigurationConfigMaps, Secrets
StockagePersistent Volumes, Storage Classes

Kubernetes ne fait pas tourner vos conteneurs directement — il déclare un état souhaité et s’assure en permanence que l’état réel correspond. C’est le principe du contrôle déclaratif : vous dites “je veux 3 réplicas de mon API”, Kubernetes fait le nécessaire pour que ce soit toujours le cas.


Architecture de Kubernetes
#

Un cluster Kubernetes se compose de deux parties : le control plane (le cerveau) et les worker nodes (les bras).

Schéma d’architecture
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌─────────────────────────────────────────────────────────────────┐
│                        CONTROL PLANE                            │
│                                                                 │
│  ┌──────────────┐  ┌───────────┐  ┌────────────┐  ┌─────────┐  │
│  │  API Server   │  │   etcd    │  │ Scheduler  │  │Controller│  │
│  │  (kube-api)   │◄►│ (key-val) │  │            │  │ Manager  │  │
│  └──────┬───────┘  └───────────┘  └────────────┘  └─────────┘  │
│         │                                                       │
└─────────┼───────────────────────────────────────────────────────┘
          │  HTTPS (kubeconfig)
    ┌─────┴──────────────────────────────────────────────────┐
    │                                                        │
┌───▼─────────────────────┐       ┌──────────────────────────┐
│       WORKER NODE 1     │       │       WORKER NODE 2      │
│                         │       │                          │
│  ┌────────┐ ┌────────┐  │       │  ┌────────┐ ┌────────┐  │
│  │kubelet │ │kube-   │  │       │  │kubelet │ │kube-   │  │
│  │        │ │proxy   │  │       │  │        │ │proxy   │  │
│  └───┬────┘ └────────┘  │       │  └───┬────┘ └────────┘  │
│      │                  │       │      │                   │
│  ┌───▼──────────────┐   │       │  ┌───▼──────────────┐    │
│  │ Container Runtime │   │       │  │ Container Runtime │    │
│  │ (containerd)      │   │       │  │ (containerd)      │    │
│  └──────────────────┘   │       │  └──────────────────┘    │
│                         │       │                          │
│  ┌─────┐ ┌─────┐       │       │  ┌─────┐ ┌─────┐        │
│  │Pod A│ │Pod B│       │       │  │Pod C│ │Pod D│        │
│  └─────┘ └─────┘       │       │  └─────┘ └─────┘        │
└─────────────────────────┘       └──────────────────────────┘

Le Control Plane
#

Le control plane gère l’ensemble du cluster. Il tourne généralement sur des nœuds dédiés (les “masters”).

API Server (kube-apiserver)
#

Le point d’entrée unique du cluster. Toute interaction passe par lui : kubectl, les dashboards, les autres composants internes. Il expose une API REST et valide chaque requête (authentification, autorisation, admission).

Quand vous tapez kubectl get pods, votre requête arrive à l’API Server, qui va lire l’état dans etcd et vous renvoyer la réponse.

etcd
#

Une base de données clé-valeur distribuée qui stocke tout l’état du cluster : quels pods tournent, quelles configurations sont actives, quels secrets existent. C’est la source de vérité. Si etcd est perdu sans backup, le cluster est perdu.

En production, etcd tourne en cluster de 3 ou 5 instances pour la haute disponibilité.

Scheduler (kube-scheduler)
#

Quand un nouveau pod doit être créé, le Scheduler décide sur quel nœud le placer. Il prend en compte :

  • Les ressources disponibles (CPU, mémoire)
  • Les contraintes d’affinité/anti-affinité
  • Les taints et tolerations
  • La topologie (zones, régions)

Controller Manager (kube-controller-manager)
#

Un ensemble de boucles de contrôle qui surveillent l’état du cluster et le corrigent si nécessaire. Quelques exemples :

  • ReplicaSet Controller — Vérifie que le bon nombre de pods tourne. Si un pod meurt, il en relance un.
  • Deployment Controller — Gère les rolling updates et rollbacks.
  • Node Controller — Surveille la santé des nœuds.
  • Job Controller — Gère les tâches ponctuelles.

Les Worker Nodes
#

Les nœuds (nodes) sont les machines qui font tourner les conteneurs.

kubelet
#

L’agent qui tourne sur chaque nœud. Il reçoit les instructions de l’API Server (“lance ce pod avec ces specs”) et s’assure que les conteneurs correspondants tournent via le container runtime. Il rapporte aussi l’état du nœud et des pods au control plane.

kube-proxy
#

Gère les règles réseau sur chaque nœud. Quand vous créez un Service Kubernetes, kube-proxy configure les règles iptables (ou IPVS) pour router le trafic vers les bons pods.

Container Runtime
#

Le moteur qui fait tourner les conteneurs. Kubernetes utilise l’interface CRI (Container Runtime Interface). Le runtime le plus courant est containerd. Docker n’est plus supporté directement depuis Kubernetes 1.24, mais les images Docker restent compatibles.


Concepts fondamentaux
#

Pods
#

Le pod est la plus petite unité déployable dans Kubernetes. Un pod encapsule un ou plusieurs conteneurs qui partagent :

  • Le même réseau (même adresse IP, mêmes ports)
  • Le même stockage (volumes partagés)
  • Le même cycle de vie

Dans 90% des cas, un pod = un conteneur. Les pods multi-conteneurs servent pour des patterns spécifiques (sidecar, init containers).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: v1
kind: Pod
metadata:
  name: mon-api
  labels:
    app: mon-api
spec:
  containers:
    - name: api
      image: nginx:1.27
      ports:
        - containerPort: 80

Important : On ne déploie presque jamais des pods directement. On utilise des Deployments qui gèrent les pods pour nous.

Deployments
#

Un Deployment déclare l’état souhaité pour vos pods : quelle image, combien de réplicas, quelle stratégie de mise à jour. Il crée un ReplicaSet qui maintient le bon nombre de pods.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mon-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mon-api
  template:
    metadata:
      labels:
        app: mon-api
    spec:
      containers:
        - name: api
          image: nginx:1.27
          ports:
            - containerPort: 80

Avec cette config, Kubernetes maintient toujours 3 pods nginx actifs. Si un nœud tombe, les pods sont recréés ailleurs.

Services
#

Les pods sont éphémères — ils peuvent être recréés avec une IP différente à tout moment. Un Service fournit une adresse stable pour accéder à un groupe de pods.

Les types de Services :

  • ClusterIP (par défaut) — IP interne au cluster uniquement
  • NodePort — Expose le service sur un port de chaque nœud (30000-32767)
  • LoadBalancer — Provisionne un load balancer externe (cloud)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: Service
metadata:
  name: mon-api-service
spec:
  selector:
    app: mon-api
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP

Ce Service route tout le trafic sur le port 80 vers les pods ayant le label app: mon-api.

Namespaces
#

Les namespaces isolent logiquement les ressources dans un cluster. Par défaut, Kubernetes crée :

  • default — namespace par défaut
  • kube-system — composants système
  • kube-public — ressources publiques

En pratique, on crée des namespaces par environnement (dev, staging, prod) ou par équipe.

1
2
kubectl create namespace dev
kubectl get pods -n dev

Installation locale avec Kind
#

Pourquoi Kind ?
#

Kind (Kubernetes IN Docker) crée des clusters Kubernetes en utilisant des conteneurs Docker comme nœuds. Avantages :

  • Léger — Pas de VM, juste des conteneurs
  • Rapide — Un cluster prêt en 30 secondes
  • Multi-nœuds — Simulez un vrai cluster avec plusieurs workers
  • CI-friendly — Utilisé par le projet Kubernetes lui-même pour ses tests

Installation
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# macOS
brew install kind kubectl

# Linux (amd64)
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

# Installer kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

Créer un cluster
#

1
2
3
4
5
6
# Cluster simple (1 nœud)
kind create cluster --name mon-cluster

# Vérifier
kubectl cluster-info --context kind-mon-cluster
kubectl get nodes

Pour un cluster multi-nœuds, créez un fichier de configuration :

1
2
3
4
5
6
7
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
  - role: worker
  - role: worker
1
kind create cluster --name lab --config kind-config.yaml

Vous obtenez un cluster avec 1 control plane et 2 workers, le tout en conteneurs Docker.


Premier déploiement
#

On va déployer une application nginx, la scaler, et l’exposer.

Étape 1 : Créer un Deployment
#

1
kubectl create deployment nginx-demo --image=nginx:1.27

Vérifiez :

1
2
kubectl get deployments
kubectl get pods

Vous devriez voir un pod nginx-demo-xxxxx en status Running.

Étape 2 : Scaler le Deployment
#

1
2
kubectl scale deployment nginx-demo --replicas=3
kubectl get pods

Trois pods tournent maintenant. Supprimez-en un pour voir Kubernetes le recréer :

1
2
3
4
5
# Notez le nom d'un pod
kubectl delete pod nginx-demo-xxxxx
# Quelques secondes plus tard...
kubectl get pods
# → Un nouveau pod a été créé automatiquement

Étape 3 : Exposer avec un Service
#

1
2
kubectl expose deployment nginx-demo --port=80 --type=NodePort
kubectl get services

Pour accéder au service depuis votre machine avec Kind :

1
kubectl port-forward service/nginx-demo 8080:80

Ouvrez http://localhost:8080 — vous verrez la page d’accueil nginx.

Étape 4 : Déployer via fichier YAML
#

Créez un fichier demo-app.yaml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-k8s
  labels:
    app: hello-k8s
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-k8s
  template:
    metadata:
      labels:
        app: hello-k8s
    spec:
      containers:
        - name: hello
          image: hashicorp/http-echo:latest
          args:
            - "-text=Hello depuis Kubernetes !"
          ports:
            - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: hello-k8s-svc
spec:
  selector:
    app: hello-k8s
  ports:
    - port: 80
      targetPort: 5678
  type: ClusterIP
1
2
3
4
kubectl apply -f demo-app.yaml
kubectl get all -l app=hello-k8s
kubectl port-forward service/hello-k8s-svc 8081:80
# curl http://localhost:8081 → "Hello depuis Kubernetes !"

Commandes kubectl essentielles
#

Navigation et inspection#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Lister les ressources
kubectl get pods                    # Pods du namespace default
kubectl get pods -A                 # Tous les namespaces
kubectl get pods -o wide            # Avec IP et nœud
kubectl get deployments
kubectl get services
kubectl get nodes

# Détails d'une ressource
kubectl describe pod <nom-du-pod>
kubectl describe deployment <nom>
kubectl describe node <nom-du-noeud>

# Logs
kubectl logs <nom-du-pod>
kubectl logs <nom-du-pod> -f        # Follow (temps réel)
kubectl logs <nom-du-pod> --tail=50 # 50 dernières lignes

Gestion des ressources
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Créer / mettre à jour depuis un fichier
kubectl apply -f mon-fichier.yaml
kubectl apply -f mon-dossier/       # Tous les YAML du dossier

# Supprimer
kubectl delete -f mon-fichier.yaml
kubectl delete pod <nom>
kubectl delete deployment <nom>

# Scaler
kubectl scale deployment <nom> --replicas=5

# Éditer en live (ouvre $EDITOR)
kubectl edit deployment <nom>

Debugging
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Shell dans un pod
kubectl exec -it <nom-du-pod> -- /bin/sh

# Événements du cluster
kubectl get events --sort-by=.metadata.creationTimestamp

# État d'un pod qui ne démarre pas
kubectl describe pod <nom-du-pod>   # Regarder la section "Events"

# Port-forward pour tester un service
kubectl port-forward svc/<nom-service> 8080:80

Contextes et namespaces
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Voir le contexte actuel
kubectl config current-context

# Lister les contextes
kubectl config get-contexts

# Changer de contexte
kubectl config use-context kind-mon-cluster

# Définir un namespace par défaut
kubectl config set-context --current --namespace=dev

Exercices pratiques
#

Exercice 1 : Créer et observer un cluster
#

  1. Créez un cluster Kind avec 1 control plane et 2 workers
  2. Listez les nœuds avec kubectl get nodes
  3. Inspectez un nœud avec kubectl describe node
  4. Identifiez les pods système dans le namespace kube-system
1
2
3
4
5
# Solution
kind create cluster --name exercice --config kind-config.yaml
kubectl get nodes
kubectl describe node exercice-worker
kubectl get pods -n kube-system

Exercice 2 : Déployer, scaler, détruire
#

  1. Déployez httpd:2.4 (Apache) avec 2 réplicas
  2. Vérifiez que les 2 pods tournent
  3. Scalez à 5 réplicas
  4. Supprimez un pod et observez la recréation
  5. Supprimez le deployment
1
2
3
4
5
6
7
# Solution
kubectl create deployment apache --image=httpd:2.4 --replicas=2
kubectl get pods -w                          # -w = watch
kubectl scale deployment apache --replicas=5
kubectl delete pod apache-xxxxx              # Remplacez par un vrai nom
kubectl get pods                             # Un nouveau pod apparaît
kubectl delete deployment apache

Exercice 3 : Exposer un service et tester
#

  1. Déployez nginx:1.27 avec 3 réplicas
  2. Créez un Service de type ClusterIP sur le port 80
  3. Utilisez port-forward pour accéder au service
  4. Vérifiez avec curl http://localhost:8080
1
2
3
4
5
# Solution
kubectl create deployment web --image=nginx:1.27 --replicas=3
kubectl expose deployment web --port=80 --type=ClusterIP
kubectl port-forward svc/web 8080:80 &
curl http://localhost:8080

Exercice 4 : Travailler avec les namespaces
#

  1. Créez un namespace test
  2. Déployez nginx dans ce namespace
  3. Listez les pods (sans -n — vous ne verrez rien dans default)
  4. Listez les pods du namespace test
  5. Nettoyez en supprimant le namespace (supprime tout dedans)
1
2
3
4
5
6
# Solution
kubectl create namespace test
kubectl create deployment nginx --image=nginx:1.27 -n test
kubectl get pods                # Rien dans default
kubectl get pods -n test        # Le pod est là
kubectl delete namespace test   # Tout est supprimé

Exercice 5 : Déploiement déclaratif complet
#

Créez un fichier YAML qui contient :

  • Un Deployment blog avec l’image nginx:1.27, 3 réplicas
  • Un Service blog-svc de type NodePort qui pointe vers le Deployment

Appliquez-le, vérifiez que tout fonctionne, puis nettoyez avec kubectl delete -f.


Nettoyage
#

Quand vous avez terminé, supprimez vos clusters Kind :

1
2
3
kind delete cluster --name mon-cluster
kind delete cluster --name lab
kind delete cluster --name exercice

Récapitulatif
#

Dans ce premier chapitre, vous avez appris :

  • Pourquoi Kubernetes existe — orchestrer des conteneurs à l’échelle, de manière déclarative
  • L’architecture — control plane (API Server, etcd, Scheduler, Controller Manager) et worker nodes (kubelet, kube-proxy, container runtime)
  • Les concepts clés — Pods, Deployments, Services, Namespaces
  • Kind — pour créer des clusters locaux légers en quelques secondes
  • kubectl — les commandes essentielles pour naviguer, déployer et débugger

Dans le prochain chapitre, on ira plus loin avec les ConfigMaps, Secrets, les Persistent Volumes et la gestion avancée des déploiements (rolling updates, health checks, resource limits).


Cet article fait partie de la série Apprendre Kubernetes. Retrouvez tous les chapitres sur devopslab.ch.

Apprendre Kubernetes - Cet article fait partie d'une série.
Partie 1: Cet article

Articles connexes