Je vous propose ici un parcours pratique pour découvrir Kubernetes, avec pour cette première partie les objectifs suivants :
Mais tout d'abord, quelques mots sur Kubernetes.
Kubernetes, souvent abrégé en K8s, est un orchestrateur de conteneurs open-source initialement développé par Google. Son origine remonte à Borg, un système interne de gestion de clusters utilisé par Google pour exécuter des milliers d'applications conteneurisées. En 2014, Google a ouvert le projet sous le nom de Kubernetes, qui est aujourd’hui maintenu par la Cloud Native Computing Foundation (CNCF).
Kubernetes repose sur plusieurs principes clés :
L’objectif principal de Kubernetes est de fournir une plateforme permettant d'exécuter et de gérer des conteneurs à grande échelle, tout en assurant leur haute disponibilité, leur résilience et leur observabilité. Il permet ainsi aux équipes DevOps de déployer, gérer et mettre à l’échelle des applications conteneurisées de manière efficace.
Kubernetes est composé de plusieurs éléments clés :
Il gère l’ensemble du cluster et prend des décisions sur le placement des pods, leur mise à l’échelle et leur redémarrage en cas de défaillance. Il comprend :
Chaque nœud exécute les charges de travail sous forme de pods et contient les composants suivants :
Un cluster Kubernetes est généralement structuré autour d’un ensemble de nœuds maîtres (Masters) et de nœuds de travail (Workers) :
Les namespaces permettent de segmenter un cluster Kubernetes en plusieurs espaces isolés. Ils sont utiles pour :
Le pod est le plus petit élément déployable dans Kubernetes, il représente un ou plusieurs conteneurs partageant le même réseau et espace de stockage.
Ils permettent de rendre accessibles les applications en exposant les pods de manière stable, même si leur adresse IP change.
Gèrent la mise en place et la mise à jour des pods en assurant la tolérance aux pannes.
Kubernetes permet une mise à l’échelle des applications de deux manières :
Voici, pour résumer, un schéma issu de l'article Wikipedia concernant Kubernetes :
Kubernetes utilise des fichiers de configuration déclaratifs, au format YAML. Ces fichiers de configuration déclaratifs permettent de définir l'état souhaité du système de manière précise et reproductible. Cela assure une cohérence dans les déploiements, quel que soit l'environnement.
Plutôt que de spécifier une série d'étapes pour atteindre un état, on décrit simplement l'état final désiré. Kubernetes se charge ensuite de maintenir cet état, simplifiant ainsi la gestion à long terme des applications et infrastructures. Ceci apporte de nombreux avantages :
Cette approche déclarative offre ainsi une gestion plus robuste, flexible et maintenable des applications conteneurisées dans Kubernetes.
Kubernetes offre de nombreux avantages pour la gestion des applications conteneurisées. Voici les principaux atouts de cette plateforme d'orchestration :
Bien que Kubernetes soit une plateforme puissante pour l'orchestration de conteneurs, elle présente plusieurs inconvénients notables :
En conclusion, bien que Kubernetes offre de nombreux avantages, son adoption doit être soigneusement évaluée en fonction des besoins spécifiques du projet et des ressources disponibles pour gérer sa complexité et ses exigences.
Minikube est un outil qui permet de créer et gérer un cluster Kubernetes local sur une seule machine. Il est principalement destiné à l'apprentissage, aux tests et au développement, en évitant la complexité d'un cluster multi-nœuds.
Pourquoi utiliser Minikube ?
Je vous propose donc de partir d'un clone de la machine Debian GUI du miniLAB, que nous allons "muscler" un peu selon les indications ci-dessus.
Clonage :
Configuration :
On démarre notre VM debian-minikube et on se logge avec l'utilisateur sudoer.
Enfin, avant de rentrer dans le vif du sujet, on installe Docker CE selon la méthode recommandée, déjà rencontrée pendant les TP Docker, et qui est résumée ici.
Vérifions les mises à jour et l'installation des paquets prérequis :
sudo apt update && sudo apt upgrade
sudo apt -y install ca-certificates curl fonts-noto-color-emoji bash-completion
Supprimons ensuite les paquets qui pourraient être en conflit (peu probable avec une machine toute neuve) :
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt remove $pkg; done
On ajoute la clé publique GPG Docker officielle au trousseau apt :
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
Utilisez la commande suivante (sur une seule ligne) pour ajouter le dépôt stable :
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
On relance une mise à jour de l’index apt et on en profite pour faire les mises à jour éventuelles :
sudo apt update && sudo apt upgrade
On peut maintenant installer la dernière version de Docker CE et ses outils :
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Pour vérifier l’état du service Docker Engine, un classique :
systemctl status docker
Ajoutez votre utilisateur au groupe Docker (adaptez bien entendu en fonction du nom choisi) :
sudo adduser pascal docker
Il faut déconnecter et reconnecter l’utilisateur pour que l’appartenance au groupe soit prise en compte.
Activer Docker au démarrage avec systemd (par sécurité) :
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
Enfin on teste Docker en exécutant l'image hello-world :
docker run hello-world
Il est prudent de réaliser un snapshot de la VM à ce stade.
kubectl est l’outil en ligne de commande permettant d’interagir avec un cluster Kubernetes. Il sert à déployer, gérer et surveiller les ressources Kubernetes.
Principales fonctionnalités :
Pour l'installer, on télécharge le binaire :
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
Que l'on rend exécutable dans le système :
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
Petite vérification :
kubectl version --client
On installe également l'autocomplétion spécifique de kubectl pour le bash :
echo 'source <(kubectl completion bash)' >> ~/.bashrc
source ~/.bashrc
Téléchargement du binaire minikube-linux-amd64
:
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
et installation sur le système avec le nom minikube
:
sudo install minikube-linux-amd64 /usr/local/bin/minikube
Vérification :
minikube version
Il est prudent de réaliser un snapshot de la VM à ce stade.
Démarrage d'un cluster avec le driver Docker avec les options par défaut :
minikube start --driver=docker
Après quelques instants, le cluster est prêt :
😄 minikube v1.35.0 sur Debian 12.10 (vbox/amd64)
✨ Utilisation du pilote docker basé sur la configuration de l'utilisateur
📌 Utilisation du pilote Docker avec le privilège root
👍 Démarrage du nœud "minikube" primary control-plane dans le cluster "minikube"
🚜 Extraction de l'image de base v0.0.46...
💾 Téléchargement du préchargement de Kubernetes v1.32.0...
> preloaded-images-k8s-v18-v1...: 333.57 MiB / 333.57 MiB 100.00% 20.36 M
> gcr.io/k8s-minikube/kicbase...: 500.31 MiB / 500.31 MiB 100.00% 19.64 M
🔥 Création de docker container (CPU=2, Memory=2200Mo) ...
🐳 Préparation de Kubernetes v1.32.0 sur Docker 27.4.1...
▪ Génération des certificats et des clés
▪ Démarrage du plan de contrôle ...
▪ Configuration des règles RBAC ...
🔗 Configuration de bridge CNI (Container Networking Interface)...
🔎 Vérification des composants Kubernetes...
▪ Utilisation de l'image gcr.io/k8s-minikube/storage-provisioner:v5
🌟 Modules activés: storage-provisioner, default-storageclass
🏄 Terminé ! kubectl est maintenant configuré pour utiliser "minikube" cluster et espace de noms "default" par défaut.
Vérifions la présence du cluster :
minikube profile list
ce qui donne :
|----------|-----------|---------|--------------|------|---------|--------|-------|----------------|--------------------|
| Profile | VM Driver | Runtime | IP | Port | Version | Status | Nodes | Active Profile | Active Kubecontext |
|----------|-----------|---------|--------------|------|---------|--------|-------|----------------|--------------------|
| minikube | docker | docker | 192.168.49.2 | 8443 | v1.32.0 | OK | 1 | * | * |
|----------|-----------|---------|--------------|------|---------|--------|-------|----------------|--------------------|
On voit qu'une IP sur un nouveau réseau est mentionné. Jetons un oeil à la table de routage du système :
ip -c route
qui retourne :
default via 192.168.1.1 dev enp0s3
169.254.0.0/16 dev enp0s3 scope link metric 1000
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.116
192.168.49.0/24 dev br-2af7a79010e7 proto kernel scope link src 192.168.49.1
A l'instar de Docker (avec l'interface docker0), minikube a créé une interface et un réseau spécifiques pour le cluster (ligne 5).
kubectl version
kubectl cluster-info
kubectl get nodes
Un seul nœud pour le moment, le master :
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 19m v1.32.0
kubectl describe node minikube
Beaucoup d'informations sont retournées par cette commande, notamment :
Name: minikube
Roles: control-plane
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=minikube
kubernetes.io/os=linux
minikube.k8s.io/commit=dd5d320e41b5451cdf3c01891bc4e13d189586ed-dirty
minikube.k8s.io/name=minikube
minikube.k8s.io/primary=true
minikube.k8s.io/updated_at=2025_03_15T19_04_21_0700
minikube.k8s.io/version=v1.35.0
node-role.kubernetes.io/control-plane=
node.kubernetes.io/exclude-from-external-load-balancers=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: unix:///var/run/cri-dockerd.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Sat, 15 Mar 2025 19:04:18 +0100
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
MemoryPressure False Sat, 15 Mar 2025 19:24:25 +0100 Sat, 15 Mar 2025 19:04:16 +0100 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Sat, 15 Mar 2025 19:24:25 +0100 Sat, 15 Mar 2025 19:04:16 +0100 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Sat, 15 Mar 2025 19:24:25 +0100 Sat, 15 Mar 2025 19:04:16 +0100 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Sat, 15 Mar 2025 19:24:25 +0100 Sat, 15 Mar 2025 19:04:18 +0100 KubeletReady kubelet is posting ready status
Capacity:
cpu: 2
ephemeral-storage: 19480400Ki
hugepages-2Mi: 0
memory: 4009232Ki
pods: 110
Allocatable:
cpu: 2
ephemeral-storage: 19480400Ki
hugepages-2Mi: 0
memory: 4009232Ki
pods: 110
System Info:
Machine ID: 1c02c414cb79487d9a9d79cfe798032e
System UUID: 04e59769-c364-4c84-a45e-15f026c660cb
Boot ID: b924ab65-269b-459d-ba70-0f5559dc14e7
Kernel Version: 6.1.0-30-amd64
OS Image: Ubuntu 22.04.5 LTS
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://27.4.1
Kubelet Version: v1.32.0
Kube-Proxy Version: v1.32.0
PodCIDR: 10.244.0.0/24
PodCIDRs: 10.244.0.0/24
Liste des pods actuellement en cours d’exécution sur le nœud (non "terminés").
On voit notamment que les services de contrôle et de gestion de Kubernetes sont eux-mêmes des pods, dans le namespace kube-system :
Non-terminated Pods: (7 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
kube-system coredns-668d6bf9bc-9l4cc 100m (5%) 0 (0%) 70Mi (1%) 170Mi (4%) 21m
kube-system etcd-minikube 100m (5%) 0 (0%) 100Mi (2%) 0 (0%) 22m
kube-system kube-apiserver-minikube 250m (12%) 0 (0%) 0 (0%) 0 (0%) 22m
kube-system kube-controller-manager-minikube 200m (10%) 0 (0%) 0 (0%) 0 (0%) 22m
kube-system kube-proxy-tkl9f 0 (0%) 0 (0%) 0 (0%) 0 (0%) 21m
kube-system kube-scheduler-minikube 100m (5%) 0 (0%) 0 (0%) 0 (0%) 22m
kube-system storage-provisioner 0 (0%) 0 (0%) 0 (0%) 0 (0%) 22m
Affiche l’utilisation du CPU et de la mémoire par rapport aux capacités du nœud.
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 750m (37%) 0 (0%)
memory 170Mi (4%) 170Mi (4%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
Affiche les événements récents (logs) liés au nœud, utiles pour diagnostiquer des problèmes.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Starting 21m kube-proxy
Warning PossibleMemoryBackedVolumesOnDisk 22m kubelet The tmpfs noswap option is not supported. Memory-backed volumes (e.g. secrets, emptyDirs, etc.) might be swapped to disk and should no longer be considered secure.
Normal Starting 22m kubelet Starting kubelet.
Normal NodeAllocatableEnforced 22m kubelet Updated Node Allocatable limit across pods
Normal NodeHasSufficientMemory 22m kubelet Node minikube status is now: NodeHasSufficientMemory
Normal NodeHasNoDiskPressure 22m kubelet Node minikube status is now: NodeHasNoDiskPressure
Normal NodeHasSufficientPID 22m kubelet Node minikube status is now: NodeHasSufficientPID
Normal RegisteredNode 22m node-controller Node minikube event: Registered Node minikube in Controller
kubectl get namespaces
NAME STATUS AGE
default Active 51m
kube-node-lease Active 51m
kube-public Active 51m
kube-system Active 51m
Kubernetes utilise les namespaces pour isoler et organiser les ressources au sein d'un cluster. Voici les rôles des quatre namespaces initiaux :
kubectl describe namespace kube-system
kubectl get pods -n kube-system
kubectl create deployment nginx-demo --image=nginx
kubectl get deployments
kubectl get pods
Cette commande retourne les pods du namespace default
; pour voir les pods de tous les namespaces :
kubectl get pods --all-namespaces
kubectl expose deployment nginx-demo --type=NodePort --port=80
kubectl get services
qui retourne :
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 65m
nginx-demo NodePort 10.97.158.161 <none> 80:31739/TCP 23s
On distingue ici deux types de services : ClusterIP et NodePort.
Dans Kubernetes, les services ClusterIP et NodePort sont deux types de services utilisés pour exposer des applications, mais ils diffèrent dans leur portée et leur accessibilité.
Le choix entre ClusterIP et NodePort dépend des besoins d'accessibilité de l'application. ClusterIP est préféré pour les services internes, tandis que NodePort est utilisé lorsqu'une exposition externe est nécessaire, tout en gardant à l'esprit les implications en termes de sécurité et de gestion du trafic.
minikube service nginx-demo --url
Cette commande retourne l'url permettant d'accéder au service, ici : la page web par défaut de Nginx :
kubectl scale deployment nginx-demo --replicas=3
kubectl get pods
Le service utilise désormais trois pods :
NAME READY STATUS RESTARTS AGE
nginx-demo-87cd4cbb7-9xnnw 1/1 Running 0 73m
nginx-demo-87cd4cbb7-chgqh 1/1 Running 0 6s
nginx-demo-87cd4cbb7-x4wrh 1/1 Running 0 6s
Changer l'image du déploiement :
kubectl set image deployment/nginx-demo nginx=nginx:1.19
Suivre le déploiement
kubectl rollout status deployment/nginx-demo
Changer l'image puis aussitôt suivre le déploiement :
kubectl set image deployment/nginx-demo nginx=nginx:1.26 && kubectl rollout status deployment/nginx-demo
kubectl rollout undo deployment/nginx-demo
kubectl rollout history deployment/nginx-demo
Activation du dashboard :
minikube dashboard
Exploration du dashboard :
Exercices pratiques personnels :
Voici enfin des commandes pour gérer le cycle de vie du cluster Minikube.
minikube pause
minikube unpause
minikube stop
minikube start
minikube delete
minikube start
minikube status
minikube ip
minikube ssh
Il est intéressant de remarquer ici que minikube est un container Docker, dans lequel tourne une instance de Docker (Docker imbriqué, ou DinD : Docker-in-Docker), avec un certain nombre d'images en cours d'exécution :
docker ps
minikube logs
minikube delete
minikube delete --all
Au terme de ce premier parcours que j'espère vous avez pu suivre avec attention et sans encombre, vous avez pu :