Aller au contenu
Conteneurs & Orchestration medium

Déployer Kubernetes avec Kubespray

21 min de lecture

logo kubernetes

Kubespray déploie des clusters Kubernetes en utilisant Ansible. Ce guide construit un lab KVM reproductible servant de base à des déploiements plus robustes. Contrairement à kubeadm qui nécessite des commandes manuelles sur chaque nœud, Kubespray automatise tout depuis votre poste de travail.

CritèreKubespraykubeadmk0sk3sRKE2
TypePlaybooks AnsibleBootstrap toolDistributionDistributionDistribution
OrientationProd, multi-cloudStandard upstreamEdge, prod, CIEdge, IoT, devEnterprise, sécurité
InstallationAnsibleCommandesk0sctl (YAML)Script uniqueScript
CNI défautConfigurableAucunkube-routerFlannelCanal
HA native✅ AnsibleManuel✅ Multi-controller✅ Multi-server✅ Intégrée
Profil CISSelon configManuelManuelManuel✅ Intégré
Cas d'usageProd automatiséeBare metal, formationEdge, CI/CD, prodEdge, IoT, devConformité, prod

À la fin de ce guide, vous saurez :

  • Provisionner des VMs KVM configurées via cloud-init pour un cluster Kubernetes
  • Préparer l'environnement Kubespray avec les bonnes versions d'Ansible et dépendances
  • Créer un inventaire personnalisé définissant la topologie du cluster
  • Déployer un cluster complet avec Calico, containerd et CoreDNS en une seule commande
  • Valider que tous les composants fonctionnent correctement
  • Personnaliser les options (CNI, runtime, addons) selon vos besoins

Kubespray déploie les mêmes composants que kubeadm mais automatise la configuration. Les besoins sont donc identiques :

RôleCPURAM (min)RAM (recommandé)DisqueQuantité
Control plane2 vCPU2 Go2 Go20 Go1 (ou 3+ pour HA)
Worker2 vCPU1 Go2 Go20 Go2+
Poste Ansible1 vCPU1 Go1 Go5 GoVotre machine locale

Le minimum Kubespray pour les workers est 1 Go, mais ce guide recommande 2 Go pour éviter les problèmes lors du téléchargement parallèle des images.

Sur votre poste de travail (machine de contrôle Ansible) :

  • Python 3.10+ avec pip
  • Git pour cloner le repository Kubespray
  • SSH avec une clé configurée (les VMs doivent être accessibles sans mot de passe)

Sur les VMs cibles :

  • Ubuntu 24.04 ou Rocky Linux 9 (distribution supportée par Kubespray)
  • Python 3 installé (requis par Ansible)
  • Accès sudo sans mot de passe pour l'utilisateur SSH
  • Accès Internet pour télécharger images et binaires (sauf configuration offline dédiée)

Ce guide a été validé avec les versions suivantes :

ComposantVersion
Kubesprayv2.30.0
Kubernetesv1.34.3
Ansiblecore 2.17.x+
CNICalico 3.30.6 (plugin par défaut)

Nous allons créer un cluster avec 1 control plane et 2 workers sur le réseau libvirt par défaut :

Architecture du lab Kubespray avec Ansible et 3 VMs sur KVM

Téléchargez l'image cloud Ubuntu 24.04 si elle n'est pas déjà présente :

Fenêtre de terminal
# Vérifier si l'image existe
ls -lh /var/lib/libvirt/images/ubuntu-24.04-cloud.img
# Si absente, télécharger
sudo curl -L -o /var/lib/libvirt/images/ubuntu-24.04-cloud.img \
https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

Créez un fichier user-data pour configurer l'utilisateur SSH sur les VMs. Remplacez VOTRE_CLE_SSH_PUBLIQUE par le contenu de votre ~/.ssh/id_ed25519.pub :

user-data
#cloud-config
hostname: ${HOSTNAME}
manage_etc_hosts: true
users:
- name: kube
sudo: ALL=(ALL) NOPASSWD:ALL
groups: users, sudo
shell: /bin/bash
lock_passwd: true
ssh_authorized_keys:
- VOTRE_CLE_SSH_PUBLIQUE
packages:
- qemu-guest-agent
- python3
runcmd:
- swapoff -a
- sed -i '/swap/d' /etc/fstab
- systemctl enable qemu-guest-agent

Créez un fichier network-config pour chaque VM avec son IP statique :

network-config (exemple pour ks-cp1)
version: 2
ethernets:
enp1s0:
dhcp4: false
addresses:
- 192.168.122.50/24
routes:
- to: default
via: 192.168.122.1
nameservers:
addresses:
- 192.168.122.1
- 8.8.8.8
  1. Générer les ISOs cloud-init pour chaque VM :

    Fenêtre de terminal
    # Pour ks-cp1
    cloud-localds ks-cp1-cloud-init.iso user-data-cp1 \
    --network-config network-config-cp1
    # Répéter pour ks-worker1 et ks-worker2 avec leurs fichiers respectifs
  2. Créer les disques avec backing file :

    Fenêtre de terminal
    for vm in ks-cp1 ks-worker1 ks-worker2; do
    sudo qemu-img create -f qcow2 \
    -b /var/lib/libvirt/images/ubuntu-24.04-cloud.img \
    -F qcow2 \
    /var/lib/libvirt/images/${vm}.qcow2 20G
    done
  3. Créer les VMs avec virt-install :

    Fenêtre de terminal
    for vm in ks-cp1 ks-worker1 ks-worker2; do
    sudo virt-install \
    --name ${vm} \
    --memory 2048 \
    --vcpus 2 \
    --disk /var/lib/libvirt/images/${vm}.qcow2 \
    --disk /var/lib/libvirt/images/${vm}-cloud-init.iso,device=cdrom \
    --os-variant ubuntu24.04 \
    --network network=default \
    --graphics none \
    --console pty,target_type=serial \
    --noautoconsole \
    --import
    done
  4. Vérifier la connectivité SSH :

    Fenêtre de terminal
    for ip in 192.168.122.50 192.168.122.51 192.168.122.52; do
    ssh -o StrictHostKeyChecking=accept-new kube@${ip} hostname
    done

Si les trois hostnames s'affichent (ks-cp1, ks-worker1, ks-worker2), vos VMs sont prêtes.

Utilisez toujours une version taggée pour la stabilité :

Fenêtre de terminal
git clone https://github.com/kubernetes-sigs/kubespray.git \
--depth 1 --branch v2.30.0
cd kubespray

Kubespray nécessite des versions spécifiques d'Ansible et de ses dépendances :

Fenêtre de terminal
# Créer un environnement virtuel isolé
python3 -m venv venv
source venv/bin/activate
# Installer les dépendances
pip install -U pip
pip install -r requirements.txt
# Vérifier Ansible
ansible --version

La sortie doit indiquer ansible [core 2.17.x] ou supérieur pour Kubespray v2.30.0.

Kubespray fournit un inventory sample que vous personnalisez :

Fenêtre de terminal
cp -r inventory/sample inventory/mycluster

Remplacez le contenu de inventory/mycluster/hosts.yaml par votre topologie :

inventory/mycluster/hosts.yaml
all:
hosts:
ks-cp1:
ansible_host: 192.168.122.50
ip: 192.168.122.50
access_ip: 192.168.122.50
ks-worker1:
ansible_host: 192.168.122.51
ip: 192.168.122.51
access_ip: 192.168.122.51
ks-worker2:
ansible_host: 192.168.122.52
ip: 192.168.122.52
access_ip: 192.168.122.52
children:
kube_control_plane:
hosts:
ks-cp1:
kube_node:
hosts:
ks-worker1:
ks-worker2:
etcd:
hosts:
ks-cp1:
k8s_cluster:
children:
kube_control_plane:
kube_node:
calico_rr:
hosts: {}

Avant le déploiement, vérifiez que Ansible peut se connecter à tous les nœuds :

Fenêtre de terminal
ansible all -i inventory/mycluster/hosts.yaml -m ping -u kube

Résultat attendu :

ks-cp1 | SUCCESS => { "ping": "pong" }
ks-worker1 | SUCCESS => { "ping": "pong" }
ks-worker2 | SUCCESS => { "ping": "pong" }

Avant de déployer, vous pouvez ajuster les paramètres dans inventory/mycluster/group_vars/.

Éditez inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml :

# Version Kubernetes (dans la plage supportée par votre release Kubespray)
kube_version: v1.34.3
# Nom DNS du cluster
cluster_name: cluster.local
VariableFichierValeur par défautDescription
kube_versionk8s-cluster.ymlv1.34.3Version Kubernetes
kube_network_plugink8s-cluster.ymlcalicoCNI, garder par défaut en lab
container_managerk8s-cluster.ymlcontainerdRuntime, containerd est le standard actuel
kube_proxy_modek8s-cluster.ymlipvsMode kube-proxy (iptables, ipvs)
cluster_namek8s-cluster.ymlcluster.localNom DNS du cluster
kube_pods_subnetk8s-cluster.yml10.233.64.0/18CIDR des pods
kube_service_addressesk8s-cluster.yml10.233.0.0/18CIDR des services

Le déploiement s'effectue avec le playbook cluster.yml. Comptez 10-20 minutes selon votre connexion Internet (téléchargement des images) :

Fenêtre de terminal
ansible-playbook -i inventory/mycluster/hosts.yaml cluster.yml \
-u kube -b --become-user=root

Le playbook exécute plusieurs phases :

  1. Préparation : configuration système, désactivation swap, modules kernel
  2. Téléchargement : binaires (kubectl, kubeadm, kubelet) et images conteneurs
  3. etcd : installation et configuration du cluster etcd
  4. Control plane : initialisation avec kubeadm, certificats
  5. Workers : jointure au cluster
  6. Réseau : déploiement de Calico (ou CNI choisi)
  7. Addons : CoreDNS, metrics-server (si activé)
PLAY RECAP *********************************************************************
ks-cp1 : ok=624 changed=135 unreachable=0 failed=0 skipped=1090
ks-worker1 : ok=413 changed=82 unreachable=0 failed=0 skipped=640
ks-worker2 : ok=413 changed=82 unreachable=0 failed=0 skipped=636

failed=0 sur tous les nœuds indique un déploiement réussi.

Le fichier kubeconfig se trouve sur le control plane. Récupérez-le sur votre poste :

Fenêtre de terminal
# Méthode simple avec scp (recommandée)
ssh kube@192.168.122.50 "sudo cat /etc/kubernetes/admin.conf" > ~/.kube/kubespray-config
# Remplacer l'adresse localhost par l'IP du control plane
sed -i 's/127.0.0.1/192.168.122.50/g' ~/.kube/kubespray-config
# Configurer kubectl
export KUBECONFIG=~/.kube/kubespray-config
Fenêtre de terminal
kubectl get nodes -o wide

Sortie attendue :

NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE RUNTIME
ks-cp1 Ready control-plane 19m v1.34.3 192.168.122.50 Ubuntu 24.04.3 LTS containerd://2.2.1
ks-worker1 Ready <none> 19m v1.34.3 192.168.122.51 Ubuntu 24.04.3 LTS containerd://2.2.1
ks-worker2 Ready <none> 19m v1.34.3 192.168.122.52 Ubuntu 24.04.3 LTS containerd://2.2.1

Les trois nœuds doivent être Ready.

Fenêtre de terminal
kubectl get pods -A

Tous les pods doivent être Running :

NamespacePods attendus
kube-systemcalico-node (3), calico-kube-controllers
kube-systemcoredns (2), dns-autoscaler
kube-systemkube-apiserver, kube-controller-manager, kube-scheduler
kube-systemkube-proxy (3), nodelocaldns (3)
kube-systemnginx-proxy (workers uniquement)

Validez que vous pouvez déployer une application :

Fenêtre de terminal
# Créer un déploiement nginx
kubectl create deployment nginx --image=nginx:alpine
# Exposer en NodePort
kubectl expose deployment nginx --port=80 --type=NodePort
# Attendre que le pod soit prêt
kubectl wait --for=condition=Ready pod -l app=nginx --timeout=60s
# Vérifier
kubectl get pods,svc

Résultat attendu :

NAME READY STATUS RESTARTS AGE
pod/nginx-6f564d4fd9-xxxxx 1/1 Running 0 30s
NAME TYPE CLUSTER-IP PORT(S) AGE
service/kubernetes ClusterIP 10.233.0.1 443/TCP 20m
service/nginx NodePort 10.233.33.101 80:30965/TCP 10s

Le service nginx est accessible sur http://<IP_WORKER>:30965.

Nettoyez après le test :

Fenêtre de terminal
kubectl delete deployment nginx
kubectl delete svc nginx

Le test nginx valide peu de choses. Pour vérifier la résolution DNS et la connectivité inter-pods :

Fenêtre de terminal
# Lancer un pod de test
kubectl run dnstest --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup kubernetes.default.svc.cluster.local

Résultat attendu : une adresse IP dans le range 10.233.0.x (service ClusterIP).

Ansible ne peut pas se connecter aux VMs :

Fenêtre de terminal
# Vérifier la connectivité SSH
ssh -v kube@192.168.122.50
# Vérifier que la clé est autorisée
ssh kube@192.168.122.50 "cat ~/.ssh/authorized_keys"
# Vérifier que Python est installé
ansible all -i inventory/mycluster/hosts.yaml -m raw -a "which python3" -u kube

kubectl ne peut pas joindre l'API server :

Fenêtre de terminal
# Vérifier que l'adresse est correcte dans kubeconfig
grep server ~/.kube/kubespray-config
# Tester la connectivité réseau
nc -zv 192.168.122.50 6443
# Vérifier que l'API server tourne
ssh kube@192.168.122.50 "sudo crictl ps | grep kube-apiserver"

Généralement un problème de ressources ou de taints :

Fenêtre de terminal
# Décrire le pod pour voir les événements
kubectl describe pod <pod-name>
# Vérifier les ressources disponibles
kubectl describe nodes | grep -A5 "Allocated resources"
# Vérifier les taints
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

Si le déploiement a échoué à mi-chemin, relancez simplement la même commande. Ansible est idempotent et reprendra où il s'est arrêté :

Fenêtre de terminal
ansible-playbook -i inventory/mycluster/hosts.yaml cluster.yml \
-u kube -b --become-user=root
  1. Provisionner la nouvelle VM avec cloud-init
  2. Ajouter l'entrée dans hosts.yaml sous kube_node
  3. Exécuter le playbook scale.yml :
Fenêtre de terminal
ansible-playbook -i inventory/mycluster/hosts.yaml scale.yml \
-u kube -b --become-user=root --limit=nouveau-worker

Kubespray fournit un playbook dédié pour la suppression propre :

Fenêtre de terminal
# Méthode recommandée : playbook remove-node
ansible-playbook -i inventory/mycluster/hosts.yaml remove-node.yml \
-u kube -b --become-user=root \
-e "node=ks-worker2"

Ce playbook effectue automatiquement le drain, la suppression des composants Kubernetes sur le nœud et le nettoyage. Après exécution, retirez manuellement le nœud de votre fichier hosts.yaml.

  1. Modifier kube_version dans group_vars/k8s_cluster/k8s-cluster.yml
  2. Exécuter le playbook upgrade-cluster.yml :
Fenêtre de terminal
ansible-playbook -i inventory/mycluster/hosts.yaml upgrade-cluster.yml \
-u kube -b --become-user=root

Pour supprimer complètement Kubernetes des nœuds :

Fenêtre de terminal
ansible-playbook -i inventory/mycluster/hosts.yaml reset.yml \
-u kube -b --become-user=root

Ce playbook :

  • Arrête et supprime tous les conteneurs
  • Supprime les binaires Kubernetes
  • Nettoie les règles iptables
  • Supprime les fichiers de configuration

Pour supprimer aussi les VMs :

Fenêtre de terminal
for vm in ks-cp1 ks-worker1 ks-worker2; do
sudo virsh destroy ${vm}
sudo virsh undefine ${vm} --remove-all-storage
done

Kubespray industrialise le déploiement de clusters Kubernetes :

  • Infrastructure as Code : votre cluster est défini dans des fichiers YAML versionnables
  • Reproductibilité : le même inventory produit le même cluster à chaque exécution
  • Automatisation : upgrades, scaling, suppression de nœuds via playbooks dédiés
  • Base solide : ce lab constitue un socle pour des déploiements plus robustes

Ce guide vous a permis de déployer un lab reproductible. Pour passer en production, il faut encore :

  • 3 control planes + load balancer devant l'API server
  • Backup etcd externalisé et testé régulièrement
  • Monitoring, alerting et logs centralisés
  • Sécurité réseau (NetworkPolicies, firewall configuré)
  • Plan de reprise d'activité (PRA) documenté

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn