# Kubernetes

# Cheat Sheets

#### **Liste des commandes intéressantes K8S.**

Lister tous les pods qui ne sont pas liés au fonctionnement même de k8s :

```bash
kubectl get all --all-namespaces --field-selector metadata.namespace!=kube-system
```

Supprimer les namespaces entiers :

```bash
kubectl delete ns calico-apiserver calico-system longhorn-system tigera-operator
```

Supprimer un pod qui est en terminated :

```bash
kubectl patch pod <nom-du-pod> -n <namespace> \ -p '{"metadata":{"finalizers":[]}}' \ --type=merge
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-32 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="5" id="bkmrk-" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cc2af9c8e9d85bbb","c_5aad08af481cd12e",null,"rc_d026a2055aa170eb",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-32"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-32"></div></div></div>

# Instructions

**Cette documentation est faite de chapitre à suivre dans l'ordre pour une installation réussie d'un cluster K8S.**

# Architecture Type

# Architecture Utilisée

#### Architecture

<table border="1" id="bkmrk-hostname-ram-cpu-dis" style="border-collapse: collapse; width: 100%; height: 419.738px;"><colgroup><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col></colgroup><tbody><tr style="height: 64.7375px;"><td class="align-center" style="height: 64.7375px;">##### **Hostname**

</td><td class="align-center" style="height: 64.7375px;">##### **RAM**

</td><td class="align-center" style="height: 64.7375px;">##### **CPU**

</td><td class="align-center" style="height: 64.7375px;">##### **DISQUE**

</td><td class="align-center" style="height: 64.7375px;">##### **IP**

</td><td style="height: 64.7375px;">##### **FONCTION**

</td></tr><tr style="height: 46.5px;"><td style="height: 46.5px;">k8s-master-1  
</td><td style="height: 46.5px;">4 go</td><td style="height: 46.5px;">2</td><td style="height: 46.5px;">60 SSD</td><td style="height: 46.5px;">192.168.1.101</td><td style="height: 46.5px;">etcd + control-plane</td></tr><tr style="height: 46.5px;"><td style="height: 46.5px;">k8s-master-2</td><td style="height: 46.5px;">4 go</td><td style="height: 46.5px;">2</td><td style="height: 46.5px;">60 SSD</td><td style="height: 46.5px;">192.168.1.102</td><td style="height: 46.5px;">etcd + control-plane</td></tr><tr style="height: 46.5px;"><td style="height: 46.5px;">k8s-master-3</td><td style="height: 46.5px;">4 go</td><td style="height: 46.5px;">2</td><td style="height: 46.5px;">60 SSD</td><td style="height: 46.5px;">192.168.1.103</td><td style="height: 46.5px;">etcd + control-plane</td></tr><tr style="height: 46.5px;"><td style="height: 46.5px;">k8s-worker-1</td><td style="height: 46.5px;">16 go</td><td style="height: 46.5px;">4</td><td style="height: 46.5px;">60 SSD + 100 Go HDD (/opt)</td><td style="height: 46.5px;">192.168.1.104</td><td style="height: 46.5px;">  
</td></tr><tr style="height: 46.5px;"><td style="height: 46.5px;">k8s-worker-2</td><td style="height: 46.5px;">16 go</td><td style="height: 46.5px;">4</td><td style="height: 46.5px;">60 SSD + 100 Go HDD (/opt)</td><td style="height: 46.5px;">192.168.1.105</td><td style="height: 46.5px;">  
</td></tr><tr style="height: 46.5px;"><td style="height: 46.5px;">k8s-worker-3</td><td style="height: 46.5px;">16 go</td><td style="height: 46.5px;">4</td><td style="height: 46.5px;">60 SSD + 100 Go HDD (/opt)</td><td style="height: 46.5px;">192.168.1.106</td><td style="height: 46.5px;"></td></tr><tr style="height: 29.6px;"><td style="height: 29.6px;">VIP CLUSTER</td><td style="height: 29.6px;">192.168.1.100</td><td style="height: 29.6px;">  
</td><td style="height: 29.6px;">  
</td><td style="height: 29.6px;">  
</td><td style="height: 29.6px;"></td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">VIP WORKERS</td><td style="height: 46.4px;">192.168.1.2 à 192.168.1.8 </td><td style="height: 46.4px;">  
</td><td style="height: 46.4px;">  
</td><td style="height: 46.4px;">  
</td><td style="height: 46.4px;"></td></tr></tbody></table>

<p class="callout info">Tous les noeuds sont sur debian 13.</p>

# Prérequis

# Préparation du Système

#### Préparation du système

<p class="callout warning">Commandes à réaliser sur tous les noeuds</p>

##### 1) Désactivation de la swap

```bash
swapoff -a
```

Désactivation de la swap de manière pérenne :

```bash
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
```

##### 2) Configuration du kernel

Chargement au démarage des modules pour k8s :

```bash
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
```

Chargement immédiat des modules pour k8s :

```bash
modprobe overlay
modprobe br_netfilter
```

<p class="callout success">Le module overlay permet le fonctionnement du système de fichier OverlayFS.  
Le module br\_netfiltrer permet d'appliquer les iptables à un bridge.</p>

Configuration des paramètres réseaux :

```bash
cat <<EOF | 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
```

<p class="callout success">Permet aux bridges de faire appel au FW iptables  
Permet d'active le routage</p>

Application des paramètres :

```bash
sysctl --system
```

# Installation des Dépendances

#### installation des Dépendances

<p class="callout warning">Commandes à réaliser sur tous les noeuds</p>

##### Installation des packets courrants :

```bash
apt-get update 
apt-get install -y ca-certificates curl gnupg lsb-release htop jq tcpdump ethtool
```

##### Installation de containerd.io

```bash
install -m 0755 -d /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg

chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/debian bookworm stable" \
  | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update

apt install -y containerd.io
```

Configuration de containerd :

```bash
containerd config default | sudo tee /etc/containerd/config.toml
```

Activation de containerd :

```bash
systemctl enable containerd
```

Activation de l'emploie de systemd comme gestionnaire de Cgroup :

```bash
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
```

Redémarage de Containerd :

```bash
systemctl restart containerd
```

##### Installation de kubernet

Installation de kubelet kubeadm et kubectl :

```bash
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | gpg --dearmor | sudo tee /etc/apt/keyrings/kubernetes-apt-keyring.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt update

sudo apt install -y kubelet kubeadm kubectl

sudo apt-mark hold kubelet kubeadm kubectl
```

# Création du cluster K8S

# Préparation du cluster HA (KubeVip)

#### Préparation du cluster HA (KubeVip)

<p class="callout warning">Sur tous les noeuds master UNIQUEMENT</p>

```bash
export VIP="192.168.1.100"
export INTERFACE="ens18"
```

<p class="callout info">Ici ens18 correspond à mon interface de prod et 192.168.1.100 correspondra à l'ip qui se "baladera" sur mes noeuds master selon leur disponiblité -&gt; elle n'est pas fixée à un seul endroit.</p>

```bash
KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases/latest | jq -r ".name")
echo "Version kube-vip : $KVVERSION"
```

```bash
sudo mkdir -p /etc/kubernetes/manifests/
# Pull de l'image kube-vip
sudo ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION
# Génération du manifeste Static Pod
sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip \
/kube-vip manifest pod \
--interface $INTERFACE \
--address $VIP \
--controlplane \
--services \
--arp \
--leaderElection | sudo tee /etc/kubernetes/manifests/kube-vip.yaml
```

<p class="callout danger">Il faut copier coller le fichier manifeste au même endroit sur master 2 et 3.</p>

# Initialisation du cluster

#### Initialisation du cluster

<p class="callout warning">Sur le noeuds k8s-master-1 UNIQUEMENT</p>

Application "à la main" de l'ip vip le temps qu'elle soit gérée par K8S :

```bash
sudo ip addr add 192.168.1.100/32 dev ens18
```

Initialisation du cluster :

```bash
sudo kubeadm init \
--control-plane-endpoint "192.168.1.100:6443" \
--upload-certs \
--pod-network-cidr=10.10.0.0/16
```

```bash
sudo kubeadm init phase upload-certs --upload-certs
```

Configurer kubectl pour l'utilisateur courant :

```bash
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

 Vérification du bon déploiement du cluster "basique" :

```bash
kubectl get pods -n kube-system
```

```bash
NAME                                   READY   STATUS    RESTARTS   AGE
etcd-k8s-master-1                      1/1     Running   0          4m57s
kube-apiserver-k8s-master-1            1/1     Running   0          4m57s
kube-controller-manager-k8s-master-1   1/1     Running   0          4m57s
kube-scheduler-k8s-master-1            1/1     Running   0          4m57s
kube-vip-k8s-master-1                  1/1     Running   0          4m57s
```

# Déploiement du Réseau K8S

⚠️⚠️⚠️⚠️NE CHOISIR QU'UNE SEULE SOLUTION DE RÉSEAU ⚠️⚠️⚠️⚠️

# Calico

#### Déploiement du réseau Calico 

```bash
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
```

Attendre que l'opérateur ait fini :

```bash
kubectl rollout status deployment tigera-operator -n tigera-operator
```

Déployer les ressources Calico :

```bash
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml
```

Définir le sous réseau de K8S :

```bash
kubectl patch installation default --type=merge -p '{"spec": {"calicoNetwork": {"ipPools": [{"cidr": "10.10.0.0/16", "encapsulation": "VXLANCrossSubnet", "natOutgoing": "Enabled", "nodeSelector": "all()"}]}}}'
```

Suvi des états :

```
watch kubectl get pods -n calico-system
```

# Cilium

#### Installation du réseau Cilium 

Installation de cilium-cli :

```bash
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
sudo tar xzvf cilium-linux-amd64.tar.gz -C /usr/local/bin
rm cilium-linux-amd64.tar.gz
```

Déploiement :

```
cilium install --set ipam.operator.clusterPoolIPv4PodCIDRList="10.10.0.0/16"
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-168 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="6" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_b8d74a3caa98e15d","c_fcb4ad331681ddd4",null,"rc_71108aef33d9eead",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-168"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-168"></div></div></div>Attendre que le statut soit opérationnel :

```bash
cilium status --wait
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-169 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="8" id="bkmrk--2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_b8d74a3caa98e15d","c_fcb4ad331681ddd4",null,"rc_71108aef33d9eead",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-169"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-169"></div></div></div>Vérification de la conectivité :

```bash
cilium connectivity check
```

Suivi des pods :

```
watch kubectl get pods -n kube-system -l k8s-app=cilium
```

MAJ :

```bash
cilium upgrade   --set l2announcements.enabled=true \
  --set externalIPs.enabled=true \
  --set kubeProxyReplacement=true
```

Appliquer les changements :

```bash
 kubectl get pods -n kube-system | grep cili | grep -v opera | grep -v envoy | awk '{print $1}' | xargs kubectl delete po -n kube-system
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-171 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="12" id="bkmrk--4" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_b8d74a3caa98e15d","c_fcb4ad331681ddd4",null,"rc_71108aef33d9eead",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-171"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-171"></div></div></div>

# Finalisation de l'installation du cluster

# Configuration du cluster

#### Configuration du cluster

Désactivation de l'ip VIP "manuelle" :

```bash
sudo ip addr del 192.168.1.100/32 dev ens18
```

Ajout de l'ip vp dans le configmap de kubeadmin :

```
kubectl edit configmap kubeadm-config -n kube-system
```

```yaml
apiVersion: v1
data:
  ClusterConfiguration: |
    apiServer: {}
    apiVersion: kubeadm.k8s.io/v1beta4
    caCertificateValidityPeriod: 87600h0m0s
    certificateValidityPeriod: 8760h0m0s
    certificatesDir: /etc/kubernetes/pki
    clusterName: kubernetes
    controllerManager: {}
--> controlPlaneEndpoint: "192.168.1.100:6443"
```

Ici on ajoute uniquement "controlPlaneEndpoint.

```bash
kubeadm init phase upload-certs --upload-certs
```

Application du label control-plane à k8s-master-1

```bash
kubectl label node k8s-master-1 node-role.kubernetes.io/control-plane=
```

**Génération de la commande permettant d'ajouter des noeuds masters :**

```bash
sudo kubeadm token create --print-join-command --certificate-key $(sudo kubeadm init phase upload-certs --upload-certs | tail -1)
```

**Génération de la commande permettant d'ajouter des noeuds worker :**

```
kubeadm token create --print-join-command
```

# Ajout des différents noeuds au cluster

#### Ajout des différents noeuds master au cluster

<p class="callout warning">Commandes à exécuter sur les noeuds k8s-master-2 et k8s-master-3</p>

```bash
kubeadm join 192.168.1.100:6443 --token ld3z42.3n2zglgdtoyd2to2 --discovery-token-ca-cert-hash sha256:03d97c70e97b300bb1088fa63f1005d52dcf45d813e6ec535897f2151c8a61c2 --control-plane --certificate-key c9413180b64c612ee58713da91a4d9b77e95bee06b424aa500ebb4b16fb7769d
```


#### Ajout des différents noeuds worker au cluster

<p class="callout warning">Commandes à exécuter sur les noeuds k8s-worker-1, k8s-worker-2 et k8s-worker-3</p>

```yaml
// Envoyer la commande générée par kubeadm token create --print-join-command
```

#### Résultat : 

```bash
kubectl get nodes
```

```python
NAME           STATUS   ROLES           AGE     VERSION
k8s-master-1   Ready    control-plane   81m     v1.32.12
k8s-master-2   Ready    control-plane   6m13s   v1.32.12
k8s-master-3   Ready    control-plane   4m8s    v1.32.12
k8s-worker-1   Ready    <none>          2m3s    v1.32.12
k8s-worker-2   Ready    <none>          115s    v1.32.12
k8s-worker-3   Ready    <none>          105s    v1.32.12
```

<p class="callout success">Félicitation ! Vous venez de déployer votre tout premier cluster Kubernettes !</p>

#### Ajout des lablels "workers" aux noeuds workers :

```bash
kubectl label node k8s-worker-1 node-role.kubernetes.io/worker="true"
kubectl label node k8s-worker-2 node-role.kubernetes.io/worker="true"
kubectl label node k8s-worker-3 node-role.kubernetes.io/worker="true"
```

<p class="callout info">Sera utilise au moment des deployments</p>

# Déploiement d'une solution de stockage

Il peut y avoir plusieurs solutions de stockage utilisées par un même cluster.

# LongHorn

#### Déployer une solution de stockage

**Installation des prérequits sur TOUS LES NOEUDS :**

```bash
sudo apt-get update
sudo apt-get install -y open-iscsi nfs-common
sudo systemctl enable --now iscsid
```

**Installation de Helm sur le master 1 :**

```bash
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
bash get_helm.sh
```

**Préparation et déploiement de Longhorn :**

```bash
helm repo add longhorn https://charts.longhorn.io
helm repo update
```

**Dans le fichier : /root/longhorn-values.yaml :**

```yaml
defaultSettings:
  defaultDataPath: "/opt/longhorn"
```

**Déploiement de longhorn :**

```bash
helm install longhorn longhorn/longhorn \
  --namespace longhorn-system \
  --create-namespace \
  -f /root/longhorn-values.yaml
```

Résultat :

```bash
LAST DEPLOYED: Wed Apr 15 22:49:57 2026
NAMESPACE: longhorn-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Longhorn is now installed on the cluster!

Please wait a few minutes for other Longhorn components such as CSI deployments, Engine Images, and Instance Managers to be initialized.

Visit our documentation at https://longhorn.io/docs/
```

**Vérifications :**

```bash
kubectl get pods -n longhorn-system
```

```bash
NAME                                                READY   STATUS    RESTARTS      AGE
csi-attacher-5bcb65bf95-44fv7                       1/1     Running   1 (66s ago)   2m27s
csi-attacher-5bcb65bf95-jvqxj                       1/1     Running   0             2m27s
csi-attacher-5bcb65bf95-pgf8h                       1/1     Running   0             2m27s
csi-provisioner-5d498c6944-d65sl                    1/1     Running   0             2m27s
csi-provisioner-5d498c6944-dfl96                    1/1     Running   0             2m27s
csi-provisioner-5d498c6944-wvmvs                    1/1     Running   0             2m27s
csi-resizer-6c6474c996-9k94v                        1/1     Running   0             2m26s
csi-resizer-6c6474c996-mjtsj                        1/1     Running   0             2m27s
csi-resizer-6c6474c996-t94bs                        1/1     Running   0             2m26s
csi-snapshotter-5cc5fb45d9-pxz5r                    1/1     Running   0             2m26s
csi-snapshotter-5cc5fb45d9-swr6x                    1/1     Running   0             2m26s
csi-snapshotter-5cc5fb45d9-wsdh6                    1/1     Running   0             2m26s
engine-image-ei-75a03ec3-8r6p4                      1/1     Running   0             3m23s
engine-image-ei-75a03ec3-nmbdp                      1/1     Running   0             3m23s
engine-image-ei-75a03ec3-tl4x2                      1/1     Running   0             3m23s
engine-image-ei-75a03ec3-vcq2q                      1/1     Running   0             3m23s
instance-manager-8904e58b7c0d881b70d813ddd4fe86f4   1/1     Running   0             2m54s
instance-manager-9176dd8e42515fe6146f445c7a1bc3ad   1/1     Running   0             2m53s
instance-manager-9805597396c5db2820496e3f125bc6bc   1/1     Running   0             2m53s
instance-manager-eaeed3ca06747e29c0f3aa8b9557c5c8   1/1     Running   0             2m53s
longhorn-csi-plugin-7vtx8                           3/3     Running   0             2m26s
longhorn-csi-plugin-brx6d                           3/3     Running   0             2m26s
longhorn-csi-plugin-d4fxc                           3/3     Running   0             2m26s
longhorn-csi-plugin-tsrrg                           3/3     Running   0             2m26s
longhorn-driver-deployer-746f54969f-9gmlb           1/1     Running   0             4m5s
longhorn-manager-b7q7k                              2/2     Running   0             4m5s
longhorn-manager-fk6f4                              2/2     Running   0             4m5s
longhorn-manager-xghbf                              2/2     Running   0             4m5s
longhorn-manager-xt4xq                              2/2     Running   0             4m5s
longhorn-ui-5df99fc477-7zt5s                        1/1     Running   0             4m5s
longhorn-ui-5df99fc477-tzwdp                        1/1     Running   0             4m5s
```

<span style="text-decoration: underline;">**Accéder à l'interface graphique :**</span>

```bash
kubectl patch svc longhorn-frontend -n longhorn-system -p '{"spec": {"type": "NodePort"}}'
```

Afficher le port :

```bash
kubectl get svc longhorn-frontend -n longhorn-system
```

**On va utiliser le port :**

```bash
NAME                TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
longhorn-frontend   NodePort   10.102.85.80   <none>        80:32555/TCP   6m22s
```

Exemple ici : http://192.168.1.104:32555/#/dashboard

<p class="callout info">On peut utiliser n'importe quelle IP du cluster.</p>

[![image.png](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/scaled-1680-/IGbimage.png)](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/IGbimage.png)

#####   
Tester le stockage (pour aller plus loin) : 

<span style="text-decoration: underline;">**Déclaration du PVC :**</span>

```bash
hello-pvc.yaml
```

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: longhorn-hello-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn # On utilise le driver Longhorn
  resources:
    requests:
      storage: 1Gi # 1 Go c'est largement assez pour un test
```

**<u>Création d'un conteneur utilisant le PVC : </u>**

```
hello-app.yaml
```

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello-longhorn
spec:
  containers:
  - name: hello-world
    image: busybox
    # On écrit la date dans /data/coucou.txt en boucle
    command: ["sh", "-c", "while true; do date >> /data/coucou.txt; echo 'Donnée écrite !'; sleep 5; done"]
    volumeMounts:
    - name: storage-volume
      mountPath: /data
  volumes:
  - name: storage-volume
    persistentVolumeClaim:
      claimName: longhorn-hello-pvc
```

<span style="text-decoration: underline;">**Application des changements :**</span>

```bash
kubectl apply -f hello-pvc.yaml
kubectl apply -f hello-app.yaml
```

<span style="text-decoration: underline;">**Côté interface graphique :**</span>

[![image.png](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/scaled-1680-/jL1image.png)](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/jL1image.png)

<span style="text-decoration: underline;">**Suppression du pod :** </span>

```bash
kubectl delete pod hello-longhorn
```

<span style="text-decoration: underline;">**Suppression du pvc :** </span>

```
kubectl delete pvc longhorn-hello-pvc
```

<div _ngcontent-ng-c3460292570="" class="code-block ng-tns-c3460292570-128 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiDrK254_CTAxUAAAAAHQAAAAAQYg" decode-data-ved="1" id="bkmrk--13" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_51b325c2d0d4593e","c_a28d9286aabbaa6c",null,"rc_9a271958ca57b1e4",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3460292570="" class="formatted-code-block-internal-container ng-tns-c3460292570-128"><div _ngcontent-ng-c3460292570="" class="animated-opacity ng-tns-c3460292570-128"></div></div></div>

# Déployer un Load balancer avec une VIP

# Avec Cilium

<p class="callout warning">Cette documentation ne peut être exécutée uniquement sur un cluster ayant pour réseau Cilium.</p>

<span style="text-decoration: underline;">**Déclaration de la pool possible d'IP VIP :**</span>

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
  name: worker-vip-pool
spec:
  blocks:
    - start: "192.168.1.2"
      stop:  "192.168.1.9"
  serviceSelector:
    matchLabels:
      expose: "true"
EOF
```

<span style="text-decoration: underline;">**Déclaration de la mise en réseau :** </span>

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: cilium.io/v2alpha1
kind: CiliumL2AnnouncementPolicy
metadata:
  name: worker-l2-policy
  namespace: kube-system
spec:
  nodeSelector:
    matchLabels:
      node-role.kubernetes.io/worker: "true"
  serviceSelector:
    matchLabels:
      expose: "true"
  loadBalancerIPs: true
  externalIPs: false
  interfaces:
    - ens18
EOF
```

<span style="text-decoration: underline;">**Exemple de déploiement et de service permetant d'exposer un pod web via une VIP :** </span>

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
        - name: hello
          image: hashicorp/http-echo:latest
          args:
            - "-text=Hello from Cilium VIP 👋"
            - "-listen=:8080"
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: hello-world
  namespace: default
  labels:
    expose: "true"
  annotations:
    lbipam.cilium.io/ips: "192.168.1.2"   # IP fixe dans le pool
spec:
  type: LoadBalancer
  selector:
    app: hello-world
  ports:
    - port: 80
      targetPort: 8080
EOF
```

<span style="text-decoration: underline;">**Résultat :**</span>

[![image.png](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/scaled-1680-/8o5image.png)](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/8o5image.png)

# Déployer un serveur de télémétrie

# Déployer metrics-server

Installation :

```bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
```

Application du no verify TLS :

```bash
kubectl patch deployment metrics-server -n kube-system \
  --type=json \
  -p='[
    {
      "op": "add",
      "path": "/spec/template/spec/containers/0/args/-",
      "value": "--kubelet-insecure-tls"
    },
    {
      "op": "add",
      "path": "/spec/template/spec/containers/0/args/-",
      "value": "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname"
    }
  ]'
```

Attendre le rollout :

```bash
kubectl rollout status deployment/metrics-server -n kube-system
```

Afficher des infos ram et cpu des nodes et des pods :

```bash
kubectl top nodes
kubectl top pods -A
```

# Déployer des applications dans K8S !

# Minecraft

<p class="callout success">Quelle joie pour moi de déployer un serveur minecraft dans K8S !</p>

<span style="text-decoration: underline;">**En prérequits à ce tuto**</span> :

- [https://docs.nehemiebarkia.fr/books/kubernetes/page/avec-cilium](https://docs.nehemiebarkia.fr/books/kubernetes/page/avec-cilium)
- [https://docs.nehemiebarkia.fr/books/kubernetes/page/longhorn](https://docs.nehemiebarkia.fr/books/kubernetes/page/longhorn)

<span style="text-decoration: underline;">**Création du namespace Minecraft :**</span>

```bash
kubectl create namespace minecraft
```

<span style="text-decoration: underline;">**Déclaration du PVC :**</span>

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: minecraft-srv-01-pvc
  namespace: minecraft
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 10Gi
EOF
```

<span style="text-decoration: underline;">**Déploiement &amp; service minecraft** </span>:

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minecraft-01
  namespace: minecraft
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: minecraft-01
  template:
    metadata:
      labels:
        app: minecraft-01
    spec:
      containers:
        - name: minecraft-01
          image: itzg/minecraft-server:java8
          env:
            - name: EULA
              value: "TRUE"
            - name: VERSION
              value: "1.12.2"
            - name: TYPE
              value: "MOHIST"
            - name: MEMORY
              value: "4G"
            - name: FORGE_VERSION
              value: "14.23.5.2860"   # version Forge stable pour 1.12.2
            - name: REMOVE_OLD_MODS
              value: "false"           # ne pas supprimer les mods au redémarrage
            - name: ONLINE_MODE
              value: "true"
          ports:
            - containerPort: 25565
          resources:
            requests:
              memory: "4.5Gi"
              cpu: "1000m"
            limits:
              memory: "6Gi"
              cpu: "4000m"
          volumeMounts:
            - name: storage-volume
              mountPath: /data
      volumes:
      - name: storage-volume
        persistentVolumeClaim:
          claimName: minecraft-srv-01-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: minecraft-01
  namespace: minecraft
  labels:
    expose: "true"
  annotations:
    lbipam.cilium.io/ips: "192.168.1.3"
spec:
  type: LoadBalancer
  selector:
    app: minecraft-01
  ports:
    - port: 25565
      targetPort: 25565
EOF
```

# Factorio

**Création du Namespace et du label :**

```bash
kubectl create namespace factorio
```

**Création du PVC :**

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: factorio-srv-01-pvc
  namespace: factorio
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 10Gi
EOF
```

**Déployment + Service :**

```yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: factorio-mod-list
  namespace: factorio
data:
  mod-list.json: |
    {
      "mods": [
        {
          "name": "base",
          "enabled": true
        }
      ]
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: factorio-01
  namespace: factorio
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: factorio-01
  template:
    metadata:
      labels:
        app: factorio-01
    spec:
      securityContext:
        runAsUser: 845
        runAsGroup: 845
        fsGroup: 845
      containers:
        - name: factorio-01
          image: factoriotools/factorio:latest-rootless
          ports:
            - containerPort: 34197
              protocol: UDP
          env:
            - name: UPDATE_MODS_ON_START
              value: "false"
            - name: DLC_SPACE_AGE
              value: "false"

          volumeMounts:
            - name: storage-volume
              mountPath: /factorio
            - name: mod-list
              mountPath: /factorio/config/mod-list.json
              subPath: mod-list.json
      volumes:
      - name: storage-volume
        persistentVolumeClaim:
          claimName: factorio-srv-01-pvc
      - name: mod-list
        configMap:
          name: factorio-mod-list
---
apiVersion: v1
kind: Service
metadata:
  name: factorio-01
  namespace: factorio
  labels:
    expose: "true"
  annotations:
    lbipam.cilium.io/ips: "10.0.20.2"
spec:
  type: LoadBalancer
  selector:
    app: factorio-01
  ports:
    - port: 34197
      targetPort: 34197
      protocol: UDP
EOF
```

# AUTRE_Installation complètes

Ce chaptire comprend des exemples d'installation de A à Z. Ce sont en gros des copier collés des différents blocs que vous pouvez consulter dans le livre "kubernetes"

# Initialisation de mon tout premier cluster HA

#### Architecture

<table border="1" id="bkmrk-hostname-ram-cpu-dis" style="border-collapse: collapse; width: 100%; height: 343.05px;"><colgroup><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col><col style="width: 16.6826%;"></col></colgroup><tbody><tr style="height: 64.65px;"><td class="align-center" style="height: 64.65px;">##### **Hostname**

</td><td class="align-center" style="height: 64.65px;">##### **RAM**

</td><td class="align-center" style="height: 64.65px;">##### **CPU**

</td><td class="align-center" style="height: 64.65px;">##### **DISQUE**

</td><td class="align-center" style="height: 64.65px;">##### **IP**

</td><td style="height: 64.65px;">##### **FONCTION**

</td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">k8s-master-1  
</td><td style="height: 46.4px;">4 go</td><td style="height: 46.4px;">2</td><td style="height: 46.4px;">60 SSD + 100 HDD (/opt)</td><td style="height: 46.4px;">192.168.1.101</td><td style="height: 46.4px;">etcd + control-plane</td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">k8s-master-2</td><td style="height: 46.4px;">4 go</td><td style="height: 46.4px;">2</td><td style="height: 46.4px;">60 SSD + 100 HDD (/opt)</td><td style="height: 46.4px;">192.168.1.102</td><td style="height: 46.4px;">etcd + control-plane</td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">k8s-master-3</td><td style="height: 46.4px;">4 go</td><td style="height: 46.4px;">2</td><td style="height: 46.4px;">60 SSD + 100 HDD (/opt) </td><td style="height: 46.4px;">192.168.1.103</td><td style="height: 46.4px;">etcd + control-plane</td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">k8s-worker-1</td><td style="height: 46.4px;">16 go</td><td style="height: 46.4px;">4</td><td style="height: 46.4px;">60 SSD + 100 HDD (/opt)</td><td style="height: 46.4px;">192.168.1.104</td><td style="height: 46.4px;">  
</td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">k8s-worker-2</td><td style="height: 46.4px;">16 go</td><td style="height: 46.4px;">4</td><td style="height: 46.4px;">60 SSD + 100 HDD (/opt)</td><td style="height: 46.4px;">192.168.1.105</td><td style="height: 46.4px;">  
</td></tr><tr style="height: 46.4px;"><td style="height: 46.4px;">k8s-worker-3</td><td style="height: 46.4px;">16 go</td><td style="height: 46.4px;">4</td><td style="height: 46.4px;">60 SSD + 100 HDD (/opt)</td><td style="height: 46.4px;">192.168.1.106</td><td style="height: 46.4px;">  
</td></tr></tbody></table>

<p class="callout info">Tous les noeuds sont sur debian 13.</p>

#### Plan de déploiement du cluster :

- Préparation du système
- installation des prérequits 
    - conainer.io
    - kubelet
    - kubeadm
    - kubectl
- Préparation du cluster HA (KubeVip)
- Initialisation du cluster
- Configuration du cluster
- Ajout des différents noeud au cluster

#### Préparation du système

<p class="callout warning">Commandes à réaliser sur tous les noeuds</p>

##### 1) Désactivation de la swap

```bash
swapoff -a
```

Désactivation de la swap de manière pérenne :

```bash
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
```

##### 2) Configuration du kernel

Chargement au démarage des modules pour k8s :

```bash
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
```

Chargement immédiat des modules pour k8s :

```bash
modprobe overlay
modprobe br_netfilter
```

<p class="callout success">Le module overlay permet le fonctionnement du système de fichier OverlayFS.  
Le module br\_netfiltrer permet d'appliquer les iptables à un bridge.</p>

Configuration des paramètres réseaux :

```bash
cat <<EOF | 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
```

<p class="callout success">Permet aux bridges de faire appel au FW iptables  
Permet d'active le routage</p>

Application des paramètres :

```bash
sysctl --system
```


#### installation des prérequits

<p class="callout warning">Commandes à réaliser sur tous les noeuds</p>

##### Installation des packets courrants :

```bash
apt-get update 
apt-get install -y ca-certificates curl gnupg lsb-release htop jq tcpdump ethtool
```

##### Installation de containerd.io

```bash
install -m 0755 -d /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg

chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/debian bookworm stable" \
  | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update

apt install -y containerd.io
```

Configuration de containerd :

```bash
containerd config default | sudo tee /etc/containerd/config.toml
```

Activation de containerd :

```bash
systemctl enable containerd
```

Activation de l'emploie de systemd comme gestionnaire de Cgroup :

```bash
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
```

Redémarage de Containerd :

```bash
systemctl restart containerd
```

##### Installation de kubernet

Installation de kubelet kubeadm et kubectl :

```bash
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | gpg --dearmor | sudo tee /etc/apt/keyrings/kubernetes-apt-keyring.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt update

sudo apt install -y kubelet kubeadm kubectl

sudo apt-mark hold kubelet kubeadm kubectl
```

#### Préparation du cluster HA (KubeVip)

<p class="callout warning">Sur tous les noeuds master UNIQUEMENT</p>

```bash
export VIP="192.168.1.100"
export INTERFACE="ens18"
```

<p class="callout info">Ici ens18 correspond à mon interface de prod et 192.168.1.100 correspondra à l'ip qui se "baladera" sur mes noeuds master selon leur disponiblité -&gt; elle n'est pas fixée à un seul endroit.</p>

```bash
KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases/latest | jq -r ".name")
echo "Version kube-vip : $KVVERSION"
```

```bash
sudo mkdir -p /etc/kubernetes/manifests/
# Pull de l'image kube-vip
sudo ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION
# Génération du manifeste Static Pod
sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip \
/kube-vip manifest pod \
--interface $INTERFACE \
--address $VIP \
--controlplane \
--services \
--arp \
--leaderElection | sudo tee /etc/kubernetes/manifests/kube-vip.yaml
```

#### Initialisation du cluster

<p class="callout warning">Sur le noeuds k8s-master-1 UNIQUEMENT</p>

Application "à la main" de l'ip vip le temps qu'elle soit gérée par K8S :

```bash
sudo ip addr add 192.168.1.100/32 dev ens18
```

Initialisation du cluster :

```bash
sudo kubeadm init \
--control-plane-endpoint "192.168.1.100:6443" \
--upload-certs \
--pod-network-cidr=10.10.0.0/16
```

```bash
sudo kubeadm init phase upload-certs --upload-certs
```

Configurer kubectl pour l'utilisateur courant :

```bash
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

 Vérification du bon déploiement du cluster "basique" :

```bash
kubectl get pods -n kube-system
```

```bash
NAME                                   READY   STATUS    RESTARTS   AGE
etcd-k8s-master-1                      1/1     Running   0          4m57s
kube-apiserver-k8s-master-1            1/1     Running   0          4m57s
kube-controller-manager-k8s-master-1   1/1     Running   0          4m57s
kube-scheduler-k8s-master-1            1/1     Running   0          4m57s
kube-vip-k8s-master-1                  1/1     Running   0          4m57s
```

#### Déploiement du réseau Calico 

```bash
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/tigera-operator.yaml
```

Attendre que l'opérateur ait fini :

```bash
kubectl rollout status deployment tigera-operator -n tigera-operator
```

Déployer les ressources Calico :

```bash
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/custom-resources.yaml
```

Définir le sous réseau de K8S :

```bash
kubectl patch installation default --type=merge -p '{"spec": {"calicoNetwork": {"ipPools": [{"cidr": "10.10.0.0/16", "encapsulation": "VXLANCrossSubnet", "natOutgoing": "Enabled", "nodeSelector": "all()"}]}}}'
```

Suvi des états :

```
watch kubectl get pods -n calico-system
```

#### Configuration du cluster

Désactivation de l'ip VIP "manuelle" :

```bash
sudo ip addr del 192.168.1.100/32 dev ens18
```

Ajout de l'ip vp dans le configmap de kubeadmin :

```
kubectl edit configmap kubeadm-config -n kube-system
```

```yaml
apiVersion: v1
data:
  ClusterConfiguration: |
    apiServer: {}
    apiVersion: kubeadm.k8s.io/v1beta4
    caCertificateValidityPeriod: 87600h0m0s
    certificateValidityPeriod: 8760h0m0s
    certificatesDir: /etc/kubernetes/pki
    clusterName: kubernetes
    controllerManager: {}
--> controlPlaneEndpoint: "192.168.1.100:6443"
```

Ici on ajoute uniquement "controlPlaneEndpoint.

```bash
kubeadm init phase upload-certs --upload-certs
```

Application du label control-plane à k8s-master-1

```bash
kubectl label node k8s-master-1 node-role.kubernetes.io/control-plane=
```

**Génération de la commande permettant d'ajouter des noeuds masters :**

```bash
sudo kubeadm token create --print-join-command --certificate-key $(sudo kubeadm init phase upload-certs --upload-certs | tail -1)
```

**Génération de la commande permettant d'ajouter des noeuds worker :**

```
kubeadm token create --print-join-command
```

#### Ajout des différents noeuds master au cluster

<p class="callout warning">Commandes à exécuter sur les noeuds k8s-master-2 et k8s-master-3</p>

```bash
kubeadm join 192.168.1.100:6443 --token ld3z42.3n2zglgdtoyd2to2 --discovery-token-ca-cert-hash sha256:03d97c70e97b300bb1088fa63f1005d52dcf45d813e6ec535897f2151c8a61c2 --control-plane --certificate-key c9413180b64c612ee58713da91a4d9b77e95bee06b424aa500ebb4b16fb7769d
```


#### Ajout des différents noeuds worker au cluster

<p class="callout warning">Commandes à exécuter sur les noeuds k8s-worker-1, k8s-worker-2 et k8s-worker-3</p>

```yaml
// Envoyer la commande générée par kubeadm token create --print-join-command
```

#### Résultat : 

```bash
kubectl get nodes
```

```python
NAME           STATUS   ROLES           AGE     VERSION
k8s-master-1   Ready    control-plane   81m     v1.32.12
k8s-master-2   Ready    control-plane   6m13s   v1.32.12
k8s-master-3   Ready    control-plane   4m8s    v1.32.12
k8s-worker-1   Ready    <none>          2m3s    v1.32.12
k8s-worker-2   Ready    <none>          115s    v1.32.12
k8s-worker-3   Ready    <none>          105s    v1.32.12
```

<p class="callout success">Félicitation ! Vous venez de déployer votre tout premier cluster Kubernettes !</p>

#### Déployer une solution de stockage

**Installation des prérequits sur TOUS LES NOEUDS :**

```bash
sudo apt-get update
sudo apt-get install -y open-iscsi nfs-common
sudo systemctl enable --now iscsid
```

**Installation de Helm sur le master 1 :**

```bash
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
bash get_helm.sh
```

**Préparation et déploiement de Longhorn :**

```bash
helm repo add longhorn https://charts.longhorn.io
helm repo update
```

**Dans le fichier : /root/longhorn-values.yaml :**

```yaml
defaultSettings:
  defaultDataPath: "/opt/longhorn"
```

**Déploiement de longhorn :**

```bash
helm install longhorn longhorn/longhorn \
  --namespace longhorn-system \
  --create-namespace \
  -f /root/longhorn-values.yaml
```

Résultat :

```bash
LAST DEPLOYED: Wed Apr 15 22:49:57 2026
NAMESPACE: longhorn-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Longhorn is now installed on the cluster!

Please wait a few minutes for other Longhorn components such as CSI deployments, Engine Images, and Instance Managers to be initialized.

Visit our documentation at https://longhorn.io/docs/
```

**Vérifications :**

```bash
kubectl get pods -n longhorn-system
```

```bash
NAME                                                READY   STATUS    RESTARTS      AGE
csi-attacher-5bcb65bf95-44fv7                       1/1     Running   1 (66s ago)   2m27s
csi-attacher-5bcb65bf95-jvqxj                       1/1     Running   0             2m27s
csi-attacher-5bcb65bf95-pgf8h                       1/1     Running   0             2m27s
csi-provisioner-5d498c6944-d65sl                    1/1     Running   0             2m27s
csi-provisioner-5d498c6944-dfl96                    1/1     Running   0             2m27s
csi-provisioner-5d498c6944-wvmvs                    1/1     Running   0             2m27s
csi-resizer-6c6474c996-9k94v                        1/1     Running   0             2m26s
csi-resizer-6c6474c996-mjtsj                        1/1     Running   0             2m27s
csi-resizer-6c6474c996-t94bs                        1/1     Running   0             2m26s
csi-snapshotter-5cc5fb45d9-pxz5r                    1/1     Running   0             2m26s
csi-snapshotter-5cc5fb45d9-swr6x                    1/1     Running   0             2m26s
csi-snapshotter-5cc5fb45d9-wsdh6                    1/1     Running   0             2m26s
engine-image-ei-75a03ec3-8r6p4                      1/1     Running   0             3m23s
engine-image-ei-75a03ec3-nmbdp                      1/1     Running   0             3m23s
engine-image-ei-75a03ec3-tl4x2                      1/1     Running   0             3m23s
engine-image-ei-75a03ec3-vcq2q                      1/1     Running   0             3m23s
instance-manager-8904e58b7c0d881b70d813ddd4fe86f4   1/1     Running   0             2m54s
instance-manager-9176dd8e42515fe6146f445c7a1bc3ad   1/1     Running   0             2m53s
instance-manager-9805597396c5db2820496e3f125bc6bc   1/1     Running   0             2m53s
instance-manager-eaeed3ca06747e29c0f3aa8b9557c5c8   1/1     Running   0             2m53s
longhorn-csi-plugin-7vtx8                           3/3     Running   0             2m26s
longhorn-csi-plugin-brx6d                           3/3     Running   0             2m26s
longhorn-csi-plugin-d4fxc                           3/3     Running   0             2m26s
longhorn-csi-plugin-tsrrg                           3/3     Running   0             2m26s
longhorn-driver-deployer-746f54969f-9gmlb           1/1     Running   0             4m5s
longhorn-manager-b7q7k                              2/2     Running   0             4m5s
longhorn-manager-fk6f4                              2/2     Running   0             4m5s
longhorn-manager-xghbf                              2/2     Running   0             4m5s
longhorn-manager-xt4xq                              2/2     Running   0             4m5s
longhorn-ui-5df99fc477-7zt5s                        1/1     Running   0             4m5s
longhorn-ui-5df99fc477-tzwdp                        1/1     Running   0             4m5s
```

<span style="text-decoration: underline;">**Accéder à l'interface graphique :**</span>

```bash
kubectl patch svc longhorn-frontend -n longhorn-system -p '{"spec": {"type": "NodePort"}}'
```

Afficher le port :

```bash
kubectl get svc longhorn-frontend -n longhorn-system
```

**On va utiliser le port :**

```bash
NAME                TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
longhorn-frontend   NodePort   10.102.85.80   <none>        80:32555/TCP   6m22s
```

Exemple ici : http://192.168.1.104:32555/#/dashboard

<p class="callout info">On peut utiliser n'importe quelle IP du cluster.</p>

[![image.png](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/scaled-1680-/IGbimage.png)](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/IGbimage.png)

##### Tester le stockage : 

<span style="text-decoration: underline;">**Déclaration du PVC :**</span>

```bash
hello-pvc.yaml
```

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: longhorn-hello-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn # On utilise le driver Longhorn
  resources:
    requests:
      storage: 1Gi # 1 Go c'est largement assez pour un test
```

**<u>Création d'un conteneur utilisant le PVC : </u>**

```
hello-app.yaml
```

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello-longhorn
spec:
  containers:
  - name: hello-world
    image: busybox
    # On écrit la date dans /data/coucou.txt en boucle
    command: ["sh", "-c", "while true; do date >> /data/coucou.txt; echo 'Donnée écrite !'; sleep 5; done"]
    volumeMounts:
    - name: storage-volume
      mountPath: /data
  volumes:
  - name: storage-volume
    persistentVolumeClaim:
      claimName: longhorn-hello-pvc
```

<span style="text-decoration: underline;">**Application des changements :**</span>

```bash
kubectl apply -f hello-pvc.yaml
kubectl apply -f hello-app.yaml
```

<span style="text-decoration: underline;">**Côté interface graphique :**</span>

[![image.png](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/scaled-1680-/jL1image.png)](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/jL1image.png)

<span style="text-decoration: underline;">**Suppression du pod :** </span>

```bash
kubectl delete pod hello-longhorn
```

<span style="text-decoration: underline;">**Suppression du pvc :** </span>

```
kubectl delete pvc longhorn-hello-pvc
```

<div _ngcontent-ng-c3460292570="" class="code-block ng-tns-c3460292570-128 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiDrK254_CTAxUAAAAAHQAAAAAQYg" decode-data-ved="1" id="bkmrk--13" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_51b325c2d0d4593e","c_a28d9286aabbaa6c",null,"rc_9a271958ca57b1e4",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3460292570="" class="formatted-code-block-internal-container ng-tns-c3460292570-128"><div _ngcontent-ng-c3460292570="" class="animated-opacity ng-tns-c3460292570-128"></div></div></div>

# Cluster HA - Loghorn - Cilium - KubeVip

#### Architecture

<table border="1" id="bkmrk-hostname-ram-cpu-dis" style="border-collapse: collapse; width: 100%; height: 343.779px;"><colgroup><col style="width: 16.6847%;"></col><col style="width: 16.6847%;"></col><col style="width: 16.6847%;"></col><col style="width: 16.6847%;"></col><col style="width: 16.6847%;"></col><col style="width: 16.6847%;"></col></colgroup><tbody><tr style="height: 64.7443px;"><td class="align-center" style="height: 64.7443px;">##### **Hostname**

</td><td class="align-center" style="height: 64.7443px;">##### **RAM**

</td><td class="align-center" style="height: 64.7443px;">##### **CPU**

</td><td class="align-center" style="height: 64.7443px;">##### **DISQUE**

</td><td class="align-center" style="height: 64.7443px;">##### **IP**

</td><td style="height: 64.7443px;">##### **FONCTION**

</td></tr><tr style="height: 46.5057px;"><td style="height: 46.5057px;">k8s-master-1  
</td><td style="height: 46.5057px;">4 go</td><td style="height: 46.5057px;">2</td><td style="height: 46.5057px;">60 SSD</td><td style="height: 46.5057px;">192.168.1.101</td><td style="height: 46.5057px;">etcd + control-plane</td></tr><tr style="height: 46.5057px;"><td style="height: 46.5057px;">k8s-master-2</td><td style="height: 46.5057px;">4 go</td><td style="height: 46.5057px;">2</td><td style="height: 46.5057px;">60 SSD</td><td style="height: 46.5057px;">192.168.1.102</td><td style="height: 46.5057px;">etcd + control-plane</td></tr><tr style="height: 46.5057px;"><td style="height: 46.5057px;">k8s-master-3</td><td style="height: 46.5057px;">4 go</td><td style="height: 46.5057px;">2</td><td style="height: 46.5057px;">60 SSD</td><td style="height: 46.5057px;">192.168.1.103</td><td style="height: 46.5057px;">etcd + control-plane</td></tr><tr style="height: 46.5057px;"><td style="height: 46.5057px;">k8s-worker-1</td><td style="height: 46.5057px;">16 go</td><td style="height: 46.5057px;">4</td><td style="height: 46.5057px;">60 SSD + 100 Go HDD (/opt)</td><td style="height: 46.5057px;">192.168.1.104</td><td style="height: 46.5057px;">  
</td></tr><tr style="height: 46.5057px;"><td style="height: 46.5057px;">k8s-worker-2</td><td style="height: 46.5057px;">16 go</td><td style="height: 46.5057px;">4</td><td style="height: 46.5057px;">60 SSD + 100 Go HDD (/opt)</td><td style="height: 46.5057px;">192.168.1.105</td><td style="height: 46.5057px;">  
</td></tr><tr style="height: 46.5057px;"><td style="height: 46.5057px;">k8s-worker-3</td><td style="height: 46.5057px;">16 go</td><td style="height: 46.5057px;">4</td><td style="height: 46.5057px;">60 SSD + 100 Go HDD (/opt)</td><td style="height: 46.5057px;">192.168.1.106</td><td style="height: 46.5057px;"></td></tr><tr><td>VIP CLUSTER</td><td>192.168.1.100</td><td>  
</td><td>  
</td><td>  
</td><td></td></tr><tr><td>VIP WORKERS</td><td>192.168.1.99</td><td>  
</td><td>  
</td><td>  
</td><td></td></tr></tbody></table>

<p class="callout info">Tous les noeuds sont sur debian 13.</p>

#### Résumé :

Type de cluster : **Haute Disponibilité**

Stockage : **Loghorn**

Réseau : **Cilium**

Exposition des workers : **KubeVip**

#### Préparation du systèm

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)



#### Installation des prérequits

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)

#### Préparation du cluster HA (KubeVip)

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)


#### Initialisation du cluster

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)


#### Installation du réseau Cilium 

Installation de cilium-cli :

```bash
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
sudo tar xzvf cilium-linux-amd64.tar.gz -C /usr/local/bin
rm cilium-linux-amd64.tar.gz
```

Déploiement :

```
cilium install --set ipam.operator.clusterPoolIPv4PodCIDRList="10.10.0.0/16"
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-168 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="6" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_b8d74a3caa98e15d","c_fcb4ad331681ddd4",null,"rc_71108aef33d9eead",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-168"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-168"></div></div></div>Attendre que le statut soit opérationnel :

```bash
cilium status --wait
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-169 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="8" id="bkmrk--2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_b8d74a3caa98e15d","c_fcb4ad331681ddd4",null,"rc_71108aef33d9eead",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-169"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-169"></div></div></div>Vérification de la conectivité :

```bash
cilium connectivity check
```

Suivi des pods :

```
watch kubectl get pods -n kube-system -l k8s-app=cilium
```

<div _ngcontent-ng-c3082907845="" class="code-block ng-tns-c3082907845-171 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="12" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_b8d74a3caa98e15d","c_fcb4ad331681ddd4",null,"rc_71108aef33d9eead",null,null,"fr",null,1,null,null,1,0]]"><div _ngcontent-ng-c3082907845="" class="formatted-code-block-internal-container ng-tns-c3082907845-171"><div _ngcontent-ng-c3082907845="" class="animated-opacity ng-tns-c3082907845-171"></div></div></div>cilium upgrade --set l2announcements.enabled=true \\  
\--set externalIPs.enabled=true \\  
\--set kubeProxyReplacement=true

 kubectl get pods -n kube-system | grep cili | grep -v opera | grep -v envoy | awk '{print $1}' | xargs kubectl delete po -n kube-system

#### Configuration du cluster

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)

#### Ajout des différents noeuds master au cluster

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)

#### Déployer Loghorn

CF : [https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha](https://docs.nehemiebarkia.fr/books/kubernetes/page/initialisation-de-mon-tout-premier-cluster-ha)

#### Ajout des lablels "workers" aux noeuds workers :

```bash
kubectl label node k8s-worker-1 node-role.kubernetes.io/worker="true"
kubectl label node k8s-worker-2 node-role.kubernetes.io/worker="true"
kubectl label node k8s-worker-3 node-role.kubernetes.io/worker="true"
```

#### Déployer une VIP pour les noeuds Workers

cat &lt;&lt;EOF | kubectl apply -f -  
apiVersion: cilium.io/v2alpha1  
kind: CiliumLoadBalancerIPPool  
metadata:  
 name: worker-vip-pool  
spec:  
 blocks:  
\- start: "192.168.1.2"  
 stop: "192.168.1.9"  
 serviceSelector:  
 matchLabels:  
 expose: "true"  
EOF

cat &lt;&lt;EOF | kubectl apply -f -  
apiVersion: cilium.io/v2alpha1  
kind: CiliumL2AnnouncementPolicy  
metadata:  
 name: worker-l2-policy  
 namespace: kube-system  
spec:  
 nodeSelector:  
 matchLabels:  
 node-role.kubernetes.io/worker: "true"  
 serviceSelector:  
 matchLabels:  
 expose: "true"  
 loadBalancerIPs: true  
 externalIPs: false  
 interfaces:  
\- ens18  
EOF

cat &lt;&lt;EOF | kubectl apply -f -  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
 name: hello-world  
 namespace: default  
spec:  
 replicas: 2  
 selector:  
 matchLabels:  
 app: hello-world  
 template:  
 metadata:  
 labels:  
 app: hello-world  
 spec:  
 containers:  
\- name: hello  
 image: hashicorp/http-echo:latest  
 args:  
\- "-text=Hello from Cilium VIP 👋"  
\- "-listen=:8080"  
 ports:  
\- containerPort: 8080  
\---  
apiVersion: v1  
kind: Service  
metadata:  
 name: hello-world  
 namespace: default  
 labels:  
 expose: "true"  
 annotations:  
 lbipam.cilium.io/ips: "192.168.1.2" # IP fixe dans le pool  
spec:  
 type: LoadBalancer  
 selector:  
 app: hello-world  
 ports:  
\- port: 80  
 targetPort: 8080  
EOF

[![image.png](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/scaled-1680-/8o5image.png)](https://docs.nehemiebarkia.fr/uploads/images/gallery/2026-04/8o5image.png)