<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kubeadm on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/kubeadm/</link><description>Recent content in Kubeadm on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Sun, 29 Mar 2026 18:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/kubeadm/index.xml" rel="self" type="application/rss+xml"/><item><title>101 façons de déployer Kubernetes : 125 solutions, des PRs communautaires et une UI qui s'améliore</title><link>https://blog.zwindler.fr/2026/03/29/101-facons-de-deployer-kubernetes-v3/</link><pubDate>Sun, 29 Mar 2026 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/03/29/101-facons-de-deployer-kubernetes-v3/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/03/125-kube.webp" alt="Featured image of post 101 façons de déployer Kubernetes : 125 solutions, des PRs communautaires et une UI qui s'améliore" /&gt;&lt;h2 id="il-bouge-encore"&gt;Il bouge encore
&lt;/h2&gt;&lt;p&gt;Depuis la sortie de &lt;a class="link" href="https://blog.zwindler.fr/2026/02/09/101-facons-de-deployer-kubernetes-nouvelle-ui/" &gt;l&amp;rsquo;interface web du projet&lt;/a&gt; début février, le projet a continué à évoluer. Ajout de solutions manquantes, petites améliorations de l&amp;rsquo;UI, contributions externes, optimisations de performances&amp;hellip; Bref, un bon petit mois bien rempli pour ce gros side project que j&amp;rsquo;aimerais faire grossir.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://zwindler.github.io/101-ways-to-deploy-kubernetes/" target="_blank" rel="noopener"
&gt;101-ways-to-deploy-kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note : si vous n&amp;rsquo;avez pas suivi les épisodes précédents :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2025/11/02/93-facons-de-deployer-kubernetes/" &gt;93 façons de déployer Kubernetes&lt;/a&gt; — le Google Sheet original&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2026/01/04/101-facons-de-deployer-kubernetes-v2/" &gt;101 façons de déployer Kubernetes (v2)&lt;/a&gt; — passage sur GitHub&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2026/02/09/101-facons-de-deployer-kubernetes-nouvelle-ui/" &gt;Une nouvelle UI pour explorer les 118+ solutions&lt;/a&gt; — l&amp;rsquo;appli Astro + Tailwind&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="7-nouvelles-solutions"&gt;7 nouvelles solutions
&lt;/h2&gt;&lt;p&gt;Le catalogue est passé de 118 à &lt;strong&gt;125 solutions&lt;/strong&gt;. Voici les ajouts depuis le dernier article :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Xen Orchestra&lt;/strong&gt; - ajouté pendant un stream de Cuistops =&amp;gt; Déploiement de clusters Kubernetes (MicroK8s) via les &amp;ldquo;recettes&amp;rdquo; de Xen Orchestra, la plateforme de management de Vates. Catégorie ManagementPlatform.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Charmed Kubernetes&lt;/strong&gt; - suite à un commentaire sur LinkedIn, j&amp;rsquo;ai remplacé l&amp;rsquo;entrée &amp;ldquo;Juju&amp;rdquo; par Charmed Kubernetes, qui est le vrai nom du produit Canonical pour déployer Kubernetes via Juju.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kubeaver&lt;/strong&gt; - découvert en scrollant bluesky sans but =&amp;gt; un installateur Kubernetes offline/online avec une GUI, basé sur Kubespray et Ansible. Certifié CNCF conformance (pour ce que ça vaut&amp;hellip;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;talos-bootstrap&lt;/strong&gt; - script interactif de Cozystack pour bootstrapper des clusters Kubernetes sur Talos OS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;boot-to-talos&lt;/strong&gt; - Outil de Cozystack (encore) qui convertit n&amp;rsquo;importe quel OS existant en Talos Linux, complètement depuis le userspace. Partiellement utilisé par Quentin dans un contexte que je ne peux révéler ;-)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TOPF&lt;/strong&gt; - Talos Orchestrator by PostFinance, un CLI pour gérer des clusters Kubernetes basés sur Talos. Découvert sur le discord de Cuistops&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Talhelper&lt;/strong&gt; - Outil CLI pour créer des clusters Talos en mode GitOps, à partir d&amp;rsquo;un seul fichier YAML déclaratif. Je l&amp;rsquo;avais initialement mis de côté mais à y réfléchir, pourquoi pas le mettre.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On notera qu&amp;rsquo;au même titre que kubeadm et k3s, il y a beaucoup de solutions qui s&amp;rsquo;appuient sur &lt;strong&gt;Talos Linux&lt;/strong&gt;. De mon point de vue, ça valide l&amp;rsquo;OS et ça confirme l&amp;rsquo;adoption croissante de cet OS immutable pour Kubernetes.&lt;/p&gt;
&lt;h2 id="refonte-complète-des-tags"&gt;Refonte complète des tags
&lt;/h2&gt;&lt;p&gt;Un gros chantier a été la &lt;strong&gt;refonte de tous les tags&lt;/strong&gt; du catalogue. Ils étaient incohérents : des noms d&amp;rsquo;outils utilisés comme tags (openshift, rancher&amp;hellip;), des tags redondants (on-premise + self-hosted), des tags manquants ou parfois faux (par ex. &amp;ldquo;lightweight&amp;rdquo; sur des outils qui lancent des VMs).&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai nettoyé les tags de &lt;strong&gt;toutes les catégories&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Desktop&lt;/strong&gt; : suppression des noms d&amp;rsquo;outils comme tags, ajout de &lt;code&gt;gui&lt;/code&gt; pour Docker Desktop, Orbstack, Podman Desktop, Rancher Desktop&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selfhosted&lt;/strong&gt; : suppression du tag redondant &lt;code&gt;on-premise&lt;/code&gt; (29 solutions), ajout de tags pertinents (&lt;code&gt;automation&lt;/code&gt;, &lt;code&gt;edge&lt;/code&gt;, &lt;code&gt;lightweight&lt;/code&gt;, &lt;code&gt;bare-metal&lt;/code&gt;&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ManagementPlatform&lt;/strong&gt; : toutes les solutions ont maintenant 3 tags (&lt;code&gt;multi-cloud&lt;/code&gt;, &lt;code&gt;managed&lt;/code&gt;, &lt;code&gt;gui&lt;/code&gt;, &lt;code&gt;automation&lt;/code&gt;&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KubernetesInKubernetes&lt;/strong&gt; : correction de vcluster (&lt;code&gt;virtualization&lt;/code&gt; → &lt;code&gt;lightweight&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="de-nouveaux-filtres-dans-lui"&gt;De nouveaux filtres dans l&amp;rsquo;UI
&lt;/h2&gt;&lt;p&gt;J&amp;rsquo;ai ajouté un &lt;strong&gt;filtre par nombre d&amp;rsquo;étoiles GitHub&lt;/strong&gt; qui n&amp;rsquo;apparaît que quand le filtre &amp;ldquo;Open Source only&amp;rdquo; est activé. Plutôt pratique pour identifier rapidement les projets les plus populaires (&amp;gt; 100, &amp;gt; 1k, &amp;gt; 10k stars).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/stars-filter.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;occasion aussi de réorganiser la barre de filtres : le sélecteur de statut (Active/Abandoned) est passé en dropdown compact, et le layout général a été retravaillé pour rester lisible même avec plus de filtres.&lt;/p&gt;
&lt;p&gt;Dernier point, lorsque vous faites une recherche dans la barre principale, une variable vient d&amp;rsquo;ajouter à l&amp;rsquo;URL : pratique pour partager des solutions directement avec le lien.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/search.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="les-contributions-dantoine-caron-slashgear"&gt;Les contributions d&amp;rsquo;Antoine Caron (Slashgear)
&lt;/h2&gt;&lt;p&gt;Un grand merci à &lt;a class="link" href="https://bsky.app/profile/slashgear.dev" target="_blank" rel="noopener"
&gt;Antoine Caron (@slashgear)&lt;/a&gt; qui, au-delà de m&amp;rsquo;avoir aidé sur &lt;a class="link" href="https://blog.zwindler.fr/2026/02/19/optimisation-webperf-avif-precompression/" &gt;les performances&lt;/a&gt; et &lt;a class="link" href="https://blog.zwindler.fr/2026/02/20/securite-headers-http-observatory-hugo/" &gt;la sécurité&lt;/a&gt; de ce blog, a aussi contribué directement au projet 101 ways avec plusieurs PRs !&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hiérarchie des headings&lt;/strong&gt; - les cartes utilisaient des &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt; sans &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; dans la page. Antoine a corrigé ça pour une hiérarchie correcte (&lt;code&gt;h1&lt;/code&gt; → &lt;code&gt;h2&lt;/code&gt;), ce qui améliore la navigation pour les lecteurs d&amp;rsquo;écran.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibilité du champ de recherche&lt;/strong&gt; - ajout d&amp;rsquo;un vrai &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; (en &lt;code&gt;sr-only&lt;/code&gt;) et passage du &lt;code&gt;type=&amp;quot;text&amp;quot;&lt;/code&gt; à &lt;code&gt;type=&amp;quot;search&amp;quot;&lt;/code&gt; pour une meilleure sémantique.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skip links&lt;/strong&gt; - ajout de liens &amp;ldquo;skip to content&amp;rdquo; pour la navigation au clavier (WCAG 2.1, critère 2.4.1). Trois liens : vers la recherche, les filtres, et le contenu principal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="amélioration-des-performances"&gt;Amélioration des performances
&lt;/h2&gt;&lt;p&gt;En parlant de performances, le site s&amp;rsquo;est aussi amélioré côté PageSpeed. Voici un avant/après sur Lighthouse mobile :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/101-avant.avif"
loading="lazy"
alt="Score PageSpeed avant optimisation : 82"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/101-apr%c3%a8s.avif"
loading="lazy"
alt="Score PageSpeed après optimisation : 99"
&gt;&lt;/p&gt;
&lt;p&gt;De &lt;strong&gt;82 à 99&lt;/strong&gt; en performances mobiles, avec du 100/100 en bonnes pratiques et SEO.&lt;/p&gt;
&lt;p&gt;Ces gains viennent d&amp;rsquo;un ensemble de corrections, notamment la résolution du &lt;strong&gt;clipping des cartes au hover&lt;/strong&gt;, un bug CSS assez vicieux lié à &lt;code&gt;content-visibility: auto&lt;/code&gt; qui impliquait &lt;code&gt;contain: paint&lt;/code&gt; et coupait le haut des cartes quand elles se soulevaient au survol. Antoine avait identifié le problème avec l&amp;rsquo;&lt;code&gt;overflow-hidden&lt;/code&gt;, et Copilot a trouvé la cause racine dans le CSS containment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/clipping.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="merci-"&gt;Merci !
&lt;/h2&gt;&lt;p&gt;Un grand merci à tous ceux qui contribuent, que ce soit en me mentionnant les outils manquants, en soumettant des PRs, ou simplement en partageant le projet.&lt;/p&gt;
&lt;p&gt;Merci spécial à &lt;strong&gt;Antoine Caron&lt;/strong&gt; pour ses PRs sur l&amp;rsquo;accessibilité et la CI - c&amp;rsquo;est vraiment chouette de voir quelqu&amp;rsquo;un prendre le temps d&amp;rsquo;améliorer un projet open source qui n&amp;rsquo;est pas le sien. Et c&amp;rsquo;est d&amp;rsquo;autant plus appréciable qu&amp;rsquo;Antoine m&amp;rsquo;avait déjà aidé sur ce blog avec &lt;a class="link" href="https://blog.zwindler.fr/2026/02/19/optimisation-webperf-avif-precompression/" &gt;l&amp;rsquo;optimisation des images en AVIF&lt;/a&gt; et &lt;a class="link" href="https://blog.zwindler.fr/2026/02/20/securite-headers-http-observatory-hugo/" &gt;les security headers HTTP&lt;/a&gt;. 🙏&lt;/p&gt;
&lt;p&gt;Le projet compte maintenant &lt;strong&gt;125 solutions&lt;/strong&gt;. Si vous en connaissez d&amp;rsquo;autres, n&amp;rsquo;hésitez pas à &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes/issues" target="_blank" rel="noopener"
&gt;ouvrir une issue&lt;/a&gt; ou une PR (ou juste à me ping, en cas de flemme) !&lt;/p&gt;
&lt;p&gt;👉 &lt;a class="link" href="https://zwindler.github.io/101-ways-to-deploy-kubernetes/" target="_blank" rel="noopener"
&gt;zwindler.github.io/101-ways-to-deploy-kubernetes&lt;/a&gt;&lt;/p&gt;</description></item><item><title>101 façons de déployer Kubernetes : une nouvelle UI pour explorer les 118+ solutions</title><link>https://blog.zwindler.fr/2026/02/09/101-facons-de-deployer-kubernetes-nouvelle-ui/</link><pubDate>Mon, 09 Feb 2026 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/02/09/101-facons-de-deployer-kubernetes-nouvelle-ui/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/02/101-kubernetes-ui-screenshot.webp" alt="Featured image of post 101 façons de déployer Kubernetes : une nouvelle UI pour explorer les 118+ solutions" /&gt;&lt;h2 id="de-google-sheet-à-une-vraie-application-web"&gt;De Google Sheet à une vraie application web
&lt;/h2&gt;&lt;p&gt;Vous vous souvenez peut-être de mes précédents articles sur ce projet : d&amp;rsquo;abord un &lt;a class="link" href="https://blog.zwindler.fr/2025/11/02/93-facons-de-deployer-kubernetes/" &gt;simple Google Sheet avec 93 méthodes&lt;/a&gt;, puis un &lt;a class="link" href="https://blog.zwindler.fr/2026/01/04/101-facons-de-deployer-kubernetes-v2/" &gt;dépôt GitHub avec plus de 100 entrées&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Aujourd&amp;rsquo;hui, je peux présenter la dernière itération de ce projet : &lt;strong&gt;une vraie interface web&lt;/strong&gt; pour explorer toutes ces solutions !&lt;/p&gt;
&lt;p&gt;👉 &lt;a class="link" href="https://zwindler.github.io/101-ways-to-deploy-kubernetes/" target="_blank" rel="noopener"
&gt;101-ways-to-deploy-kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/101-kubernetes-ui-screenshot.avif"
loading="lazy"
alt="Interface web du projet 101 ways to deploy Kubernetes"
&gt;&lt;/p&gt;
&lt;h2 id="pourquoi-une-ui-"&gt;Pourquoi une UI ?
&lt;/h2&gt;&lt;p&gt;Le tableau Markdown sur GitHub, c&amp;rsquo;était déjà mieux que le Google Sheet pour la collaboration, mais à peine. Difficile à parser, difficile de rajouter des colonnes sans que ça devienne trop le bazar (c&amp;rsquo;était déjà le cas, ahah), et surtout, ultra MOCHE.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/01/101-kubernetes-v2-screenshot.avif"
loading="lazy"
alt="Ancien tableau Markdown sur GitHub, difficile à lire"
&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai donc décidé de transformer tout ça en une interface moderne et intuitive, avec l&amp;rsquo;aide d&amp;rsquo;un LLM.&lt;/p&gt;
&lt;h2 id="stack-technique--astro--tailwind"&gt;Stack technique : Astro + Tailwind
&lt;/h2&gt;&lt;p&gt;Pour ce projet, j&amp;rsquo;ai choisi une stack simple mais efficace :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="link" href="https://astro.build/" target="_blank" rel="noopener"
&gt;Astro&lt;/a&gt;&lt;/strong&gt; : un framework moderne qui génère des sites statiques ultra-rapides&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="link" href="https://tailwindcss.com/" target="_blank" rel="noopener"
&gt;Tailwind CSS&lt;/a&gt;&lt;/strong&gt; : pour un design responsive sans prise de tête&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le résultat ? Un site léger, plutôt rapide, et qui fonctionne aussi bien sur &lt;strong&gt;desktop&lt;/strong&gt; que sur &lt;strong&gt;mobile&lt;/strong&gt; (même si l&amp;rsquo;expérience desktop reste plus confortable vu la quantité de données).&lt;/p&gt;
&lt;h2 id="les-fonctionnalités"&gt;Les fonctionnalités
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Des cartes pour chaque solution&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Fini le tableau digne d&amp;rsquo;un dev back (non, pire, un ingé kube&amp;hellip;) ! Chaque outil dispose maintenant de sa propre &amp;ldquo;carte&amp;rdquo; animée avec :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le logo du projet&lt;/li&gt;
&lt;li&gt;Le type de licence (OSS ou propriétaire)&lt;/li&gt;
&lt;li&gt;Le nombre d&amp;rsquo;étoiles GitHub&lt;/li&gt;
&lt;li&gt;Des liens directs vers le projet et des ressources tierces (blogs indépendants, REX, tutos&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/101-kubernetes-zoom.avif"
loading="lazy"
alt="Vue détaillée d’une carte de solution Kubernetes avec logo, licence et étoiles GitHub"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Des filtres puissants&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Vous cherchez uniquement des solutions open source ? Des outils pour le développement local ? Des plateformes de management ?&lt;/p&gt;
&lt;p&gt;Les filtres par &lt;strong&gt;catégories&lt;/strong&gt; permettent de naviguer facilement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Desktop (développement local)&lt;/li&gt;
&lt;li&gt;Managed (offres cloud)&lt;/li&gt;
&lt;li&gt;Self-hosted (automatisation on-premise)&lt;/li&gt;
&lt;li&gt;Infra As Code&lt;/li&gt;
&lt;li&gt;Kubernetes OS (systèmes spécialisés)&lt;/li&gt;
&lt;li&gt;Management Platform&lt;/li&gt;
&lt;li&gt;Kubernetes in Kubernetes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et vous pouvez aussi filtrer par &lt;strong&gt;statut&lt;/strong&gt; (actif, abandonné) ou afficher uniquement les solutions &lt;strong&gt;open source&lt;/strong&gt; ou &lt;strong&gt;production ready&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Une barre de recherche&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Vous savez ce que vous cherchez ? Tapez directement le nom dans la barre de recherche pour trouver la solution en un instant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Des tags pour affiner&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Au-delà des catégories, les tags permettent d&amp;rsquo;identifier rapidement les technologies sous-jacentes (kubeadm, k3s, k0s&amp;hellip;).&lt;/p&gt;
&lt;h2 id="le-saviez-vous--au-moins-18-outils-utilisent-kubeadm-"&gt;Le saviez-vous ? Au moins 18 outils utilisent kubeadm !
&lt;/h2&gt;&lt;p&gt;En compilant toutes ces données, j&amp;rsquo;ai découvert quelque chose de fascinant : &lt;strong&gt;au moins 18 outils&lt;/strong&gt; utilisent &lt;code&gt;kubeadm&lt;/code&gt; comme backend pour déployer Kubernetes ! 🤯&lt;/p&gt;
&lt;p&gt;Et ce n&amp;rsquo;est même pas en comptant les offres managées des cloud providers !&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est typiquement le genre d&amp;rsquo;information qu&amp;rsquo;on peut maintenant visualiser instantanément grâce à cette nouvelle interface.&lt;/p&gt;
&lt;h2 id="un-projet-collaboratif"&gt;Un projet collaboratif
&lt;/h2&gt;&lt;p&gt;Le projet reste &lt;strong&gt;100% open source&lt;/strong&gt; et collaboratif. Les données sont toujours stockées dans le dépôt GitHub, et l&amp;rsquo;UI est générée automatiquement à partir de ces données (j&amp;rsquo;ai même rajouté des previews pour les PRs).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Il manque un outil ou un provider ?&lt;/strong&gt; Vous avez repéré un bug ? N&amp;rsquo;hésitez pas à &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes/issues" target="_blank" rel="noopener"
&gt;ouvrir une issue&lt;/a&gt; ou à soumettre une Pull Request !&lt;/p&gt;
&lt;p&gt;Le projet compte maintenant &lt;strong&gt;118 solutions&lt;/strong&gt; (et je sais qu&amp;rsquo;il en manque certainement), avec pour chacune :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Des liens à jour&lt;/li&gt;
&lt;li&gt;Le statut du projet&lt;/li&gt;
&lt;li&gt;Des références externes (tutoriels, retours d&amp;rsquo;expérience&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="essayez-commentez-partagez"&gt;Essayez, commentez, partagez
&lt;/h2&gt;&lt;p&gt;Rendez-vous sur &lt;a class="link" href="https://zwindler.github.io/101-ways-to-deploy-kubernetes/" target="_blank" rel="noopener"
&gt;zwindler.github.io/101-ways-to-deploy-kubernetes&lt;/a&gt; pour explorer toutes ces solutions !&lt;/p&gt;
&lt;p&gt;OK, c&amp;rsquo;est un infâme &amp;ldquo;call to action&amp;rdquo; comme on en voit sur tous les réseaux sociaux. Soit.&lt;/p&gt;
&lt;p&gt;Cependant, je ne peux pas savoir si c&amp;rsquo;est utile (ou non) si vous ne le faites pas. Je peux le laisser en l&amp;rsquo;état (ça n&amp;rsquo;est pas génant en soit, j&amp;rsquo;ai plein d&amp;rsquo;autres side projects qui n&amp;rsquo;attendent que mon temps libre) ou le faire vivre, si ça vous plait / sert.&lt;/p&gt;
&lt;p&gt;Et si vous trouvez ce projet utile, n&amp;rsquo;hésitez pas à :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Star&lt;/strong&gt; le projet sur &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes" target="_blank" rel="noopener"
&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partager&lt;/strong&gt; avec vos collègues de la communauté Cloud Native&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contribuer&lt;/strong&gt; en ajoutant des outils manquants ou en corrigeant des erreurs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Merci d&amp;rsquo;avance ! 🙏&lt;/p&gt;</description></item><item><title>101 façons de déployer Kubernetes (v2) : maintenant sur Github avec plus de méthodes, plus de détails, plus de tout</title><link>https://blog.zwindler.fr/2026/01/04/101-facons-de-deployer-kubernetes-v2/</link><pubDate>Sun, 04 Jan 2026 10:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/01/04/101-facons-de-deployer-kubernetes-v2/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/01/101-kubernetes-v2-screenshot.webp" alt="Featured image of post 101 façons de déployer Kubernetes (v2) : maintenant sur Github avec plus de méthodes, plus de détails, plus de tout" /&gt;&lt;h2 id="une-nouvelle-version-une-nouvelle-maison"&gt;Une nouvelle version, une nouvelle maison
&lt;/h2&gt;&lt;p&gt;Il y a quelques mois, je vous présentais mon &lt;a class="link" href="https://blog.zwindler.fr/2025/11/02/93-facons-de-deployer-kubernetes/" &gt;tableau recensant 93 façons différentes de déployer Kubernetes&lt;/a&gt;, sur Google Sheets.&lt;/p&gt;
&lt;p&gt;À la suite de la remarque de Ludovic Piot qui aurait aimé contribuer un ou deux outils manquants, j&amp;rsquo;ai pris un peu (beaucoup, en vrai) de temps pendant ces vacances pour &lt;strong&gt;déménager tout ça sur Github&lt;/strong&gt; : &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes" target="_blank" rel="noopener"
&gt;101-ways-to-deploy-kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/01/101-kubernetes-v2-screenshot2.avif"
loading="lazy"
alt="Capture d’écran du dépôt GitHub 101 ways to deploy Kubernetes v2"
&gt;&lt;/p&gt;
&lt;p&gt;Pourquoi sur un dépôt &lt;code&gt;git&lt;/code&gt; plutôt que sur un Google Sheet comme au début ? Parce que &lt;strong&gt;ça me permet facilement de rendre ce projet vraiment collaboratif&lt;/strong&gt;, notamment via des PRs (et surtout leur validation ou non).&lt;/p&gt;
&lt;p&gt;Google Sheets, c&amp;rsquo;était bien pour commencer, quand c&amp;rsquo;était un outil perso pour m&amp;rsquo;aider à écrire mon livre, mais pour la collaboration, c&amp;rsquo;était pas viable.&lt;/p&gt;
&lt;h2 id="quoi-de-neuf-dans-cette-v2-"&gt;Quoi de neuf dans cette v2 ?
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Contributions facilitées&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le projet dispose maintenant d&amp;rsquo;un &lt;strong&gt;&lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener"
&gt;CONTRIBUTING.md&lt;/a&gt;&lt;/strong&gt; qui explique comment participer.&lt;/p&gt;
&lt;p&gt;Vous connaissez une solution qui n&amp;rsquo;est pas listée ? Vous avez repéré une erreur ? Un lien cassé ? Il vous suffit de faire une Pull Request !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;De nombreuses nouvelles méthodes (j&amp;rsquo;ai pas compté mais probablement une douzaine)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le projet est passé de 93 à &lt;strong&gt;plus de 100 méthodes&lt;/strong&gt; ! J&amp;rsquo;ai continué mes explorations et ajouté une douzaine de nouvelles solutions, dont certaines que vous m&amp;rsquo;aviez suggérées.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Informations sur les licences&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai enrichi le tableau avec &lt;strong&gt;des détails sur les licences&lt;/strong&gt; de chaque projet. C&amp;rsquo;est particulièrement important pour identifier d&amp;rsquo;un coup d&amp;rsquo;oeil si un produit est réellement open source ou si c&amp;rsquo;est une solution à licence propriétaire ou commerciale.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/01/101-kubernetes-v2-screenshot.avif"
loading="lazy"
alt="Tableau des méthodes de déploiement Kubernetes avec informations de licence"
&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai eu le débat avec Ludovic justement, qui voulait comprendre pourquoi je n&amp;rsquo;avais pas listé &amp;ldquo;MKE (Mirantis Kubernetes Engine)&amp;rdquo;. Je lui avais répondu à l&amp;rsquo;époque que c&amp;rsquo;était parce que je ne pouvais pas avoir accès à une version d&amp;rsquo;essai en tant que &amp;ldquo;random des Internets&amp;rdquo; sans passer par un commercial, mais l&amp;rsquo;argument n&amp;rsquo;était pas hyper solide.&lt;/p&gt;
&lt;p&gt;Pour trouver une règle &amp;ldquo;unique&amp;rdquo; à indiquer dans le &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener"
&gt;CONTRIBUTING.md&lt;/a&gt;, j&amp;rsquo;ai donc réintégré une partie des solutions que j&amp;rsquo;avais &amp;ldquo;censurées&amp;rdquo;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While the heart of the cloud native ecosystem is open source, both open source and closed source (proprietary) tools are accepted in this list. What matters is whether the tool helps deploy Kubernetes clusters, not its licensing model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nombreuses références externes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai fait un &lt;strong&gt;important travail&lt;/strong&gt; sur la partie &amp;ldquo;références externes&amp;rdquo;. L&amp;rsquo;idée du répo, au delà de juste fournir une liste à la prévert, est de référencer des articles de tiers indiquant &lt;strong&gt;comment&lt;/strong&gt; mettre en place ces solutions et bénéficier des retours d&amp;rsquo;expérience de la communauté.&lt;/p&gt;
&lt;p&gt;Dans l&amp;rsquo;idée de rendre le projet plus international (ça sera tout aussi utile aux anglophones qu&amp;rsquo;aux petits frenchies de ma communauté), j&amp;rsquo;ai récupéré en priorité des liens en anglais, pour le plus de solutions possibles de cette liste. Il en reste encore qui n&amp;rsquo;en ont pas, mais ça progresse.&lt;/p&gt;
&lt;p&gt;Note importante : au-delà de la documentation officielle (qui existe très souvent pour la grande majorité des projets), j&amp;rsquo;ai en priorité voulu recenser :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Des tutoriels de qualité de la communauté&lt;/li&gt;
&lt;li&gt;Des articles de blog détaillés&lt;/li&gt;
&lt;li&gt;Des retours d&amp;rsquo;expérience concrets&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="un-projet-toujours-sous-cc-by-sa-40"&gt;Un projet toujours sous CC BY-SA 4.0
&lt;/h2&gt;&lt;p&gt;Le contenu reste sous licence &lt;a class="link" href="https://creativecommons.org/licenses/by-sa/4.0/deed.fr" target="_blank" rel="noopener"
&gt;CC BY-SA 4.0 (Attribution - Share Alike)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cela signifie que vous êtes libre de :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Partager&lt;/strong&gt; : copier et redistribuer le contenu&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapter&lt;/strong&gt; : remixer, transformer et créer à partir de ce matériel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sous les conditions suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Attribution&lt;/strong&gt; : vous devez créditer le projet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partage dans les mêmes conditions&lt;/strong&gt; : si vous adaptez le contenu, vous devez le distribuer sous la même licence&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="comment-contribuer-"&gt;Comment contribuer ?
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est simple :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Forkez le dépôt &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes" target="_blank" rel="noopener"
&gt;101-ways-to-deploy-kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ajoutez ou modifiez le contenu (en suivant le format du tableau)&lt;/li&gt;
&lt;li&gt;Soumettez une Pull Request&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lisez le &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener"
&gt;CONTRIBUTING.md&lt;/a&gt; pour plus de détails sur le processus et les bonnes pratiques.&lt;/p&gt;
&lt;p&gt;Toutes les contributions sont les bienvenues : nouvelles entrées, corrections, enrichissements, suggestions&amp;hellip;&lt;/p&gt;
&lt;h2 id="et-la-suite-"&gt;Et la suite ?
&lt;/h2&gt;&lt;p&gt;Le projet va continuer à évoluer au fil des découvertes et de vos contributions.&lt;/p&gt;
&lt;p&gt;Je continue aussi à explorer de nouvelles solutions et à enrichir les informations existantes. Et qui sait, peut-être qu&amp;rsquo;on dépassera les 150 méthodes d&amp;rsquo;ici la fin de l&amp;rsquo;année ? 😄&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est le moment où je fais mon influenceur et que je vous demande de ne pas hésiter à :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Star&lt;/strong&gt; le projet sur Github si vous le trouvez utile ⭐⭐⭐&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contribuer&lt;/strong&gt; en ajoutant vos découvertes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partager&lt;/strong&gt; autour de vous si vous le trouvez utile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rendez-vous sur &lt;a class="link" href="https://github.com/zwindler/101-ways-to-deploy-kubernetes" target="_blank" rel="noopener"
&gt;github.com/zwindler/101-ways-to-deploy-kubernetes&lt;/a&gt; !&lt;/p&gt;</description></item><item><title>93 façons de déployer Kubernetes : j'ai recensé (presque) toutes les méthodes existantes</title><link>https://blog.zwindler.fr/2025/11/02/93-facons-de-deployer-kubernetes/</link><pubDate>Sun, 02 Nov 2025 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2025/11/02/93-facons-de-deployer-kubernetes/</guid><description>&lt;img src="https://blog.zwindler.fr/2025/11/93-kubernetes-screenshot.webp" alt="Featured image of post 93 façons de déployer Kubernetes : j'ai recensé (presque) toutes les méthodes existantes" /&gt;&lt;h2 id="un-projet-documentaire-un-peu-fou"&gt;Un projet documentaire un peu fou
&lt;/h2&gt;&lt;p&gt;Quand j&amp;rsquo;ai commencé à écrire mon livre &lt;a class="link" href="https://www.editions-eyrolles.com/livre/kubernetes" target="_blank" rel="noopener"
&gt;&amp;ldquo;Kubernetes : 50 solutions pour les postes de développement et les clusters de production&amp;rdquo;&lt;/a&gt;, je me suis rapidement rendu compte d&amp;rsquo;un problème : &lt;strong&gt;il existe une infinité de façons de déployer Kubernetes&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Bon, pas &lt;em&gt;littéralement&lt;/em&gt; une infinité, mais quand même&amp;hellip; beaucoup. Trop ?&lt;/p&gt;
&lt;p&gt;Pour structurer mon livre et choisir quelles solutions j&amp;rsquo;allais couvrir, j&amp;rsquo;ai fait ce que tout bon nerd ferait : &lt;strong&gt;j&amp;rsquo;ai créé un tableau&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Un très grand tableau.&lt;/p&gt;
&lt;p&gt;Un &lt;strong&gt;Google Sheet&lt;/strong&gt; qui recense actuellement &lt;strong&gt;93 méthodes différentes&lt;/strong&gt; pour déployer Kubernetes. Comme je n&amp;rsquo;aime pas &amp;ldquo;gâcher&amp;rdquo;, je le partage avec vous aujourd&amp;rsquo;hui &lt;a class="link" href="https://creativecommons.org/licenses/by-sa/4.0/deed.fr" target="_blank" rel="noopener"
&gt;en CC BY-SA 4.0 (Attribution - Share Alike)&lt;/a&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.google.com/spreadsheets/d/1zjOLU8MblsN8VPwUyHNDFbBQ7EihHM2joD2Q9Tv2DiI/edit?usp=sharing" target="_blank" rel="noopener"
&gt;93 façons de déployer Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2025/11/93-kubernetes-screenshot.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="que-contient-ce-tableau-"&gt;Que contient ce tableau ?
&lt;/h2&gt;&lt;p&gt;Le tableau est structuré avec plusieurs colonnes pour vous aider à naviguer dans cette jungle :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nom du produit (et éditeur quand c&amp;rsquo;est intéressant)&lt;/li&gt;
&lt;li&gt;URL du produit : j&amp;rsquo;ai essayé de restreindre aux produits open source (ou aux services managés &lt;strong&gt;publics&lt;/strong&gt;) même s&amp;rsquo;il y a quelques exceptions&lt;/li&gt;
&lt;li&gt;Type de solution (j&amp;rsquo;y reviendrai)&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Basé sur&amp;rdquo; : là, c&amp;rsquo;est un truc assez rigolo&amp;hellip; beaucoup de projets sont des surcouches de kubeadm, k3s ou k0s. Tous ne le disent pas ouvertement, et je m&amp;rsquo;en suis rendu compte en les essayant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et peut-être un peu moins intéressant (peut-être que ça disparaîtra)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Est-ce que j&amp;rsquo;en parle dans mon livre ?&lt;/li&gt;
&lt;li&gt;Est-ce que j&amp;rsquo;en parle sur mon blog ?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="les-différentes-catégories-doutils"&gt;Les différentes catégories d&amp;rsquo;outils
&lt;/h2&gt;&lt;p&gt;Pour structurer d&amp;rsquo;abord ma pensée, et ensuite mon livre, j&amp;rsquo;ai essayé de classer ces méthodes en catégories.&lt;/p&gt;
&lt;p&gt;Certaines sont assez évidentes (une offre managée, on voit tout de suite de quoi il s&amp;rsquo;agit), d&amp;rsquo;autres, un peu plus personnelles (et donc discutables).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes sur desktop (Local Development)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Les outils pour développer en local sur votre machine. On parle ici des Minikube, kind et autres Docker Desktop&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure as Code (IaC)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Les outils qui vous permettent de décrire le déploiement de Kubernetes via du code (opentofu, crossplane, pulumi&amp;hellip;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes in Kubernetes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Parce que pourquoi faire simple quand on peut faire&amp;hellip; recursif ? 🤯. Ca se limite pour l&amp;rsquo;instant à vCluster et k3k.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OS spécialisés&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Des systèmes d&amp;rsquo;exploitation conçus spécifiquement pour faire tourner Kubernetes. Je pense bien sûr à Talos Linux, mais pas que ;-P.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes managés (les offres cloud clés en main)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pas besoin de faire un dessin, on pense direct à la triplette EKS / AKS / GKE, mais aussi aux solutions françaises (OVHcloud Managed Kubernetes, bientôt Clever Cloud :smirk:)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plateformes de management de clusters&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Là, c&amp;rsquo;est une catégorie un peu à part, qui vont nous permettre de gérer plein de clusters Kubernetes et même de générer de nouveaux clusters gérés par des clusters&amp;hellip; Souvent des bonnes usines à gaz comme Gardener ou pire Kubermatic Kubernetes Platform. On a quand même des trucs un peu plus funs comme Kamaji.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outils d&amp;rsquo;automatisation pour self-hosted&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Les solutions qui automatisent le déploiement sur vos propres machines, comme kubeadm, k3s et k0s (la triplette, base d&amp;rsquo;à peu près 50% des autres solutions du marché).&lt;/p&gt;
&lt;h2 id="la-révélation--tout-le-monde-copie-sur-son-voisin"&gt;La révélation : tout le monde copie sur son voisin
&lt;/h2&gt;&lt;p&gt;En remplissant ce tableau, j&amp;rsquo;ai découvert quelque chose de marrant : &lt;strong&gt;une grande majorité des outils ne réinventent pas la roue&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Beaucoup de projets sont en fait des &lt;strong&gt;surcouches&lt;/strong&gt; ou des &lt;strong&gt;wrappers&lt;/strong&gt; autour de trois solutions de base que je cite juste avant (kubeadm, k3s et k0s). Et parfois, on a &lt;strong&gt;aussi&lt;/strong&gt; des surcouches de solutions un peu plus confidentielles.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;info n&amp;rsquo;est pas toujours disponible, j&amp;rsquo;ai parfois découvert ça au détour d&amp;rsquo;un blogpost, ou même en allant fouiller les entrailles de la solution.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est typiquement le genre de colonne intéressante pour bien se rendre compte qu&amp;rsquo;au delà de l&amp;rsquo;apparente diversité de ces solutions de déploiement, il y a en fait un gros standard et quelques variations.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;espère réussir à dénicher plus d&amp;rsquo;indices similaires pour remplir encore un peu plus cette colonne :).&lt;/p&gt;
&lt;h2 id="un-document-vivant"&gt;Un document vivant
&lt;/h2&gt;&lt;p&gt;Ce tableau n&amp;rsquo;est pas figé. Le nombre d&amp;rsquo;outils évolue régulièrement (j&amp;rsquo;en découvre de nouveaux presque chaque semaine).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Si vous connaissez une méthode qui n&amp;rsquo;est pas listée&lt;/strong&gt;, n&amp;rsquo;hésitez pas à commenter sur les réseaux.&lt;/p&gt;
&lt;p&gt;Note : je rappelle que je vise en priorité les solutions &lt;strong&gt;open source&lt;/strong&gt; ou services managés &lt;strong&gt;publics&lt;/strong&gt; (je viens de virer Mirantis Kubernetes Engine pour cette raison).&lt;/p&gt;
&lt;h2 id="et-sinon-il-me-reste-quoi-à-tester-"&gt;Et sinon, il me reste quoi à tester ?
&lt;/h2&gt;&lt;p&gt;J&amp;rsquo;ai déjà teasé sur les réseaux sociaux fréquentables, dans la liste des trucs que je n&amp;rsquo;ai pas encore testé mais qui pourraient me motiver, il y a :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kamaji.clastix.io" target="_blank" rel="noopener"
&gt;kamaji&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/portainer/kubesolo" target="_blank" rel="noopener"
&gt;kubesolo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubeclipper/kubeclipper" target="_blank" rel="noopener"
&gt;kubeclipper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://tarook.cloud/en" target="_blank" rel="noopener"
&gt;tarook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ClusterConfiguration : introduction aux APIs de kubeadm pour installer vos clusters</title><link>https://blog.zwindler.fr/2023/12/17/kubeadmcfg-introduction-api-kubeadm/</link><pubDate>Sun, 17 Dec 2023 12:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/12/17/kubeadmcfg-introduction-api-kubeadm/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/12/bare-metal-kuberetes-2.webp" alt="Featured image of post ClusterConfiguration : introduction aux APIs de kubeadm pour installer vos clusters" /&gt;&lt;h2 id="créer-des-clusters-kubernetes-avec-kubeadm-mais-sans-cli-à-rallonge"&gt;Créer des clusters Kubernetes avec &lt;code&gt;kubeadm&lt;/code&gt;, mais sans CLI à rallonge
&lt;/h2&gt;&lt;p&gt;Un des premiers articles que j&amp;rsquo;ai écrits sur &lt;a class="link" href="https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/" &gt;Kubernetes était l&amp;rsquo;installation d&amp;rsquo;un cluster avec &lt;code&gt;kubeadm&lt;/code&gt;&lt;/a&gt;. A l&amp;rsquo;époque, j&amp;rsquo;avais testé avec les options de bases et ça marchait très très bien déjà.&lt;/p&gt;
&lt;p&gt;Mais quand on commence à avoir des clusters un peu plus proches de la production, on se retrouve rapidement à rajouter plein d&amp;rsquo;options dans la CLI.&lt;/p&gt;
&lt;p&gt;Pire, à un certain niveau de complexité, certaines options ne fonctionnent pas ensemble !&lt;/p&gt;
&lt;p&gt;Note: c&amp;rsquo;est ce qui m&amp;rsquo;est arrivé quand j&amp;rsquo;ai essayé d&amp;rsquo;automatiser l&amp;rsquo;installation de &lt;code&gt;kubeadm&lt;/code&gt; avec Ansible. On pourra débattre de l&amp;rsquo;intérêt d&amp;rsquo;automatiser une install kubeadm avec Ansible alors que Kubespray existe, &lt;a class="link" href="https://blog.zwindler.fr/2017/12/05/installer-kubernetes-kubespray-ansible/" &gt;cf cet autre article que j&amp;rsquo;ai écrit en 2017&lt;/a&gt; mais c&amp;rsquo;est au-delà du scope de cet article&amp;hellip;&lt;/p&gt;
&lt;h2 id="pour-faire-propre-arrêtez-de-passer-la-terre-entière-en-arguments"&gt;Pour faire propre, arrêtez de passer la terre entière en arguments
&lt;/h2&gt;&lt;p&gt;Clairement, à partir de 5 ou 6 options, c&amp;rsquo;est le moment de se demander s&amp;rsquo;il ne serait pas préférable d&amp;rsquo;utiliser un fichier de configuration pour gérer nos clusters.&lt;/p&gt;
&lt;p&gt;Et ça tombe bien, kubeadm dispose d&amp;rsquo;une API (plusieurs en fait), on va donc pouvoir écrire du YAML &lt;strong&gt;avant&lt;/strong&gt; même d&amp;rsquo;avoir notre cluster Kubernetes opérationnel. YAY ! (font les YAML engineers)&lt;/p&gt;
&lt;h2 id="concrètement-comment-ça-se-présente-"&gt;Concrètement comment ça se présente ?
&lt;/h2&gt;&lt;p&gt;Plutôt que de passer tous nos arguments dans notre commande &lt;code&gt;kubeadm&lt;/code&gt;, on va remplir un fichier &lt;code&gt;kubeadmcfg.yaml&lt;/code&gt; qui va nous servir de configuration. En vrai, on va même en avoir plusieurs, puisque les nodes n&amp;rsquo;ont pas tous le même rôle dans notre workflow de création de cluster.&lt;/p&gt;
&lt;p&gt;Le premier fichier sera un fichier qui contiendra la &lt;strong&gt;ClusterConfiguration&lt;/strong&gt; (cf &lt;a class="link" href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/control-plane-flags/#customizing-the-control-plane-with-flags-in-clusterconfiguration" target="_blank" rel="noopener"
&gt;doc officielle&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;A noter, vous pouvez récupérer le fichier des valeurs par défaut avec la commande :&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;$ kubeadm config print init-defaults&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;kubeadm.k8s.io/v1beta3&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;InitConfiguration&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;bootstrapTokens&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="nt"&gt;groups&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;system:bootstrappers:kubeadm:default-node-token&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;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;abcdef.0123456789abcdef&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;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;24h0m0s&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;usages&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;signing&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;authentication&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;localAPIEndpoint&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;advertiseAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;@&lt;span class="l"&gt;IP&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;bindPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6443&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;nodeRegistration&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;criSocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unix:///var/run/containerd/containerd.sock&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;IfNotPresent&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;node&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;taints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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="nn"&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;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;kubeadm.k8s.io/v1beta3&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;ClusterConfiguration&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;apiServer&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;timeoutForControlPlane&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;4m0s&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;certificatesDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/etc/kubernetes/pki&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;clusterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kubernetes&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;controllerManager&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="nt"&gt;dns&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="nt"&gt;etcd&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;local&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;dataDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/var/lib/etcd&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;imageRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;registry.k8s.io&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;kubernetesVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.28.0&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;networking&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;dnsDomain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cluster.local&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;serviceSubnet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10.96.0.0&lt;/span&gt;&lt;span class="l"&gt;/12&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;scheduler&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A partir de là, on va pouvoir customiser notre control plane, via des sections correspondant à chaque composant du control plane :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;apiServer&lt;/li&gt;
&lt;li&gt;controllerManager&lt;/li&gt;
&lt;li&gt;scheduler&lt;/li&gt;
&lt;li&gt;etcd&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-quoi-ça-peut-bien-servir-"&gt;A quoi ça peut bien servir ?
&lt;/h2&gt;&lt;p&gt;Forcément les possibilités sont très nombreuses et je ne vais pas toutes les lister. Mais je vais vous donner quelques exemples.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;exemple le plus parlant est évidemment l&amp;rsquo;ajout d&amp;rsquo;arguments aux différents composants. Ici, j&amp;rsquo;ajoute l&amp;rsquo;authentification OIDC au cluster et mes feature gates pour activer les APIs alpha :&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;kubeadm.k8s.io/v1beta3&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;ClusterConfiguration&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;apiServer&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;extraArgs&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;feature-gates&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 class="l"&gt;kube_feature_gates }}&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;oidc-issuer-url&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 class="l"&gt;kube_oidc_issuer_url }}&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;oidc-client-id&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_oidc_client_id }}&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;oidc-username-claim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;email&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;oidc-groups-claim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;groups&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;Si vous avez plusieurs virtual IPs qui permettent de vous connecter à votre cluster Kubernetes, il sera probablement nécessaire de supporter plusieurs certSANs pour la partie TLS :&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;kubeadm.k8s.io/v1beta3&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;ClusterConfiguration&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;apiServer&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;certSANs&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="s2"&gt;&amp;#34;{{ control_plane_endpoint_ip }}&amp;#34;&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="s2"&gt;&amp;#34;{{ control_plane_endpoint_ip_for_humans }}&amp;#34;&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;Dans le cas où vos machines ont plusieurs IPs, il pourra être nécessaire d&amp;rsquo;indiquer au cluster les bonnes IPs pour le contacter. Petit piège, il faut modifier dans une autre API que j&amp;rsquo;ai omis pour l&amp;rsquo;instant : &lt;strong&gt;InitConfiguration&lt;/strong&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="nn"&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;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;kubeadm.k8s.io/v1beta3&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;InitConfiguration&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;localAPIEndpoint&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;advertiseAddress&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 class="l"&gt;app_ip }}&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;bindPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6443&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;Si vous avez suivi &lt;a class="link" href="https://blog.zwindler.fr/2023/11/30/kubernetes-error-etcdserver-mvcc-database-space-exceeded/" &gt;mon précédent article sur mon petit souci de prod avec etcd qui était spammé par Kyverno&lt;/a&gt;, vous saurez qu&amp;rsquo;il faut tuner la base etcd. Comme ceci par exemple :&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;kubeadm.k8s.io/v1beta3&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;ClusterConfiguration&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;etcd&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;local&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;extraArgs&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;quota-backend-bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;5368709120&amp;#34;&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;auto-compaction-retention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1&amp;#34;&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;auto-compaction-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;periodic&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;Et de mon côté, j&amp;rsquo;ai besoin de changer le nom de domaine des services Kubernetes. Je le fais comme ceci :&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;kubeadm.k8s.io/v1beta3&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;ClusterConfiguration&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;networking&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;dnsDomain&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 class="l"&gt;kube_dns_domain }}&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;Une fois que c&amp;rsquo;est bien configuré comme on en a envie :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/usr/bin/kubeadm init --config=/etc/kubernetes/kubeadmcfg.yaml --upload-certs --skip-certificate-key-print
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="et-ensuite-"&gt;Et ensuite ?
&lt;/h2&gt;&lt;p&gt;La &lt;strong&gt;ClusterConfiguration&lt;/strong&gt;, c&amp;rsquo;est cool, mais il existe d&amp;rsquo;autres API utiles avec kubeadm, je le disais plus haut.&lt;/p&gt;
&lt;p&gt;Lorsqu&amp;rsquo;on va ajouter des nodes au control plane, on ne va pas pouvoir réutiliser la &lt;strong&gt;ClusterConfiguration&lt;/strong&gt; et l&amp;rsquo;&lt;strong&gt;InitConfiguration&lt;/strong&gt;, car elles servent pour TOUT le cluster et sont unique. On les a déjà configurées quand on a fait l&amp;rsquo;init du premier node de control plane.&lt;/p&gt;
&lt;p&gt;On va donc utiliser la &lt;strong&gt;JoinConfiguration&lt;/strong&gt;, qui nous permet là aussi de définir des trucs importants comme :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;localAPIEndpoint.advertiseAddress si on a plusieurs IPs sur la machine (exemple ci dessus).&lt;/li&gt;
&lt;li&gt;discovery.bootstrapToken.token (et caCertHashes) qui va permettre de faciliter l&amp;rsquo;automatisation du join des nodes&lt;/li&gt;
&lt;/ul&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="nn"&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;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;kubeadm.k8s.io/v1beta3&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;JoinConfiguration&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;caCertPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/etc/kubernetes/pki/ca.crt&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;discovery&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;bootstrapToken&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;apiServerEndpoint&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 class="l"&gt;control_plane_endpoint }}&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;token&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 class="l"&gt;kubeadm_token }}&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;caCertHashes&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;sha256:{{ kubeadm_cacert_hash }}&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;unsafeSkipCAVerification&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;nodeRegistration&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="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ansible_nodename }}&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;controlPlane&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;certificateKey&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 class="l"&gt;kubeadm_certificate_key }}&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;localAPIEndpoint&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;advertiseAddress&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 class="l"&gt;app_ip }}&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;bindPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6443&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;% endif %}&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;Une fois que ce fichier est créé sur la machine du control plane qui va rejoindre la première, on peut lancer la commande &lt;code&gt;kubeadm join&lt;/code&gt; qui devrait bien se passer ;-).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubeadm join {{ control_plane_endpoint_ip }} --config /etc/kubernetes/kubeadmcfg.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Utiliser les fichiers de configuration de &lt;code&gt;kubeadm&lt;/code&gt; n&amp;rsquo;est pas trivial car assez mal documenté (je trouve, les docs sont éclatés entre plusieurs pages et les exemples pas parlants dans mon cas).&lt;/p&gt;
&lt;p&gt;Je ne vais pas mentir, je me suis arraché les cheveux et j&amp;rsquo;ai demandé de l&amp;rsquo;aide plusieurs fois sur X.&lt;/p&gt;
&lt;p&gt;Bien sûr, vous pouvez aller potasser la doc officielle &lt;a class="link" href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/control-plane-flags/#customizing-the-control-plane-with-flags-in-clusterconfiguration" target="_blank" rel="noopener"
&gt;Customizing components with the kubeadm API&lt;/a&gt; et &lt;a class="link" href="https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/" target="_blank" rel="noopener"
&gt;kubeadm Configuration (v1beta3)&lt;/a&gt; mais j&amp;rsquo;ai quand même eu du mal à comprendre COMMENT l&amp;rsquo;utiliser, la première fois.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;espère que cet article pourra aider à mieux comprendre comment les différentes API s&amp;rsquo;articulent entre elles et comment les utiliser.&lt;/p&gt;</description></item><item><title>Kubernetes - Error from server: etcdserver: mvcc: database space exceeded</title><link>https://blog.zwindler.fr/2023/11/30/kubernetes-error-etcdserver-mvcc-database-space-exceeded/</link><pubDate>Thu, 30 Nov 2023 12:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2023/11/30/kubernetes-error-etcdserver-mvcc-database-space-exceeded/</guid><description>&lt;img src="https://blog.zwindler.fr/2023/11/bear-metal-kubernetes.webp" alt="Featured image of post Kubernetes - Error from server: etcdserver: mvcc: database space exceeded" /&gt;&lt;h2 id="petite-panique-en-prod-"&gt;Petite panique en prod !
&lt;/h2&gt;&lt;p&gt;Ca ne sera une surprise pour personne, j&amp;rsquo;administre des clusters Kubernetes en production (et aussi pour le fun, oui je suis bizarre). Et des fois, quand on a des workloads un peu inhabituels, on a des petites surprises rigolotes.&lt;/p&gt;
&lt;p&gt;Pour vous situer un peu le contexte, j&amp;rsquo;ai un cluster &amp;ldquo;on-prem&amp;rdquo; d&amp;rsquo;une grosse soixantaine de nodes physiques baremetal, sur lesquels je fais tourner (entre autres) des jobs éphémères très courts.&lt;/p&gt;
&lt;p&gt;Ca génère beaucoup de trafic sur la base de données etcd (beaucoup d&amp;rsquo;événement de création / destruction de pods) et ça nous a déjà posé des problèmes dans le passé (notamment pour tout ce qui est collecte de métriques, on effondre prometheus même avec beaucoup de RAM).&lt;/p&gt;
&lt;p&gt;Mais ça tenait.&lt;/p&gt;
&lt;h2 id="et-là-cest-le-drame"&gt;Et là, c&amp;rsquo;est le drame&amp;hellip;
&lt;/h2&gt;&lt;p&gt;Depuis peu, j&amp;rsquo;ai aussi commencé à ajouter plein de nouvelles &amp;ldquo;policies&amp;rdquo; sur Kyverno (pour ceux qui ne connaissent pas j&amp;rsquo;ai fait &lt;a class="link" href="https://blog.zwindler.fr/2022/08/01/vos-politiques-de-conformite-sur-kubernetes-avec-kyverno/" &gt;un article sur le sujet&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Et j&amp;rsquo;ai découvert un peu à mes dépens que Kyverno ajoute BEAUCOUP de pression sur etcd, en créant énormément d&amp;rsquo;événements (évaluation des policies pour chaque objet Kubernetes, et comme j&amp;rsquo;en ai beaucoup&amp;hellip;).&lt;/p&gt;
&lt;p&gt;A un tel point, qu&amp;rsquo;à un moment donnée, toutes les opérations d&amp;rsquo;écriture sur l&amp;rsquo;API server renvoyaient l&amp;rsquo;erreur suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Error: etcdserver: mvcc: database space exceeded
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/11/ah.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Ca pue la DB pleine 😬😬😬. Pourtant, aucune alerte sur mes espaces disques !? Bizarre.&lt;/p&gt;
&lt;p&gt;De toute façon, pour ne rien arranger, les pods etcd n&amp;rsquo;étant plus &lt;em&gt;healthy&lt;/em&gt; puisque la base est supposément pleine, l&amp;rsquo;API server crashe au bout d&amp;rsquo;un moment et je n&amp;rsquo;avais plus la main sur rien pour debug.&lt;/p&gt;
&lt;p&gt;PANIK!&lt;/p&gt;
&lt;h2 id="remettre-les-gaz"&gt;Remettre les gaz
&lt;/h2&gt;&lt;p&gt;Petite &amp;ldquo;astuce du pro&amp;rdquo; quand votre control plane Kubernetes est dans le mal, à un moment plus rien ne marche car les pods etcd / apiserver se mettent en &lt;code&gt;crashloop backoff&lt;/code&gt;, étant alternativement down et pas relancé à cause du &amp;ldquo;backoff&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Un bon moyen de contourner ça, quand vous avez la main sur le control plane (donc pas sur du managé, mais de toute façon c&amp;rsquo;est pas votre problème), c&amp;rsquo;est de restart le &lt;code&gt;kubelet&lt;/code&gt; sur tous les nodes du control plane en même temps.&lt;/p&gt;
&lt;p&gt;Pourquoi ? Parce que le restart du &lt;code&gt;kubelet&lt;/code&gt; remet à 0 tous les compteurs et que vos pods ne sont donc pas dans la phase de &amp;ldquo;backoff&amp;rdquo; trop longtemps, ce qui évite les problématiques de &amp;ldquo;pas assez de membres etcd sont on, donc je me saborde&amp;rdquo; et ainsi de suite.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/11/crashloop_backoff_robusta.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://whyk8s.substack.com/p/why-crashloopbackoff-is-a-good-thing" target="_blank" rel="noopener"
&gt;Source du diagramme : Substack de Natan Yellin pour robusta.dev&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="nettoyer-la-base-etcd"&gt;Nettoyer la base etcd
&lt;/h2&gt;&lt;p&gt;Maintenant que c&amp;rsquo;est fait, j&amp;rsquo;avais suffisamment de pods etcd vivants (à défaut d&amp;rsquo;être opérationnel).&lt;/p&gt;
&lt;p&gt;Un petit coup d&amp;rsquo;oeil sur mes graphes dans Grafana me montrent qu&amp;rsquo;il s&amp;rsquo;est effectivement &amp;ldquo;passé un truc&amp;rdquo; quand j&amp;rsquo;ai activé les nouvelles policies Kyverno.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/11/etcd_stats.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Et &amp;ldquo;CÔM PAR HASAR&amp;rdquo;, ça marche plus quand la taille de 2 des 3 bases de données etcd atteint 2 Gio&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2023/11/etcd_full.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Une rapide recherche sur Internet me confirme que ma base est pleine, et que la solution à mon problème est de compacter puis défragmenter ma base.&lt;/p&gt;
&lt;p&gt;Comme tout est un peu cassé, on trouve des commandes bash à envoyer pour récupérer la dernière révision, compacter puis défragmenter la 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;&lt;span class="c1"&gt;# get latest revision&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;REVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;ETCDCTL_API&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; etcdctl --endpoints&lt;span class="o"&gt;=&lt;/span&gt;https://127.0.0.1:2379 --cacert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/ca.crt --cert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.crt --key&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.key endpoint status --write-out&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;json&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; egrep -o &lt;span class="s1"&gt;&amp;#39;&amp;#34;revision&amp;#34;:[0-9]*&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; egrep -o &lt;span class="s1"&gt;&amp;#39;[0-9].*&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&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;&lt;span class="c1"&gt;# compact&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ETCDCTL_API&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; etcdctl --endpoints&lt;span class="o"&gt;=&lt;/span&gt;https://127.0.0.1:2379 --cacert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/ca.crt --cert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.crt --key&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.key compact &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REVISION&lt;/span&gt;&lt;span class="si"&gt;}&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;&lt;span class="c1"&gt;# defrag&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ETCDCTL_API&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; etcdctl --endpoints&lt;span class="o"&gt;=&lt;/span&gt;https://127.0.0.1:2379 --cacert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/ca.crt --cert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.crt --key&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.key defrag
&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="c1"&gt;# SUPER MEGA IMPORTANT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ETCDCTL_API&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt; etcdctl --endpoints&lt;span class="o"&gt;=&lt;/span&gt;https://127.0.0.1:2379 --cacert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/ca.crt --cert&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.crt --key&lt;span class="o"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/peer.key alarm disarm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;J&amp;rsquo;ai rajouté &lt;em&gt;SUPER MEGA IMPORTANT&lt;/em&gt; sur la dernière instruction parce que, comme je suis un peu neuneu, je ne l&amp;rsquo;avais initialement pas lancée.&lt;/p&gt;
&lt;p&gt;Bah oui. L&amp;rsquo;idée de désarmer une alarme me paraissait complètement incongrue. L&amp;rsquo;alarme, je veux la garder. Non ?&lt;/p&gt;
&lt;p&gt;Mais en fait, &lt;strong&gt;c&amp;rsquo;est le comportement normal&lt;/strong&gt;. Le cluster etcd est prévu pour se bloquer, et &lt;strong&gt;ne plus rien faire&lt;/strong&gt;, tant que l&amp;rsquo;alarme n&amp;rsquo;a pas été désarmé, même si le souci d&amp;rsquo;espace est résolu&amp;hellip;&lt;/p&gt;
&lt;p&gt;Ok, je saurais la prochaine fois&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What does &amp;ldquo;mvcc: database space exceeded&amp;rdquo; mean and how do I fix it?
The multi-version concurrency control data model in etcd keeps an exact history of the keyspace. Without periodically compacting this history (e.g., by setting &amp;ndash;auto-compaction), etcd will eventually exhaust its storage space. If etcd runs low on storage space, it raises a space quota alarm to protect the cluster from further writes. So long as the alarm is raised, etcd responds to write requests with the error mvcc: database space exceeded.&lt;/p&gt;
&lt;p&gt;To recover from the low space quota alarm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compact etcd&amp;rsquo;s history.&lt;/li&gt;
&lt;li&gt;Defragment every etcd endpoint.
&lt;strong&gt;- Disarm the alarm.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;memberID:11111111111111111111111 alarm:NOSPACE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note : comme etcd ne revenait pas à la vie, j&amp;rsquo;ai balancé 50 fois la commande de compaction et ça me renvoyait une erreur qui me laissait penser qu&amp;rsquo;il y avait un autre problème. Et non, c&amp;rsquo;est bien que la compaction a été correctement faite ;-).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;error: code = OutOfRange desc = etcdserver: mvcc: required revision has been compacted&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Error: etcdserver: mvcc: required revision has been compacted
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="éviter-que-ça-se-reproduise"&gt;Éviter que ça se reproduise
&lt;/h2&gt;&lt;p&gt;OK, maintenant que la DB est restaurée, comment on s&amp;rsquo;assure que ça ne se reproduise pas ?&lt;/p&gt;
&lt;p&gt;En réalité, les paramètres par défaut de la base etcd (locale) de &lt;code&gt;kubeadm&lt;/code&gt; ne sont pas terribles.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;abord, on voit que j&amp;rsquo;ai tapé la limite des 2 Gio, limite par défaut dans etcd, alors que je n&amp;rsquo;ai que 60-70 nodes et quelques milliers de pods (ok, j&amp;rsquo;en crée des centaines de milliers par jour, but still).&lt;/p&gt;
&lt;p&gt;La documentation de Rancher conseille de monter cette limite à 5 Go (&lt;a class="link" href="https://ranchermanager.docs.rancher.com/how-to-guides/advanced-user-guides/tune-etcd-for-large-installs" target="_blank" rel="noopener"
&gt;Tuning etcd for Large Installations&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;On va donc modifier la valeur &lt;code&gt;quota-backend-bytes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ensuite, il faut activer la compaction automatique pour notre etcd. Comme j&amp;rsquo;utilise kubeadm et un fichier kubeadmcfg, je dois rajouter une section dans mon fichier pour tuner les paramètres&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;etcd&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;local&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;extraArgs&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;quota-backend-bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;5368709120&amp;#34;&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;auto-compaction-retention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1&amp;#34;&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;auto-compaction-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;periodic&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;Puis régénérer les manifests sur tous mes nodes de control plane (malheureusement, ça ne se fait pas tout seul, cf &lt;a class="link" href="https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-reconfigure/#reflecting-clusterconfiguration-changes-on-control-plane-nodes" target="_blank" rel="noopener"
&gt;la documentation officielle de Kubernetes - Reflecting ClusterConfiguration changes on control plane nodes&lt;/a&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;kubeadm init phase etcd &lt;span class="nb"&gt;local&lt;/span&gt; --config kubeadmcfg.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note: attention, les arguments attendus sont des strings, donc entourez bien toutes les valeurs numériques entre quotes :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;json: cannot unmarshal number into Go struct field LocalEtcd.etcd.local.extraArgs of type string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dernier point, s&amp;rsquo;il est possible de dire à etcd de réaliser la compaction tout seul comme un grand, a priori le defrag n&amp;rsquo;est pas automatique.&lt;/p&gt;
&lt;p&gt;La plupart du temps ça n&amp;rsquo;est peut-être pas gênant mais comme je suis extrêmement bourrin avec la création / destruction de pods, j&amp;rsquo;ai dû automatiser aussi cette partie &amp;ldquo;defrag&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;En attendant de trouver mieux, j&amp;rsquo;ai donc rajouté un cron&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-cron" data-lang="cron"&gt;00 */3 * * * /usr/bin/etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key --endpoints https://@IP:2379 defrag --cluster
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bon, c&amp;rsquo;était pas l&amp;rsquo;opération la plus fun de l&amp;rsquo;année, mais maintenant ça remarche 😂.&lt;/p&gt;
&lt;h2 id="sources-complémentaires"&gt;Sources complémentaires
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://etcd.io/blog/2023/how_to_debug_large_db_size_issue/" target="_blank" rel="noopener"
&gt;etcd blog - How to debug large db size issue?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://etcd.io/docs/v3.5/op-guide/maintenance/#auto-compaction" target="_blank" rel="noopener"
&gt;etcd documentation - History compaction: v3 API Key-Value Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://discuss.kubernetes.io/t/etcdserver-mvcc-database-space-exceeded/22806/3" target="_blank" rel="noopener"
&gt;Kubernetes Community forums - Etcdserver: mvcc: database space exceeded&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://grosser.it/2020/11/14/etcd-db-size-based-compaction/" target="_blank" rel="noopener"
&gt;grosser.it - ETCD db size based compaction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://gist.github.com/grosser/11d5d18c7aab8226788d190bb68479dc" target="_blank" rel="noopener"
&gt;gist grosser.it - script pour compaction / defrag automatique (un peu bourrin)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://platform9.com/kb/kubernetes/cluster-op-fail-etcdserver-mvcc-database-space-exceed" target="_blank" rel="noopener"
&gt;Platform9 KB - Cluster Operations Fail With Error - etcdserver: mvcc: database space exceeded &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Installer Kubernetes avec Kubespray (Ansible)</title><link>https://blog.zwindler.fr/2017/12/05/installer-kubernetes-kubespray-ansible/</link><pubDate>Tue, 05 Dec 2017 12:45:25 +0000</pubDate><guid>https://blog.zwindler.fr/2017/12/05/installer-kubernetes-kubespray-ansible/</guid><description>&lt;img src="https://blog.zwindler.fr/2017/12/kubespray.webp" alt="Featured image of post Installer Kubernetes avec Kubespray (Ansible)" /&gt;&lt;h2 id="kubeadm-quand-on-a-pas-ou-mal-accès-à-internet"&gt;Kubeadm quand on a pas ou mal accès à Internet
&lt;/h2&gt;&lt;p&gt;Rapidement pour resituer un peu le sujet, Kubernetes est un produit permettant de gérer des clusters de machines exécutant des containers en production. Un moyen simple d’installer cet outil complexe est d’utiliser l’outil &lt;strong&gt;kubeadm&lt;/strong&gt;, qui était jusqu’à il y a peu déconseillé pour la production (la documentation de la version 1.8 ne le mentionne pas mais le message apparaît toujours lors du &lt;code&gt;kubeadm init&lt;/code&gt;). Pour y voir plus clair, &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=kubernetes" &gt;vous pouvez lire les articles que j’ai écris à ce sujet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dans le cadre d’un déploiement d’un cluster Kubernetes on-premise, j’ai été assez ennuyé par le proxy. En théorie, on peut utiliser kubeadm derrière un proxy mais de nombreux utilisateurs remontent des difficultés de ce côté là (je ne suis pas le seul, ouf). Si vous voulez plus d’info à ce sujet j’ai mis un paragraphe en fin d’article.&lt;/p&gt;
&lt;h2 id="kubespray-à-la-rescousse"&gt;Kubespray à la rescousse
&lt;/h2&gt;&lt;p&gt;Depuis quelques mois, il existe une nouvelle manière de déployer Kubernetes, qui s’appelle &lt;strong&gt;Kubespray&lt;/strong&gt;. Et cerise sur le MacDo, ce méthode utilise Ansible (et vous savez comme &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ansible" &gt;je suis friand d’Ansible&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;J’ai donc décidé de tester et, vous vous en doutez puisque j’en fais un article, j’ai réussi à installer Kubernetes avec &lt;strong&gt;Kubespray&lt;/strong&gt; derrière mon proxy capricieux ;-).&lt;/p&gt;
&lt;p&gt;A noter, Kubespray ne se limite pas à déployer un Kubernetes &lt;em&gt;on premise&lt;/em&gt;, puisqu’il supporte aussi AWS et OpenStack via l’utilisation de scripts Terraform (outil qui fera l’objet d’un petit article à venir).&lt;/p&gt;
&lt;p&gt;Vous pouvez trouver la documentation sur les sites suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/setup/production-environment/tools/" target="_blank" rel="noopener"
&gt;La documentation sur le site de Kubernetes (attention pas toujours à jour)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes-sigs/kubespray/blob/master/docs/getting_started/getting-started.md" target="_blank" rel="noopener"
&gt;La documentation sur le Github du projet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installation-des-prérequis"&gt;Installation des prérequis
&lt;/h2&gt;&lt;p&gt;Un petit tour sur le Github nous donne les prérequis :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/11/requirement.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A ceci j’ajouterai le fait que Kubernetes demande maintenant que la swap soit désactivée sur tous les nœuds ! Si ce n’est pas déjà fait, il faut passer sur tous les serveurs et la désactiver (ne pas oublier &lt;strong&gt;la fstab aussi!&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubespray&lt;/strong&gt; nécessite l’installation des outils de développements sur la machine qui exécute le script Ansible, ainsi que Python 3. Sur les CentOS / RHEL 7, la version de Python est la 2.7, qui n’est donc pas compatible avec le script Python 3 qui génère le fichier d’inventaire pour le déploiement Ansible.&lt;/p&gt;
&lt;p&gt;En soit, ce n’est pas vital, mais ça facilite quand même le travail donc ça vaut le coup.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum -y install yum-utils
yum -y groupinstall development
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
yum -y install python36u python-netaddr
yum -y install python-pip
pip install --upgrade Jinja2
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="récupération-et-configuration-de-kubespray"&gt;Récupération et configuration de kubespray
&lt;/h2&gt;&lt;p&gt;Les sources de Kubespray sous sur Github, on les récupère&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;git clone https://github.com/kubernetes-incubator/kubespray
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Récupérer les dépendances pip&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 pip install -r requirements.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On copie le dossier inventory d’origine pour se faire sa propre conf :&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="nb"&gt;cd&lt;/span&gt; kubespray
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp -r inventory inventaire_kubernetes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On déclare les adresses IPs des futurs nœuds kubernetes puis on lance le script pour générer l’inventaire :&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="nb"&gt;declare&lt;/span&gt; -a &lt;span class="nv"&gt;IPS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;192.168.1.101 192.168.1.102 192.168.1.103 192.168.1.104&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;CONFIG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;inventaire_kubernetes/inventory.cfg python3.6 contrib/inventory_builder/inventory.py &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IPS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On peut regarder le contenu de modifier le fichier inventaire_kubernetes/inventory.cfg si nécessaire :&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;all]&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;master01 ansible_host=192.168.1.101 ip=192.168.1.101&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;worker01 ansible_host=192.168.1.102 ip=192.168.1.102&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;worker02 ansible_host=192.168.1.103 ip=192.168.1.103&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;worker03 ansible_host=192.168.1.104 ip=192.168.1.104&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;kube-master]&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;master01&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;worker01&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;kube-node]&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;master01&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;worker01&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;worker02&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;worker03&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;etcd]&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;master01&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;worker01&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;worker02&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;k8s-cluster:children]&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;kube-node&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;kube-master&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;calico-rr]&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="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;vault]&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;master01&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;worker01&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;worker02&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;Typiquement ici dans mon cas, n’ayant que 4 machines et ne souhaitant pas faire tourner de container sur les masters (bien que ce soit possible), j’ai prévu de ne mettre qu’un master et 3 workers.&lt;/p&gt;
&lt;p&gt;Du coup, les groupes sont à adapter en fonction des rôles de chacun. J’ai retiré worker01 du groupe &lt;strong&gt;kube-master&lt;/strong&gt;. Idéalement bien entendu, il aurait fallu avoir plus d’un master (3 idéalement ou au moins 2).&lt;/p&gt;
&lt;p&gt;Idem pour la répartition du &lt;strong&gt;vault&lt;/strong&gt; et du &lt;strong&gt;etcd&lt;/strong&gt; sur les workers. Le mieux serait d’avoir un peu de haute disponibilité supplémentaire sur ces composants et donc de les répartir comme le propose le script d’inventaire, mais rien ne vous y oblige.&lt;/p&gt;
&lt;h2 id="déploiement-du-cluster"&gt;Déploiement du cluster
&lt;/h2&gt;&lt;p&gt;Maintenant que notre inventaire est prêt, Kubespray déploie le cluster avec ce oneliner :&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;ansible-playbook -i inventaire_kubernetes/inventory.cfg cluster.yml -b -v --private-key&lt;span class="o"&gt;=&lt;/span&gt;~/.ssh/id_rsa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pas mal hein ? Par rapport à l’installation avec kubeadm que je décris dans &lt;a class="link" href="https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/" &gt;Installer un cluster Kubernetes sur des VMs CentOS 7&lt;/a&gt;, c’est quand même bien plus simple !&lt;/p&gt;
&lt;p&gt;Oui oui, vous avez compris, c’est déjà fini !&lt;/p&gt;
&lt;h2 id="bonus--changer-le-service-du-dashboard-de-kubernetes-pour-le-publier-sur-un-port"&gt;Bonus : Changer le service du dashboard de kubernetes pour le publier sur un port
&lt;/h2&gt;&lt;p&gt;Contrairement à kubeadm, Kubespray installe le dashboard par défaut, pas besoin d’importer et d’appliquer le YAML.&lt;/p&gt;
&lt;p&gt;Cependant, même si normalement on préfère accéder au dashboard de Kubernetes avec le kubeproxy, on peut vouloir dans certains cas accéder directement au Dashboard depuis un port fixe.&lt;/p&gt;
&lt;p&gt;Pour ce faire, on remplace le ClusterIP (interne à Kubernetes uniquement) par un Nodeport en récupérant la configuration du service, en la modifiant et en la ré-appliquant :&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 get svc kubernetes-dashboard --namespace=kube-system -o yaml &amp;gt; kubernetes-dashboard-svc.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="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;vi kubernetes-dashboard-svc.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;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;Service&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;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;k8s-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;kubernetes-dashboard&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;kubernetes-dashboard&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;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;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;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&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;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;TCP&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;targetPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9090&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;k8s-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;kubernetes-dashboard&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;NodePort&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;Une fois les modification faites, on réapplique la configuration et on vérifie que ça a fonctionné&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 kubernetes-dashboard-svc.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 get svc --namespace&lt;span class="o"&gt;=&lt;/span&gt;kube-system
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME CLUSTER-IP EXTERNAL-IP PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt; AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kube-dns 10.233.0.3 &amp;lt;none&amp;gt; 53/UDP,53/TCP 97d
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubernetes-dashboard 10.233.33.140 &amp;lt;nodes&amp;gt; 80:30000/TCP 97d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le Dashboard est disponible sur le port 30000 !&lt;/p&gt;
&lt;h2 id="bonus--kubeadm-et-les-proxy-internet"&gt;Bonus : Kubeadm et les proxy internet
&lt;/h2&gt;&lt;p&gt;J’en parle en début de l’article, j’ai beaucoup galéré avec kubeadm et sa gestion de proxy. Si vous n’en avez pas, ça marche très bien mais si vous avez un proxy, kubeadm fait des appels à Internet via de multiples canaux (je n’ai pas vérifié si c’était mieux en 1.8) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;docker pull pour récupérer les images&lt;/li&gt;
&lt;li&gt;un accès direct&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J’ai eu beau ajouter ‘with_proxy’, configurer les variables HTTP_PROXY/HTTPS_PROXY/NO_PROXY (et en minuscules) aussi bien au niveau de l’OS que du démon Docker mais rien n’y a fait&amp;hellip;&lt;/p&gt;
&lt;p&gt;Quelques pistes si vous voulez vous y essayer :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/kubeadm/issues/292" target="_blank" rel="noopener"
&gt;Une personne qui a eu le même genre de soucis que moi (si je ne met pas  » »with-proxy= » ça bloque, si je le met, ça bloque un peu plus loin)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/reference/generated/kubeadm/#kubeadm-init" target="_blank" rel="noopener"
&gt;La documentation officielle de kubeadm init&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/kubeadm/issues/182" target="_blank" rel="noopener"
&gt;kubeadm init should provide a HTTP_PROXY configure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/kubeadm/issues/324" target="_blank" rel="noopener"
&gt;Where does kubeadm take the proxy settings from?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/kubeadm/issues/257" target="_blank" rel="noopener"
&gt;with KUBE_REPO_PREFIX, but the kubeadm is using « gcr.io/google_containers/pause-amd64 »&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On peut même également installer un cluster Kubernetes avec kubeadm sans accès à Internet en préchargeant les images docker nécessaires, mais là encore, l’outil kubeadm se bloque au moment d’aller vérifier sur Internet s’il existe des images plus récentes à télécharger.&lt;/p&gt;</description></item><item><title>Installer un cluster Kubernetes sur des VMs CentOS 7</title><link>https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/</link><pubDate>Wed, 07 Jun 2017 12:00:53 +0000</pubDate><guid>https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/</guid><description>&lt;img src="https://blog.zwindler.fr/2017/06/kubernetes2.webp" alt="Featured image of post Installer un cluster Kubernetes sur des VMs CentOS 7" /&gt;&lt;h2 id="kubernetes-cest-quoi-ça-"&gt;Kubernetes, c’est quoi ça ?
&lt;/h2&gt;&lt;p&gt;Dans cet article, je vais vous guider pour installer pas à pas un cluster Kubernetes sur des serveurs CentOS/RHEL 7. Attention cet article est un gros morceau !&lt;/p&gt;
&lt;p&gt;Pour ceux qui ne connaissent pas Kubernetes, il faut savoir que c’est un des leaders dans le domaine des orchestrateurs de containers Docker ou Rkt.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/06/kubernetes01.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Un bel empilage de couches, pour au final exécuter des applications dans des containers LXC (ou Windows)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour ce qui est de la genèse de Kubernetes, c’est un outil dont le code provient de Borg d’un outil maison de chez Google. Au bout de 10 ans d’utilisation, quand les containers Linux ont commencés à percer, le code source a été légué en 2015 à la &lt;a class="link" href="https://www.cncf.io/" target="_blank" rel="noopener"
&gt;CNCF (Cloud Native Computing Foundation)&lt;/a&gt;. L’outil est donc maintenant open source.&lt;/p&gt;
&lt;p&gt;Sa couverture fonctionnelle est (pour l’instant) supérieure à celle de &lt;a class="link" href="https://blog.zwindler.fr/2017/01/31/premiers-pas-avec-swarm-fr/" &gt;Docker Swarm&lt;/a&gt;, notamment grâce à :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une gestion de la multitenancy via les namespaces&lt;/li&gt;
&lt;li&gt;une gestion des secrets (bien que limitée)&lt;/li&gt;
&lt;li&gt;une gestion des replicas pour un même container, avec scale-up/down&lt;/li&gt;
&lt;li&gt;une gestion native du loadbalancing&lt;/li&gt;
&lt;li&gt;une gestion des rolling upgrades&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un article sympa d’Octo &lt;a class="link" href="http://blog.octo.com/docker-en-production-la-bataille-sanglante-des-orchestrateurs-de-conteneurs/" target="_blank" rel="noopener"
&gt;résume pas mal l’écosystème et la guerre qui fait rage dans ce domaine&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Avant de commencer le tutoriel, il faut déjà avoir une bonne connaissance de l’écosystème de la containerisation (sujet sur lequel &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=container" &gt;j’ai écris quelques articles&lt;/a&gt; mais qui est bien plus vaste que ça!).&lt;br&gt;
Il faut savoir que Kubernetes est aussi un outil assez complet mais complexe, avec ses propres concepts et sa terminologie associée. Je vous conseille d’abord de vous familiariser avec ces concepts sur &lt;a class="link" href="https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes" target="_blank" rel="noopener"
&gt;un des tutos de Digital Ocean (ils sont souvent très biens fait)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour ceux qui sont extrêmement pressés, on peut dire brièvement que, dans la terminologie Kubernetes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un &lt;strong&gt;Node&lt;/strong&gt; est un serveur qui exécute les applications&lt;/li&gt;
&lt;li&gt;le &lt;strong&gt;Kubelet&lt;/strong&gt; est un service (au sens démon) présent sur tous les nodes qui leur permet de discuter et de recevoir les ordres&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Pod&lt;/strong&gt;, généralement décrit comme « la plus petite unité de traitement de Kubernetes ». Il est composé d’un ou plusieurs containers et on le caractérise généralement comme « &lt;strong&gt;une&lt;/strong&gt; application »&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Service&lt;/strong&gt; représente un répartiteur de charge qui est conscient de la présence d’un ensemble de containers (backend) et qui permet de rediriger les flux entrants vers eux&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Deployment&lt;/strong&gt; est un ensemble de sous éléments (comme les Pods et les Services, mais aussi d’autres que je ne présentent pas) qui permet de déployer une application avec toutes ses caractéristiques (volumes, secrets) et ses contraintes (nombres de réplicas)&lt;/li&gt;
&lt;li&gt;toutes les interactions avec Kubernetes se font avec une seule commande : &lt;strong&gt;kubeadm&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/06/kubernetes02.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Source : kubernetes.io&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="solutions-de-déploiement"&gt;Solutions de déploiement
&lt;/h2&gt;&lt;p&gt;D’abord, la première chose à dire est qu’il existe de nombreuses manières de déployer Kubernetes qui a donc créé un page dédiée à centraliser &lt;a class="link" href="https://kubernetes.io/docs/setup/" target="_blank" rel="noopener"
&gt;l’ensemble des solutions possibles&lt;/a&gt;. Et elle est longue !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/kubernetes2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ceci n’est qu’une fraction des solutions actuellement proposées sur le site. Ça ne rentre pas sur mon écran 29 pouces&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dans mon cas, je suis parti du plus simple pour moi, avec les ressources que j’ai à disposition, c’est à dire 2 machines virtuelles sous CentOS 7.3 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;controlplane01 : 192.168.100.100&lt;/li&gt;
&lt;li&gt;worker01 : 192.168.100.101&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour autant, les solutions avec Vagrant ou sur des clouds publics sont aussi des solutions valables pour commencer si vous maitrisez ces outils. Je vous laisserai regarder la documentation associée si ça vous intéresse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A noter&lt;/strong&gt;, en fonction de la solutions choisie, il existe aussi des considérations réseaux à avoir, et &lt;a class="link" href="https://kubernetes.io/docs/concepts/cluster-administration/networking/" target="_blank" rel="noopener"
&gt;elles sont documentées ici&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="le-plus-simple--minikube"&gt;Le plus simple : Minikube
&lt;/h2&gt;&lt;p&gt;Je ne vais pas m’attarder sur cette méthode mais celle qui me semble vraiment la plus simple si vous voulez commencer rapidement à jouer avec Kubernetes est d’utiliser &lt;strong&gt;minikube&lt;/strong&gt;. Elle utilise de la virtualisation pour déployer l’environnement Kubernetes de manière automatisée sur votre poste et ça fonctionne très bien.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;minikube start
Starting local Kubernetes cluster...
Running pre-create checks...
Creating machine...
Starting local Kubernetes cluster...
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="la-solution-de-larticle--utiliser-kubeadm"&gt;La solution de l’article : Utiliser Kubeadm
&lt;/h2&gt;&lt;p&gt;On ne va pas se le cacher, installer Kubernetes à la main est complexe. Tellement complexe qu’il existe de nombreuses méthodes clé en main pour automatiser le processus.&lt;/p&gt;
&lt;p&gt;La solution que je vous présente ici est un script qui package l’installation des différents composants de Kubernetes. Ces composants sont en fait containerisés pour faciliter leur déploiement.&lt;/p&gt;
&lt;p&gt;La documentation officielle de cette méthode est disponible à l’adresse &lt;a class="link" href="https://kubernetes.io/docs/getting-started-guides/kubeadm/" target="_blank" rel="noopener"
&gt;suivante&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="configuration-des-dépôts"&gt;Configuration des dépôts
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Sur les deux nœuds&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A noter : Dans le cas où vous ne disposeriez pas d’un serveur DNS en propre, le plus simple est de configurer sur vos deux machines leurs noms complets dans le fichier « hosts ». Cela vous évitera des bugs et effets de bords.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;echo &amp;#34;192.168.100.100 controlplane01.example.org
192.168.100.101 worker01.example.org&amp;#34; &amp;gt;&amp;gt; /etc/hosts
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Configurer les repositories officiels :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://yum.kubernetes.io/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
#yum install -y yum-utils
#yum-config-manager \
# --add-repo \
# https://download.docker.com/linux/centos/docker-ce.repo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;J’ai volontairement commenté l’ajout du dépôt de Docker car à date, la dernière version de Kubernetes n’a pas encore complètement validé les dernières versions de Docker (celles depuis le grand renommage, qui sont sur le modèle YY.MM comme la 17.03). C’est pourquoi j’utilise dans ce tutoriel la version packagée par mon OS, la 1.12.6.&lt;/p&gt;
&lt;h3 id="selinux"&gt;SELinux
&lt;/h3&gt;&lt;p&gt;A l’heure actuelle, SELinux est mal supporté par kubelet, le client de Kubernetes présent sur chaque machine. Il est donc malheureusement nécessaire de désactiver cette sécurité pour pouvoir utiliser Kubernetes, pour l’instant.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Disabling SELinux by running setenforce 0 is required in order to allow containers to access the host filesystem, which is required by pod networks for example. You have to do this until SELinux support is improved in the kubelet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Il se peut aussi que le firewall pose des problèmes s’il est activé et mal configuré&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dans le cadre d’un PoC, on pourra éventuellement se permettre de désactiver le firewall et SELinux si on estime que l’environnement est suffisamment sécurisé. C’est bien entendu hors de question pour tout autre environnement non éphémère !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;setenforce 0
vi /etc/selinux/config
[...]
SELINUX=disabled
systemctl disable firewalld
systemctl stop firewalld
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="installation-des-packages"&gt;Installation des packages
&lt;/h3&gt;&lt;p&gt;Comme dit plus haut, j’installe la version Docker de l’OS et non la dernière version. Dans les versions suivantes, Kubernetes aura probablement rattrapé ce retard (si ce n’est pas déjà le cas). On termine par démarrer Docker puis le démon kubelet.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum install -y docker kubelet kubeadm kubectl kubernetes-cni
#yum install -y docker-ce kubelet kubeadm kubectl kubernetes-cni
systemctl enable docker &amp;amp;&amp;amp; systemctl start docker
systemctl enable kubelet &amp;amp;&amp;amp; systemctl start kubelet
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="initialisation-du-cluster"&gt;Initialisation du cluster
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Maintenant que les prérequis sont installés, on peut démarrer Kubernetes. L’ensemble des commandes de Kubernetes utilise le binaire kubeadm et la première à utiliser est kubeadm init.&lt;/p&gt;
&lt;p&gt;Attention cependant, la commande kubeadm init peut nécessiter des arguments complémentaires en fonction du fournisseur de réseau qui sera choisi.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubeadm init
#ou
kubeadm init --pod-network-cidr 10.244.0.0/16 #Si on utilise flannel
#ou
kubeadm init --pod-network-cidr=192.168.0.0/16 #Si on utilise Calico
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si vous avez un proxy chez vous, n’hésitez pas d’exporter la variable http_proxy et à configurer docker pour l’utiliser (voir &lt;a class="link" href="https://stackoverflow.com/questions/23111631/cannot-download-docker-images-behind-a-proxy" target="_blank" rel="noopener"
&gt;ce thread sur stackoverflow&lt;/a&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;export http_proxy=http://@IP_proxy.zwindler.fr:8080/
export no_proxy=localhost,127.0.0.0,[@IP_control_plane]
mkdir /etc/systemd/system/docker.service.d
cat &amp;gt; /etc/systemd/system/docker.service.d/http-proxy.conf &amp;lt;&amp;lt; EOF
[Service]
Environment=&amp;#34;HTTP_PROXY=http://@IP_proxy.zwindler.fr:8080/&amp;#34;
EOF
systemctl daemon-reload
systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On termine l’initialisation côté serveur controlplane avec les commandes suivantes (indiquées dans le retour donné par le kubeadm init) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A noter, en toute fin de retour, kubeadm nous donne la ligne de commande nécessaire pour ajouter des nœuds supplémentaires au cluster via un token. Copiez et conservez cette partie pour plus tard. NE PAS LE FAIRE MAINTENANT !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#You can now join any number of machines by running the following on each node
#as root:
# kubeadm join --token &amp;lt;token&amp;gt; &amp;lt;ip_controlplane&amp;gt;:6443
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A partir de là, le cluster va s’initialiser et déployer tous les containers nécessaires. Cela peut prendre un certain temps et certains containers peuvent passer par un état Fail, mais au final tout doit être dans l’état « Running », à l’exception des kube-dns*.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system etcd-controlplane01.example.org 1/1 Running 0 13m
kube-system kube-apiserver-controlplane01.example.org 1/1 Running 0 12m
kube-system kube-controller-manager-controlplane01.example.org 1/1 Running 0 13m
kube-system kube-dns-3913472980-gnt72 0/3 Pending 0 13m
kube-system kube-proxy-4m1nd 1/1 Running 0 13m
kube-system kube-scheduler-controlplane01.example.org 1/1 Running 0 13m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vérifiez la présence du controlplane avec la commande :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get nodes
NAME STATUS AGE VERSION
controlplane01.example.org NotReady 12m v1.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A noter : Le Nœud restera à NotReady tant que les containers « kube-dns- » ne seront pas démarrés. Or, les « kube-dns- » ne démarreront pas tant que la configuration des « Network Pods » n’est pas faite (on va voir ça plus loin), ce qui est donc normal pour l’instant.&lt;/p&gt;
&lt;h3 id="waiting-for-the-control-plane-to-become-ready-qui-ne-rend-jamais-la-main"&gt;« waiting for the control plane to become ready » qui ne rend jamais la main
&lt;/h3&gt;&lt;p&gt;En cas de blocage sur l’étape « &lt;em&gt;[apiclient] Created API client, waiting for the control plane to become ready&lt;/em&gt;« , vérifier les logs dans &lt;strong&gt;/var/log/messages&lt;/strong&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Apr 26 16:27:58 controlplane01 kubelet: error: failed to run Kubelet: failed to create kubelet: misconfiguration: kubelet cgroup driver: &amp;#34;cgroupfs&amp;#34; is different from docker cgroup driver: &amp;#34;systemd&amp;#34;
Apr 26 16:27:58 controlplane01 systemd: kubelet.service: main process exited, code=exited, status=1/FAILURE
Apr 26 16:27:58 controlplane01 systemd: Unit kubelet.service entered failed state.
Apr 26 16:27:58 controlplane01 systemd: kubelet.service failed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ceci est du à un &lt;a class="link" href="https://github.com/kubernetes/kubernetes/issues/43805" target="_blank" rel="noopener"
&gt;bug de kubeadm sur CentOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il n’y a pas vraiment de solution à partir de là. On ne peut pas utiliser « kubeadm reset » pour désinstaller proprement car cela supprime le fichier &lt;strong&gt;10-kubeadm.conf&lt;/strong&gt;, celui qui doit être corrigé/modifié.&lt;br&gt;
La seule possibilité d’est d’interrompre le processus « kubeadm init », de modifier le 10-kubeadm.conf puis de recommencer.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[CTRL-C]
sed -i &amp;#39;s#Environment=&amp;#34;KUBELET_KUBECONFIG_ARGS=-.*#Environment=&amp;#34;KUBELET_KUBECONFIG_ARGS=--kubeconfig=/etc/kubernetes/kubelet.conf --require-kubeconfig=true --cgroup-driver=systemd&amp;#34;#g&amp;#39; /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
systemctl daemon-reload
systemctl restart kubelet
#Puis relancer
kubeadm init #--pod-network-cidr 10.244.0.0/16
[kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters.
[init] Using Kubernetes version: v1.6.2
[init] Using Authorization mode: RBAC
[preflight] Running pre-flight checks
[preflight] WARNING: docker version is greater than the most recently validated version. Docker version: 17.03.1-ce. Max validated version: 1.12
[preflight] Some fatal errors occurred:
/etc/kubernetes/manifests is not empty
[preflight] If you know what you are doing, you can skip pre-flight checks with `--skip-preflight-checks`
kubeadm init --skip-preflight-checks
#Là, ça devrait fonctionner
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="taint-node"&gt;Taint node
&lt;/h3&gt;&lt;p&gt;Par défaut, Kubernetes n’utilise pas le controlplane pour faire tourner des pods. Si vous voulez changer ce comportement, on peut le faire avec la commande suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl taint nodes --all node-role.kubernetes.io/controlplane-
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="configuration-des-network-pods"&gt;Configuration des Network Pods
&lt;/h2&gt;&lt;p&gt;La première chose à configurer sur le cluster est le « Network Pod ». On a le choix entre un certain nombre de modules, dont la liste est disponible sur &lt;a class="link" href="https://kubernetes.io/docs/concepts/cluster-administration/addons/" target="_blank" rel="noopener"
&gt;cette documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="flannel"&gt;Flannel
&lt;/h3&gt;&lt;p&gt;La configuration la plus couramment utilisée semble être flannel (de CoreOS), donc le fichier de configuration yaml est disponible sur Github&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
serviceaccount &amp;#34;flannel&amp;#34; created
configmap &amp;#34;kube-flannel-cfg&amp;#34; created
daemonset &amp;#34;kube-flannel-ds&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="calico"&gt;Calico
&lt;/h3&gt;&lt;p&gt;On peut aussi essayer &lt;a class="link" href="http://docs.projectcalico.org/v2.1/getting-started/kubernetes/installation/hosted/kubeadm/" target="_blank" rel="noopener"
&gt;Calico&lt;/a&gt;. Personnellement j’ai eu des disfonctionnement avec la version Flannel et donc j’utilise Calico.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f http://docs.projectcalico.org/v2.4/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml
configmap &amp;#34;calico-config&amp;#34; created
daemonset &amp;#34;calico-etcd&amp;#34; created
service &amp;#34;calico-etcd&amp;#34; created
daemonset &amp;#34;calico-node&amp;#34; created
deployment &amp;#34;calico-policy-controller&amp;#34; created
clusterrolebinding &amp;#34;calico-cni-plugin&amp;#34; created
clusterrole &amp;#34;calico-cni-plugin&amp;#34; created
serviceaccount &amp;#34;calico-cni-plugin&amp;#34; created
clusterrolebinding &amp;#34;calico-policy-controller&amp;#34; created
clusterrole &amp;#34;calico-policy-controller&amp;#34; created
serviceaccount &amp;#34;calico-policy-controller&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Les pods pour le réseaux se créent. Vérifiez que tout a bien fonctionné avant d’ajouter des nœuds dans le cluster :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get pods --all-namespaces
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="ajout-de-nœuds-supplémentaires"&gt;Ajout de nœuds supplémentaires
&lt;/h2&gt;&lt;p&gt;A partir de cette étape, le cluster Kubernetes fonctionne réellement, tous les composants sont opérationnels, à ceci près que c’est un cluster avec seulement une machine. On peut donc maintenant intégrer les machines supplémentaires.&lt;/p&gt;
&lt;p&gt;Récupérez la commande avec le token que vous avez conservé précédemment (lors du kubeadm init) et exécutez la sur le nœud « worker ».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sur le worker&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubeadm join --token &amp;lt;token&amp;gt; 192.168.100.100:6443
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si on obtient l’erreur suivante, il faut ajouter 2 lignes dans le fichier « sysctl.conf » et appliquer la modification.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[preflight] Some fatal errors occurred:
/proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1
[preflight] If you know what you are doing, you can skip pre-flight checks with `--skip-preflight-checks`
echo &amp;#34;net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1&amp;#34; &amp;gt;&amp;gt; /etc/sysctl.conf
sysctl -p
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Vérifier la présence du controlplane et de son worker avec la commande kubectl :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get nodes
NAME STATUS AGE VERSION
worker01.example.org NotReady 1m v1.6.2
controlplane01.example.org Ready 33m v1.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="déployer-la-console-web"&gt;Déployer la console web
&lt;/h2&gt;&lt;p&gt;Bravo, votre cluster Kubernetes fonctionne !&lt;/p&gt;
&lt;p&gt;Un bon moyen de débuter est d’installer la WebUI de Kubernetes. Comme tout le reste sur Kubernetes, elle se déploie simplement avec un fichier YAML. La documentation officielle est &lt;a class="link" href="https://kubernetes.io/docs/tasks/web-ui-dashboard/" target="_blank" rel="noopener"
&gt;disponible à cette adresse&lt;/a&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;&lt;span class="c1"&gt;# Add kubernetes-dashboard repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Deploy a Helm Release named &amp;#34;kubernetes-dashboard&amp;#34; using the kubernetes-dashboard chart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --create-namespace --namespace kubernetes-dashboard
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La console est déployée. Elle est accessible de 2 manières.&lt;/p&gt;
&lt;h3 id="kubectl-proxy"&gt;kubectl proxy
&lt;/h3&gt;&lt;p&gt;Cette sous commande kubectl permet de faire un tunnel entre le poste depuis lequel la commande est lancée et le serveur exécutant les pods. Cette commande est pratique pour tester les connexions à des pods sans avoir à travailler sur le serveur (depuis son poste par exemple).&lt;/p&gt;
&lt;p&gt;Le Dashboard deviendra accessible via l’URL :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;http://localhost:8001/ui&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cependant, dans ce cas là, l’interface ne sera disponible que depuis votre poste, ce qui peut ne pas vous convenir.&lt;/p&gt;
&lt;h3 id="via-le-serveur-controlplane"&gt;Via le serveur controlplane
&lt;/h3&gt;&lt;p&gt;On peut également accéder à la console directement depuis l’URL /ui, qui pointe sur le serveur « controlplane » (controlplane01 dans notre cas).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;https://@ip_controlplane]/ui&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La console demandera un login/mdp que l’on peut retrouver avec kubectl&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl config view
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="le-mot-de-la-fin"&gt;Le mot de la fin
&lt;/h2&gt;&lt;p&gt;Ça y est, vous savez tout.&lt;/p&gt;
&lt;p&gt;Vous êtes maintenant en mesure de déployer vos premières applications avec Kubernetes, et vous amuser à Scale-up &amp;amp; scale-down, faire des rolling upgrades, tester la haute disponibilité et la répartition de charge !&lt;/p&gt;
&lt;p&gt;Have fun :)&lt;/p&gt;</description></item></channel></rss>