ITSkillsCenter
Self-hosting

Déployer Cilium CNI avec eBPF sur Kubernetes pas-à-pas

12 دقائق للقراءة

Article principal · Ce tutoriel fait partie de la série Kubernetes domestique sur Proxmox VE. Tutoriel précédent : kubeadm vs k3s. Tutoriel suivant : Rook-Ceph storage.

Une fois Kubernetes bootstrappé, les nœuds restent en état NotReady tant qu un CNI n est pas installé. Le CNI (Container Network Interface) est la couche qui donne une adresse IP à chaque pod, route les paquets entre nœuds, applique les politiques réseau et alimente l observabilité du trafic. Cilium est aujourd hui le CNI le plus mature parmi ceux qui utilisent eBPF, une technologie du noyau Linux qui permet d exécuter des programmes safe directement dans le datapath kernel. La version stable 1.19.3 sortie au printemps 2026 ajoute le support des Cilium Network Policies multi-cluster et améliore les performances du Bandwidth Manager. Ce tutoriel installe Cilium 1.19, active Hubble pour l observabilité, et met en place les premières politiques réseau.

Étape 1 — Installer la CLI cilium et préparer le cluster

La CLI cilium est l outil officiel de gestion : elle installe le chart Helm, gère les composants Hubble, et fournit des commandes de diagnostic comme cilium connectivity test. On la télécharge depuis les releases GitHub officielles.

# Installer cilium-cli sur le poste de travail
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 xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz
cilium version --client

La sortie de cilium version --client doit afficher une version compatible avec Cilium 1.19. La CLI est ensuite indépendante du cluster ; elle s adapte au kubeconfig actif.

Étape 2 — Préparer Talos pour Cilium en mode kube-proxy replacement

Cilium peut remplacer kube-proxy entièrement, ce qui élimine iptables au profit d eBPF natif. C est le mode recommandé. Sur Talos, ce changement se déclare au niveau de la machineconfig, parce que Talos provisionne kube-proxy par défaut.

# Désactiver kube-proxy au niveau Talos
cat > patch-no-kube-proxy.yaml <<EOF
cluster:
  proxy:
    disabled: true
  network:
    cni:
      name: none
EOF

talosctl patch machineconfig -n 192.168.1.61,192.168.1.62,192.168.1.63 \
  --patch-file patch-no-kube-proxy.yaml

# Redémarrer les control plane pour appliquer
talosctl reboot -n 192.168.1.61
sleep 60
talosctl reboot -n 192.168.1.62
sleep 60
talosctl reboot -n 192.168.1.63

Le redémarrage séquentiel maintient le quorum etcd. À la fin, kubectl get pods -n kube-system ne doit plus lister de pod kube-proxy. Les nœuds restent NotReady jusqu à ce que Cilium prenne le relais.

Étape 3 — Installer Cilium 1.19 avec Helm

L installation passe par Helm pour avoir un contrôle fin sur les options. Le chart officiel est dans le dépôt cilium.

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

# Installer Cilium 1.19 avec eBPF kube-proxy replacement
helm install cilium cilium/cilium --version 1.19.3 \
  --namespace kube-system \
  --set kubeProxyReplacement=true \
  --set k8sServiceHost=192.168.1.60 \
  --set k8sServicePort=6443 \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set ipam.mode=kubernetes \
  --set bpf.masquerade=true

Helm déploie le DaemonSet cilium-agent sur chaque nœud, l opérateur cilium-operator, Hubble Relay et Hubble UI. Compter trois à cinq minutes avant que tous les pods passent en Running. L étape clé est l initialisation eBPF dans le kernel de chaque nœud, qu on peut surveiller avec kubectl logs -n kube-system -l k8s-app=cilium -f.

Étape 4 — Vérifier la connectivité du cluster

Cilium fournit une commande de test exhaustive qui déploie temporairement des pods et vérifie chaque chemin réseau : pod-to-pod intra-nœud, pod-to-pod inter-nœud, pod-to-service ClusterIP, pod-to-DNS, et plus.

cilium status --wait
# Doit afficher Cilium: OK, Operator: OK, Hubble Relay: OK, ClusterMesh: disabled

cilium connectivity test
# Lance environ 90 tests sur 3 à 5 minutes
# Résultat attendu : 90 tests passed

Si tous les tests passent, le réseau du cluster est sain. Les nœuds basculent en Ready, CoreDNS sort de Pending, et toute charge déployée à partir de maintenant aura sa connectivité réseau garantie. Si un test échoue, la sortie indique exactement quel chemin pose problème, ce qui oriente le diagnostic vers le firewall, la MTU ou la machineconfig Talos.

Étape 5 — Activer Hubble UI pour observer le trafic

Hubble est le composant d observabilité de Cilium. Il capture les flux L3/L4/L7 directement en eBPF (sans coût pour les pods) et les expose via une UI web et une CLI. Pour y accéder localement, on fait un port-forward.

cilium hubble port-forward &
# Hubble Relay devient accessible sur localhost:4245

cilium hubble ui --port-forward 12000
# Ouvre http://localhost:12000 dans le navigateur

L interface affiche un graphe vivant des communications entre pods et namespaces. Cliquer sur une flèche montre les flux récents avec verbose method, status code HTTP et latence. C est un outil que l on garde ouvert pendant le diagnostic d un problème de connectivité ou la conception d une politique réseau.

Étape 6 — Déployer une charge test et l observer

Pour vérifier que l ensemble fonctionne avec une vraie charge, on déploie une application web minimaliste et on génère du trafic.

kubectl create namespace demo
kubectl run web --image=nginx --port=80 --namespace demo
kubectl expose pod web --port=80 --namespace demo

kubectl run client --image=curlimages/curl --namespace demo \
  --rm -it --restart=Never -- \
  sh -c "for i in 1 2 3 4 5; do curl -s -o /dev/null -w '%{http_code}\n' http://web; done"

Les cinq codes 200 confirment que le pod client peut joindre le service web via le ClusterIP. Dans Hubble UI, ces requêtes apparaissent en temps réel sur le graphe du namespace demo, avec la méthode HTTP et le code de réponse. C est exactement ce que l on attend d un CNI moderne : connectivité fonctionnelle plus visibilité fine du trafic.

Étape 7 — Écrire la première Cilium Network Policy

Sans politique, tous les pods peuvent communiquer librement. Pour appliquer le principe du moindre privilège, on commence par un default-deny dans le namespace, puis on autorise explicitement le flux légitime.

# default-deny.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: default-deny
  namespace: demo
spec:
  endpointSelector: {}
  ingress:
  - {}
  egress:
  - {}
---
# allow-client-to-web.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-client-to-web
  namespace: demo
spec:
  endpointSelector:
    matchLabels:
      run: web
  ingress:
  - fromEndpoints:
    - matchLabels:
        run: client
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
kubectl apply -f default-deny.yaml
kubectl apply -f allow-client-to-web.yaml

# Tester : seul le client autorisé peut joindre web
kubectl run intruder --image=curlimages/curl --namespace demo \
  --rm -it --restart=Never -- \
  curl -s -o /dev/null -w '%{http_code}\n' --max-time 3 http://web
# Doit afficher 000 (timeout) car la politique bloque

kubectl run client --image=curlimages/curl --namespace demo \
  --rm -it --restart=Never -- \
  curl -s -o /dev/null -w '%{http_code}\n' http://web
# Doit afficher 200 car le client est autorisé

Le premier code 000 confirme que la politique bloque le trafic non autorisé ; le second code 200 confirme qu elle laisse passer le trafic légitime. Ce pattern — default-deny puis allowlist — est la base de la sécurité réseau dans Kubernetes et s applique exactement de la même manière en production.

Étape 8 — Activer le L7 visibility et les politiques HTTP

Cilium ne se limite pas au L4. Avec eBPF, il peut inspecter les en-têtes HTTP et appliquer des règles au niveau de la méthode et du chemin. C est utile pour exposer un service en lecture seule sans réécrire l application.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-readonly
  namespace: demo
spec:
  endpointSelector:
    matchLabels:
      run: web
  ingress:
  - fromEndpoints:
    - matchLabels:
        run: client
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/"

Avec cette politique, un POST ou un DELETE depuis le pod client recevront un 403 Forbidden généré par Cilium, sans même atteindre nginx. La trace correspondante apparaît dans Hubble avec le drop reason explicite. Cette capacité L7 distingue Cilium des CNI iptables-based comme Calico standard.

Étape 9 — Sauvegarder la configuration Cilium

Le chart Helm installé contient l ensemble des paramètres. Sauvegarder le fichier de valeurs est essentiel pour reproduire ou rétablir l installation.

helm get values cilium -n kube-system > cilium-values.yaml
git add cilium-values.yaml
# Versionner dans le dépôt Git utilisé par Argo CD (tutoriel suivant)

Voir le fichier cilium-values.yaml apparaître avec les options exactes utilisées permet à n importe quel autre opérateur de reconstruire un Cilium identique en une commande helm upgrade --install --values cilium-values.yaml.

Erreurs fréquentes et résolutions

Symptôme Cause Résolution
Tous les pods cilium-agent restent en CrashLoopBackOff kube-proxy non désactivé sur les nœuds Vérifier la machineconfig Talos puis redémarrer chaque nœud
cilium connectivity test échoue sur pod-to-pod inter-node MTU mal configurée (ex. tunnel VXLAN sur lien 1500) Ajouter --set tunnelProtocol=geneve --set MTU=1450 au helm install
Hubble UI affiche un graphe vide Hubble Relay n est pas joignable depuis le port-forward Vérifier kubectl logs -n kube-system -l k8s-app=hubble-relay
Les CiliumNetworkPolicy ne semblent pas appliquées Confusion entre NetworkPolicy (k8s standard) et CiliumNetworkPolicy Vérifier le apiVersion: cilium.io/v2 et la présence du CRD
Performance réseau dégradée après installation Bandwidth Manager non activé Activer --set bandwidthManager.enabled=true et redémarrer les agents

Pour la suite du parcours

Le réseau Kubernetes est opérationnel et observable. Les pods peuvent communiquer, les politiques peuvent être appliquées, le trafic est visible dans Hubble. La prochaine couche manquante est le stockage persistant : sans CSI, on ne peut faire tourner que des charges éphémères. Le tutoriel Stockage persistant avec Rook-Ceph sur Kubernetes détaille la mise en place de Ceph distribué sur les workers via l opérateur Rook. Pour la vue d ensemble, retourner au guide principal Kubernetes domestique sur Proxmox VE.

Ressources et documentation officielle

Étape 10 — Comprendre ce que eBPF change vraiment

L atout central de Cilium par rapport aux CNI iptables est la performance et l observabilité, et les deux découlent du même choix technique : exécuter le code de routage et de filtrage directement dans le noyau Linux via eBPF, sans traverser la stack iptables. Sur un cluster avec mille services et dix mille endpoints, iptables doit évaluer linéairement ses chaînes pour chaque paquet — la latence devient mesurable. Avec eBPF, Cilium compile une table de hachage qui résout chaque flux en O(1).

L impact pratique en homelab reste modeste sur des charges légères (un Raspberry Pi avec dix pods ne verra aucune différence). Mais sur un cluster avec Rook-Ceph qui pousse des dizaines de milliers de paquets par seconde entre OSD, la suppression de iptables apporte un gain net en latence et en CPU consommé par le datapath.

Une seconde conséquence est la programmabilité. Cilium peut charger des programmes eBPF utilisateurs (via Tetragon, son outil sœur) qui surveillent les appels système au niveau du noyau. C est ce qui permet à des outils comme Falco de détecter des comportements anormaux (un pod qui tente d ouvrir /etc/shadow, un binaire qui démarre depuis /tmp) sans patcher le kernel.

Étape 11 — Activer le BGP pour exposer des services

Cilium 1.19 inclut un opérateur BGP qui peut annoncer les LoadBalancer IPs vers le routeur du réseau local. C est une alternative à MetalLB pour les utilisateurs qui ont un routeur compatible BGP (OPNsense, MikroTik, OpenWrt avec FRR, pfSense avec FRR). Le résultat : les services type: LoadBalancer obtiennent une IP routable du réseau local, sans NAT, sans tunnel.

apiVersion: cilium.io/v2
kind: CiliumBGPClusterConfig
metadata:
  name: cilium-bgp
spec:
  nodeSelector:
    matchLabels:
      bgp: enabled
  bgpInstances:
  - name: instance-65000
    localASN: 65000
    peers:
    - name: home-router
      peerASN: 65001
      peerAddress: 192.168.1.1
      peerConfigRef:
        name: peer-config-default

Une fois l adjacence BGP établie (vérifiable avec cilium bgp peers), chaque service LoadBalancer crée une route /32 annoncée au routeur, qui la propage vers le LAN. Pour les utilisateurs sans routeur BGP, MetalLB reste l alternative la plus simple ; on l installe en quelques lignes de Helm et on attribue une plage IP libre du LAN.

Étape 12 — Surveiller la consommation des composants Cilium

Une fois l installation stabilisée, vérifier la consommation réelle des composants permet de détecter une anomalie tôt. Les valeurs typiques en homelab à six nœuds, charge légère, sont les suivantes : cilium-agent consomme 80 à 150 Mio de RSS par nœud, cilium-operator environ 60 Mio, hubble-relay environ 40 Mio, hubble-ui environ 30 Mio. Si l agent dépasse 500 Mio sur un nœud, il y a probablement une fuite ou une politique mal écrite qui explose la table d états.

kubectl top pods -n kube-system -l k8s-app=cilium
kubectl top pods -n kube-system -l k8s-app=hubble-relay
cilium status --verbose | grep -A 5 "Memory"
# Affiche la consommation eBPF maps par nœud

Voir les valeurs rester stables sur la journée confirme que rien ne fuit. Les tableaux de bord Prometheus livrés avec kube-prometheus-stack incluront ces métriques, ce qui automatisera la surveillance dans le tutoriel observabilité.

Étape 13 — Préparer la transition vers les politiques métier

Les politiques default-deny et l autorisation explicite démontrées plus haut sont les briques de base. En production homelab, la pratique courante consiste à appliquer un default-deny au niveau du namespace dès sa création, puis à versionner les politiques d autorisation à côté du manifest applicatif. Argo CD, déployé au tutoriel suivant, synchronisera l ensemble. La discipline qui paie consiste à écrire la politique en même temps que le déploiement, jamais après. C est plus rapide à coder, et les surprises de blocage en production sont éliminées dès la phase de développement.

Une bonne pratique complémentaire consiste à activer le mode audit avant le mode enforce sur les politiques sensibles. Cilium permet d annoter une politique avec policy.cilium.io/audit-mode: "true" (ou d activer le mode globalement avec --policy-audit-mode=true sur le daemon), ce qui logge les drops dans Hubble sans bloquer le trafic. On observe pendant 24 ou 48 heures, on ajuste, puis on passe en enforce. Ce pattern évite les indisponibilités de service consécutives à une mauvaise estimation des dépendances.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité