Introduction

Kubernetes s'est imposé comme le standard de l'orchestration de conteneurs, mais sa réputation de complexité n'est pas usurpée : entre la distribution à choisir, le CNI (réseau), le stockage et l'ingress, il est facile de se perdre. L'objectif de cet article est de fournir une procédure reproductible pour amener un cluster de zéro à un état « prêt à recevoir des applications ».

Nous avons retenu RKE2 (la distribution Kubernetes durcie de Rancher/SUSE) pour sa simplicité d'installation et sa conformité sécurité par défaut, et Cilium comme CNI pour ses performances (eBPF) et sa capacité à remplacer kube-proxy.

Le périmètre couvert ici correspond au socle de l'infrastructure :

  1. Préparation des machines (OS)
  2. Installation du master (control-plane RKE2)
  3. Jonction des workers
  4. Installation du réseau (Cilium) - l'étape qui rend le cluster réellement opérationnel

À la fin de ces quatre étapes, tous les nœuds passent en Ready et le cluster est capable d'ordonnancer des workloads. Nous indiquons ensuite les briques qui viennent naturellement compléter ce socle (stockage, certificats, GitOps…).

Architecture cible

L'infrastructure de référence repose sur trois machines minimum, avec des IPs statiques :

Rôle Nom IP
Master (control-plane + etcd) kube_master 192.0.2.10
Worker 1 kube_w1 192.0.2.11
Worker 2 kube_w2 192.0.2.12

Rôle Nom IP
Master (control-plane + etcd) kube_master 192.0.2.10
Worker 1 kube_w1 192.0.2.11
Worker 2 kube_w2 192.0.2.12

Le modèle est bien sûr extensible : il suffit d'ajouter des workers (worker-03, worker-04…) en répétant l'étape de jonction.

Point d'attention : Deux IPs libres dans le LAN sont réservées pour les services de type LoadBalancer annoncés par Cilium : 192.0.2.240/32 (pool interne) et 192.0.2.241/32 (pool WAN).

Les adresses IP, noms d'hôtes et domaines utilisés dans cet article sont des exemples (plage de documentation 192.0.2.0/24). Remplacez-les par les valeurs propres à votre environnement.

Pré-requis

Un accès SSH par clé vers chaque nœud

  • Un utilisateur avec droits sudo (ici k8sadmin)
  • Un accès Internet sortant depuis les machines (téléchargement des binaires et des charts Helm)
  • Helm v4 installé sur la machine opérateur (voir la documentation officielle)

Étape 1 - Préparation des machines

Avant toute installation, chaque nœud doit être préparé de façon identique : disque étendu, service iSCSI activé (prérequis pour un futur stockage type Longhorn) et accès SSH par clé configurée.

Étendre la partition principale

À la création des VM, l'espace disque disponible n'est pas toujours utilisé en totalité :

sudo apt install cloud-guest-utils -y # outils pour redimensionner la partition

sudo growpart /dev/sda 1 # /dev/sda = disque, 1 = n° de partition

sudo resize2fs /dev/sda1 # étend le système de fichiers à l'espace récupéré

Selon le type de stockage (LVM par exemple), la commande peut différer :

lvextend -l +100%FREE -r /dev/mapper/ubuntu--vg-ubuntu--lv

Activer iSCSI

Composant nécessaire au bon fonctionnement de solutions de stockage comme Longhorn :

sudo apt install open-iscsi

sudo systemctl enable iscsid

Propager la clé SSH sur les nœuds

Depuis la machine opérateur :

Syntaxe : ssh-copy-id <utilisateur>@<IP-du-noeud>

Remplacez les IP ci-dessous par celles de VOS machines.

ssh-copy-id Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. # master

ssh-copy-id Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. # worker 1

ssh-copy-id Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. # worker 2

Configurer un template SSH (optionnel)

On simplifie les connexions futures via `~/.ssh/config`. Notez l'hôte `kube_tunnel`, pratique pour exposer localement l'API server (port `6443`) :

"Host" = alias que VOUS choisissez ; "HostName" = l'IP réelle de la machine.

Host kube_master

HostName 192.0.2.10 # ← IP du master

User k8sadmin # ← utilisateur sudo présent sur la machine

Port 22

Host kube_tunnel # même machine que le master, mais dédié au tunnel API (port 6443)

HostName 192.0.2.10 # ← IP du master (identique à ci-dessus)

LocalForward 6443 localhost:6443

RequestTTY no

RemoteCommand sleep infinity

User k8sadmin

Port 22

Host kube_w1

HostName 192.0.2.11 # ← IP du worker 1

User k8sadmin

Port 22

Host kube_w2

HostName 192.0.2.12 # ← IP du worker 2

User k8sadmin

Port 22

Vérification

ssh kube_master whoami # → k8sadmin
ssh kube_master systemctl is-active iscsid # → active

Étape 2 - Installation du master (RKE2)

On installe le serveur RKE2 sur le premier nœud. Choix structurant : le master démarre avec `cni: none` et `disable-kube-proxy: true`, car Cilium (étape 4) assure lui-même le réseau et le remplacement de `kube-proxy`. 

Point d'attention : Tant que Cilium n'est pas installé, le master reste NotReady. C'est normal et attendu. Le couple cni: none + disable-kube-proxy: true n'est viable que parce que Cilium (kubeProxyReplacement: true) prendra le relais.

Installation du binaire

ssh kube_master

curl -sfL https://get.rke2.io --output install.sh

sudo chmod +x install.sh

sudo ./install.sh

Configuration initiale

sudo mkdir -p /etc/rancher/rke2/

sudo tee /etc/rancher/rke2/config.yaml <<EOF

cni: "none"

disable:

rke2-ingress-nginx

disable-kube-proxy: true

write-kubeconfig-mode: "0644"

tls-san: # liste des adresses/noms par lesquels l'API du cluster sera jointe

"192.0.2.10" # ← IP du master (à remplacer par la vôtre)

"127.0.0.1"

"localhost"

etcd-snapshot-schedule-cron: "0 */12 * * *"

etcd-snapshot-retention: 5

EOF

On désactive volontairement l'ingress NGINX embarqué : l'ingress sera géré plus tard via Envoy Gateway (Gateway API). Les snapshots etcd sont planifiés toutes les 12 h avec 5 générations conservées.

Activation et démarrage

sudo systemctl enable rke2-server.service

sudo systemctl start rke2-server.service

Deux arborescences sont créées :

  •  `/var/lib/rancher` : binaires et état du cluster (etcd inclus)
  •  `/etc/rancher` : configuration effective du serveur

Accès à kubectl

# Persistance du PATH

echo 'export PATH=$PATH:/var/lib/rancher/rke2/bin' >> ~/.bashrc

export PATH=$PATH:/var/lib/rancher/rke2/bin

Configuration de kubectl

mkdir -p ~/.kube

sudo cp /etc/rancher/rke2/rke2.yaml ~/.kube/config

Vérification

kubectl get nodes

Résultat :

NAME STATUS ROLES AGE VERSION

k8smaster NotReady control-plane,etcd 5m v1.35.4+rke2r1

Étape 3 - Jonction des workers

Chaque worker installe RKE2 en mode agent, se connecte au master via son URL et un token de jonction, puis démarre son service.

Récupérer le token (sur le master)

sudo cat /var/lib/rancher/rke2/server/node-token

Point d'attention : Ce token est sensible : quiconque le possède peut rejoindre le cluster. Ne pas le committer, ne pas le rejouer après rotation sans précaution.

Installer l'agent (sur le worker 1)

ssh kube_w1

sudo curl -sfL https://get.rke2.io | sudo INSTALL_RKE2_TYPE="agent" sh -

sudo systemctl enable rke2-agent.service

sudo mkdir -p /etc/rancher/rke2/

sudo nano /etc/rancher/rke2/config.yaml

Contenu du fichier de configuration :

server: https://192.0.2.10:9345 # ← IP du MASTER (port 9345 = port de jonction RKE2)

token: <token> # ← coller ici le token récupéré à l'étape a.

node-name: "worker-01" # ← nom unique de CE worker (worker-02, worker-03…)

node-label:

"role=worker"

node-ip: "192.0.2.11" # ← IP de CE worker (celle de la machine courante)

cni: none

Deux IP différentes coexistent dans ce fichier : server pointe vers le master, tandis que node-ip est l'IP de la machine worker sur laquelle vous êtes en train de travailler. Ne les confondez pas.

Puis on démarre :

sudo systemctl start rke2-agent.service

Répéter pour les autres workers

La procédure est identique sur chaque worker. Seuls node-name et node-ip changent (worker-02 / 192.0.2.12, etc.).

Vérification - depuis le master :

kubectl get nodes

Tous les nœuds apparaissent, mais restent NotReady : le réseau n'existe toujours pas. C'est l'objet de l'étape suivante.

Étape 4 - Le réseau avec Cilium (CNI)

C'est l'étape charnière. Cilium joue ici un double rôle : il fournit le CNI et remplace kube-proxy (mode eBPF). Une fois installé, tous les nœuds passent Ready.

L'installation combine : le chart Helm cilium/cilium, un pool d'IPs L2 pour les services LoadBalancer, et une policy d'annonce L2 (sans BGP).

Tant que Cilium n'est pas déployé, rien ne fonctionne dans le cluster : ni DNS, ni services, ni ingress. C'est une étape bloquante pour toutes les suivantes.

Ajouter le dépôt Helm

helm repo add cilium https://helm.cilium.io/

helm repo update

Fichier de valeurs

Créer ciliumValues.yaml. Points clés : kubeProxyReplacement: true, chiffrement WireGuard du trafic inter-nœuds, et annonces L2 activées.

kubeProxyReplacement: true

k8sServiceHost: "192.0.2.10" # ← IP du master (API server)

k8sServicePort: "6443" # port standard de l'API Kubernetes

bpf:

masquerade: true

encryption:

enabled: true

type: wireguard

hubble:

enabled: true

relay:

enabled: true

ui:

enabled: true

ingress:

enabled: false

ingressController:

enabled: false

gatewayAPI:

enabled: false

ipam:

mode: kubernetes

bandwidthManager:

enabled: true

bbr: true

l2announcements:

enabled: true

authentication:

enabled: true

mutual:

spire:

enabled: true

Installer Cilium

helm install cilium cilium/cilium -n kube-system -f ciliumValues.yaml

Pool d'IPs pour les LoadBalancer

Créer CiliumLB.yaml - un pool interne, un pool WAN, et la policy d'annonce L2 :

#Pool interne : IP(s) distribuée(s) aux services LoadBalancer accessibles depuis le LAN

apiVersion: "cilium.io/v2"

kind: CiliumLoadBalancerIPPool

metadata:

name: ip-pool

namespace: kube-system

spec:

blocks:

cidr: "192.0.2.240/32" # ← IP libre de VOTRE réseau (ici une seule adresse, /32)

---

#Pool WAN : IP(s) réservée(s) aux services exposés vers l'extérieur

apiVersion: cilium.io/v2

kind: CiliumLoadBalancerIPPool

metadata:

name: ip-pool-wan

spec:

blocks:

cidr: 192.0.2.241/32 # ← autre IP libre de VOTRE réseau

disabled: false

---

apiVersion: "cilium.io/v2alpha1"

kind: CiliumL2AnnouncementPolicy

metadata:

name: l2-policy

namespace: kube-system

spec:

loadBalancerIPs: true

nodeSelector:

matchExpressions:

key: "kubernetes.io/hostname"

operator: Exists

kubectl apply -f CiliumLB.yaml

L'IP 192.0.2.240/32 est alors annoncée sur tous les nœuds via L2 (ARP/NDP), rendant les services LoadBalancer joignables depuis le LAN — le tout sans BGP.

Vérification

Tous les nœuds → Ready

kubectl get nodes

DaemonSets Cilium (un pod par nœud)

kubectl -n kube-system get ds -l k8s-app=cilium

Pools d'IPs

kubectl -n kube-system get ciliumloadbalancerippools

Annonces L2

kubectl -n kube-system get ciliuml2announcementpolicies

À ce stade, le cluster est fonctionnel : tous les nœuds sont Ready et peuvent ordonnancer des pods.

Pour aller plus loin : d'un cluster "Ready" à un cluster "operator-ready"

Un cluster Ready sait faire tourner des pods, mais une infrastructure de production a besoin de quelques briques complémentaires. Une fois le socle en place, l'ordre recommandé est le suivant :

# Brique Rôle
05 local-path (StorageClass) Provisioner de stockage de démarrage, avant Longhorn
6 metrics-server kubectl top et autoscaling (HPA)
7 cert-manager Émission automatique des certificats TLS
8 Reflector Réplication de Secret/ConfigMap entre namespaces
9 Sealed Secrets Chiffrement des secrets versionnés dans Git
10 ArgoCD Bascule en GitOps (App-of-Apps)
11 Envoy Gateway Ingress moderne via Gateway API

L'objectif final est une infrastructure pilotée en GitOps : une fois ArgoCD installé et la bascule « App-of-Apps » effectuée, l'état du cluster est décrit dans un dépôt Git et réconcilié automatiquement.

Conclusion

En quatre étapes - préparation, master, workers, réseau - on obtient un cluster Kubernetes fonctionnel, sécurisé par défaut (RKE2) et doté d'un réseau performant (Cilium/eBPF).

La clé du succès tient en une phrase : respecter l'ordre des étapes.

Le passage des nœuds en NotReady puis Ready au fil de l'installation n'est pas un bug, c'est le signal que le pipeline se déroule comme prévu.

À partir de ce socle, l'ajout des briques de stockage, de certificats et de GitOps transforme progressivement le cluster en une plateforme d'exploitation complète.

Un projet Business Apps ? Nos développeurs Business Apps sont à votre écoute ! Contactez-nous !