<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>EBPF on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/ebpf/</link><description>Recent content in EBPF on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Sun, 15 Mar 2026 18:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/ebpf/index.xml" rel="self" type="application/rss+xml"/><item><title>Flannel et NetworkPolicies : comment ajouter le support avec Cilium en CNI chaining</title><link>https://blog.zwindler.fr/2026/03/15/flannel-networkpolicies-cilium-cni-chaining/</link><pubDate>Sun, 15 Mar 2026 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/03/15/flannel-networkpolicies-cilium-cni-chaining/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/03/flannel-cilium-chaining.webp" alt="Featured image of post Flannel et NetworkPolicies : comment ajouter le support avec Cilium en CNI chaining" /&gt;&lt;h2 id="flannel-flannel-flannel"&gt;Flannel, flannel, flannel&amp;hellip;
&lt;/h2&gt;&lt;p&gt;Flannel est un CNI simple et populaire 😢.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est le CNI par défaut de k3s, celui que la moitié des tutos kubeadm utilisent, et on le retrouve aussi dans pas mal d&amp;rsquo;offres managées.&lt;/p&gt;
&lt;p&gt;OK, il est simple, il route les paquets entre les pods, il supporte VXLAN et WireGuard, il se configure en 2 minutes. Que demander de plus ?&lt;/p&gt;
&lt;p&gt;Ben justement. Il y a un truc que flannel ne fait &lt;strong&gt;pas&lt;/strong&gt; : les NetworkPolicies. (Et c&amp;rsquo;est très grave).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Flannel is focused on networking. For network policy, other projects such as Calico can be used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Edit]&lt;/strong&gt; Contrairement à ce que j&amp;rsquo;écris ici, flannel supporte en fait les NetworkPolicies depuis au moins 2 ans, via l&amp;rsquo;implémentation de référence &lt;a class="link" href="https://github.com/kubernetes-sigs/kube-network-policies" target="_blank" rel="noopener"
&gt;kube-network-policies&lt;/a&gt; du projet Kubernetes. L&amp;rsquo;option n&amp;rsquo;est pas mise en avant dans le README et ce n&amp;rsquo;est probablement pas plus recommandé en production, mais elle existe. Voir la &lt;a class="link" href="https://github.com/flannel-io/flannel/blob/master/Documentation/netpol.md" target="_blank" rel="noopener"
&gt;documentation officielle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Et le piège, c&amp;rsquo;est que si vous n&amp;rsquo;avez pas lu cette petite ligne dans le &lt;strong&gt;README.md&lt;/strong&gt;, rien ne vous le dit explicitement.&lt;/p&gt;
&lt;p&gt;Vous pouvez parfaitement créer des objets &lt;code&gt;NetworkPolicy&lt;/code&gt; dans votre cluster, &lt;code&gt;kubectl apply&lt;/code&gt; ne bronchera pas, &lt;code&gt;kubectl get netpol&lt;/code&gt; vous les listera gentiment. Sauf que&amp;hellip; elles ne sont pas enforced. Le trafic passe quand même. Votre deny-all ne deny rien du tout.&lt;/p&gt;
&lt;h2 id="on-vérifie-pour-être-bien-sûr"&gt;On vérifie pour être bien sûr
&lt;/h2&gt;&lt;p&gt;Avant de résoudre quoi que ce soit, vérifions que le problème existe. En partant du prérequis qu&amp;rsquo;on a un cluster Kubernetes qui a flannel comme CNI et que tout est fonctionnel, on va déployer deux pods dans deux namespaces différents : un client (curl) et un serveur (nginx).&lt;/p&gt;
&lt;p&gt;On vérifie que le client peut joindre le serveur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -n netpol-test-a client -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -s --max-time &lt;span class="m"&gt;5&lt;/span&gt; http://server.netpol-test-b.svc.cluster.local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On obtient la page d&amp;rsquo;accueil nginx. Jusque-là, tout est normal. Maintenant, on applique une NetworkPolicy &lt;em&gt;deny-all&lt;/em&gt; sur le namespace du serveur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 01-deny-all-ingress.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;NetworkPolicy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;deny-all-ingress&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;netpol-test-b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;podSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;policyTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;Ingress&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f 01-deny-all-ingress.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et on re-teste :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -n netpol-test-a client -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -s --max-time &lt;span class="m"&gt;5&lt;/span&gt; http://server.netpol-test-b.svc.cluster.local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Résultat : la page nginx s&amp;rsquo;affiche toujours.&lt;/strong&gt; La NetworkPolicy est bien créée (&lt;code&gt;kubectl get netpol -n netpol-test-b&lt;/code&gt; la montre), mais elle n&amp;rsquo;est pas enforced. Le trafic passe comme si de rien n&amp;rsquo;était.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est le comportement attendu avec flannel (par défaut). Flannel ne fait que du routage L3 (overlay VXLAN ou WireGuard). Il n&amp;rsquo;implémente pas de contrôleur NetworkPolicy. Les objets existent dans etcd, mais personne ne les traduit en règles de filtrage.&lt;/p&gt;
&lt;p&gt;On nettoie la policy avant de passer à la suite :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl delete -f 01-deny-all-ingress.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="les-alternatives-pour-ajouter-le-support"&gt;Les alternatives pour ajouter le support
&lt;/h2&gt;&lt;p&gt;Pendant longtemps j&amp;rsquo;ai pensé que c&amp;rsquo;était une fatalité. Je pense toujours que n&amp;rsquo;est pas un bon choix pour n&amp;rsquo;importe quelle production.&lt;/p&gt;
&lt;p&gt;MAIS récemment, j&amp;rsquo;ai découvert qu&amp;rsquo;il était possible de chaîner les CNI au sein d&amp;rsquo;un même cluster, et ainsi d&amp;rsquo;avoir un CNI qui gère la majorité des tâches (ici Flannel) et un autre qui se charge d&amp;rsquo;autres tâches, comme par exemple enforcer des Netpols.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est d&amp;rsquo;ailleurs le principe de Canal, que je connaissais de nom mais que je n&amp;rsquo;avais jamais exploré. En fait, c&amp;rsquo;est ni plus ni moins qu&amp;rsquo;un manifeste qui déploie Flannel comme CNI principal avec Calico pour l&amp;rsquo;enforcing des NetOK fine, it&amp;rsquo;s truepols !&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Canal was the name of Tigera and CoreOS’s project to integrate Calico and flannel.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note : &lt;a class="link" href="https://github.com/projectcalico/canal?tab=readme-ov-file" target="_blank" rel="noopener"
&gt;le projet GitHub a été archivé en octobre 2025&lt;/a&gt; mais en théorie ça devrait encore fonctionner, si on trouve la doc correcte (pas trouvé, les liens sont KO, mais j&amp;rsquo;ai pas vraiment cherché non plus).&lt;/p&gt;
&lt;p&gt;Vous avez donc compris le principe, on va ajouter un composant qui va &lt;strong&gt;watch&lt;/strong&gt; les objets NetworkPolicy et les traduire en règles de filtrage effectives (iptables, eBPF, nftables&amp;hellip;), &lt;strong&gt;sans toucher au flannel existant&lt;/strong&gt;. C&amp;rsquo;est ce qu&amp;rsquo;on appelle le &amp;ldquo;CNI chaining&amp;rdquo; ou le mode &amp;ldquo;policy-only&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Il existe plusieurs solutions :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Calico (Canal)&lt;/strong&gt;, Historiquement, la combinaison flannel + Calico s&amp;rsquo;appelle &amp;ldquo;Canal&amp;rdquo;, dont je viens de parler. &lt;strong&gt;Mais&lt;/strong&gt; le manifeste Canal officiel embarque son propre flannel dans le même DaemonSet que calico-node. Si votre flannel est déjà installé et géré (par vous, par un opérateur, par un provider&amp;hellip;), vous ne voulez probablement pas le remplacer. Et l&amp;rsquo;opérateur Tigera (la méthode Helm &amp;ldquo;officielle&amp;rdquo;) ne supporte pas non plus le déploiement en mode policy-only sur un flannel existant. Bref, c&amp;rsquo;est faisable mais ça nécessite un peu d&amp;rsquo;effort. Flemme.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;kube-router&lt;/strong&gt;, kube-router peut fonctionner en mode firewall-only (&lt;code&gt;--run-firewall=true&lt;/code&gt;) et n&amp;rsquo;a besoin que d&amp;rsquo;iptables/ipset. C&amp;rsquo;est d&amp;rsquo;ailleurs ce que k3s utilise par défaut pour les NetworkPolicies. C&amp;rsquo;est la solution la plus légère (a priori ~50 Mo de RAM par node). Vérifiez que votre kernel dispose du module &lt;code&gt;ip_set&lt;/code&gt;, sinon ça ne fonctionnera pas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cilium en mode CNI chaining&lt;/strong&gt;, C&amp;rsquo;est la solution que j&amp;rsquo;ai retenue et qu&amp;rsquo;on va détailler. Cilium s&amp;rsquo;attache aux interfaces veth créées par flannel et ajoute ses programmes eBPF pour le policy enforcement. Pas de dépendance à iptables ou ipset, et en bonus on récupère Hubble pour l&amp;rsquo;observabilité réseau.&lt;/p&gt;
&lt;h2 id="installer-cilium-en-mode-cni-chaining"&gt;Installer Cilium en mode CNI chaining
&lt;/h2&gt;&lt;h3 id="prérequis"&gt;Prérequis
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Un cluster Kubernetes fonctionnel avec flannel&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm&lt;/code&gt; v3+&lt;/li&gt;
&lt;li&gt;Un kernel &amp;gt;= 4.19 (idéalement &amp;gt;= 5.10 pour toutes les features eBPF)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="récupérer-la-configuration-cni-de-flannel"&gt;Récupérer la configuration CNI de flannel
&lt;/h3&gt;&lt;p&gt;Cilium en mode chaining doit connaître la configuration CNI existante. On va la récupérer depuis un node :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl debug node/&lt;span class="k"&gt;$(&lt;/span&gt;kubectl get nodes -o &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{.items[0].metadata.name}&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -it --image&lt;span class="o"&gt;=&lt;/span&gt;busybox -- cat /host/etc/cni/net.d/10-flannel.conflist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sur mon cluster, ça donne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cbr0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;cniVersion&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0.3.1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;plugins&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;flannel&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;delegate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hairpinMode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;isDefaultGateway&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;portmap&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;capabilities&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;portMappings&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Notez le champ &lt;code&gt;name&lt;/code&gt;&lt;/strong&gt; (ici &lt;code&gt;cbr0&lt;/code&gt;). On en aura besoin.&lt;/p&gt;
&lt;h3 id="créer-le-configmap-de-chaining"&gt;Créer le ConfigMap de chaining
&lt;/h3&gt;&lt;p&gt;On va créer un ConfigMap qui reprend la config flannel et y ajoute le plugin &lt;code&gt;cilium-cni&lt;/code&gt; en chaining :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ConfigMap&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cni-configuration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kube-system&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cni-config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|-&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;name&amp;#34;: &amp;#34;cbr0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;cniVersion&amp;#34;: &amp;#34;0.3.1&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;plugins&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;type&amp;#34;: &amp;#34;flannel&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;delegate&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;hairpinMode&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;isDefaultGateway&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;type&amp;#34;: &amp;#34;portmap&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;capabilities&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;portMappings&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;type&amp;#34;: &amp;#34;cilium-cni&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;chaining-mode&amp;#34;: &amp;#34;generic-veth&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt; : le champ &lt;code&gt;name&lt;/code&gt; doit correspondre à celui de votre &lt;em&gt;conflist&lt;/em&gt; flannel. Si le vôtre s&amp;rsquo;appelle &lt;code&gt;cni0&lt;/code&gt; ou autre chose, adaptez.&lt;/p&gt;
&lt;p&gt;Avant d&amp;rsquo;appliquer, vérifiez aussi que votre CNI utilise bien des interfaces &lt;strong&gt;veth&lt;/strong&gt; (c&amp;rsquo;est le cas par défaut avec flannel, mais mieux vaut s&amp;rsquo;en assurer). Depuis un node :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip -d link &lt;span class="p"&gt;|&lt;/span&gt; grep veth
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Vous devriez voir des interfaces de type &lt;code&gt;veth&lt;/code&gt; correspondant à vos pods, par exemple :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;103: lxcb3901b7f9c02@if102: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; ...
veth addrgenmode eui64 numtxqueues 1 numrxqueues 1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si c&amp;rsquo;est bien le cas, le mode &lt;code&gt;generic-veth&lt;/code&gt; de Cilium fonctionnera. On applique :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f cilium-cni-configmap.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="installer-cilium-via-helm"&gt;Installer Cilium via Helm
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo add cilium https://helm.cilium.io/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Voici les values pour le mode chaining :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# cilium-values.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;cni&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;chainingMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;generic-veth&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;customConf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;configMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cni-configuration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;install&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;routingMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;native&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;enableIPv4Masquerade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;enableIPv6Masquerade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;hubble&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;relay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Les points importants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cni.chainingMode: generic-veth&lt;/code&gt;, c&amp;rsquo;est le mode chaining, Cilium s&amp;rsquo;attache aux interfaces veth existantes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cni.customConf: true&lt;/code&gt; + &lt;code&gt;cni.configMap&lt;/code&gt;, on fournit notre propre config CNI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;routingMode: native&lt;/code&gt;, flannel gère le routage, pas Cilium&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enableIPv4Masquerade: false&lt;/code&gt;, flannel gère le masquerading&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hubble.enabled: true&lt;/code&gt;, l&amp;rsquo;observabilité réseau, c&amp;rsquo;est le gros bonus de Cilium&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm install cilium cilium/cilium --version 1.19.1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --namespace kube-system &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -f cilium-values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On attend que tout soit prêt :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl rollout status daemonset/cilium -n kube-system --timeout&lt;span class="o"&gt;=&lt;/span&gt;120s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="vérification"&gt;Vérification
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -n kube-system ds/cilium -- cilium status
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ce qui nous intéresse :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Kubernetes: Ok 1.35 (v1.35.0) [linux/amd64]
CNI Chaining: generic-veth
Cilium: Ok 1.19.1
Hubble: Ok
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La ligne &lt;code&gt;CNI Chaining: generic-veth&lt;/code&gt; confirme que Cilium fonctionne en mode &lt;em&gt;chaining&lt;/em&gt; et ne remplace pas flannel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt; : les pods qui existaient avant l&amp;rsquo;installation de Cilium ne sont pas automatiquement gérés par Cilium. Il faut les redémarrer pour que Cilium attache ses programmes eBPF. Pensez à faire un &lt;code&gt;kubectl rollout restart&lt;/code&gt; de vos workloads de test (ou à les recréer).&lt;/p&gt;
&lt;h2 id="tester-les-networkpolicies"&gt;Tester les NetworkPolicies
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est le moment de vérité. On re-applique notre deny-all :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f 01-deny-all-ingress.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -n netpol-test-a client -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -s --max-time &lt;span class="m"&gt;5&lt;/span&gt; http://server.netpol-test-b.svc.cluster.local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Résultat : timeout&lt;/strong&gt; ! Cette fois, la NetworkPolicy est bien enforced. Le trafic est bloqué.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai enchaîné avec les autres scénarios classiques de NetworkPolicy, et tout fonctionne :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Allow ingress sélectif par namespace&lt;/strong&gt;, en ajoutant une policy qui autorise le trafic depuis &lt;code&gt;netpol-test-a&lt;/code&gt; uniquement, le curl passe depuis ce namespace mais reste bloqué depuis &lt;code&gt;default&lt;/code&gt;. L&amp;rsquo;isolation par namespace fonctionne.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deny-all egress&lt;/strong&gt;, en bloquant tout le trafic sortant du client, même la résolution DNS est bloquée (timeout immédiat).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allow egress sélectif&lt;/strong&gt;, en autorisant uniquement le DNS (port 53) et le serveur (port 80 dans le namespace &lt;code&gt;netpol-test-b&lt;/code&gt;), le curl vers le serveur passe mais &lt;code&gt;curl http://example.com&lt;/code&gt; reste bloqué.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bref, ingress, egress, sélectif par namespace, tout marche comme attendu.&lt;/p&gt;
&lt;h2 id="bonus--hubble-lobservabilité-réseau"&gt;Bonus : Hubble, l&amp;rsquo;observabilité réseau
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est pour moi le vrai atout de Cilium par rapport aux alternatives. Hubble permet de voir en temps réel les flux réseau et les verdicts de policy :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -n kube-system ds/cilium -- &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; hubble observe --namespace netpol-test-b --last &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;Mar 15 13:20:42.287: netpol-test-a/client:40066 (ID:9745) -&amp;gt;
netpol-test-b/server:80 (ID:22271)
policy-verdict:none ALLOWED (TCP Flags: SYN)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On voit le pod source, le pod destination, le port, l&amp;rsquo;identité Cilium, et le verdict de policy. Quand vous debuggez une NetworkPolicy qui ne se comporte pas comme prévu, c&amp;rsquo;est vraiment pratique.&lt;/p&gt;
&lt;h2 id="combien-ça-coûte-en-ressources-"&gt;Combien ça coûte en ressources ?
&lt;/h2&gt;&lt;p&gt;Sur mon cluster (3 nodes), voici ce que Cilium consomme juste après installation :&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Composant&lt;/th&gt;
&lt;th&gt;Par node&lt;/th&gt;
&lt;th&gt;RAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;cilium agent&lt;/td&gt;
&lt;td&gt;oui (DaemonSet)&lt;/td&gt;
&lt;td&gt;~160 Mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cilium-envoy&lt;/td&gt;
&lt;td&gt;oui (DaemonSet)&lt;/td&gt;
&lt;td&gt;~22 Mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cilium-operator&lt;/td&gt;
&lt;td&gt;non (2 replicas)&lt;/td&gt;
&lt;td&gt;~42 Mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hubble-relay&lt;/td&gt;
&lt;td&gt;non (1 replica)&lt;/td&gt;
&lt;td&gt;~16 Mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hubble-ui&lt;/td&gt;
&lt;td&gt;non (1 replica)&lt;/td&gt;
&lt;td&gt;~21 Mo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Soit environ &lt;strong&gt;180 Mo par node&lt;/strong&gt; pour l&amp;rsquo;agent + envoy. J&amp;rsquo;ai pas de point de comparaison par rapport à Calico ou kube-router, mais ça me semble acceptable, et le fait de pouvoir avoir une vision complète sur la totalité des flux avec Hubble justifie largement le surcoût (à mon avis).&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Si jamais vous n&amp;rsquo;avez pas le choix et que vous devez composer avec flannel, et que vous voulez boucher le trou béant de sécurité que représente l&amp;rsquo;absence d&amp;rsquo;enforcement des Netpols, sachez donc qu&amp;rsquo;il est maintenant possible :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;d&amp;rsquo;activer l&amp;rsquo;ajout de l&amp;rsquo;implémentation officielle (même si je ne l&amp;rsquo;ai pas testée, ça doit marcher)&lt;/li&gt;
&lt;li&gt;de chaîner un autre CNI pour le faire&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;À défaut de l&amp;rsquo;avoir en CNI pour tout (tout bon cluster Kubernetes a Cilium comme CNI), Cilium en mode CNI chaining (generic-veth) est une solution plutôt sympa pour combler ce manque. Il ne touche pas au flannel existant, il s&amp;rsquo;y greffe. Et en bonus, vous récupérez Hubble pour l&amp;rsquo;observabilité réseau, ce qui est franchement appréciable.&lt;/p&gt;
&lt;p&gt;Have fun :)&lt;/p&gt;</description></item><item><title>J'ai testé pour vous : k8e (Kubernetes Easy Engine)</title><link>https://blog.zwindler.fr/2025/09/19/test-k8e/</link><pubDate>Fri, 19 Sep 2025 16:00:00 +0000</pubDate><guid>https://blog.zwindler.fr/2025/09/19/test-k8e/</guid><description>&lt;img src="https://blog.zwindler.fr/2025/09/k8e-logo.webp" alt="Featured image of post J'ai testé pour vous : k8e (Kubernetes Easy Engine)" /&gt;&lt;h2 id="tu-ne-faisais-pas-un-livre-sur-kubernetes-toi-"&gt;Tu ne faisais pas un livre sur Kubernetes, toi ?
&lt;/h2&gt;&lt;p&gt;Oui ! Et j&amp;rsquo;ai une bonne nouvelle : mon livre &amp;ldquo;Kubernetes : 50 solutions pour les postes de développement et les clusters de production&amp;rdquo;, édité par &lt;a class="link" href="https://www.editions-eyrolles.com/" target="_blank" rel="noopener"
&gt;Eyrolles&lt;/a&gt;, sortira le &lt;strong&gt;16 octobre 2025&lt;/strong&gt; ! Vous pouvez suivre l&amp;rsquo;état d&amp;rsquo;avancement du projet sur &lt;a class="link" href="https://50ndk.zwindler.fr" target="_blank" rel="noopener"
&gt;50ndk.zwindler.fr&lt;/a&gt;. Je ferai une annonce propre quand j&amp;rsquo;aurai la couverture définitive à vous montrer :3.&lt;/p&gt;
&lt;p&gt;En attendant la sortie, je &amp;ldquo;libère&amp;rdquo; un autre chapitre qui avait été abandonné lors de la sélection finale du livre : celui sur &lt;a class="link" href="https://github.com/xiaods/k8e" target="_blank" rel="noopener"
&gt;&lt;strong&gt;k8e&lt;/strong&gt; (Kubernetes Easy Engine)&lt;/a&gt;. Si vous suivez le blog attentivement, vous vous souviendrez peut-être que j&amp;rsquo;avais fait pareil pour &lt;a class="link" href="https://blog.zwindler.fr/2025/05/26/test-k8s-tew" &gt;k8s-tew (K8S : the easier way)&lt;/a&gt;, qui n&amp;rsquo;avait aussi pas eu la chance de figurer dans la liste des 50 méthodes qui ont leur place dans mon livre :-P.&lt;/p&gt;
&lt;h2 id="mais-revenons-à-k8e-"&gt;Mais revenons à k8e !
&lt;/h2&gt;&lt;p&gt;k8e est un wrapper pour k3s qui permet d&amp;rsquo;installer facilement un cluster multi-nodes avec &lt;a class="link" href="https://cilium.io/" target="_blank" rel="noopener"
&gt;Cilium&lt;/a&gt; configuré comme CNI et en mode &lt;em&gt;kube-proxy replacement&lt;/em&gt;. Dans la philosophie, c&amp;rsquo;est vraiment pas beaucoup plus que k3s avec un gros preflight check. On est même pas sur le niveau fonctionnel d&amp;rsquo;un &lt;code&gt;k3sup&lt;/code&gt; ou d&amp;rsquo;un &lt;code&gt;k0ctl&lt;/code&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Les développeurs mettent en avant plusieurs fonctionnalités clés :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ Key Features&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supports airgap images package for k8s components&lt;/li&gt;
&lt;li&gt;10-year valid certificate, supports cluster backup and upgrade&lt;/li&gt;
&lt;li&gt;No dependency on Ansible, HAProxy, or Keepalived; a binary tool with zero dependencies&lt;/li&gt;
&lt;li&gt;Natively supports Cilium network&lt;/li&gt;
&lt;li&gt;No kube-proxy component&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le projet se présente donc comme une alternative simplifiée pour déployer k3s avec Cilium directement intégré, ce qui évite les étapes manuelles de configuration post-installation. J&amp;rsquo;ai d&amp;rsquo;ailleurs écrit un article fin 2023 sur ces fameuses opérations manuelles, toujours disponible ici : &lt;a class="link" href="https://blog.zwindler.fr/2023/09/01/k3s-et-cilium-rapide-et-facile" &gt;k3s et cilium rapide et facile&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Comme k8e s&amp;rsquo;appuie sur k3s, les prérequis sont globalement les mêmes que pour k3s. Cependant, il y a une exigence supplémentaire importante : Cilium utilisant eBPF pour ses fonctionnalités de bas niveau, il faut un noyau Linux &lt;strong&gt;relativement&lt;/strong&gt; récent&lt;/p&gt;
&lt;p&gt;Bon, ça c&amp;rsquo;était ce qu&amp;rsquo;on disait pour les premières versions de cilium. Maintenant &lt;strong&gt;Linux kernel &amp;gt;= 4.19.57&lt;/strong&gt; c&amp;rsquo;est un vieux vieux kernel !&lt;/p&gt;
&lt;p&gt;Pour mes tests, j&amp;rsquo;ai utilisé 4 machines virtuelles dans le même LAN :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;k8e1 (control plane, 192.168.1.11)&lt;/li&gt;
&lt;li&gt;k8e2 (control plane, 192.168.1.12)&lt;/li&gt;
&lt;li&gt;k8e3 (control plane, 192.168.1.13)&lt;/li&gt;
&lt;li&gt;k8e4 (worker, 192.168.1.14)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L&amp;rsquo;installation nécessite un accès SSH avec des privilèges sudo/root sur tous les nœuds.&lt;/p&gt;
&lt;h2 id="installation-du-premier-nœud"&gt;Installation du premier nœud
&lt;/h2&gt;&lt;p&gt;Le &lt;a class="link" href="https://getk8e-site.pages.dev/docs/install/200-quick-start/" target="_blank" rel="noopener"
&gt;Getting started&lt;/a&gt; est un peu rude car on tombe sur une page en chinois simplifié par défaut&amp;hellip;&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;installation de k8e se fait via un script bash, comme beaucoup d&amp;rsquo;outils de la CNCF (RIP la sécurité). Pour le premier nœud (qui sera notre premier node control plane), on utilise la commande suivante :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e1:~$ curl -sfL https://getk8e-site.pages.dev/install.sh &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;API_SERVER_IP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.11 &lt;span class="nv"&gt;K8E_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;superSecureToken &lt;span class="nv"&gt;INSTALL_K8E_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;server --cluster-init&amp;#34;&lt;/span&gt; sh -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le script réalise plusieurs vérifications préalables (&amp;ldquo;preflight checks&amp;rdquo;) pour s&amp;rsquo;assurer que l&amp;rsquo;environnement est compatible. C&amp;rsquo;est notamment là qu&amp;rsquo;il vérifie la version du noyau Linux pour la compatibilité eBPF.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;2025-09-19 12:28:45&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;WARN&lt;span class="o"&gt;]&lt;/span&gt; System memory is less than 4GB. This may affect performance.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Finding latest version from GitHub
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v1.31.2+k8e1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Downloading package https://github.com/xiaods/k8e/releases/download/v1.31.2+k8e1/k8e as /home/denis/k8e
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/09/k8e-prereqs.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;À la fin du processus, on obtient un message de confirmation :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;2025-09-19 12:35:33&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt; systemd: Starting k8e
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;2025-09-19 12:35:41&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt; Installing cilium network cni/operator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ℹ️ Using Cilium version 1.15.6
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;🔮 Auto-detected cluster name: default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;🔮 Auto-detected kube-proxy has not been installed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ℹ️ Cilium will fully replace all functionalities of kube-proxy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;2025-09-19 12:35:42&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt; Installation completed successfully
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;2025-09-19 12:35:42&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;INFO&lt;span class="o"&gt;]&lt;/span&gt; Performing cleanup...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Point qui a été amélioré depuis la dernière fois que j&amp;rsquo;avais testé, k8e copie lui-même le kubeconfig, il n&amp;rsquo;y a plus besoin d&amp;rsquo;aller le récupérer dans &lt;code&gt;/etc/k8e/k8e.yaml&lt;/code&gt; (idem k3s, il est traditionnellement dans &lt;code&gt;/etc/rancher/k3s/k3s.yaml&lt;/code&gt;)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e1:~$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k8e1 Ready control-plane,etcd,master 62m v1.31.2+k8e1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cependant, un rapide coup d&amp;rsquo;œil permet de voir &amp;ldquo;comment&amp;rdquo; k8e le fait :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e1:~$ env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/k8e/k8e.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e1:~$ ls -l /etc/k8e/k8e.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r--r-- &lt;span class="m"&gt;1&lt;/span&gt; root root &lt;span class="m"&gt;2961&lt;/span&gt; Sep &lt;span class="m"&gt;19&lt;/span&gt; 12:35 /etc/k8e/k8e.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et là, je suis désolé, mais c&amp;rsquo;est :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/09/heretique.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Le kubeconfig cluster-admin à poil en 644, c&amp;rsquo;est NON. La doc de k8e est même encore pire, elle conseille du 666 (toujours plus).&lt;/p&gt;
&lt;h2 id="ajout-des-nœuds-supplémentaires"&gt;Ajout des nœuds supplémentaires
&lt;/h2&gt;&lt;p&gt;Une fois le premier nœud installé, on peut ajouter les autres membres du control plane. Pour les nœuds supplémentaires du control plane :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e2:~$ curl -sfL https://getk8e-site.pages.dev/install.sh &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;K8E_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;superSecureToken &lt;span class="nv"&gt;K8E_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://192.168.1.11:6443 &lt;span class="nv"&gt;INSTALL_K8E_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;server&amp;#34;&lt;/span&gt; sh -s -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e3:~$ curl -sfL https://getk8e.com/install.sh &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;K8E_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;superSecureToken &lt;span class="nv"&gt;K8E_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://192.168.1.11:6443 &lt;span class="nv"&gt;INSTALL_K8E_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;server&amp;#34;&lt;/span&gt; sh -s -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et pour le worker node :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e4:~$ curl -sfL https://getk8e-site.pages.dev/install.sh &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;K8E_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;superSecureToken &lt;span class="nv"&gt;K8E_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://192.168.1.11:6443 sh -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On peut ensuite vérifier que tous les nœuds sont bien présents :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e1:~$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k8e1 Ready control-plane,etcd,master 72m v1.31.2+k8e1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k8e2 Ready control-plane,etcd,master 2m30s v1.31.2+k8e1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k8e3 Ready control-plane,etcd,master 2m18s v1.31.2+k8e1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;k8e4 Ready &amp;lt;none&amp;gt; 75s v1.31.2+k8e1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="vérification-de-cilium"&gt;Vérification de Cilium
&lt;/h2&gt;&lt;p&gt;Une des particularités de k8e est donc l&amp;rsquo;intégration native de Cilium. On peut vérifier que Cilium fonctionne correctement en utilisant sa CLI directement sur un des nœuds du control plane (installée par défaut) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denis@k8e1:~$ cilium status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /¯¯&lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /¯¯&lt;span class="se"&gt;\_&lt;/span&gt;_/¯¯&lt;span class="se"&gt;\ &lt;/span&gt; Cilium: OK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\_&lt;/span&gt;_/¯¯&lt;span class="se"&gt;\_&lt;/span&gt;_/ Operator: OK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; /¯¯&lt;span class="se"&gt;\_&lt;/span&gt;_/¯¯&lt;span class="se"&gt;\ &lt;/span&gt; Envoy DaemonSet: disabled &lt;span class="o"&gt;(&lt;/span&gt;using embedded mode&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\_&lt;/span&gt;_/¯¯&lt;span class="se"&gt;\_&lt;/span&gt;_/ Hubble Relay: disabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\_&lt;/span&gt;_/ ClusterMesh: disabled
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DaemonSet cilium Desired: 4, Ready: 4/4, Available: 4/4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Containers: cilium Running: &lt;span class="m"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cilium-operator Running: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cluster Pods: 3/3 managed by Cilium
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Helm chart version: 1.15.6
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Image versions cilium quay.io/cilium/cilium:v1.15.6: &lt;span class="m"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cilium-operator quay.io/cilium/operator-generic:v1.15.6: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="avantages-et-inconvénients"&gt;Avantages et Inconvénients
&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Les plus&lt;/th&gt;
&lt;th&gt;Les moins&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;➕ Installation automatisée de Cilium sur k3s&lt;/td&gt;
&lt;td&gt;➖ Permissions &lt;code&gt;/etc/k8e/k8e.yaml&lt;/code&gt; en &amp;ldquo;world readable&amp;rdquo; dans la doc officielle (dangereux !)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;➖ Version de Kubernetes en retard par rapport aux dernières versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;➖ N&amp;rsquo;apporte pas énormément de valeur ajoutée par rapport à k3s seul&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;➖ Documentation limitée par rapport aux projets plus matures&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Dans les points positifs, le projet, sans être populaire, est quand même plutôt suivi avec pas mal de contributions externes et une &amp;ldquo;vie&amp;rdquo; (commits réguliers). k8e est un outil pour les fainéants qui veulent installer un cluster k3s avec Cilium plus rapidement (oui c&amp;rsquo;est un point positif).&lt;/p&gt;
&lt;p&gt;Mais, à quel prix ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un kubeconfig à 644, lisible par tous les utilisateurs unix des control planes&lt;/li&gt;
&lt;li&gt;Une installation en &lt;code&gt;curl | bash&lt;/code&gt; (exactement comme &lt;code&gt;k3s&lt;/code&gt;, à ceci près que j&amp;rsquo;ai plus confiance en &lt;strong&gt;Rancher labs&lt;/strong&gt; qu&amp;rsquo;en &lt;strong&gt;xiaods&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Des versions datées (kube 1.31, cilium 1.15)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pas la peine que je vous dise ce que j&amp;rsquo;en pense, je pense que vous avez compris.&lt;/p&gt;</description></item><item><title>Migration du routage de cilium de iptables vers eBPF... à chaud !</title><link>https://blog.zwindler.fr/2023/10/20/migration-routage-cilium-iptables-ebpf/</link><pubDate>Fri, 20 Oct 2023 06:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/10/20/migration-routage-cilium-iptables-ebpf/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/10/cilium-logo.webp" alt="Featured image of post Migration du routage de cilium de iptables vers eBPF... à chaud !" /&gt;&lt;h2 id="contexte"&gt;Contexte
&lt;/h2&gt;&lt;p&gt;Il se pourrait que j&amp;rsquo;aie configuré des clusters Kubernetes de prod avec &lt;a class="link" href="https://cilium.io/" target="_blank" rel="noopener"
&gt;cilium&lt;/a&gt; en mode &lt;code&gt;iptables&lt;/code&gt; et non pas &lt;code&gt;eBPF&lt;/code&gt;. Mais vous n&amp;rsquo;avez aucune preuve&amp;hellip;&lt;/p&gt;
&lt;p&gt;Cependant, dans l&amp;rsquo;hypothèse hautement improbable où j&amp;rsquo;aurais pu faire une boulette pareille, voilà comment je m&amp;rsquo;y serai pris pour résoudre le problème.&lt;/p&gt;
&lt;p&gt;#trollface&lt;/p&gt;
&lt;p&gt;Imaginons donc qu&amp;rsquo;en vérifiant la configuration de Cilium, voici ce que vous avez trouvé :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="l"&gt;kubectl -n cilium exec -it cilium-aaaaa -- cilium status&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;...]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;Host Routing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Legacy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;Masquerading: IPTables [IPv4: Enabled, IPv6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Disabled]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;...]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Damned!&lt;/p&gt;
&lt;p&gt;A y regarder de plus près, les containers cilium-agent dans vos pods cilium prennent beaucoup de CPU et de RAM et commencent à engorger vos workers&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C&amp;rsquo;est la cata&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="pourquoi-ça-"&gt;Pourquoi ça ?
&lt;/h2&gt;&lt;p&gt;Les premières implémentations du &lt;em&gt;réseau imaginaire&lt;/em&gt; de Kubernetes (les fameux CNI plugins) utilisaient &lt;code&gt;iptables&lt;/code&gt;. Or, on sait depuis très longtemps, notamment dans le cas d&amp;rsquo;usage de Kubernetes, qu&amp;rsquo;&lt;code&gt;iptables&lt;/code&gt; est assez mauvais pour gérer de grandes quantités de règles.&lt;/p&gt;
&lt;p&gt;Dans le cas particulier de Kubernetes, le nombre de règles à tendance à augmenter de manière exponentielle avec la taille du cluster et le CPU consommé pour router des paquets réseaux avec&amp;hellip;&lt;/p&gt;
&lt;p&gt;À un moment donné, parcourir la liste des règles prend tout le CPU d&amp;rsquo;un nœud donné et le rend non réactif.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Allo patron ? On est mal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;C&amp;rsquo;est une des raisons pour lesquelles j&amp;rsquo;aime beaucoup cilium comme CNI plugin, les développeurs font partie des premiers à avoir misé sur &lt;a class="link" href="https://ebpf.io/" target="_blank" rel="noopener"
&gt;eBPF&lt;/a&gt; comme remplacement d&amp;rsquo;iptables (même s&amp;rsquo;il existe d&amp;rsquo;autres implémentations / d&amp;rsquo;autres technos qui règles ce problème).&lt;/p&gt;
&lt;h2 id="comment-en-est-on-arrivé-là-"&gt;Comment en est on arrivé là ?
&lt;/h2&gt;&lt;p&gt;A vrai dire, j&amp;rsquo;ai juste lu la doc et fait confiance&amp;hellip;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We introduced eBPF-based host-routing in Cilium 1.9 to fully bypass iptables and the upper host stack, and to achieve a faster network namespace switch compared to regular veth device operation. &lt;strong&gt;This option is automatically enabled if your kernel supports it&lt;/strong&gt;. To validate whether your installation is running with eBPF host-routing, run cilium status in any of the Cilium pods and look for the line reporting the status for &amp;ldquo;Host Routing&amp;rdquo; which should state &amp;ldquo;BPF&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Grosso modo, &lt;a class="link" href="https://docs.cilium.io/en/stable/operations/system_requirements/" target="_blank" rel="noopener"
&gt;selon la doc officielle, si on dispose du kernel correct et des modules qui vont bien&lt;/a&gt;, l&amp;rsquo;installation de cilium est censée activer automatiquement le mode eBPF&amp;hellip; Sauf qu&amp;rsquo;on voit bien un peu plus haut que ce n&amp;rsquo;est pas le cas, malgré un kernel récent (6.2).&lt;/p&gt;
&lt;p&gt;En creusant un peu plus les logs, voilà ce qu&amp;rsquo;on peut trouver :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n cilium logs cilium-7b5cp
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;info &lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;BPF host routing requires enable-bpf-masquerade. Falling back to legacy host routing (enable-host-legacy-routing=true).&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;subsys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;daemon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bon&amp;hellip; visiblement, il manque une option dans la chart Helm.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kubeProxyReplacement: strict
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ bpf:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ masquerade: true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Problem solved, fin de l&amp;rsquo;article ?&lt;/p&gt;
&lt;h2 id="problème"&gt;Problème
&lt;/h2&gt;&lt;p&gt;Alors oui, forcément, on peut modifier la chart comme un⋅e bourrin⋅e et fin de l&amp;rsquo;histoire.&lt;/p&gt;
&lt;p&gt;Mais admettons qu&amp;rsquo;on ait pas envie de couper le trafic de production&amp;hellip; Comment on fait ?&lt;/p&gt;
&lt;p&gt;La solution la plus clean qui me vient en tête est la suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on &lt;code&gt;drain&lt;/code&gt; un node&lt;/li&gt;
&lt;li&gt;on lui change sa configuration&lt;/li&gt;
&lt;li&gt;on l&amp;rsquo;&lt;code&gt;uncordon&lt;/code&gt; pour lui remettre un peu de trafic dessus&lt;/li&gt;
&lt;li&gt;on vérifie que la nouvelle configuration fonctionne
ET&lt;/li&gt;
&lt;li&gt;on vérifie que les nodes peuvent se parler entre eux entre ceux en &lt;code&gt;iptables&lt;/code&gt; et ceux en &lt;code&gt;eBPF&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bah oui, ça serait dommage d&amp;rsquo;avoir la moitié du cluster qui peut pas communiquer avec l&amp;rsquo;autre moitié&amp;hellip;&lt;/p&gt;
&lt;h2 id="vérifier-la-connectivité"&gt;Vérifier la connectivité
&lt;/h2&gt;&lt;p&gt;Ce qui est cool avec cilium (je vous ai déjà dit que j&amp;rsquo;aime cilium ?), c&amp;rsquo;est qu&amp;rsquo;on a déjà du tooling pour tout tester.&lt;/p&gt;
&lt;p&gt;La CLI cilium dispose d&amp;rsquo;une sous commande &lt;code&gt;cilium connectivity test&lt;/code&gt; qui lance des dizaines de tests internes/externes pour tester que tout est OK.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ ~ cilium -n cilium connectivity &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ℹ️ Monitor aggregation detected, will skip some flow validation steps
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;✨ &lt;span class="o"&gt;[&lt;/span&gt;node&lt;span class="o"&gt;]&lt;/span&gt; Deploying echo-same-node service...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;✨ &lt;span class="o"&gt;[&lt;/span&gt;node&lt;span class="o"&gt;]&lt;/span&gt; Deploying DNS &lt;span class="nb"&gt;test&lt;/span&gt; server configmap...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;✨ &lt;span class="o"&gt;[&lt;/span&gt;node&lt;span class="o"&gt;]&lt;/span&gt; Deploying same-node deployment...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;✨ &lt;span class="o"&gt;[&lt;/span&gt;node&lt;span class="o"&gt;]&lt;/span&gt; Deploying client deployment...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;✅ All &lt;span class="m"&gt;32&lt;/span&gt; tests &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;265&lt;/span&gt; actions&lt;span class="o"&gt;)&lt;/span&gt; successful, &lt;span class="m"&gt;2&lt;/span&gt; tests skipped, &lt;span class="m"&gt;0&lt;/span&gt; scenarios skipped.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Il existe aussi une commande &lt;code&gt;cilium-health&lt;/code&gt;, embarquée dans le container cilium-agent, qui permet de remonter des statistiques périodiques de latences entre tous les nodes du cluster. Utile !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl -n cilium &lt;span class="nb"&gt;exec&lt;/span&gt; -it cilium-ccccc -c cilium-agent -- cilium-health status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Probe time: 2023-09-12T14:47:03Z
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Nodes:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; node-02 &lt;span class="o"&gt;(&lt;/span&gt;localhost&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Host connectivity to 172.31.0.152:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ICMP to stack: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;860.424µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HTTP to agent: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;110.142µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Endpoint connectivity to 10.0.2.56:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ICMP to stack: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;783.861µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HTTP to agent: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;256.419µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; node-01:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Host connectivity to 172.31.0.151:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ICMP to stack: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;813.324µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HTTP to agent: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;553.445µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Endpoint connectivity to 10.0.1.53:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ICMP to stack: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;865.976µs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HTTP to agent: OK, &lt;span class="nv"&gt;RTT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.440655ms
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et enfin, on peut juste regarder la commande &lt;code&gt;cilium status&lt;/code&gt; qui nous dit qui est &amp;ldquo;reachable&amp;rdquo; (là encore, dans le container cilium-agent)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;➜ kubectl -n cilium &lt;span class="nb"&gt;exec&lt;/span&gt; -ti cilium-ddddd -- cilium status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Host Routing: Legacy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Masquerading: IPTables &lt;span class="o"&gt;[&lt;/span&gt;IPv4: Enabled, IPv6: Disabled&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cluster health: 5/5 reachable &lt;span class="o"&gt;(&lt;/span&gt;2023-09-14T12:01:51Z&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="changer-la-configuration-dun-node"&gt;Changer la configuration d&amp;rsquo;un node
&lt;/h2&gt;&lt;p&gt;On a de la chance, car, depuis la version 1.13 de cilium (la dernière en date est la 1.14), il est possible d&amp;rsquo;appliquer des configurations différentes pour un sous ensemble de nodes (documentation officielle du &lt;a class="link" href="https://docs.cilium.io/en/stable/configuration/per-node-config/#per-node-configuration" target="_blank" rel="noopener"
&gt;Per-node configuration&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Note : avant ça, c&amp;rsquo;était quand même possible, &lt;em&gt;de manière temporaire&lt;/em&gt;, en éditant la ConfigMap de cilium à la main, puis en redémarrant les pods concernés pour prise en compte.&lt;/p&gt;
&lt;p&gt;Il existe maintenant une CRD pour le faire, qui s&amp;rsquo;appelle &lt;strong&gt;CiliumNodeConfig&lt;/strong&gt;. Les seules choses qu&amp;rsquo;on a à faire, c&amp;rsquo;est ajouter un label sur un node (io.cilium.enable-ebpf: &amp;ldquo;true&amp;rdquo;) et ajouter le manifest suivant sur notre cluster :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; cilium-fix.yaml &lt;span class="s"&gt;&amp;lt;&amp;lt; EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;apiVersion: cilium.io/v2alpha1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;kind: CiliumNodeConfig
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; namespace: cilium
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; name: cilium-switch-from-iptables-ebpf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; nodeSelector:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; matchLabels:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; io.cilium.enable-ebpf: &amp;#34;true&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; defaults:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; enable-bpf-masquerade: &amp;#34;true&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl apply -f cilium-fix.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl label node node-05 --overwrite &lt;span class="s1"&gt;&amp;#39;io.cilium.enable-ebpf=true&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si jamais on est en production, le plus propre est donc de &lt;code&gt;kubectl drain&lt;/code&gt; le Node préalablement.&lt;/p&gt;
&lt;p&gt;Par curiosité, j&amp;rsquo;ai quand même essayé de le faire &amp;ldquo;à chaud&amp;rdquo;, pour le fun.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai déployé un daemonset contenant &lt;a class="link" href="https://github.com/zwindler/vhelloworld" target="_blank" rel="noopener"
&gt;une app en V(lang) qui répond simplement le nom du container dans une page web&lt;/a&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="l"&gt;cat &amp;gt; vhelloworld-daemonset.yaml &amp;lt;&amp;lt; EOF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;apps/v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;DaemonSet&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vhelloworld-daemonset&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vhelloworld&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vhelloworld&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vhelloworld&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;zwindler/vhelloworld:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;containerPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8081&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="l"&gt;EOF&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="l"&gt;kubectl apply -f vhelloworld-daemonset.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -o wide
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vhelloworld-daemonset-q4h44 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 3m31s 10.0.4.87 nodekube-05 &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vhelloworld-daemonset-w97pv 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 3m31s 10.0.3.85 nodekube-04 &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Puis j&amp;rsquo;ai créé des containers contenant un shell et &lt;code&gt;curl&lt;/code&gt; pour vérifier périodiquement et depuis plusieurs nodes que les containers sont bien accessibles :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl run -it --image curlimages/curl:latest curler -- /bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;If you don&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;t see a &lt;span class="nb"&gt;command&lt;/span&gt; prompt, try pressing enter.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~ $ curl http://10.0.4.87:8081
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-g2zdw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~ $ curl http://10.0.3.85:8081
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-65k2n
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~ $ &lt;span class="k"&gt;while&lt;/span&gt; true&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; date
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl http://10.0.4.87:8081
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl http://10.0.3.85:8081
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sleep &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Une fois le label appliqué sur un node, son pod cilium tué (via un &lt;code&gt;kubectl delete&lt;/code&gt;), les pods sont restés accessibles&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Fri Sep &lt;span class="m"&gt;15&lt;/span&gt; 14:05:34 UTC &lt;span class="m"&gt;2023&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-g2zdw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-65k2n
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Fri Sep &lt;span class="m"&gt;15&lt;/span&gt; 14:05:35 UTC &lt;span class="m"&gt;2023&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-g2zdw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-65k2n
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Fri Sep &lt;span class="m"&gt;15&lt;/span&gt; 14:05:36 UTC &lt;span class="m"&gt;2023&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-g2zdw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hello from vhelloworld-daemonset-65k2n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A un moment donné, cilium a redémarré, remarqué la présence de pods existants, et pris le relais avec eBPF !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;evel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;info &lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Rewrote endpoint BPF program&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;containerID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8b7be1b032 &lt;span class="nv"&gt;datapathPolicyRevision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nv"&gt;desiredPolicyRevision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="nv"&gt;endpointID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1018&lt;/span&gt; &lt;span class="nv"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4773&lt;/span&gt; &lt;span class="nv"&gt;ipv4&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10.0.3.85 &lt;span class="nv"&gt;ipv6&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;k8sPodName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default/vhelloworld-daemonset-w97pv &lt;span class="nv"&gt;subsys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;endpoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;info &lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Restored endpoint&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;endpointID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1018&lt;/span&gt; &lt;span class="nv"&gt;ipAddr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;[10.0.3.85 ]&amp;#34;&lt;/span&gt; &lt;span class="nv"&gt;subsys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;endpoint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ca-fonctionne-mais-est-ce-que-cest-mieux-en-termes-de-consommation-de-ressources-"&gt;Ca fonctionne, mais est ce que c&amp;rsquo;est mieux en termes de consommation de ressources ?
&lt;/h2&gt;&lt;p&gt;Ca, c&amp;rsquo;était &lt;strong&gt;la&lt;/strong&gt; bonne nouvelle. Je m&amp;rsquo;attendais à des gains car le cluster était vraiment pas loin de souffrir.&lt;/p&gt;
&lt;p&gt;Les containers cilium prenaient 10% des CPU de mes nodes, et plusieurs Go de RAM en mode &lt;code&gt;iptables&lt;/code&gt;. Ca aurait rapidement pu monter bien plus haut, si j&amp;rsquo;avais agrandi le cluster au-delà des 50 nodes / 2000 pods.&lt;/p&gt;
&lt;p&gt;Le passage au mode eBPF a permis de retrouver des niveaux totalement indolores (1% de CPU par node, 1-2% de RAM) par rapport aux configurations de mes machines.&lt;/p&gt;
&lt;p&gt;Pas mal, hein ?&lt;/p&gt;
&lt;h2 id="bonus"&gt;Bonus
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://isovalent.com/blog/post/tutorial-migrating-to-cilium-part-1/" target="_blank" rel="noopener"
&gt;Un tutoriel bien velu pour migrer totalement de CNI à chaud (de flannel à cilium)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>k3s et cilium rapide et facile</title><link>https://blog.zwindler.fr/2023/09/01/k3s-et-cilium-rapide-et-facile/</link><pubDate>Fri, 01 Sep 2023 10:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/09/01/k3s-et-cilium-rapide-et-facile/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/09/k3s_cilium.webp" alt="Featured image of post k3s et cilium rapide et facile" /&gt;&lt;h2 id="contexte"&gt;Contexte
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://k3s.io/" target="_blank" rel="noopener"
&gt;K3s&lt;/a&gt; est une distribution de Kubernetes éditée par Rancher (et certifiée par la CNCF) que je trouve super pratique car légère et supportant plusieurs plateformes (en particulier ARM):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;x86_64&lt;/li&gt;
&lt;li&gt;armhf&lt;/li&gt;
&lt;li&gt;arm64/aarch64&lt;/li&gt;
&lt;li&gt;s390x&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je l&amp;rsquo;ai déjà utilisée par le passé (&lt;a class="link" href="https://blog.zwindler.fr/2019/03/21/deployer-en-5-minutes-un-cluster-kubernetes-sur-arm-avec-k3s-et-ansible/" target="_blank" rel="noopener"
&gt;ici&lt;/a&gt;) pour faire un cluster kubernetes avec des vieux Raspberry Pi. A l&amp;rsquo;époque, on pouvait même faire tourner les nodes &amp;ldquo;workers&amp;rdquo; sur des RPi 1 (je ne sais pas si c&amp;rsquo;est toujours possible).&lt;/p&gt;
&lt;p&gt;La particularité de k3s est que tout est intégré dans un seul binaire. Nécessairement, des choix techniques ont été fais pour rendre l&amp;rsquo;installation et l&amp;rsquo;utilisation la plus légère possible. Parmi ces choix techniques, il y a l&amp;rsquo;utilisation de &lt;a class="link" href="https://github.com/flannel-io/flannel" target="_blank" rel="noopener"
&gt;flannel comme &amp;ldquo;CNI plugin&amp;rdquo;&lt;/a&gt; (pour faire simple, le réseau virtuel qui permet aux containers de parler en eux).&lt;/p&gt;
&lt;p&gt;Je ne suis vraiment PAS fan de flannel qui m&amp;rsquo;a posé beaucoup de soucis en production, qui ne supporte pas les &amp;ldquo;Network Policies&amp;rdquo;, qui a pendant plusieurs années utilisé comme backend etcd2 alors que ce logiciel était marqué comme obsolète (deprecated) depuis plusieurs années, &amp;hellip;&lt;/p&gt;
&lt;p&gt;A l&amp;rsquo;inverse, je suis très fan de &lt;a class="link" href="https://cilium.io/" target="_blank" rel="noopener"
&gt;cilium&lt;/a&gt;, qui a beaucoup de fonctionnalités sympa grâce à l&amp;rsquo;usage de eBPF en termes de performance et de sécurité et a pas mal de traction dans l&amp;rsquo;écosystème.&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Dans ce tutoriel, je pars du principe que vous avez installé un serveur avec Ubuntu 22.04.&lt;/p&gt;
&lt;p&gt;Cilium est très friand d&amp;rsquo;eBPF, dont il tire la plupart de ces fonctionnalités. Et comme eBPF est quelque chose d&amp;rsquo;assez récent dans le kernel Linux, le mieux est de mettre à jour notre serveur et de lui mettre un kernel plus récent :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo apt update -y
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo apt upgrade -y
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo apt install curl linux-image-generic-hwe-22.04 -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Une fois que c&amp;rsquo;est fait, on reboot le serveur pour la prise en compte du nouveau kernel.&lt;/p&gt;
&lt;h2 id="installation-de-k3s"&gt;Installation de k3s
&lt;/h2&gt;&lt;p&gt;On installe donc &lt;a class="link" href="https://docs.k3s.io/installation" target="_blank" rel="noopener"
&gt;k3s&lt;/a&gt;, en remplaçant flannel par cilium (voir documentation &lt;a class="link" href="https://docs.k3s.io/installation/network-options" target="_blank" rel="noopener"
&gt;Installation - Network options&lt;/a&gt;). La doc conseille de retirer le support des network-policy. Je me demande comment c&amp;rsquo;est géré puisque flannel n&amp;rsquo;est pas censé les supporter :thinking_face:.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl -sfL https://get.k3s.io &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;INSTALL_K3S_EXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--flannel-backend=none --disable &amp;#34;traefik&amp;#34;&amp;#39;&lt;/span&gt; sh -s - --disable-network-policy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On vérifie que k3s est démarré et fonctionne :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl status k3s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;● k3s.service - Lightweight Kubernetes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/etc/systemd/system/k3s.service&lt;span class="p"&gt;;&lt;/span&gt; enabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Fri 2023-09-01 12:32:55 UTC&lt;span class="p"&gt;;&lt;/span&gt; 1min 13s ago
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Docs: https://k3s.io
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Process: &lt;span class="m"&gt;1724&lt;/span&gt; &lt;span class="nv"&gt;ExecStartPre&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/sh -xc ! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited, &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0/SUCCESS&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Process: &lt;span class="m"&gt;1726&lt;/span&gt; &lt;span class="nv"&gt;ExecStartPre&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/sbin/modprobe br_netfilter &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited, &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0/SUCCESS&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Process: &lt;span class="m"&gt;1727&lt;/span&gt; &lt;span class="nv"&gt;ExecStartPre&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/sbin/modprobe overlay &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited, &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0/SUCCESS&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Par défaut, le &amp;ldquo;kubeconfig&amp;rdquo; d&amp;rsquo;administration est déposé dans le fichier &lt;code&gt;/etc/rancher/k3s/k3s.yaml&lt;/code&gt;, dont le propriétaire est root. Il existe un flag &lt;code&gt;--write-kubeconfig-mode&lt;/code&gt; dans k3s pour modifier les droits de ce fichier mais cela le rendrait &amp;ldquo;world readable&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Pour éviter de faire ça, on récupère le kube/config pour notre utilisateur &amp;ldquo;ubuntu&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Comme le binaire k3s embarque tout, dont kubectl, on va aussi devoir lui dire de ne pas utiliser ce fichier en forçant la variable d&amp;rsquo;environnement $KUBECONFIG.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mkdir ~/.kube
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo chown ubuntu:ubuntu ~/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ chmod &lt;span class="m"&gt;600&lt;/span&gt; ~/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.kube/config
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export KUBECONFIG=~/.kube/config&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;source &amp;lt;(kubectl completion bash)&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;alias k=kubectl&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube01 NotReady control-plane,master 70s v1.27.4+k3s1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ici, kube01 est marqué NOTREADY. C&amp;rsquo;est normal car on a pas de CNI plugin (donc pas de réseau interne).&lt;/p&gt;
&lt;h2 id="ajout-dun-second-node"&gt;Ajout d&amp;rsquo;un second node
&lt;/h2&gt;&lt;p&gt;Sur le premier node, récupérez le token pour que le second puisse rejoindre le cluster :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /var/lib/rancher/k3s/server/node-token
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Une fois que c&amp;rsquo;est fait, connectez vous sur le node à rajouter au cluster, installez le kernel &lt;code&gt;hwe&lt;/code&gt;, rebootez&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo apt update
sudo apt upgrade
sudo apt install curl linux-image-generic-hwe-22.04 -y
sudo reboot
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une fois que le node est à jour et prêt à rejoindre le cluster, lancez la commande suivante :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;IP_MASTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;IP.DE.VOTRE.MASTER
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;K3STOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;le:token:du:master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sfL https://get.k3s.io &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;K3S_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP_MASTER&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;:6443 &lt;span class="nv"&gt;K3S_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;K3STOKEN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; sh -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Au bout de quelques secondes, votre node va apparaître dans la liste des nodes.&lt;/p&gt;
&lt;h2 id="cni-plugin--ingresscontroller"&gt;CNI plugin + ingressController
&lt;/h2&gt;&lt;p&gt;Nos nodes sont toujours en &amp;ldquo;Not Ready&amp;rdquo;. On installe helm et on ajoute le CNI plugin :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 &lt;span class="p"&gt;|&lt;/span&gt; bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nv"&gt;CILIUM_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1.14.2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm repo add cilium https://helm.cilium.io/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ helm upgrade --install cilium cilium/cilium --version&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CILIUM_VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set global.tag&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;v&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CILIUM_VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; --set global.containerRuntime.integration&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;containerd&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set global.containerRuntime.socketPath&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/var/run/k3s/containerd/containerd.sock&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set global.kubeProxyReplacement&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;strict&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set global.bpf.masquerade&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set ingressController.enabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set ingressController.default&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --namespace cilium &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --create-namespace
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: pour le fun, j&amp;rsquo;ai aussi ajouté le support de l&amp;rsquo;ingressController de cilium. Comme ça c&amp;rsquo;est fait :D.&lt;/p&gt;
&lt;p&gt;Au bout de quelques secondes, notre cluster devrait devenir opérationnel. On a aussi metric server (pour les stats de base).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get pods -A
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAMESPACE NAME READY STATUS RESTARTS AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system cilium-operator-86dbc96dd6-hlgtt 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 56s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system cilium-operator-86dbc96dd6-h7sq6 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 56s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system cilium-pxrrz 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 56s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system cilium-psjr4 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 56s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system svclb-cilium-ingress-c27a13c6-x7tld 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 32s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system local-path-provisioner-957fdf8bc-5w9n9 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 6m9s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system coredns-77ccd57875-zlvpc 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 6m9s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system svclb-cilium-ingress-c27a13c6-8dbf6 2/2 Running &lt;span class="m"&gt;0&lt;/span&gt; 34s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-system metrics-server-648b5df564-xr29p 1/1 Running &lt;span class="m"&gt;0&lt;/span&gt; 6m9s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Voilà pour ce très court article sur k3s et cilium.&lt;/p&gt;
&lt;p&gt;Ce setup, rapide à installer sur une install fraîche est ma base pour beaucoup d&amp;rsquo;expérimentations avec Kubernetes.&lt;/p&gt;</description></item><item><title>Kubecon Europe 2021 – Récap’ du jeudi</title><link>https://blog.zwindler.fr/2021/05/06/kubecon-europe-2021-recap-du-jeudi/</link><pubDate>Thu, 06 May 2021 17:00:00 +0000</pubDate><guid>https://blog.zwindler.fr/2021/05/06/kubecon-europe-2021-recap-du-jeudi/</guid><description>&lt;img src="https://blog.zwindler.fr/2021/05/old.webp" alt="Featured image of post Kubecon Europe 2021 – Récap’ du jeudi" /&gt;&lt;h2 id="deuxième-jour-de-kubecon"&gt;&lt;strong&gt;Deuxième jour de Kubecon&lt;/strong&gt;
&lt;/h2&gt;&lt;p&gt;Hier, je vous faisais un &lt;a class="link" href="https://blog.zwindler.fr/2021/05/05/kubecon-europe-2021-recap-du-mercredi/" &gt;petit résumé de la première journée de Kubecon !&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Si vous ne l’avez pas lu, je vous conseille de commencer par là, car je ne vais pas refaire la petite intro avec le contexte.&lt;/p&gt;
&lt;p&gt;Aujourd’hui, les talks ont été très condensés et j’ai fait un gros focus réseau / sécu, comme vous pourrez le voir dans la suite de l’article :)&lt;/p&gt;
&lt;h2 id="keynotes"&gt;Keynotes
&lt;/h2&gt;&lt;p&gt;Aujourd’hui, c’était moins dense en termes de nombre de keynotes.&lt;/p&gt;
&lt;p&gt;La première keynote a été réalisée par Stephen Augustus, Co-Chair &amp;amp; Head of Open Source chez Cisco. Il a donné quelques nouvelles sur le projet Kubernetes. Le plus gros morceau est le fait qu’il ait été acté que la release cycle allait passer à 15 semaines, ce qui fait 3 releases par an maintenant au lieu de 4. Il a également parlé du fait que les SIGs doivent opt-in les modifications qu’ils veulent inclure dans chaque release et a aussi acté le retour des &lt;a class="link" href="https://github.com/kubernetes/community/blob/master/events/community-meeting.md" target="_blank" rel="noopener"
&gt;community meetings&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Les deux talks qui ont suivi étaient sans intérêt, avec un talk sponsorisé de Veeam très très basique sur la sécurité et un talk sur Linkerd qui sauve le monde du COVID-19, que j’ai trouvé plus que déplacé. Je ne me suis pas privé pour le dire sur Twitter d’ailleurs (lol).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2021/05/old.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Le talk suivant (sponsorisé aussi) rattrapait un peu le niveau, avec un focus sur &lt;a class="link" href="https://knative.dev/" target="_blank" rel="noopener"
&gt;Knative&lt;/a&gt; réalisé par Brenda Chan de chez VMware. Je n’ai pas encore regardé en détail ce qu’on pouvait faire avec knative et ce talk m’a donné envie de creuser le sujet.&lt;/p&gt;
&lt;p&gt;La dernière keynote était assez intéressante, avec un REX sur l’intégration des projets cloud native par les équipes de Deutsche Telekom. Après avoir présenté les problèmes auxquels ses équipes ont du faire face, Vuk Gojnic a présenté &lt;a class="link" href="https://github.com/telekom/das-schiff" target="_blank" rel="noopener"
&gt;Das schiff&lt;/a&gt;, la solution qu’ils ont implémenté pour déployer des clusters Kubernetes distribués (as a service).&lt;/p&gt;
&lt;h2 id="what-do-you-mean-k8s-doesnt-have-users-how-do-i-manage-user-access-then"&gt;&lt;strong&gt;What Do You Mean K8s Doesn’t Have Users? How Do I Manage User Access Then?&lt;/strong&gt;
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://kccnceu2021.sched.com/event/iE4h/what-do-you-mean-k8s-doesnt-have-users-how-do-i-manage-user-access-then-jussi-nummelin-mirantis-inc" target="_blank" rel="noopener"
&gt;Page de la session&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://static.sched.com/hosted_files/kccnceu2021/2a/KubeConEU2021_UserMgmt.pdf" target="_blank" rel="noopener"
&gt;Slides&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La journée a commencé plutôt soft avec un talk assez généraliste sur l’AuthN/AuthZ pr Jussi Nummelin de chez Mirantis. Il a pointé du doigt un vrai problème dans Kubernetes : il n’y a pas de gestion des utilisateurs humains a proprement parlé.&lt;/p&gt;
&lt;p&gt;C’est d’ailleurs écrit noir sur blanc dans la documentation officielle de Kubernetes !&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is assumed that a cluster-independent service manages normal users
&amp;ndash;&lt;a class="link" href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/" target="_blank" rel="noopener"
&gt;kubernetes.io/docs/reference/access-authn-authz/authentication/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tout ce qui est authentification dans Kubernetes passe soit par certificat x509, soit par des tokens de service account soit par des webhook. Tout ceci est donc plutôt réservé aux pods, comptes de services et pas du tout adapté pour des personnes en chair et en os.&lt;/p&gt;
&lt;p&gt;Je ne parlerai même pas de l’authentification ‘static token file’ qui est un réel scandale qui ne devrait même pas être utilisée en lab.&lt;/p&gt;
&lt;p&gt;La seule option viable est donc bien l’implémentation d’une authentification tierce via un connecter OIDC comme Dex, par exemple.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2021/05/dex-horizontal-color.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/dexidp/dex" target="_blank" rel="noopener"
&gt;github.com/dexidp/dex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="falcomg-thats-awesome---new-things-fixed-things-and-you-panel"&gt;&lt;strong&gt;FalcOMG That’s AWESOME - New Things, Fixed Things, and YOU Panel&lt;/strong&gt;
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://kccnceu2021.sched.com/event/iE69/falcomg-thats-awesome-new-things-fixed-things-and-you-panel-leo-didonato-leonardo-grasso-sysdig-rajakavitha-kodhandapani-linode-thomas-labarussias-qonto?iframe=no" target="_blank" rel="noopener"
&gt;Page de la session&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[Slides](&lt;a class="link" href="https://static.sched.com/hosted_files/kccnceu2021/a1/FalcOMG" target="_blank" rel="noopener"
&gt;https://static.sched.com/hosted_files/kccnceu2021/a1/FalcOMG&lt;/a&gt; That)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette session avait pour but de présenter tout un tas de choses à propos du &lt;a class="link" href="https://falco.org/" target="_blank" rel="noopener"
&gt;projet Falco&lt;/a&gt;. Pour rappel, Falco est un cloud-native security runtime, initié par Sysdig en 2016. Il utilise eBPF (encore lui) pour détecter voire empêcher les workloads suspects sur vos machines Linux (pas que Kubernetes donc). Les dernières parties qui manquaient ont été données par sysdig en février 2021 (kernel modules + ebpf probe + runtime security).&lt;/p&gt;
&lt;p&gt;Après une longue introduction du projet (donné à la CNCF en 2018, accepté en tant qu’Incubating en 2020), deux mainteneurs (Leonardo Grasso et Leonardo Di Donato) ont présentés le processus de release ainsi que la façon dont les artefacts (cf falco open infra) sont générés automatiquement (&lt;a class="link" href="https://download.falco.org/?prefix=driver/ae104eb20ff0198a5dcb0c91cc36c86e7c3f25c7/" target="_blank" rel="noopener"
&gt;plus de 3500&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;L’équipe de falco est également très impliquée dans l’accès à cette technologie pour tous et recherche activement des traducteurs pour traduire le site et la documentation de falco dans le plus de langues possible. Le processus d’internationalisation a été présenté par Radhika Puthiyetath, technical writer chez sysdig. C’était assez intéressant de voir que le processus mis en place était assez simple et donc accessible au plus grand nombre.&lt;/p&gt;
&lt;p&gt;Enfin, l’outil &lt;a class="link" href="https://github.com/falcosecurity/falcosidekick" target="_blank" rel="noopener"
&gt;falco sidekick&lt;/a&gt; a été présenté par Thomas Labarussias, SRE chez Qonto. Il s’agit d’un démon permettant de collecter l’ensemble des événements transmis par falco (présent sur tous vos nodes kube par exemple) et de les forwarder à une 30aines d’outputs différents en fonction de certaines règles.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2021/05/falcosidekick_color.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;On peut ainsi mettre en place de l’alerting ou loguer les événements dans des SIEM ou des moteurs de recherche (Elasticsearch) pour traitements ultérieurs par exemple.&lt;/p&gt;
&lt;h2 id="uncovering-a-sophisticated-kubernetes-attack-in-real-time"&gt;&lt;strong&gt;Uncovering a Sophisticated Kubernetes Attack in Real-Time&lt;/strong&gt;
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://kccnceu2021.sched.com/event/iE2u/uncovering-a-sophisticated-kubernetes-attack-in-real-time-jed-salazar-natalia-reka-ivanko-isovalent?iframe=no" target="_blank" rel="noopener"
&gt;Page de la session&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://static.sched.com/hosted_files/kccnceu2021/3e/UncoveringASophisticatedAttackInRealTime_JedSalazar_NataliaRekaIvanko_06052021.pdf" target="_blank" rel="noopener"
&gt;Slides&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Troisième talk de la journée sur la sécurité !!! Natália Réka Ivánkó (Security Engineer chez Isovalent) et Jed Salazar (Manager, Platform Security chez Tesla) nous on présenté un panel assez large de risques de sécurité et de vecteurs d’attaques accessibles depuis un cluster Kubernetes.&lt;/p&gt;
&lt;p&gt;Après avoir balayé très rapidement les solutions classiques pour réduire les risques (Distroless base images, OPA, pas de shells pour réduire la surface d’attaques, analyse statique des images et analyse au runtime), ils ont cherché à comprendre ce qu’on pouvait faire de plus.&lt;/p&gt;
&lt;p&gt;On peut aussi appliquer à la sécurité le mindset « devops » (on parle parfois de devsecops) en considérant que ce qu’on a mis en place en termes de sécurité doit être (1) testé et (2) observé.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2021/05/trust_but_verify.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Et selon eux, le meilleur outil pour le faire, c’est eBPF. Ils nous ont donc ensuite présenté plusieurs scenarii d’attaques dans lesquels &lt;a class="link" href="https://cilium.io/" target="_blank" rel="noopener"
&gt;Cilium&lt;/a&gt; (eBPF-based Networking, Observability, and Security) était utilisé pour connecter, surveiller et sécuriser les événements sur le réseau de kubernetes.&lt;/p&gt;
&lt;p&gt;Le talk était riche et dense et il est extrêmement dur pour moi de le résumer ici. Je serais probablement amené à en reparler sur le blog tant le sujet est pléthorique.&lt;/p&gt;
&lt;h2 id="how-to-break-your-kubernetes-cluster-with-networking"&gt;&lt;strong&gt;How to Break your Kubernetes Cluster with Networking&lt;/strong&gt;
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://kccnceu2021.sched.com/event/iE5i/how-to-break-your-kubernetes-cluster-with-networking-thomas-graf-isovalent?iframe=no" target="_blank" rel="noopener"
&gt;Page de la session&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://static.sched.com/hosted_files/kccnceu2021/d0/Kubecon%20EU%2021%20-%20Breaking%20Kubernetes%20with%20Networking.pdf" target="_blank" rel="noopener"
&gt;Slides&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’ai vraiment adoré le talk précédent mais alors celui là c’est le meilleur que j’ai vu depuis le début de cet Kubecon. Thomas Graf, en plus d’être un excellent pédagogue est un excellent speaker. C’est le CTO d’Isovalent (tiens tiens tiens, encore eux !) et il est core member du projet Cilium (encore lui !).&lt;/p&gt;
&lt;p&gt;Là aussi, le talk était extrêmement dense et Thomas Graf s’est employé à brosser toutes les façons de casser son cluster Kubernetes avec le réseau. Cela va de bête erreurs DNS à l’utilisation de kube-proxy + iptables en passant par des CRD watchers qui DDoS votre API server et en finissant par des histoires d’horreur de changement de CNI (ou double run) qui cassent tout le réseau du cluster (kids, don’t do this at home).&lt;/p&gt;
&lt;p&gt;Une fois de plus, le talk était tellement dense qu’il est difficile de le résumer. Ce qu’on peut en retenir simplement, c’est que le mieux est encore de rester le plus simple possible dans la limite de vos besoins et de ne pas ajouter trop de couches juste parce qu’elles sont « shiny ». (Et je suis évidemment à 100% d’accord).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Oooooooh! Shiny ones!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="les-talks-que-jaurai-voulu-voir"&gt;&lt;strong&gt;Les talks que j’aurai voulu voir&lt;/strong&gt;
&lt;/h2&gt;&lt;p&gt;Je l’ai déjà dit hier, choisir c’est renoncer.&lt;/p&gt;
&lt;p&gt;Si j’avais pu, je serai également allé voir &lt;strong&gt;BuildKit CLI for kubectl: A New Way to Build Container Images&lt;/strong&gt; par curiosité pour l’outil, que je ne connais pas. Mais les dieux du scheduling en ont voulu autrement (c’était pendant la présentation sur Falco).&lt;/p&gt;
&lt;h2 id="fin-de-la-journée"&gt;&lt;strong&gt;Fin de la journée&lt;/strong&gt;
&lt;/h2&gt;&lt;p&gt;Si on peut appeler ça la fin de la journée puisque le dernier talk a fini vers 15h ;-) mais en vrai c’était tellement intense il y avait pas mal à débriefer.&lt;/p&gt;
&lt;p&gt;Maintenant qu’on est au 2/3 de la Kubecon, je vois 2 sujets prioritaires qu’il va falloir que j’investigue sérieusement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la partie eBPF, avec un vrai choix technique côté CNI (test de Cilium à faire absolument) et évaluation des outils de sécus basés sur des programmes BPF&lt;/li&gt;
&lt;li&gt;la partie CI/CD avec flux, flagger, litmus (mais plutôt réservée pour mes copains ingés CI/CD, je ne ferai que suivre le mouvement)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On verra si la journée de demain changera un peu ces priorité ou pas (probablement que non).&lt;/p&gt;
&lt;p&gt;Et en attendant, have fun :)&lt;/p&gt;</description></item></channel></rss>