Périmètre de ce runbook
Ce document couvre
  • Installer Kubernetes (Minikube / kubeadm)
  • Configurer réseau et CoreDNS
  • Stockage persistant (PV / PVC)
  • Déployer une application web + MariaDB
  • Exposer via Ingress
  • Snapshot et shutdown propre
Hors périmètre
  • Control plane (etcd, API server, scheduler)
  • Sécurisation (RBAC, TLS, Network Policies)
  • Services managés (EKS, AKS, GKE)
  • Observabilité (Grafana, Prometheus)
  • GitOps et CI/CD (ArgoCD, Helm)
Ce runbook traite la couche infra uniquement : installer, déployer, persister, sauvegarder. L'architecture du control plane, la sécurisation et les services managés feront l'objet d'un second volet.
Repère vSphere : etcd ≈ base de configuration vCenter · API server ≈ vCenter server · nodes ≈ hôtes ESXi · kubeadm ≈ déploiement sans vCenter. Si vous avez administré vSphere, la logique est identique — seule la couche d'abstraction change.
Étape 1 / 6
Choisir et préparer l'infrastructure
Disposer d'une ou plusieurs machines sur lesquelles Kubernetes sera installé. Choisissez un cas, respectez les minimums.
CPU
4 vCPU
RAM
8 Go
Disque
20 Go
OS recommandé
Ubuntu 22.04
ou Debian 12 · WSL2
Réseau : mode bridge de l'hyperviseur (ou WSL2 miroir) pour rendre le cluster accessible depuis votre LAN.
Nœuds minimum
2 machines
1 control-plane · 1 worker
Par nœud
2 CPU · 4 Go
20 Go disque OS
Réseau
Bridge switch commun
Stockage
Disque séparé
optionnel mais recommandé
Datastore
vSAN ou VMFS
Réseau VM
Port group bridge
IP routables, pas NAT
Template VM
Ubuntu 22.04
2 vCPU · 4 Go · 20 Go
Stockage : CSI vSphere pour PVC sur vSAN, ou disque virtuel séparé pour volumes hostPath.
Vérification OS
cat /etc/os-release
Résultat attendu : VERSION_ID="22.04"
Étape 2 / 6
Installer Kubernetes
Deux voies : Minikube pour test local, kubeadm pour multi-nœuds.
Télécharger Minikube + kubectl
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube curl -LO "https://dl.k8s.io/release/$(curl -L -s \ https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
Démarrer le cluster
minikube start --cpus=4 --memory=8192 --driver=docker
Vérification
kubectl get nodes # doit afficher minikube Ready kubectl get pods -A # tous les pods système doivent être Running
Prérequis — désactiver le swap
sudo swapoff -a sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
Le swap non désactivé fait échouer kubelet silencieusement. Vérifiez : free -h — la ligne Swap doit afficher 0.
Installer containerd + kubeadm
sudo apt update && sudo apt install -y containerd sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo systemctl restart containerd sudo apt install -y kubeadm=1.28.1-00 kubelet=1.28.1-00 kubectl=1.28.1-00 sudo apt-mark hold kubeadm kubelet kubectl
Initialiser le control-plane
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Vérification
kubectl get nodes # tous les nœuds doivent être Ready
Étape 3 / 6
Configurer le réseau et CoreDNS
CoreDNS résout les noms de services à l'intérieur du cluster. Sans lui, les pods ne se trouvent pas.
Activer l'addon Ingress (Minikube)
minikube addons enable ingress
Sur bare metal / vSphere, installez le contrôleur Ingress NGINX via manifest officiel — non inclus par défaut.
Vérifier CoreDNS
kubectl -n kube-system get pods | grep coredns kubectl -n kube-system describe deployment coredns | grep -A5 Resources
Deux pods CoreDNS doivent être en état Running.
Sans resource limits sur CoreDNS, un pic de requêtes DNS peut saturer un nœud entier. Vérifiez que limits.memory est défini.
Modifier CoreDNS si besoin
kubectl -n kube-system edit deployment coredns
Étape 4 / 6
Stockage persistant et MariaDB
Un pod détruit sans PersistentVolume perd toutes ses données. Cette étape garantit la persistance pour MariaDB.
PersistentVolume + PersistentVolumeClaim
path_volume.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: mariadb-pv spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce hostPath: path: /data/mariadb --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mariadb-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 2Gi
hostPath est réservé au test local. En production, utilisez un CSI driver ou NFS — le volume doit suivre le pod sur n'importe quel nœud.
Créer le secret MariaDB
kubectl create secret generic mariadb-secret \ --from-literal=root-password='MotDePasseFort'
Les secrets K8s sont encodés base64, pas chiffrés. En production, utilisez Vault ou Sealed Secrets — jamais de mot de passe en clair dans un ConfigMap.
Déployer MariaDB en StatefulSet
Mariadb-statefulset.yaml — resource limits
resources: requests: memory: "256Mi" cpu: "200m" limits: memory: "512Mi" cpu: "500m"
Utilisez un StatefulSet (pas un Deployment) pour toute base de données — il garantit l'identité stable du pod et l'attachement du volume.
Étape 5 / 6
Application web et Ingress
Déployer nginx en 2 réplicas, créer le Service, configurer l'Ingress pour router le trafic HTTP entrant.
Deployment + Service
application_web_via_ingres.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: nginx image: nginx:alpine ports: - containerPort: 80 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "100m" --- apiVersion: v1 kind: Service metadata: name: web-svc spec: selector: app: web ports: - port: 80 targetPort: 80
Règle Ingress
ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress spec: rules: - host: monapp.local http: paths: - path: / pathType: Prefix backend: service: name: web-svc port: number: 80
Pas de TLS ici. En production, ajoutez tls: dans la spec Ingress + cert-manager. Un Ingress HTTP sans TLS expose tout le trafic en clair.
Cycle de vie des pods — réflexes
kubectl get pods -w # surveiller en temps réel kubectl describe pod <nom> # CrashLoopBackOff → lire Events kubectl logs <pod> # lire les erreurs applicatives kubectl get ingress # vérifier que l'ADDRESS est assignée
Étape 6 / 6
Snapshot pré-maintenance et shutdown propre
Avant toute intervention, capturer l'état du cluster et des données. Séquence obligatoire.
Séquence — ordre obligatoire
1
Snapshot pré-shutdown
Capture l'état complet. Si quelque chose tourne mal, vous pouvez restaurer.
2
Cordon du nœud
kubectl cordon <node> — interdit tout nouveau pod. Les pods existants continuent.
3
Drain du nœud
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
4
Arrêt kubelet
sudo systemctl stop kubelet
5
Extinction machine
sudo shutdown -h now ou snapshot VMware si VM.
Script snapshot
pre_shutdown_snapshot.sh
#!/bin/bash SNAPSHOT_DIR="snapshot_$(date +%Y%m%d_%H%M%S)" mkdir -p "$SNAPSHOT_DIR" kubectl get nodes -o wide > "$SNAPSHOT_DIR/nodes.txt" kubectl get all -A -o wide > "$SNAPSHOT_DIR/all_resources.txt" kubectl get pv,pvc -A > "$SNAPSHOT_DIR/storage.txt" kubectl get ingress -A -o wide > "$SNAPSHOT_DIR/ingress.txt" kubectl get events -A --sort-by='.lastTimestamp' > "$SNAPSHOT_DIR/events.txt" kubectl get deploy,sts,svc,cm,secret -A -o yaml > "$SNAPSHOT_DIR/manifests.yaml" MARIADB_PWD=$(kubectl get secret mariadb-secret \ -o jsonpath='{.data.root-password}' | base64 -d) kubectl exec -n monprojet mariadb-0 -- \ mysqldump --all-databases -p"$MARIADB_PWD" > "$SNAPSHOT_DIR/mariadb_dump.sql" echo "Snapshot sauvegardé dans : $SNAPSHOT_DIR"
Le dump SQL ne remplace pas le snapshot PV. Faites toujours les deux. Le dossier snapshot doit être copié hors cluster après exécution.
Script shutdown complet
execute_shutdown.sh
#!/bin/bash NODE=${1:-$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')} echo "=== [1/4] Snapshot ===" && ./pre_shutdown_snapshot.sh echo "=== [2/4] Cordon ===" && kubectl cordon "$NODE" echo "=== [3/4] Drain ===" && kubectl drain "$NODE" \ --ignore-daemonsets --delete-emptydir-data --timeout=120s echo "=== [4/4] Arrêt ===" && sudo systemctl stop kubelet && sudo shutdown -h now
Reprendre après maintenance
sudo systemctl start kubelet kubectl uncordon <node> kubectl get nodes # doit repasser Ready
Sur Minikube : minikube stop et minikube start remplacent les étapes kubelet + uncordon.
Sans PodDisruptionBudget, kubectl drain peut provoquer une interruption de service silencieuse. Définissez un PDB avant toute maintenance en production.
Référence
Vocabulaire et commandes essentielles
Kubernetes ne fait rien de magique. Il suit des fichiers YAML déclaratifs. Si tu perds le fil, c'est que tu as trop de couches empilées sans besoin réel.
Concepts
ConceptRôle
PodPlus petite unité : 1 ou plusieurs conteneurs
NodeMachine physique ou virtuelle qui exécute les pods
DeploymentGère le cycle de vie des pods (copies, mise à jour, redémarrage)
ServicePoint d'entrée stable pour joindre un groupe de pods
IngressRouteur externe HTTP/HTTPS vers les services
ConfigMap / SecretParamètres (non-sensibles) ou mots de passe / tokens
PersistentVolume / PVCStockage durable pour bases de données
StatefulSetComme Deployment, mais pour les applis avec état (BDD)
Commandes de base
CommandeUtilité
kubectl get allVoir pods, services, deployments dans le namespace actuel
kubectl describe pod <nom>Détails de l'état, événements, erreurs
kubectl logs <pod>Logs du conteneur principal
kubectl exec -it <pod> -- /bin/shEntrer dans un conteneur pour déboguer
kubectl apply -f fichier.yamlCréer ou modifier une ressource
kubectl delete -f fichier.yamlSupprimer proprement
Cycle de vie d'un pod
ÉtatSignificationRéflexe
PendingEn attente de schedulingkubectl describe pod → Events
CrashLoopBackOffDémarre et plante en bouclekubectl logs <pod>
OOMKilledTué par manque de RAMAugmenter limits.memory
ImagePullBackOffImage introuvableVérifier nom image et registry
RunningOpérationnel
Ce que l'IA omet — récapitulatif
SujetOmission fréquente
kubeadmSwap non désactivé → kubelet échoue silencieusement
SecretsEncodés base64, pas chiffrés — utiliser Vault en production
IngressTLS absent par défaut — ajouter cert-manager
CoreDNSPas de resource limits → saturation nœud possible
PV hostPathNe suit pas le pod sur un autre nœud
drainSans PodDisruptionBudget → interruption silencieuse
Dump SQLNe remplace pas le snapshot PV — toujours faire les deux