ADR 019 â CNI : migration du VPC CNI vers Cilium (overlay, eBPF) (2026-06-18)
Statut
Accepté (2026-06-18) et validé live le 2026-06-18 sur un aws-start
from-scratch (tous les critÚres en fin d'ADR cochés). Rend obsolÚte la Prefix
Delegation (#79, ADR 012).
Le comment (pédagogique) est dans le guide Comprendre Cilium.
Contexte
Le cluster EKS utilise le VPC CNI (aws-node), CNI par défaut d'EKS. Chaque pod
reçoit une IP du VPC portĂ©e par une ENI du node, ce qui plafonne la densitĂ© de pods Ă
~17 sur un t3.medium. On a contourné ce plafond avec la Prefix Delegation (#79)
pour atteindre 110 pods, condition nécessaire à ArgoCD et à la stack d'observabilité.
Limites qu'on veut dépasser : densité dépendante des IP d'ENI (bricolage Prefix Delegation), NetworkPolicy L3/L4 seulement, routage des Services par kube-proxy (iptables), aucune observabilité réseau native, et un CNI spécifique à AWS alors qu'on vise la portabilité EKS / homelab / platform.
DĂ©cision 1 â Cilium en overlay VXLAN
On remplace le VPC CNI par Cilium en mode overlay (routingMode: tunnel,
encapsulation VXLAN). Les IP des pods proviennent d'un pool géré par Cilium
(ipam.mode: cluster-pool, clusterPoolIPv4PodCIDRList: ["10.42.0.0/16"]), hors du
VPC.
10.42.0.0/16est choisi distinct du VPC (10.0.0.0/16) pour éviter toute collision.- On se détache du plafond ENI : la densité ne dépend plus des IP du VPC. La Prefix Delegation (#79) devient inutile.
eni.enabled: false(on est en overlay, pas en mode ENI/IPAM AWS).- L'overlay est portable (mĂȘme datapath sur n'importe quel cluster).
Alternative écartée : Cilium en mode ENI (IP du VPC, comme le VPC CNI). Rejeté car il garderait la dépendance aux IP d'ENI et au cloud AWS, soit l'inverse du but recherché.
DĂ©cision 2 â Remplacement de kube-proxy par eBPF
kubeProxyReplacement: true : Cilium route les Services en eBPF, on supprime
kube-proxy.
- Plus d'iptables géantes pour les ClusterIP (meilleure montée en charge, perf).
- Conséquence opérationnelle : sans kube-proxy, l'agent Cilium ne peut plus joindre
l'API server via le ClusterIP
kubernetes. On lui donne l'adresse directe :k8sServiceHost= endpoint EKS (output Terraformcluster_endpoint),k8sServicePort: 443.
Alternative écartée : garder kube-proxy (Cilium pour le CNI seulement). Plus conservateur, mais on se prive de l'argument eBPF et d'une partie du gain de perf. On pourra y revenir en repli si un souci de routage Service apparaßt.
DĂ©cision 3 â Hubble + Hubble UI activĂ©s
hubble.enabled, hubble.relay.enabled, hubble.ui.enabled. Observabilité des flux
réseau (L3/L4/L7), service map, visualisation des décisions NetworkPolicy.
- ComplÚte la stack d'observabilité du Sprint 4 (Prometheus/Grafana/Loki).
- L'UI Hubble reste interne (
port-forward), jamais exposée publiquement (cohérent avec Prometheus, #81). - Tradeoff : RAM supplémentaire sur le mono-node
t3.mediumdéjà chargé. Requests basses, UI désactivable sous pression.
DĂ©cision 4 â Migration, pas from-scratch pur (gestion de l'ordre de boot)
Un managed node group EKS exige des nodes Ready dans sa fenĂȘtre de santĂ©. Or un node
n'est Ready qu'avec un CNI, et ArgoCD ne peut pas poser Cilium (il a lui-mĂȘme besoin
d'un CNI). On retient donc une migration plutĂŽt qu'un from-scratch sans aucun CNI.
Clé : distinguer le composant vpc-cni (DaemonSet aws-node, installé par défaut par
EKS) de l'addon managé aws_eks_addon.vpc_cni (la ressource Terraform qui l'adopte
et le configure).
| Décision | |
|---|---|
| Gestion managĂ©e de l'addon vpc-cni | RetirĂ©e (suppression de la ressource Terraform) â vpc-cni revient en self-managed |
| Composant vpc-cni au boot | Conservé : amÚne les nodes Ready, amorce coredns (~17 IP suffisent) |
| AprĂšs installation de Cilium | DaemonSet aws-node supprimĂ© (self-managed â aucun contrĂŽleur ne le recrĂ©e) |
SĂ©quence : (1) boot avec vpc-cni self-managed â nodes Ready ; (2) l'amorce Ansible
installe Cilium en premier ; (3) cutover : suppression d'aws-node + de kube-proxy,
redémarrage de coredns (reprend une IP overlay) ; (4) le reste de l'amorce (Envoy GW,
cert-manager, ESO, ExternalDNS, ArgoCD) tourne sur Cilium. Cilium est une brique de
socle posĂ©e par Ansible, pas par ArgoCD (mĂȘme motif que le reste de la plateforme).
Alternative écartée : garder l'addon managé. Rejeté car son contrÎleur recréerait
aws-node aprĂšs suppression â conflit avec Cilium.
PiÚges / Conséquences
- iptables rĂ©siduels de kube-proxy : aprĂšs suppression, purger les rĂšgles (sinon routage incohĂ©rent jusqu'au reboot du node). Ătape cĂąblĂ©e dans l'amorce.
maxPods: 110(launch template nodeadm) : conservé, désormais servi par l'overlay Cilium (et non plus par la Prefix Delegation). Le commentaire Terraform est mis à jour en conséquence.AmazonEKS_CNI_Policy(rÎle node) : conservée en l'état. Le vpc-cni self-managed s'en sert encore pendant la phase d'amorce. Nettoyage possible si on passe un jour à un Cilium présent dÚs le boot (pur from-scratch).- NetworkPolicy #55 : Cilium applique les NetworkPolicy Kubernetes standard, donc
allow-fastapireste valable sans modification. Ouvre la porte auxCiliumNetworkPolicy(L7), non utilisées pour l'instant. - Webhooks d'admission self-hosted (découvert en live, INC-058) : le control plane
EKS managé n'est pas un node Cilium, il ne route pas vers une IP de pod overlay
(
10.42.x). Tout webhook d'admission self-hosted enfailurePolicy: Faildevient injoignable (Address is not allowed) â l'amorce Ă©choue (cert-managerstartupapicheck, ClusterIssuer, ESO). Fix :webhook.hostNetwork: truesur cert-manager (securePort: 10260) et ESO (port: 10261) â le pod prend l'IP du node (VPC), routable. Cluster mono-node â deux ports distincts (les deux webhooks bindent le mĂȘme rĂ©seau de node), hors du 10250 du kubelet. Le webhook Envoy Gateway (failurePolicy: Ignore) n'est pas concernĂ© (no-op si injoignable). RĂšgle gĂ©nĂ©rale : sous overlay non-natif sur EKS managĂ©, tout composant que l'API server doit joindre en retour doit ĂȘtre enhostNetwork. - Cluster Ă©phĂ©mĂšre : la migration se rejoue Ă chaque
aws-start. L'amorce doit donc ĂȘtre dĂ©terministe et idempotente. Rollback =git revert+aws-start(retour au VPC CNI + Prefix Delegation), blast radius faible.
Validation
- Hors infra :
tfsec0 HIGH,terraform validate,helm template cilium(rendu des values),ansible-lint/syntax,mkdocs build. - Live, validé le 2026-06-18 (deux passages : cutover le matin, bootstrap complet le soir
aprĂšs les fixes INC-058/INC-059) :
- plus aucun
aws-node/kube-proxy, coredns en IP10.42.xâ kubeProxyReplacement: True, DNS interne OK â- NetworkPolicy
allow-fastapi: nĂ©gatif (egress port 80 âNetwork unreachable) + positif (/healthz/readyâ 200) â â Cilium enforce la NetworkPolicy K8s standard sans aws-node ni addon managĂ© - Hubble relay + UI Running â
https://api.devopsyouss.com/healthz/readyâ 200 â- ArgoCD 6/6 Applications
Synced/Healthy, stack observabilitĂ© (Prometheus/Grafana/Loki/ Alloy) debout, ESOSecretSyncedâ
- plus aucun
- Pré-requis découverts en live (sans rapport avec le datapath Cilium, voir
INC-058 + INC-059) :
les webhooks d'admission self-hosted (cert-manager, ESO) doivent ĂȘtre en
hostNetworksous overlay, et l'install ArgoCD ne doit pas utiliserhelm --wait.
Date : 2026-06-18 Sprint : 4 Issue : #80