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 : 

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

Supprimer les namespaces entiers : 

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

Supprimer un pod qui est en terminated :

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

Instructions

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

Architecture Type

Architecture Type

Architecture Utilisée

Architecture

Hostname
RAM
CPU
DISQUE
IP
FONCTION
k8s-master-1
4 go 2 60 SSD 192.168.1.101 etcd + control-plane
k8s-master-2 4 go 2 60 SSD 192.168.1.102 etcd + control-plane
k8s-master-3 4 go 2 60 SSD 192.168.1.103 etcd + control-plane
k8s-worker-1 16 go 4 60 SSD + 100 Go HDD (/opt) 192.168.1.104
k8s-worker-2 16 go 4 60 SSD + 100 Go HDD (/opt) 192.168.1.105
k8s-worker-3 16 go 4 60 SSD + 100 Go HDD (/opt) 192.168.1.106


 

VIP CLUSTER 192.168.1.100



VIP WORKERS 192.168.1.2 à 192.168.1.8 



Tous les noeuds sont sur debian 13.

Prérequis

Prérequis

Préparation du Système

Préparation du système

Commandes à réaliser sur tous les noeuds

1) Désactivation de la swap
swapoff -a

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

sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
2) Configuration du kernel

Chargement au démarage des modules pour k8s : 

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

Chargement immédiat des modules pour k8s : 

modprobe overlay
modprobe br_netfilter

Le module overlay permet le fonctionnement du système de fichier OverlayFS.
Le module br_netfiltrer permet d'appliquer les iptables à un bridge.

Configuration des paramètres réseaux :

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

Permet aux bridges de faire appel au FW iptables
Permet d'active le routage

Application des paramètres : 

sysctl --system

Prérequis

Installation des Dépendances

installation des Dépendances

Commandes à réaliser sur tous les noeuds

Installation des packets courrants :
apt-get update 
apt-get install -y ca-certificates curl gnupg lsb-release htop jq tcpdump ethtool
Installation de containerd.io
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 : 

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

Activation de containerd : 

systemctl enable containerd

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

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

Redémarage de Containerd :

systemctl restart containerd
Installation de kubernet

Installation de kubelet kubeadm et kubectl :

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

Création du cluster K8S

Préparation du cluster HA (KubeVip)

Préparation du cluster HA (KubeVip)

Sur tous les noeuds master UNIQUEMENT

export VIP="192.168.1.100"
export INTERFACE="ens18"

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é -> elle n'est pas fixée à un seul endroit.

KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases/latest | jq -r ".name")
echo "Version kube-vip : $KVVERSION"
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

Il faut copier coller le fichier manifeste au même endroit sur master 2 et 3.

Création du cluster K8S

Initialisation du cluster

Initialisation du cluster

Sur le noeuds k8s-master-1 UNIQUEMENT

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

sudo ip addr add 192.168.1.100/32 dev ens18

Initialisation du cluster :

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

Configurer kubectl pour l'utilisateur courant :

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" : 

kubectl get pods -n kube-system
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 ⚠️⚠️⚠️⚠️

Déploiement du Réseau K8S

Calico

Déploiement du réseau Calico 

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

Attendre que l'opérateur ait fini :

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

Déployer les ressources Calico :

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

Définir le sous réseau de K8S : 

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

Déploiement du Réseau K8S

Cilium

Installation du réseau Cilium 

Installation de cilium-cli : 

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"

Attendre que le statut soit opérationnel :

cilium status --wait

Vérification de la conectivité : 

cilium connectivity check

Suivi des pods :

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

MAJ  :

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

Appliquer les changements : 

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

Finalisation de l'installation du cluster

Finalisation de l'installation du cluster

Configuration du cluster

Configuration du cluster

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

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
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.

kubeadm init phase upload-certs --upload-certs

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

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

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

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


Finalisation de l'installation du cluster

Ajout des différents noeuds au cluster

Ajout des différents noeuds master au cluster

Commandes à exécuter sur les noeuds k8s-master-2 et k8s-master-3

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

Commandes à exécuter sur les noeuds k8s-worker-1, k8s-worker-2 et k8s-worker-3

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

Résultat : 

kubectl get nodes
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

Félicitation ! Vous venez de déployer votre tout premier cluster Kubernettes !

Ajout des lablels "workers" aux noeuds workers :

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"

Sera utilise au moment des deployments

Déploiement d'une solution de stockage

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

Déploiement d'une solution de stockage

LongHorn

Déployer une solution de stockage

Installation des prérequits sur TOUS LES NOEUDS : 

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 :

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 :

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

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

defaultSettings:
  defaultDataPath: "/opt/longhorn"

Déploiement de longhorn : 

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

Résultat : 

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 : 

kubectl get pods -n longhorn-system
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

Accéder à l'interface graphique :

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

Afficher le port :

kubectl get svc longhorn-frontend -n longhorn-system

On va utiliser le port :

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

On peut utiliser n'importe quelle IP du cluster.

image.png


Tester le stockage (pour aller plus loin) : 

Déclaration du PVC :

hello-pvc.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

Création d'un conteneur utilisant le PVC :

hello-app.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

Application des changements :

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

Côté interface graphique :

image.png

Suppression du pod : 

kubectl delete pod hello-longhorn

Suppression du pvc : 

kubectl delete pvc longhorn-hello-pvc

Déployer un Load balancer avec une VIP

Déployer un Load balancer avec une VIP

Avec Cilium

Cette documentation ne peut être exécutée uniquement sur un cluster ayant pour réseau Cilium.

 

Déclaration de la pool possible d'IP VIP :

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

Déclaration de la mise en réseau : 

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

Exemple de déploiement et de service permetant d'exposer un pod web via une VIP : 

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

Résultat :

image.png

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

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

Déployer metrics-server

Installation :

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

Application du no verify TLS : 

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 :

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

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

kubectl top nodes
kubectl top pods -A

Déployer des applications dans K8S !

Déployer des applications dans K8S !

Minecraft

Quelle joie pour moi de déployer un serveur minecraft dans K8S !

En prérequits à ce tuto :

Création du namespace Minecraft :

kubectl create namespace minecraft

Déclaration du PVC :

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

Déploiement & service minecraft :

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

Déployer des applications dans K8S !

Factorio

Création du Namespace et du label : 

kubectl create namespace factorio

Création du PVC : 

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 :

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"

AUTRE_Installation complètes

Initialisation de mon tout premier cluster HA

Architecture

Hostname
RAM
CPU
DISQUE
IP
FONCTION
k8s-master-1
4 go 2 60 SSD + 100 HDD (/opt) 192.168.1.101 etcd + control-plane
k8s-master-2 4 go 2 60 SSD + 100 HDD (/opt) 192.168.1.102 etcd + control-plane
k8s-master-3 4 go 2 60 SSD + 100 HDD (/opt)  192.168.1.103 etcd + control-plane
k8s-worker-1 16 go 4 60 SSD + 100 HDD (/opt) 192.168.1.104
k8s-worker-2 16 go 4 60 SSD + 100 HDD (/opt) 192.168.1.105
k8s-worker-3 16 go 4 60 SSD + 100 HDD (/opt) 192.168.1.106

Tous les noeuds sont sur debian 13.

Plan de déploiement du cluster :


Préparation du système

Commandes à réaliser sur tous les noeuds

1) Désactivation de la swap
swapoff -a

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

sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
2) Configuration du kernel

Chargement au démarage des modules pour k8s : 

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

Chargement immédiat des modules pour k8s : 

modprobe overlay
modprobe br_netfilter

Le module overlay permet le fonctionnement du système de fichier OverlayFS.
Le module br_netfiltrer permet d'appliquer les iptables à un bridge.

Configuration des paramètres réseaux :

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

Permet aux bridges de faire appel au FW iptables
Permet d'active le routage

Application des paramètres : 

sysctl --system

installation des prérequits

Commandes à réaliser sur tous les noeuds

Installation des packets courrants :
apt-get update 
apt-get install -y ca-certificates curl gnupg lsb-release htop jq tcpdump ethtool
Installation de containerd.io
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 : 

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

Activation de containerd : 

systemctl enable containerd

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

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

Redémarage de Containerd :

systemctl restart containerd
Installation de kubernet

Installation de kubelet kubeadm et kubectl :

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)

Sur tous les noeuds master UNIQUEMENT

export VIP="192.168.1.100"
export INTERFACE="ens18"

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é -> elle n'est pas fixée à un seul endroit.

KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases/latest | jq -r ".name")
echo "Version kube-vip : $KVVERSION"
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

Sur le noeuds k8s-master-1 UNIQUEMENT

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

sudo ip addr add 192.168.1.100/32 dev ens18

Initialisation du cluster :

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

Configurer kubectl pour l'utilisateur courant :

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" : 

kubectl get pods -n kube-system
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 

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

Attendre que l'opérateur ait fini :

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

Déployer les ressources Calico :

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

Définir le sous réseau de K8S : 

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" :

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
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.

kubeadm init phase upload-certs --upload-certs

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

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

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

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

Commandes à exécuter sur les noeuds k8s-master-2 et k8s-master-3

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

Commandes à exécuter sur les noeuds k8s-worker-1, k8s-worker-2 et k8s-worker-3

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

Résultat : 

kubectl get nodes
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

Félicitation ! Vous venez de déployer votre tout premier cluster Kubernettes !

Déployer une solution de stockage

Installation des prérequits sur TOUS LES NOEUDS : 

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 :

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 :

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

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

defaultSettings:
  defaultDataPath: "/opt/longhorn"

Déploiement de longhorn : 

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

Résultat : 

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 : 

kubectl get pods -n longhorn-system
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

Accéder à l'interface graphique :

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

Afficher le port :

kubectl get svc longhorn-frontend -n longhorn-system

On va utiliser le port :

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

On peut utiliser n'importe quelle IP du cluster.

image.png

Tester le stockage : 

Déclaration du PVC :

hello-pvc.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

Création d'un conteneur utilisant le PVC :

hello-app.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

Application des changements :

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

Côté interface graphique :

image.png

Suppression du pod : 

kubectl delete pod hello-longhorn

Suppression du pvc : 

kubectl delete pvc longhorn-hello-pvc


AUTRE_Installation complètes

Cluster HA - Loghorn - Cilium - KubeVip

Architecture

Hostname
RAM
CPU
DISQUE
IP
FONCTION
k8s-master-1
4 go 2 60 SSD 192.168.1.101 etcd + control-plane
k8s-master-2 4 go 2 60 SSD 192.168.1.102 etcd + control-plane
k8s-master-3 4 go 2 60 SSD 192.168.1.103 etcd + control-plane
k8s-worker-1 16 go 4 60 SSD + 100 Go HDD (/opt) 192.168.1.104
k8s-worker-2 16 go 4 60 SSD + 100 Go HDD (/opt) 192.168.1.105
k8s-worker-3 16 go 4 60 SSD + 100 Go HDD (/opt) 192.168.1.106


 

VIP CLUSTER 192.168.1.100



VIP WORKERS 192.168.1.99



Tous les noeuds sont sur debian 13.

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

Installation des prérequits

CF : 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

Initialisation du cluster

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

Installation du réseau Cilium 

Installation de cilium-cli : 

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"

Attendre que le statut soit opérationnel :

cilium status --wait

Vérification de la conectivité : 

cilium connectivity check

Suivi des pods :

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

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

Ajout des différents noeuds master au cluster

CF : 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

Ajout des lablels "workers" aux noeuds workers :

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 <<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 <<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 <<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