Aller au contenu

Construire un cluster Kubernetes complet

Introduction

Kubernetes est une plateforme open-source de gestion de conteneurs qui permet d’automatiser le déploiement, la mise à l’échelle et la gestion des applications conteneurisées. Installer un cluster Kubernetes chez soi peut être une excellente façon d’apprendre et de tester des applications dans un environnement contrôlé.

Personnellement, je veux mettre en place un cluster Kubernetes pour augmenter la disponibilité de mes applications hébergées et pour pouvoir intégrer de nouveaux services avec un meilleur contrôle.

Mon objectif final : Séparer clairement mes services d’entreprise (Namespace Travail) de ma domotique personnelle (Namespace Home).

Sommaire

  1. Prérequis
  2. Résumé des étapes
  3. Étape 1 : Configuration du réseau et des noms
  4. Étape 2 : Préparation système
  5. Étape 3 : Installation de Containerd
  6. Étape 4 : Installation des outils Kubernetes
  7. Étape 5 : Initialisation du cluster
  8. Étape 6 : Configuration du réseau avec Calico
  9. Étape 7 : Ajout des nœuds workers
  10. Étape 7.5 : Activation du maître comme worker
  11. Étape 8 : Configuration du stockage avec Longhorn
  12. Étape 8.5 : Ajout de disques supplémentaires
  13. Étape 9 : Organisation des namespaces
  14. Étape 10 : Création du volume persistant
  15. Étape 11 : Déploiement de la stack Travail
  16. Conclusion

Prérequis

Avant de commencer l’installation, assurez-vous d’avoir les éléments suivants :

  • 3 Ordinateurs (Echo, Delta, Foxtrot dans mon cas) avec une distribution Linux (Ubuntu/Debian recommandés)
  • Accès root ou sudo sur les machines
  • IPs fixes configurées
  • Swap désactivé sur toutes les machines
  • Connexion Internet pour télécharger les paquets

Résumé des étapes

  1. Préparer les machines (Réseau, Swap, Kernel)
  2. Installer le moteur de conteneur (Containerd)
  3. Installer les outils Kubernetes (Kubeadm, Kubelet, Kubectl)
  4. Initialiser le cluster (Sur le Maître avec CIDR Calico)
  5. Configurer le réseau (Installation de Calico)
  6. Joindre les nœuds (Création du cluster complet)
  7. Configurer le stockage (Installation de Longhorn)
  8. Organiser les environnements (Travail vs Home)
  9. Préparer le Volume Persistant (Création du PVC partagé)
  10. Déployer la Stack Travail (Bases de données & Interfaces)

C’est Parti ! 🚀

Étape 1 : Le Réseau et les Noms (Fondamental)

Kubernetes déteste que les noms d’hôtes changent ou se ressemblent.

Donnez un nom unique à chaque machine

Fenêtre de terminal
# Sur la machine maître (ex: Delta)
sudo hostnamectl set-hostname bravo
# Sur les workers (ex: Echo, Foxtrot)
sudo hostnamectl set-hostname alpha
sudo hostnamectl set-hostname foxtrot

Mappez les IP

Éditez le fichier /etc/hosts sur toutes les machines (sudo nano /etc/hosts). Ajoutez les IP de tout le monde :

192.168.1.10 bravo
192.168.1.11 alpha
192.168.1.12 foxtrot

Étape 2 : Préparation Système (Kernel & Swap)

Désactiver le Swap et charger les modules

Fenêtre de terminal
# Désactivation immédiate swap
sudo swapoff -a
# Désactivation permanente (sed commente la ligne swap dans fstab)
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# Chargement des modules noyau
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# Configuration réseau (IP Forwarding requis par K8s)
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# Appliquer sans redémarrer
sudo sysctl --system

Étape 3 : Installer Containerd (Le moteur)

Nous utilisons le dépôt officiel de Docker pour récupérer containerd, car il est plus à jour.

Ajouter les clés et le dépôt

Fenêtre de terminal
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
# Création du dossier pour les clés
sudo install -m 0755 -d /etc/apt/keyrings
# Téléchargement de la clé officielle Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Ajout du dépôt
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Installer Containerd

Fenêtre de terminal
sudo apt-get update
sudo apt-get install -y containerd.io

Configuration CRITIQUE de Containerd

Il faut générer la config par défaut et activer SystemdCgroup pour éviter les conflits avec Kubelet.

Fenêtre de terminal
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
# La commande magique pour activer SystemdCgroup = true automatiquement
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# On redémarre containerd
sudo systemctl restart containerd

Étape 4 : Installer Kubeadm, Kubelet et Kubectl

Nous installons la version 1.29 (Stable).

Ajouter le dépôt Kubernetes

Fenêtre de terminal
sudo apt-get update
sudo apt-get install -y apt-transport-https gpg
# Télécharger la clé publique
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# Ajouter le dépôt
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

Installer les paquets

Fenêtre de terminal
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
# On bloque la mise à jour automatique (pour éviter de casser le cluster lors d'un apt upgrade)
sudo apt-mark hold kubelet kubeadm kubectl

Étape 5 : Initialiser le Cluster (Maître Uniquement)

Sur le serveur maître (Delta), nous allons initialiser le Control Plane.

Fenêtre de terminal
# Initialisation avec la plage IP recommandée pour Calico
sudo kubeadm init --pod-network-cidr=192.168.0.0/16

Configuration de kubectl

Une fois terminé, configurez kubectl pour votre utilisateur (non-root) :

Fenêtre de terminal
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Étape 6 : Installer le Réseau (Calico)

Les pods ne peuvent pas communiquer sans CNI (Container Network Interface). Nous installons Calico via l’opérateur Tigera.

Fenêtre de terminal
# 1. Installer l'opérateur Tigera
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
# 2. Installer les ressources personnalisées (CRD)
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml

Vérification

Vérifiez que les pods Calico démarrent (cela peut prendre 2-3 minutes) :

Fenêtre de terminal
kubectl get pods -n calico-system

Étape 7 : Ajouter les Nœuds (Workers)

Sur vos autres serveurs (Echo et Foxtrot), exécutez la commande join récupérée à l’étape 5 :

Fenêtre de terminal
sudo kubeadm join 192.168.1.10:6443 --token <votre-token> --discovery-token-ca-cert-hash sha256:<votre-hash>

Vérification

Vérifiez sur le maître que tout le monde est là :

Fenêtre de terminal
kubectl get nodes

Étape 7.5 : Activer le Maître comme nœud de travail (Important)

Par défaut, Kubernetes “Taint” le maître pour l’empêcher d’exécuter des applications. Si vous voulez que Longhorn utilise les disques du maître (comme votre disque sdc), il faut autoriser les workloads dessus.

Fenêtre de terminal
# Autoriser le déploiement de pods sur le Control Plane
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

Étape 8 : Le Stockage Distribué (Longhorn)

Pour une infra “Homelab” avec de multiples disques éparpillés sur les serveurs, nous allons utiliser Longhorn.

Longhorn permet de “mutualiser” l’espace disque de tous les nœuds pour créer un stockage distribué et répliqué (Haute Disponibilité).

1. Prérequis (Sur TOUS les nœuds)

Longhorn a besoin de modules spécifiques pour fonctionner. Sans cela, les volumes ne pourront pas être montés.

Fenêtre de terminal
sudo apt-get install -y open-iscsi nfs-common
sudo systemctl enable --now iscsid

2. Installation de Longhorn (Sur le Master)

Nous appliquons le manifeste officiel.

Fenêtre de terminal
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.6.2/deploy/longhorn.yaml

3. Vérification

Vérifiez que tous les pods sont en statut “Running” dans le namespace longhorn-system :

Fenêtre de terminal
kubectl get pods -n longhorn-system

4. Accès au Dashboard Longhorn

Par défaut, le port-forward n’écoute que sur 127.0.0.1. Si vous lancez cette commande sur le serveur maître mais que vous voulez accéder au dashboard depuis votre PC, il faut écouter sur toutes les interfaces (0.0.0.0).

Fenêtre de terminal
# Remplacez 8083 par le port de votre choix
kubectl port-forward --address 0.0.0.0 -n longhorn-system svc/longhorn-frontend 8083:80

Vous pourrez ensuite accéder à http://<IP_DU_SERVEUR>:8083 pour configurer vos disques.

Étape 8.5 : Ajouter des disques physiques supplémentaires

Longhorn ne voit pas automatiquement vos autres disques. Il faut les déclarer.

Cas A : Disque déjà utilisé (Exemple: /mnt/data)

  • Compatibilité : Longhorn utilise uniquement l’espace libre
  • Action : Pas besoin de reformater. Assurez-vous simplement que le disque est monté

Cas B : Disque vierge (Exemple : disque sdc sur le maître)

Repérage :

Fenêtre de terminal
lsblk # ici sdc est vide

Formatage :

Fenêtre de terminal
sudo mkfs.ext4 /dev/sdc

Montage :

Fenêtre de terminal
sudo mkdir /mnt/storage-sdc
# Ajouter au fstab pour montage auto
echo "/dev/sdc /mnt/storage-sdc ext4 defaults 0 0" | sudo tee -a /etc/fstab
sudo mount -a

Configuration dans l’interface Web Longhorn (Pour les deux cas)

  1. Allez dans l’onglet Node
  2. Sur la ligne du serveur concerné (ex: bravo pour sdc), cliquez sur le menu (trois points) > Edit Node
  3. Cliquez sur Add Disk
  4. Remplissez les champs :
    • Name : Donnez un nom (ex: sdc-500g)
    • Path : Le chemin de montage (ex: /mnt/storage-sdc)
  5. Cliquez sur Save

Longhorn va scanner le dossier, voir l’espace disponible, et l’ajouter au pool global du cluster.

Étape 9 : Organisation (Travail & Home)

Pour séparer l’activité professionnelle de la maison, nous créons deux “Namespaces” (espaces de noms) distincts.

Fenêtre de terminal
# Espace pour l'entreprise
kubectl create namespace travail
# Espace pour la maison
kubectl create namespace home

Étape 10 : Créer le Volume Persistant

Pour nos bases de données, nous allons créer un volume unique partagé (ce qui permet d’économiser de l’espace et de la gestion).

1. Créer le manifeste (demande de stockage)

Créez un fichier database-pvc.yaml ou appliquez directement ce contenu :

📄 Cliquez pour voir le contenu de database-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-persistence-claim
namespace: travail
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 5Gi

2. Appliquer la configuration

Fenêtre de terminal
kubectl apply -f database-pvc.yaml

3. Sécuriser les données (HA)

Une fois le volume créé, allez dans l’interface Web Longhorn, cliquez sur le volume, et réglez le nombre de répliques sur 3.

Cela garantit que vos données sont copiées sur vos 3 serveurs physiques, même si un serveur tombe en panne.

Étape 11 : Déploiement des Services (Stack Travail)

Voici le déploiement complet pour l’entreprise Travail. Il comprend :

  • PostgreSQL (Port 5432)
  • MongoDB (Port 27017)
  • pgAdmin 4 (Interface graphique Postgres - Port Node 30050)
  • Mongo Express (Interface graphique Mongo - Port Node 30051)

Les deux bases de données utilisent le même volume (db-persistence-claim) mais sont isolées dans des sous-dossiers (subPath).

1. Créer le fichier travail-stack.yaml

📄 Cliquez pour voir le contenu complet de travail-stack.yaml (195 lignes)
apiVersion: v1
kind: List
items:
# --- 1. POSTGRESQL ---
- apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: travail
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
- apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: travail
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
env:
- name: POSTGRES_USER
value: 'admin'
- name: POSTGRES_PASSWORD
value: 'MonMotDePasseSuperSecurise'
- name: POSTGRES_DB
value: 'travail_db'
ports:
- containerPort: 5432
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: shared-storage
subPath: postgres
volumes:
- name: shared-storage
persistentVolumeClaim:
claimName: db-persistence-claim
# --- 2. PGADMIN 4 ---
- apiVersion: v1
kind: Service
metadata:
name: pgadmin
namespace: travail
spec:
type: NodePort
selector:
app: pgadmin
ports:
- port: 80
targetPort: 80
nodePort: 30050
- apiVersion: apps/v1
kind: Deployment
metadata:
name: pgadmin
namespace: travail
spec:
replicas: 1
selector:
matchLabels:
app: pgadmin
template:
metadata:
labels:
app: pgadmin
spec:
containers:
- name: pgadmin
image: dpage/pgadmin4
env:
- name: PGADMIN_DEFAULT_EMAIL
value: 'admin@travail.com'
- name: PGADMIN_DEFAULT_PASSWORD
value: 'admin'
ports:
- containerPort: 80
# --- 3. MONGODB ---
- apiVersion: v1
kind: Service
metadata:
name: mongo
namespace: travail
spec:
selector:
app: mongo
ports:
- port: 27017
targetPort: 27017
- apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo
namespace: travail
spec:
replicas: 1
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
containers:
- name: mongo
image: mongo:6
env:
- name: MONGO_INITDB_ROOT_USERNAME
value: 'admin'
- name: MONGO_INITDB_ROOT_PASSWORD
value: 'MonMotDePasseMongo'
ports:
- containerPort: 27017
volumeMounts:
- mountPath: /data/db
name: shared-storage
subPath: mongo
volumes:
- name: shared-storage
persistentVolumeClaim:
claimName: db-persistence-claim
# --- 4. MONGO EXPRESS ---
- apiVersion: v1
kind: Service
metadata:
name: mongo-express
namespace: travail
spec:
type: NodePort
selector:
app: mongo-express
ports:
- port: 8081
targetPort: 8081
nodePort: 30051
- apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo-express
namespace: travail
spec:
replicas: 1
selector:
matchLabels:
app: mongo-express
template:
metadata:
labels:
app: mongo-express
spec:
containers:
- name: mongo-express
image: mongo-express
env:
- name: ME_CONFIG_MONGODB_ADMINUSERNAME
value: 'admin'
- name: ME_CONFIG_MONGODB_ADMINPASSWORD
value: 'MonMotDePasseMongo'
- name: ME_CONFIG_MONGODB_SERVER
value: 'mongo'
- name: ME_CONFIG_BASICAUTH_USERNAME
value: 'admin'
- name: ME_CONFIG_BASICAUTH_PASSWORD
value: 'admin'
ports:
- containerPort: 8081

2. Lancer le déploiement

Fenêtre de terminal
kubectl apply -f travail-stack.yaml

3. Accéder aux services

Vous pouvez maintenant accéder à vos outils depuis n’importe quelle machine de votre réseau :

  • pgAdmin : http://<IP_DE_VOTRE_MASTER>:30050
  • Mongo Express : http://<IP_DE_VOTRE_MASTER>:30051

Conclusion

Votre cluster est maintenant complet et taillé pour le Homelab ! 🎉

Récapitulatif

  • Infrastructure : 3 nœuds (Delta, Echo, Foxtrot)
  • Réseau : Calico
  • Stockage : Longhorn (Distribué et HA avec disques multiples)
  • Organisation : Namespaces travail et home
  • Services : Bases de données Postgres et Mongo persistantes et administrables