{"@attributes":{"version":"2.0"},"channel":{"title":"Bricklou & Co","link":"https:\/\/bricklou.ovh\/","description":"Recent content on Bricklou & Co","generator":"Hugo -- gohugo.io","language":"fr-fr","lastBuildDate":"Sun, 26 Jan 2025 00:00:00 +0100","item":[{"title":"A Kubernetes Journey","link":"https:\/\/bricklou.ovh\/posts\/2025\/01\/26\/a-kubernetes-journey\/","pubDate":"Sun, 26 Jan 2025 00:00:00 +0100","guid":"https:\/\/bricklou.ovh\/posts\/2025\/01\/26\/a-kubernetes-journey\/","description":"<p>Bonne ann\u00e9e \u00e0 tous ! \ud83c\udf89<\/p>\n<p>Pour ce premier article de 2025, nous allons parler DevOps, ou plus particuli\u00e8rement Kubernetes. Cela sera l&rsquo;occasion d&rsquo;aborder des notions d&rsquo;infrastructures,\nde d\u00e9ploiements continue, de gestion de secrets, etc.<\/p>\n<blockquote\nclass=\"not-prose [&_a]:text-teal-600 [&_a]:hover:text-teal-500 rounded-md overflow-hidden my-2 bg-amber-100 text-amber-800\"\n>\n<p\nclass=\"px-2 mt-0 font-semibold text-amber-800 bg-amber-400 text-amber-800 bg-amber-400\"\n>\n\u26a0\ufe0f\nWarning\n<\/p>\n<div class=\"px-2 py-1\">\n<p>Avant d&rsquo;aller plus loin, il est important de noter que je ne suis absolument pas un expert et il est fort probable que certaines de mes mani\u00e8res de faire ne\nsoient abssoluments pas optimales ou recommend\u00e9s. N&rsquo;h\u00e9sitez pas \u00e0 me faire part de vos retours pour m&rsquo;aider \u00e0 m&rsquo;am\u00e9liorer.<\/p>\n<\/div>\n<\/blockquote>\n<h2 id=\"introduction\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nIntroduction <a href=\"#introduction\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Cela fait maintenant plusieurs ann\u00e9es que je poss\u00e8de un home-server et il n&rsquo;a cess\u00e9 d&rsquo;\u00e9voluer sur le plan technique ou sur celui de la puissance de calcul. Au\nd\u00e9but, il y a environs 9 ans, j&rsquo;ai commenc\u00e9 avec un simple Raspberry Pi 2 sur lequel \u00e9tait install\u00e9 Docker Swarm. Au fil tu temps, j&rsquo;ai migr\u00e9 vers deux\nRaspberry Pi 3 d&rsquo;abord avec Docker Swarm puis avec Kubernetes, puis ajout\u00e9 un Raspberry Pi 4. Ensuite, il y a environ 2 ans, j&rsquo;ai remplac\u00e9 ces Raspberry Pi par\ndeux Oranges Pi 5 \u00e9quip\u00e9s de disques NVME. Enfin, l&rsquo;ann\u00e9e derni\u00e8re, j&rsquo;ai int\u00e9gr\u00e9 un PC neuf \u00e0 mon cluster Kubernetes. Et cette ann\u00e9e, j&rsquo;ai finalement d\u00e9cid\u00e9 de\nd\u00e9brancher mes Oranges Pi pour ne converver que le PC.<\/p>\n<h2 id=\"le-serveur\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nLe serveur <a href=\"#le-serveur\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<h3 id=\"le-mat\u00e9riel\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nLe mat\u00e9riel <a href=\"#le-mat%c3%a9riel\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Le serveur est un PC mont\u00e9 moi-m\u00eame pour l&rsquo;occasion. Il poss\u00e8de les caract\u00e9ristiques suivantes :<\/p>\n<ul>\n<li>Processeur : AMD Ryzen 5 5800G<\/li>\n<li>RAM : 32 Go (2x 16Go DDR5 5200MHz CL40)<\/li>\n<li>Carte m\u00e8re: ASRock B650M-H\/M.2+<\/li>\n<li>Alimentation: Cooler Master MWE Gold 550 FM (v2)<\/li>\n<li>Stockage: 1x SSD NVMe 512 Go<\/li>\n<li>Boitier: Fractal Design Core 1100<\/li>\n<\/ul>\n<p>(Et oui, je me suis fais plaisir au moment de l&rsquo;achat ! \ud83d\ude1d)<\/p>\n<h3 id=\"le-syst\u00e8me-dexploitation\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nLe syst\u00e8me d&rsquo;exploitation <a href=\"#le-syst%c3%a8me-dexploitation\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Pour le choix du syst\u00e8me d&rsquo;exploitation, j&rsquo;ai opt\u00e9 pour un choix plut\u00f4t exotique \u00e0 premi\u00e8re vue, mais assez int\u00e9ressant : <a href=\"https:\/\/nixos.org\/\">NixOS<\/a>. NixOS est\nune distribution Linux bas\u00e9e sur Nix, un gestionnaire de paquets fonctionnel. Cela implique que la configuration du syst\u00e8me est d\u00e9clarative et que les paquets\nsont isol\u00e9s les uns des autres. En plus de me simplifier l&rsquo;installation et paquets de bases, NixOS me permet aussi de rapidement configurer kubernetes (k3s) et\nd&rsquo;autres services avec assez peu de configuration. Cumul\u00e9 \u00e0 cela, j&rsquo;ai activ\u00e9 la fonctionnalit\u00e9 de <a href=\"https:\/\/wiki.nixos.org\/wiki\/Flakes\">Flake<\/a> qui m&rsquo;ouvre la\nvoie \u00e0 encore plus de capacit\u00e9 \u00e0 la configuration.<\/p>\n<h3 id=\"le-d\u00e9ploiement-du-syst\u00e8me\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nLe d\u00e9ploiement du syst\u00e8me <a href=\"#le-d%c3%a9ploiement-du-syst%c3%a8me\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Avant d&rsquo;utiliser NixOS, toutes mes infrastructures utilisaient toujours une distribution bas\u00e9 sur Debian (Debian et Armbian plus pr\u00e9cis\u00e9ment) et toute\nl&rsquo;installation des outils se faisaient par le biais de scripts Ansible.<\/p>\n<p>Ansible et Nix Flake sont deux outils ayant un objectif similaire : permettre un d\u00e9ploiement automatis\u00e9 et reproductible. Il faut tout de m\u00eame noter que leur\nproc\u00e9d\u00e9 de fonctionnement est assez diff\u00e9rent. Ansible est un outils de d\u00e9ploiement avec une configuration dite &ldquo;imp\u00e9rative&rdquo;, c&rsquo;est \u00e0 dire que l&rsquo;on d\u00e9crit les\n\u00e9tapes \u00e0 suivre pour arriver \u00e0 un \u00e9tat donn\u00e9. Nix Flake, quant \u00e0 lui, est un outil de d\u00e9ploiement avec une configuration dite &ldquo;d\u00e9clarative&rdquo;, c&rsquo;est \u00e0 dire que\nl&rsquo;on d\u00e9crit l&rsquo;\u00e9tat final que l&rsquo;on souhaite obtenir \u00e0 la fin.<\/p>\n<p>Cette diff\u00e9rence de paradigme est assez importante et c&rsquo;est ce qui m&rsquo;a pouss\u00e9 \u00e0 essayer NixOS. En effet, il faut savoir que jusqu&rsquo;\u00e0 pr\u00e9sent, je faisais tous mes\nd\u00e9ploiements via Ansible, mais au fur et \u00e0 mesure du temps, le co\u00fbt de maintenance des scripts devenait de plus en plus important en raison des mises \u00e0 jours\ndes nombreuses d\u00e9pendences n\u00e9cessaires (k3s, networking, adressage des IPs, etc.). Avec Nix Flake, j&rsquo;ai n&rsquo;ai plus trop \u00e0 me soucier de cela, et mieux encore,\ndes morceaux de mes configurations sont plus facilement r\u00e9utilisables. (C&rsquo;\u00e9tait d\u00e9j\u00e0 un peu le cas avec Ansible, mais pas autant).<\/p>\n<blockquote\nclass=\"not-prose [&_a]:text-teal-600 [&_a]:hover:text-teal-500 rounded-md overflow-hidden my-2 bg-green-200 text-green-800\"\n>\n<p\nclass=\"px-2 mt-0 font-semibold text-green-800 bg-green-400 text-green-800 bg-green-400\"\n>\n\ud83d\udca1\nTip\n<\/p>\n<div class=\"px-2 py-1\">\n<p>Pour ceux qui souhaitent en savoir plus sur NixOS, je vous recommande de lire le <a href=\"https:\/\/nixos.org\/manual\/nixos\/stable\/\">manuel officiel<\/a>.<\/p>\n<\/div>\n<\/blockquote>\n<p>Voici un petit exemple de configuration Nix pour installer et configurer K3S :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-nix\" data-lang=\"nix\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 1<\/span><span><span style=\"color:#8b949e;font-style:italic\">## Il faut imaginer que ce fichier est import\u00e9 ailleur dans la configuration, ce qui permet de<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 2<\/span><span><span style=\"color:#8b949e;font-style:italic\">## fournir le champ `pkgs` et les autres variables.<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 3<\/span><span>{\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 4<\/span><span> pkgs<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 5<\/span><span> kubeconfigFile<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 6<\/span><span> tokenFile<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 7<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># Initialize HA cluster using an embedded etcd datastore.<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 8<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># If you are configuring an HA cluster with an embedded etcd,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 9<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># the 1st server must have `clusterInit = true`<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">10<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># and other servers must connect to it using `serverAddr`.<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">11<\/span><span> <span style=\"color:#8b949e;font-style:italic\">#<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">12<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># this can be a domain name or an IP address(such as kube-vip&#39;s virtual IP)<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">13<\/span><span> masterHost<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">14<\/span><span> clusterInit <span style=\"color:#ff7b72;font-weight:bold\">?<\/span> <span style=\"color:#79c0ff;font-weight:bold\">false<\/span><span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">15<\/span><span> kubeletExtraArgs <span style=\"color:#ff7b72;font-weight:bold\">?<\/span> []<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">16<\/span><span> nodeLabels <span style=\"color:#ff7b72;font-weight:bold\">?<\/span> []<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">17<\/span><span> nodeTaints <span style=\"color:#ff7b72;font-weight:bold\">?<\/span> []<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">18<\/span><span> disableFlannel <span style=\"color:#ff7b72;font-weight:bold\">?<\/span> <span style=\"color:#79c0ff;font-weight:bold\">true<\/span><span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">19<\/span><span> nodeIps<span style=\"color:#ff7b72;font-weight:bold\">,<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">20<\/span><span> <span style=\"color:#ff7b72;font-weight:bold\">...<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">21<\/span><span>}: <span style=\"color:#ff7b72\">let<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">22<\/span><span> lib <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> pkgs<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>lib;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">23<\/span><span><span style=\"color:#ff7b72\">in<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">24<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># Installation de paquet syst\u00e8mes<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">25<\/span><span> environment<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>systemPackages <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#ff7b72\">with<\/span> pkgs; [\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">26<\/span><span> k9s <span style=\"color:#8b949e;font-style:italic\"># k9s est un outil TUI pour kubernetes<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">27<\/span><span> kubectl <span style=\"color:#8b949e;font-style:italic\"># CLI officiel pour kubernetes<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">28<\/span><span> kubecolor <span style=\"color:#8b949e;font-style:italic\"># coloration syntaxique pour kubectl (facultatif)<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">29<\/span><span> istioctl <span style=\"color:#8b949e;font-style:italic\"># outil de ligne de commande pour Istio<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">30<\/span><span> kubernetes-helm <span style=\"color:#8b949e;font-style:italic\"># outil de gestion de paquets pour kubernetes<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">31<\/span><span> clusterctl <span style=\"color:#8b949e;font-style:italic\"># CLI pour piloter kubernetes depuis son api<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">32<\/span><span> ];\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">33<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">34<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># Configuration du pare-feu<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">35<\/span><span> networking<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>firewall <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">36<\/span><span> allowedTCPPorts <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> [\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">37<\/span><span> <span style=\"color:#a5d6ff\">6443<\/span> <span style=\"color:#8b949e;font-style:italic\"># k3s: required so that pods can reach the API server (running on port 6443 by default)<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">38<\/span><span> ];\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">39<\/span><span> allowedUDPPorts <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> [\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">40<\/span><span> <span style=\"color:#a5d6ff\">8472<\/span> <span style=\"color:#8b949e;font-style:italic\"># k3s, flannel: required if using multi-node for inter-node networking<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">41<\/span><span> ];\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">42<\/span><span> };\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">43<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">44<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># Configuration de k3s<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">45<\/span><span> services<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>k3s <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">46<\/span><span> enable <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#79c0ff;font-weight:bold\">true<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">47<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># On h\u00e9rite des variables d\u00e9finies plus haut<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">48<\/span><span> <span style=\"color:#ff7b72\">inherit<\/span> package tokenFile clusterInit;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">49<\/span><span> serverAddr <span style=\"color:#ff7b72;font-weight:bold\">=<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">50<\/span><span> <span style=\"color:#ff7b72\">if<\/span> clusterInit\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">51<\/span><span> <span style=\"color:#ff7b72\">then<\/span> <span style=\"color:#a5d6ff\">&#34;&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">52<\/span><span> <span style=\"color:#ff7b72\">else<\/span> <span style=\"color:#a5d6ff\">&#34;https:\/\/<\/span><span style=\"color:#a5d6ff\">${<\/span>masterHost<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">:6443&#34;<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">53<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">54<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># On sp\u00e9cifie le role du noeud<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">55<\/span><span> role <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#a5d6ff\">&#34;server&#34;<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">56<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">57<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># On sp\u00e9cifie les flags \u00e0 passer \u00e0 k3s<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">58<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># https:\/\/docs.k3s.io\/cli\/server<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">59<\/span><span> extraFlags <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#ff7b72\">let<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">60<\/span><span> flagList <span style=\"color:#ff7b72;font-weight:bold\">=<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">61<\/span><span> [\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">62<\/span><span> <span style=\"color:#a5d6ff\">&#34;--write-kubeconfig=<\/span><span style=\"color:#a5d6ff\">${<\/span>kubeconfigFile<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">63<\/span><span> <span style=\"color:#a5d6ff\">&#34;--write-kubeconfig-mode=644&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">64<\/span><span> <span style=\"color:#a5d6ff\">&#34;--kube-apiserver-arg=&#39;--allow-privileged=true&#39;&#34;<\/span> <span style=\"color:#8b949e;font-style:italic\"># required by kubevirt<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">65<\/span><span> <span style=\"color:#a5d6ff\">&#34;--data-dir \/var\/lib\/rancher\/k3s&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">66<\/span><span> <span style=\"color:#a5d6ff\">&#34;--etcd-expose-metrics=true&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">67<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># to enable dual-stack, these flags are required<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">68<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># https:\/\/docs.k3s.io\/networking\/basic-network-options#dual-stack-ipv4--ipv6-networking<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">69<\/span><span> <span style=\"color:#a5d6ff\">&#34;--cluster-cidr=10.42.0.0\/16,2001:cafe:42::\/56&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">70<\/span><span> <span style=\"color:#a5d6ff\">&#34;--service-cidr=10.43.0.0\/16,2001:cafe:43::\/112&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">71<\/span><span> <span style=\"color:#8b949e;font-style:italic\"># disable some features we don&#39;t need<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">72<\/span><span> <span style=\"color:#a5d6ff\">&#34;--disable-helm-controller&#34;<\/span> <span style=\"color:#8b949e;font-style:italic\"># we use fluxcd instead<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">73<\/span><span> <span style=\"color:#a5d6ff\">&#34;--disable=traefik&#34;<\/span> <span style=\"color:#8b949e;font-style:italic\"># deploy our own ingress controller instead<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">74<\/span><span> <span style=\"color:#a5d6ff\">&#34;--disable=servicelb&#34;<\/span> <span style=\"color:#8b949e;font-style:italic\"># we use metallb instead<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">75<\/span><span> <span style=\"color:#a5d6ff\">&#34;--tls-san=<\/span><span style=\"color:#a5d6ff\">${<\/span>masterHost<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">76<\/span><span> <span style=\"color:#a5d6ff\">&#34;--node-ip=<\/span><span style=\"color:#a5d6ff\">${<\/span>lib<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>concatStringsSep <span style=\"color:#a5d6ff\">&#34;,&#34;<\/span> nodeIps<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">&#34;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">77<\/span><span> ]\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">78<\/span><span> <span style=\"color:#ff7b72;font-weight:bold\">++<\/span> (map (label: <span style=\"color:#a5d6ff\">&#34;--node-label=<\/span><span style=\"color:#a5d6ff\">${<\/span>label<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">&#34;<\/span>) nodeLabels)\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">79<\/span><span> <span style=\"color:#ff7b72;font-weight:bold\">++<\/span> (map (taint: <span style=\"color:#a5d6ff\">&#34;--node-taint=<\/span><span style=\"color:#a5d6ff\">${<\/span>taint<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">&#34;<\/span>) nodeTaints)\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">80<\/span><span> <span style=\"color:#ff7b72;font-weight:bold\">++<\/span> (map (arg: <span style=\"color:#a5d6ff\">&#34;--kubelet-arg=<\/span><span style=\"color:#a5d6ff\">${<\/span>arg<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">&#34;<\/span>) kubeletExtraArgs)\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">81<\/span><span> <span style=\"color:#ff7b72;font-weight:bold\">++<\/span> (lib<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>optionals disableFlannel [<span style=\"color:#a5d6ff\">&#34;--flannel-backend=none&#34;<\/span>])\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">82<\/span><span> <span style=\"color:#ff7b72;font-weight:bold\">++<\/span> (lib<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>optionals (<span style=\"color:#ff7b72;font-weight:bold\">!<\/span>disableFlannel) [<span style=\"color:#a5d6ff\">&#34;--flannel-ipv6-masq=true&#34;<\/span>]);\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">83<\/span><span> <span style=\"color:#ff7b72\">in<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">84<\/span><span> lib<span style=\"color:#ff7b72;font-weight:bold\">.<\/span>concatStringsSep <span style=\"color:#a5d6ff\">&#34; &#34;<\/span> flagList;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">85<\/span><span> };\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">86<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><p>Comme vous pouvez le constater, la configuration est assez lisible dans l&rsquo;ensemble. Le language Nix permet d&rsquo;effecter des op\u00e9rations assez complexes et ce\nscript en est un exemple. En une cinquantaine de lignes, nous avons une configuration compl\u00e8te pour installer et configurer k3s, configurer le pare-feu, et\ninstaller quelques outils suppl\u00e9mentaires.<\/p>\n<p>Si nous devions refaire la m\u00eame chose avec Ansible, cela nous prendrait beaucoup plus de lignes (pas tant que \u00e7a, mais tout de m\u00eame) et surtout, cela nous\ndemanderait de r\u00e9fl\u00e9chir en amont \u00e0 l&rsquo;ordre d&rsquo;ex\u00e9cution des t\u00e2ches \u00e0 effectuer, \u00e0 la gestion des erreurs, etc.<\/p>\n<blockquote\nclass=\"not-prose [&_a]:text-teal-600 [&_a]:hover:text-teal-500 rounded-md overflow-hidden my-2 bg-red-100 text-red-500\"\n>\n<p\nclass=\"px-2 mt-0 font-semibold text-red-800 bg-red-300 text-red-800 bg-red-300\"\n>\n\u2757\nCaution\n<\/p>\n<div class=\"px-2 py-1\">\n<p>Attention tout de m\u00eame, NixOS n&rsquo;est pas une solution miracle et il est possible de se retrouver dans des situations assez complexes si l&rsquo;on ne fait pas\nattention. Il est donc important de bien comprendre les concepts de base avant de se lancer.<\/p>\n<p>Un autre point \u00e0 noter, c&rsquo;est que NixOS, en plus de ne pas r\u00e9specter les standards POSIX sur la structure du syst\u00e8me de fichier (impliquant la mise en place\nde nombreux bricolages pour faire fonctionner certains programmes), demande une quantit\u00e9 de stockage plus importante que des distributions plus classiques.<\/p>\n<\/div>\n<\/blockquote>\n<h2 id=\"pourquoi-kubernetes-\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nPourquoi Kubernetes ? <a href=\"#pourquoi-kubernetes-\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Kubernetes est un orchestrateur de conteneurs open-source qui permet d&rsquo;automatiser le d\u00e9ploiement, la mise \u00e0 l&rsquo;\u00e9chelle et la gestion des applications\nconteneuris\u00e9es. Il est con\u00e7u pour g\u00e9rer des applications conteneuris\u00e9es sur un cluster de machines. Il a \u00e9t\u00e9 con\u00e7u \u00e0 l&rsquo;origine par Google et est maintenant\nmaintenu par la Cloud Native Computing Foundation.<\/p>\n<p>Dans mon cas, Kubernetes me permet de d\u00e9ployer et de faire la maintenance rapidement et facilement des applications sur mon serveur. Dans le cas o\u00f9 je d\u00e9ploie\nun grand nomrmes de services, avoir Kubernetes me simplifie grandement la gestion de tout cela.<\/p>\n<p>N\u00e9anmoins ! Qui dit simplicit\u00e9 au d\u00e9ploiement, dit complexit\u00e9 \u00e0 la configuration de l&rsquo;infrastructure. En effet, Kubernetes est un outil tr\u00e8s puissant mais qui\npeut \u00eatre difficile \u00e0 appr\u00e9hender. Il est donc important de bien comprendre les concepts de base avant de se lancer.<\/p>\n<h2 id=\"processus-de-d\u00e9ploiement\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nProcessus de d\u00e9ploiement <a href=\"#processus-de-d%c3%a9ploiement\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Jusque l\u00e0, j&rsquo;ai surtout parl\u00e9 de NixOS et de Kubernetes sans \u00eatre exactement rentr\u00e9 dans les d\u00e9tails de <em>pourquoi<\/em> c&rsquo;est effectivement plus simple \u00e0 utiliser.\nC&rsquo;est ce que nous allons voir maintenant.<\/p>\n<h3 id=\"continuous-integration\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nContinuous Integration <a href=\"#continuous-integration\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Afin d&rsquo;\u00e9viter de d\u00e9ployer des configurations cass\u00e9es, j&rsquo;ai mis en place des outils tel que des Github Actions et des hook <code>pre-commit<\/code> pour v\u00e9rifier la syntaxe\ndes fichiers et les formater.<\/p>\n<p>De cette mani\u00e8re, je m&rsquo;assure que les fichiers que je vais commiter sont corrects et que je n&rsquo;aurais pas de surprise lors du d\u00e9ploiement. (Cela ne garantit pas\nque le d\u00e9ploiement sera sans erreur, mais cela r\u00e9duit les risques).<\/p>\n<p>Pour cela, j&rsquo;utilise 2 outils : <code>pre-commit-hooks<\/code> qui me fait toutes les v\u00e9rifications avant le commit et <code>github actions<\/code> qui me fait les v\u00e9rifications lors\ndu push sur la branche <code>main<\/code>. En compl\u00e9ment, j&rsquo;utilise <a href=\"https:\/\/docs.renovatebot.com\/\">Renovate Bot<\/a> qui a pour r\u00f4le de v\u00e9rifier les mises \u00e0 jours des\nd\u00e9pendances de mes projets. Tous les lundis, Renovate Bot va aller scanner le projet et chercher si des mises \u00e0 jours sont disponibles. Si c&rsquo;est le cas, il va\nouvrir une PR pour me proposer d&rsquo;appliquer ces mises \u00e0 jours.<\/p>\n<h3 id=\"continuous-deployment\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nContinuous Deployment <a href=\"#continuous-deployment\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Une fois un commit pouss\u00e9 sur Github, l&rsquo;outil <a href=\"https:\/\/fluxcd.io\/\">FluxCD<\/a> (install\u00e9 dans le cluster Kubernetes) va aller chercher les derniers commits\ndisponibles. Son r\u00f4le est de synchroniser les configurations pr\u00e9sentent dans le d\u00e9p\u00f4t avec ce qui est actuellement d\u00e9ploiment en production. \u00c0 partir de l\u00e0, il\nva essayer de faire de son mieux pour appliquer les changements jusqu&rsquo;\u00e0 atteindre l&rsquo;\u00e9tat attendu. Voici un exemple de configuration que FluxCD est capable\nd&rsquo;interpr\u00e9ter pour faire la synchronisation:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-yaml\" data-lang=\"yaml\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 1<\/span><span><span style=\"color:#ff7b72\">---<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 2<\/span><span><span style=\"color:#6e7681\"><\/span><span style=\"color:#8b949e;font-style:italic\">## On utilise une ressource custom fournit par FluxCD<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 3<\/span><span><span style=\"color:#6e7681\"><\/span><span style=\"color:#7ee787\">apiVersion<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">kustomize.toolkit.fluxcd.io\/v1<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 4<\/span><span><span style=\"color:#6e7681\"><\/span><span style=\"color:#7ee787\">kind<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">Kustomization<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 5<\/span><span><span style=\"color:#6e7681\"><\/span><span style=\"color:#7ee787\">metadata<\/span>:<span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 6<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">name<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">website<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 7<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">namespace<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">flux-system<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 8<\/span><span><span style=\"color:#6e7681\"><\/span><span style=\"color:#7ee787\">spec<\/span>:<span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 9<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># On veut que cette configuration soit synchronis\u00e9 toutes les 30 minutes<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">10<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">interval<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">30m<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">11<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># Les valeurs `path` et `sourceRef` disent \u00e0 FluxCD d&#39;aller chercher les configuration dans le<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">12<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># d\u00e9p\u00f4t Git log\u00e9es au chemin sp\u00e9cifi\u00e9. Dans mon cas, cela correspond au d\u00e9p\u00f4t actuel dans le<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">13<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># dossier `.\/app` par rapport ce fichier de configuration<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">14<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">path<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">.\/k3s\/fluxcd\/apps\/base\/website\/app<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">15<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">sourceRef<\/span>:<span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">16<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">kind<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">GitRepository<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">17<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">name<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">flux-system<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">18<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">namespace<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">flux-system<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">19<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># Si besoin, on d\u00e9truit les ressources qui ne servent plus<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">20<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">prune<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#79c0ff\">true<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">21<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># On s&#39;attend ce que le d\u00e9ploiment soit fait sous 10 minutes<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">22<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">timeout<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">10m<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">23<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># On informe FluxCD qu&#39;il peut statuer le d\u00e9ploiement comme &#34;pr\u00eat&#34; uniquement lorsque le statut<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">24<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#8b949e;font-style:italic\"># de l&#39;objet sp\u00e9cifi\u00e9 est lui aussi statu\u00e9 comme &#34;pr\u00eat&#34;.<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">25<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">healthChecks<\/span>:<span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">26<\/span><span><span style=\"color:#6e7681\"> <\/span>- <span style=\"color:#7ee787\">kind<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">Deployment<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">27<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">name<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">website<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">28<\/span><span><span style=\"color:#6e7681\"> <\/span><span style=\"color:#7ee787\">namespace<\/span>:<span style=\"color:#6e7681\"> <\/span><span style=\"color:#a5d6ff\">website<\/span><span style=\"color:#6e7681\">\n<\/span><\/span><\/span><\/code><\/pre><\/div><p>Toutefois, il peut arriver qu&rsquo;il ne soit pas capable re-synchroniser en raison d&rsquo;erreur pouvant \u00eatre pr\u00e9sente \u00e0 plusieurs niveaux (erreur de configuration,\nimage non-disponible, etc.). Quand cela arrive, FluxCD est capable de m&rsquo;envoyer une notification directement sur Discord par le biais d&rsquo;un webhook. Ce qui me\npermet alors d&rsquo;intervenir pour r\u00e9gler le probl\u00e8me.<\/p>\n<h3 id=\"sauvegarde-des-donn\u00e9es\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nSauvegarde des donn\u00e9es <a href=\"#sauvegarde-des-donn%c3%a9es\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Ma pr\u00e9c\u00e9dente installation (2024) \u00e9tait \u00e9quip\u00e9 du syst\u00e8me de sauvegarde de Longhorn. Sur le papier, le proc\u00e9d\u00e9 fonctionnait bien, les volumes \u00e9taient bien copi\u00e9\nsur mon NAS via NFS. Mais quand l&rsquo;infrastructure \u00e0 l\u00e2ch\u00e9, j&rsquo;ai tout de m\u00eame perdu quelques donn\u00e9es en chemin (par exemple, des donn\u00e9es de base de donn\u00e9e\nPostgres qui n&rsquo;ont pas support\u00e9 le processus). Heureusement pour moi, je n&rsquo;ai perdu que tr\u00e8s peu de donn\u00e9e, mais cela m&rsquo;a tout de m\u00eame fait r\u00e9fl\u00e9chir \u00e0 mon plan\nde sauvegarde de mes donn\u00e9es.<\/p>\n<p>J&rsquo;en suis donc arriv\u00e9 \u00e0 la conclusion de totalement abandonner le syst\u00e8me de Longhorn et de les g\u00e9rer ind\u00e9pendament. J&rsquo;ai donc r\u00e9vis\u00e9 ma proc\u00e9dure comme suis :<\/p>\n<ul>\n<li>Toutes mes sauvegarde passent maintenant par un serveur Minio S3 install\u00e9 sur le NAS.<\/li>\n<li>Les sauvegarde de base de donn\u00e9es postgres (Cloud Native PG) sont maintenant g\u00e9r\u00e9 directement par CNPG lui m\u00eame avec\n<a href=\"https:\/\/cloudnative-pg.io\/documentation\/current\/backup\/\">son syst\u00e8me automatis\u00e9<\/a>. De cette mani\u00e8re, je suis assur\u00e9 que les sauvegardes seront compatible sans\nd\u00e9faillance li\u00e9 au processus de sauvegarde.<\/li>\n<li>Un de mes service n\u00e9cessite une base de donn\u00e9e MariaDB. Avant je ne d\u00e9ployais qu&rsquo;un simple pod et je sauvegardais le volume, mais l\u00e0 j&rsquo;ai d\u00e9cid\u00e9 d&rsquo;aller plus\nloin en installant MariaDB Operator. Ce dernier, \u00e0 la mani\u00e8re de CNPG, s&rsquo;occupe lui aussi de sauvegarder les base de donn\u00e9es sur S3.<\/li>\n<li>Pour finir, tous les autres volumes sont sauvegarder gr\u00e2ce \u00e0 <a href=\"https:\/\/volsync.readthedocs.io\/\">VolSync<\/a>, un outil sp\u00e9cialis\u00e9 dans les plan de sauvegarde de\nvolumes Kubernetes. Et vous savez quoi ? Il est aussi compatible S3 ! (sans grande surprise \ud83d\ude04)<\/li>\n<\/ul>\n<p>Toutes les sauvegardes sont ex\u00e9cut\u00e9s de mani\u00e8re hebdomadaires avec une r\u00e9tention de 4 semaines avant suppression. Ce qui me laisse une marge plut\u00f4t confortable\nen cas de panne du syst\u00e8me.<\/p>\n<pre class=\"mermaid\">\narchitecture-beta\ngroup kubernetes(server)[Cluster K8S]\ngroup nas(server)[NAS sur le reseau local]\nservice pgDb(database)[CNPG] in kubernetes\nservice mariaDb(database)[MariaDB Operator] in kubernetes\nservice volsync(disk)[VolSync] in kubernetes\nservice minio(disk)[Minio S3] in nas\njunction junctionCenter in kubernetes\npgDb:R -- L:junctionCenter\nmariaDb:T -- B:junctionCenter\nvolsync:L -- R:junctionCenter\njunctionCenter:T --&gt; B:minio\n<\/pre>\n<h3 id=\"et-les-secrets-dans-tout-\u00e7a-\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nEt les secrets dans tout \u00e7a ? <a href=\"#et-les-secrets-dans-tout-%c3%a7a-\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>La gestion des secrets est le dernier point que nous allons aborder aujourd&rsquo;hui. Bien que mon d\u00e9p\u00f4t soit priv\u00e9, je ne peux pas non plus me permettre de laisser\ndes donn\u00e9es aussi sensible (cl\u00e9 api, mot de passe, etc.) accessible tel quel dans les fichiers. Pour rem\u00e9dier \u00e0 ce probl\u00e8me, je passe par l&rsquo;outil\n<a href=\"https:\/\/github.com\/getsops\/sops\">SOPS<\/a>. Son fonctionnement est assez sommaire : il n\u00e9cessite une cl\u00e9 GPG\/SSH publique en entr\u00e9e pour chiffrer les donn\u00e9es, et\nla cl\u00e9 GPG\/SSH priv\u00e9e associ\u00e9 pour d\u00e9chifrer. \u00c0 partir de l\u00e0, on peut rajouter plusieurs cl\u00e9s correspondant \u00e0 plusieurs machine et il se d\u00e9brouillera pour\nchiffrer les donn\u00e9es pour toutes les cl\u00e9s.<\/p>\n<p>Le programme est tr\u00e8s bien int\u00e9gr\u00e9 dans FluxCD et dans Nix (via <a href=\"https:\/\/github.com\/Mic92\/sops-nix\/\">sops-nix<\/a>), ce qui en fait un outil id\u00e9al pour g\u00e9rer mes\ndonn\u00e9es sensibles.<\/p>\n<p>Par pr\u00e9caution, j&rsquo;ai quand m\u00eame un outil (<a href=\"https:\/\/www.gitguardian.com\/\">GitGuardian<\/a>) dans ma CI Github pour scanner mes fichiers \u00e0 la recherche de potentiel\nsecret oubli\u00e9. \u00c9vid\u00e9ment, si votre infrastructure est tr\u00e8s sensible (dans le contexte en entreprise par exemple), il serait toujours possible d&rsquo;installer ces\noutils en interne <em>on-premise<\/em>.<\/p>\n<h2 id=\"conclusion\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nConclusion <a href=\"#conclusion\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Cette petite aventure a \u00e9t\u00e9 \u00e0 la fois instructive et amusante. J&rsquo;ai pu tirer parti de la panne compl\u00e8te de mon ancienne installation pour repartir de z\u00e9ro et\nr\u00e9organiser toutes mes configurations. De plus, j&rsquo;ai pu combler mes lacunes et tester de nouveaux outils tels que SOPS, FluxCD, NixOS et VolSync.<\/p>\n<p>Apr\u00e8s un peu plus d&rsquo;un mois de fonctionnement, je n&rsquo;ai toujours pas rencontr\u00e9 de probl\u00e8me &ldquo;majeur&rdquo;. On peut donc supposer que c&rsquo;est migration est dans\nl&rsquo;ensemble un succ\u00e8s. \ud83d\ude0e<\/p>\n<p>Si vous souhaitez avoir plus d&rsquo;informations sur certains point, n&rsquo;h\u00e9sitez pas \u00e0 me contacter par le biais des\n<a href=\"https:\/\/github.com\/Bricklou\/website\/discussions\">Github Discussions<\/a>. J&rsquo;essaierais de vous r\u00e9pondre et de mettre \u00e0 jours ce post avec les informations\ncompl\u00e9mentaires.<\/p>"},{"title":"Let's play with MediaPipe","link":"https:\/\/bricklou.ovh\/posts\/2024\/09\/05\/lets-play-with-mediapipe\/","pubDate":"Thu, 05 Sep 2024 00:00:00 +0200","guid":"https:\/\/bricklou.ovh\/posts\/2024\/09\/05\/lets-play-with-mediapipe\/","description":"<p>Cet avril dernier, quelque temps apr\u00e8s la sortie officielle de la mise \u00e0 jours de <a href=\"https:\/\/adonisjs.com\/\">AdonisJS 6<\/a>, j&rsquo;ai eu l&rsquo;occasion de travailler sur un projet personnel qui m&rsquo;a permis de d\u00e9couvrir et d&rsquo;exp\u00e9rimenter avec <a href=\"https:\/\/mediapipe.dev\/\">MediaPipe<\/a>, une biblioth\u00e8que open-source de Google pour le traitement de flux multim\u00e9dia.<\/p>\n<h2 id=\"introduction\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nIntroduction <a href=\"#introduction\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Dans le cadre de mon alternance, j&rsquo;ai pu d\u00e9couvrir par le biais de mon tuteur un projet de recherche de Google nomm\u00e9 <a href=\"https:\/\/ai.google.dev\/edge\/mediapipe\/solutions\/guide\">MediaPipe<\/a>. Une biblioth\u00e8que open-source qui permet de traiter des flux multim\u00e9dia en temps r\u00e9el. Cela va de la d\u00e9tection d&rsquo;objets, de visages, de mains, de pose, de mouvements, etc.<\/p>\n<p>Mon tuteur s&rsquo;en servait pour proposer du <em>background replacement<\/em> lors de ses visioconf\u00e9rences. C&rsquo;est-\u00e0-dire, remplacer l&rsquo;arri\u00e8re-plan d&rsquo;une vid\u00e9o par une image ou une vid\u00e9o de son choix. Permettant ainsi de cacher son environnement de travail.<\/p>\n<p>Par curiosit\u00e9, je me suis donc lanc\u00e9 dans un mini-projet pour d\u00e9couvrir et exp\u00e9rimenter avec cette biblioth\u00e8que.<\/p>\n<h2 id=\"le-choix-de-la-stack\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nLe choix de la stack <a href=\"#le-choix-de-la-stack\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>\u00c9tant donn\u00e9 l&rsquo;aspect d\u00e9couverte du projet, je suis parti sur quelque chose de totalement nouveau pour moi.\nTout d&rsquo;abord, m\u00eame si cela n&rsquo;est pas n\u00e9cessaire, j&rsquo;ai lanc\u00e9 un projet <a href=\"https:\/\/adonisjs.com\/\">AdonisJS 6<\/a> pour le backend. Bien entendu, je ne me suis pas juste content\u00e9 de lancer un projet avec les outils par d\u00e9faut. J&rsquo;ai \u00e9galement remplac\u00e9 le moteur de rendu <a href=\"https:\/\/edgejs.dev\/\">Edge<\/a> qui est par d\u00e9faut dans Adonis, par <a href=\"https:\/\/github.com\/kitajs\/html\"><code>@kitajs\/html<\/code><\/a>, un moteur me permettant de transformer des composants JSX en page HTML. La mise en place fut l\u00e9g\u00e8rement compliqu\u00e9e, mais une fois configur\u00e9, la prise en main \u00e9tait tr\u00e8s simple et agr\u00e9able \u00e0 utiliser.<\/p>\n<p>C&rsquo;est maintenant ici que la partie la plus int\u00e9ressante arrive : le code frontend qui s&rsquo;occupera de g\u00e9rer Mediapipe. Pour cela, je suis rest\u00e9 sur un visuel succinct avec <a href=\"https:\/\/tailwindcss.com\">Tailwind<\/a>. Par contre, pour afficher mon interface avec Mediapipe, je me suis pens\u00e9 sur les <a href=\"https:\/\/developer.mozilla.org\/fr\/docs\/Web\/Web_Components\">Web Components<\/a> avec l&rsquo;utilisation de <a href=\"https:\/\/preactjs.com\/\">Preact<\/a> pour la partie JavaScript.<\/p>\n<p>Forc\u00e9ment, je suis conscient que cette stack n&rsquo;a strictement aucun sens pour un projet de production. Mais pour un projet personnel, cela m&rsquo;a permis de d\u00e9couvrir de nouvelles technologies et de m&rsquo;amuser \u00e0 les utiliser. \ud83d\ude43<\/p>\n<h2 id=\"la-mise-en-place\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nLa mise en place <a href=\"#la-mise-en-place\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<h3 id=\"kitajs\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nKitajs <a href=\"#kitajs\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Comme dit pr\u00e9c\u00e9demment, j&rsquo;ai utilis\u00e9 <a href=\"https:\/\/github.com\/kitajs\/html\"><code>@kitajs\/html<\/code><\/a> pour g\u00e9rer mes pages HTML. Pour cela, j&rsquo;ai suivi les explication fournit dans <a href=\"https:\/\/adonisjs.com\/blog\/use-tsx-for-your-template-engine\">ce post de blog<\/a>.<\/p>\n<p>Tout d&rsquo;abord, j&rsquo;ai install\u00e9 le package :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-bash\" data-lang=\"bash\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">1<\/span><span>pnpm install @kitajs\/html -D\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">2<\/span><span>pnpm install @kitajs\/ts-html-plugin -D\n<\/span><\/span><\/code><\/pre><\/div><p>Ensuite, j&rsquo;ai configur\u00e9 mon fichier <code>tsconfig.json<\/code> pour ajouter le plugin typescript :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-json\" data-lang=\"json\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 1<\/span><span><span style=\"color:#8b949e;font-style:italic\">\/\/ tsconfig.json\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 2<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span>{\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 3<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ ...\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 4<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#7ee787\">&#34;compilerOptions&#34;<\/span>: {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 5<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ ...\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 6<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#8b949e;font-style:italic\">\/\/ on configure le moteur JSX pour typescript\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 7<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#7ee787\">&#34;jsx&#34;<\/span>: <span style=\"color:#a5d6ff\">&#34;react&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 8<\/span><span> <span style=\"color:#7ee787\">&#34;jsxFactory&#34;<\/span>: <span style=\"color:#a5d6ff\">&#34;Html.createElement&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 9<\/span><span> <span style=\"color:#7ee787\">&#34;jsxFragmentFactory&#34;<\/span>: <span style=\"color:#a5d6ff\">&#34;Html.Fragment&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">10<\/span><span> <span style=\"color:#7ee787\">&#34;plugins&#34;<\/span>: [{ <span style=\"color:#7ee787\">&#34;name&#34;<\/span>: <span style=\"color:#a5d6ff\">&#34;@kitajs\/ts-html-plugin&#34;<\/span> }]\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">11<\/span><span> },\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">12<\/span><span> <span style=\"color:#7ee787\">&#34;exclude&#34;<\/span>: [<span style=\"color:#a5d6ff\">&#34;resources&#34;<\/span>]\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">13<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><p>Ce plugin va permet de faire comprendre \u00e0 Typescript comme interpr\u00e9ter les \u00e9l\u00e9ments JSX.<\/p>\n<p>Et pour finir, dans un contr\u00f4leur <code>app\/app_controller.ts<\/code> et ma vue, j&rsquo;ai pu utiliser le moteur de rendu :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-ts\" data-lang=\"ts\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">1<\/span><span><span style=\"color:#8b949e;font-style:italic\">\/\/ app\/app_controller.ts\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">2<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span><span style=\"color:#ff7b72\">import<\/span> { Home } <span style=\"color:#ff7b72\">from<\/span> <span style=\"color:#a5d6ff\">&#39;..\/..\/resources\/views\/pages\/home.js&#39;<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">3<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">4<\/span><span><span style=\"color:#ff7b72\">export<\/span> <span style=\"color:#ff7b72\">default<\/span> <span style=\"color:#ff7b72\">class<\/span> AppsController {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">5<\/span><span> index() {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">6<\/span><span> <span style=\"color:#ff7b72\">return<\/span> &lt;<span style=\"color:#7ee787\">Home<\/span> \/&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">7<\/span><span> }\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">8<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 1<\/span><span><span style=\"color:#8b949e;font-style:italic\">\/\/ resources\/views\/pages\/home.tsx\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 2<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 3<\/span><span><span style=\"color:#ff7b72\">import<\/span> { App } <span style=\"color:#ff7b72\">from<\/span> <span style=\"color:#a5d6ff\">&#34;..\/layouts\/app.js&#34;<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 4<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 5<\/span><span><span style=\"color:#ff7b72\">export<\/span> <span style=\"color:#ff7b72\">function<\/span> Home() {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 6<\/span><span> <span style=\"color:#ff7b72\">return<\/span> (\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 7<\/span><span> &lt;<span style=\"color:#7ee787\">App<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 8<\/span><span> &lt;<span style=\"color:#7ee787\">div<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;relative&#34;<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 9<\/span><span> &lt;<span style=\"color:#7ee787\">div<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;container mx-auto p-8 z-10 absolute top-0 left-0 w-full&#34;<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">10<\/span><span> &lt;<span style=\"color:#7ee787\">h1<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;font-bold text-2xl&#34;<\/span>&gt;Move your hands&lt;\/<span style=\"color:#7ee787\">h1<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">11<\/span><span> &lt;\/<span style=\"color:#7ee787\">div<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">12<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">13<\/span><span> &lt;<span style=\"color:#7ee787\">div<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;w-screen h-screen&#34;<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">14<\/span><span> &lt;<span style=\"color:#7ee787\">video<\/span><span style=\"color:#f85149\">-<\/span>container \/&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">15<\/span><span> &lt;\/<span style=\"color:#7ee787\">div<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">16<\/span><span> &lt;\/<span style=\"color:#7ee787\">div<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">17<\/span><span> &lt;\/<span style=\"color:#7ee787\">App<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">18<\/span><span> );\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">19<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><h3 id=\"web-components\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nWeb Components <a href=\"#web-components\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Vous avez d\u00fb remarqu\u00e9 dans la partie pr\u00e9c\u00e9dente que j&rsquo;ai utilis\u00e9 une balise <code>video-container<\/code>. Cette balise est un Web Component que j&rsquo;ai cr\u00e9\u00e9 pour g\u00e9rer l&rsquo;affichage de la vid\u00e9o et l&rsquo;initialisation de Mediapipe.<\/p>\n<p>La configuration d&rsquo;un Web Component est assez simple, en particulier avec Preact. Il suffit de cr\u00e9er un composant Preact et de l&rsquo;enregistrer en tant que Web Component. Voici un exemple de composant :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">1<\/span><span><span style=\"color:#8b949e;font-style:italic\">\/\/ resources\/components\/my-component.tsx\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">2<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span><span style=\"color:#ff7b72\">import<\/span> { JSX } <span style=\"color:#ff7b72\">from<\/span> <span style=\"color:#a5d6ff\">&#34;preact&#34;<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">3<\/span><span><span style=\"color:#ff7b72\">import<\/span> register <span style=\"color:#ff7b72\">from<\/span> <span style=\"color:#a5d6ff\">&#34;preact-custom-element&#34;<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">4<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">5<\/span><span><span style=\"color:#ff7b72\">function<\/span> MyComponent()<span style=\"color:#ff7b72;font-weight:bold\">:<\/span> JSX.Element {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">6<\/span><span> <span style=\"color:#ff7b72\">return<\/span> &lt;<span style=\"color:#7ee787\">div<\/span>&gt;Hello World&lt;\/<span style=\"color:#7ee787\">div<\/span>&gt;;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">7<\/span><span>}\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">8<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">9<\/span><span>register(MyComponent, <span style=\"color:#a5d6ff\">&#34;video-container&#34;<\/span>);\n<\/span><\/span><\/code><\/pre><\/div><p>Bien entendu, pour permettre \u00e0 typescript et kita de comprendre que notre composant existe et est valide, il nous faut ajouter des informations dans un fichier de d\u00e9claration :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-ts\" data-lang=\"ts\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">1<\/span><span><span style=\"color:#8b949e;font-style:italic\">\/\/ types\/kita.ts\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">2<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span><span style=\"color:#ff7b72\">declare<\/span> <span style=\"color:#ff7b72\">global<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">3<\/span><span> <span style=\"color:#ff7b72\">namespace<\/span> JSX {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">4<\/span><span> <span style=\"color:#ff7b72\">interface<\/span> IntrinsicElements {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">5<\/span><span> [<span style=\"color:#a5d6ff\">&#34;video-container&#34;<\/span>]<span style=\"color:#ff7b72;font-weight:bold\">:<\/span> HtmlTag;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">6<\/span><span> }\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">7<\/span><span> }\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">8<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><p>Et c&rsquo;est tout ! Notre composant est maintenant utilisable dans notre page HTML. (Attention, il faut bien s\u00fbr penser \u00e0 importer le script de notre composant dans notre page HTML et le d\u00e9clarer dans la configuration Vite).<\/p>\n<h3 id=\"mediapipe\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nMediapipe <a href=\"#mediapipe\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h3>\n<p>Je ne pense pas m&rsquo;\u00e9tendre sur utilisation de MediaPipe dans mon code, mais j&rsquo;aimerais quand m\u00eame aborder certains points. Par exemple, la mani\u00e8re dont j&rsquo;ai g\u00e9r\u00e9 l&rsquo;initialisation de Mediapipe.<\/p>\n<p>Tout d&rsquo;abord, j&rsquo;ai cr\u00e9\u00e9 un fichier utilitaire pour g\u00e9rer l&rsquo;initialisation de Mediapipe :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-ts\" data-lang=\"ts\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 1<\/span><span><span style=\"color:#8b949e;font-style:italic\">\/\/ resources\/ts\/utils\/vision.ts\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 2<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span><span style=\"color:#ff7b72\">import<\/span> { FilesetResolver, GestureRecognizer } <span style=\"color:#ff7b72\">from<\/span> <span style=\"color:#a5d6ff\">&#34;@mediapipe\/tasks-vision&#34;<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 3<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 4<\/span><span><span style=\"color:#ff7b72\">export<\/span> <span style=\"color:#ff7b72\">async<\/span> <span style=\"color:#ff7b72\">function<\/span> gestureRecogniser() {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 5<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ On r\u00e9cup\u00e8re le module de vision\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 6<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#ff7b72\">const<\/span> vision <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#ff7b72\">await<\/span> FilesetResolver.forVisionTasks(\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 7<\/span><span> <span style=\"color:#a5d6ff\">&#34;https:\/\/cdn.jsdelivr.net\/npm\/@mediapipe\/tasks-vision@latest\/wasm&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 8<\/span><span> );\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 9<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">10<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ On cr\u00e9e le GestureRecognizer\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">11<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#ff7b72\">return<\/span> <span style=\"color:#ff7b72\">await<\/span> GestureRecognizer.createFromOptions(vision, {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">12<\/span><span> baseOptions<span style=\"color:#ff7b72;font-weight:bold\">:<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">13<\/span><span> modelAssetPath<span style=\"color:#ff7b72;font-weight:bold\">:<\/span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">14<\/span><span> <span style=\"color:#a5d6ff\">&#34;https:\/\/storage.googleapis.com\/mediapipe-tasks\/gesture_recognizer\/gesture_recognizer.task&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">15<\/span><span> delegate<span style=\"color:#ff7b72;font-weight:bold\">:<\/span> <span style=\"color:#a5d6ff\">&#34;GPU&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">16<\/span><span> },\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">17<\/span><span> runningMode<span style=\"color:#ff7b72;font-weight:bold\">:<\/span> <span style=\"color:#a5d6ff\">&#34;VIDEO&#34;<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">18<\/span><span> numHands: <span style=\"color:#ff7b72\">2<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">19<\/span><span> });\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">20<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><p>Ensuite, j&rsquo;ai utilis\u00e9 ce fichier dans mon composant Web Component pour initialiser Mediapipe :<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"><code class=\"language-tsx\" data-lang=\"tsx\"><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 1<\/span><span><span style=\"color:#ff7b72\">function<\/span> VideoContainer()<span style=\"color:#ff7b72;font-weight:bold\">:<\/span> JSX.Element {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 2<\/span><span> <span style=\"color:#ff7b72\">const<\/span> [visionRecogniser, setVision] <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> useState&lt;<span style=\"color:#7ee787\">GestureRecognizer<\/span>&gt;();\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 3<\/span><span> <span style=\"color:#ff7b72\">const<\/span> [visionData, setVisionData] <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> useState&lt;<span style=\"color:#7ee787\">GestureRecognizerResult<\/span> <span style=\"color:#f85149\">|<\/span> null&gt;(\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 4<\/span><span> <span style=\"color:#79c0ff\">null<\/span>,\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 5<\/span><span> );\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 6<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 7<\/span><span> useEffect(() <span style=\"color:#ff7b72;font-weight:bold\">=&gt;<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 8<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ On charge le vision recogniser\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\"> 9<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#ff7b72\">const<\/span> fetchVision <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#ff7b72\">async<\/span> () <span style=\"color:#ff7b72;font-weight:bold\">=&gt;<\/span> {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">10<\/span><span> console.log(<span style=\"color:#a5d6ff\">&#34;Loading vision recogniser&#34;<\/span>);\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">11<\/span><span> <span style=\"color:#ff7b72\">const<\/span> { gestureRecogniser } <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#ff7b72\">await<\/span> <span style=\"color:#ff7b72\">import<\/span>(<span style=\"color:#a5d6ff\">&#34;..\/utils\/vision&#34;<\/span>);\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">12<\/span><span> setVision(<span style=\"color:#ff7b72\">await<\/span> gestureRecogniser());\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">13<\/span><span> };\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">14<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">15<\/span><span> fetchVision();\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">16<\/span><span> }, []);\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">17<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">18<\/span><span> <span style=\"color:#ff7b72\">let<\/span> text: <span style=\"color:#ff7b72\">string<\/span> <span style=\"color:#ff7b72;font-weight:bold\">|<\/span> <span style=\"color:#79c0ff\">null<\/span> <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#79c0ff\">null<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">19<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">20<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ On extrait les informations de Mediapipe pour les afficher\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">21<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#ff7b72\">if<\/span> (visionData <span style=\"color:#ff7b72;font-weight:bold\">&amp;&amp;<\/span> visionData.gestures.length <span style=\"color:#ff7b72;font-weight:bold\">&gt;<\/span> <span style=\"color:#a5d6ff\">0<\/span>) {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">22<\/span><span> <span style=\"color:#ff7b72\">const<\/span> categoryName <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> visionData.gestures[<span style=\"color:#a5d6ff\">0<\/span>][<span style=\"color:#a5d6ff\">0<\/span>].categoryName;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">23<\/span><span> <span style=\"color:#ff7b72\">const<\/span> categoryScore <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> (visionData.gestures[<span style=\"color:#a5d6ff\">0<\/span>][<span style=\"color:#a5d6ff\">0<\/span>].score <span style=\"color:#ff7b72;font-weight:bold\">*<\/span> <span style=\"color:#a5d6ff\">100<\/span>).toFixed(<span style=\"color:#a5d6ff\">2<\/span>);\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">24<\/span><span> <span style=\"color:#ff7b72\">const<\/span> handedness <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> visionData.handedness[<span style=\"color:#a5d6ff\">0<\/span>][<span style=\"color:#a5d6ff\">0<\/span>].displayName;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">25<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">26<\/span><span> text <span style=\"color:#ff7b72;font-weight:bold\">=<\/span> <span style=\"color:#a5d6ff\">`<\/span><span style=\"color:#a5d6ff\">${<\/span>categoryName<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\"> (<\/span><span style=\"color:#a5d6ff\">${<\/span>categoryScore<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">%) - <\/span><span style=\"color:#a5d6ff\">${<\/span>handedness<span style=\"color:#a5d6ff\">}<\/span><span style=\"color:#a5d6ff\">`<\/span>;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">27<\/span><span> }\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">28<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">29<\/span><span> <span style=\"color:#ff7b72\">if<\/span> (<span style=\"color:#ff7b72;font-weight:bold\">!<\/span>visionRecogniser) {\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">30<\/span><span> <span style=\"color:#ff7b72\">return<\/span> &lt;<span style=\"color:#7ee787\">p<\/span>&gt;Loading...&lt;\/<span style=\"color:#7ee787\">p<\/span>&gt;;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">31<\/span><span> }\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">32<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">33<\/span><span> <span style=\"color:#8b949e;font-style:italic\">\/\/ On retourne le composant\n<\/span><\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">34<\/span><span><span style=\"color:#8b949e;font-style:italic\"><\/span> <span style=\"color:#ff7b72\">return<\/span> (\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">35<\/span><span> &lt;<span style=\"color:#7ee787\">div<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;relative mx-auto p-4&#34;<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">36<\/span><span> &lt;<span style=\"color:#7ee787\">WebcamProvider<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">37<\/span><span> &lt;<span style=\"color:#7ee787\">div<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;relative w-fit mx-auto&#34;<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">38<\/span><span> &lt;<span style=\"color:#7ee787\">Video<\/span> vision<span style=\"color:#ff7b72;font-weight:bold\">=<\/span>{visionRecogniser} onVisionData<span style=\"color:#ff7b72;font-weight:bold\">=<\/span>{setVisionData} \/&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">39<\/span><span> &lt;<span style=\"color:#7ee787\">Canvas<\/span> data<span style=\"color:#ff7b72;font-weight:bold\">=<\/span>{visionData} \/&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">40<\/span><span> &lt;\/<span style=\"color:#7ee787\">div<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">41<\/span><span> &lt;\/<span style=\"color:#7ee787\">WebcamProvider<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">42<\/span><span>\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">43<\/span><span> {visionData <span style=\"color:#ff7b72;font-weight:bold\">&amp;&amp;<\/span> &lt;<span style=\"color:#7ee787\">p<\/span> class<span style=\"color:#ff7b72;font-weight:bold\">=<\/span><span style=\"color:#a5d6ff\">&#34;absolute z-10 bottom-4&#34;<\/span>&gt;{text}&lt;\/<span style=\"color:#7ee787\">p<\/span>&gt;}\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">44<\/span><span> &lt;\/<span style=\"color:#7ee787\">div<\/span>&gt;\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">45<\/span><span> );\n<\/span><\/span><span style=\"display:flex;\"><span style=\"white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681\">46<\/span><span>}\n<\/span><\/span><\/code><\/pre><\/div><p>Et voil\u00e0, notre composant est maintenant capable de g\u00e9rer Mediapipe.\nLe composant <code>&lt;Video\/&gt;<\/code> s&rsquo;occupe de r\u00e9cup\u00e9rer le flux vid\u00e9o de la webcam et de le traiter avec Mediapipe. Le composant <code>&lt;Canvas\/&gt;<\/code> s&rsquo;occupe de dessiner les informations r\u00e9cup\u00e9r\u00e9es par Mediapipe sur le flux vid\u00e9o. Et le composant <code>&lt;WebcamProvider\/&gt;<\/code> s&rsquo;occupe de g\u00e9rer l&rsquo;acc\u00e8s \u00e0 la webcam.<\/p>\n<p>\u00c0 partir de l\u00e0, il ne reste plus qu&rsquo;\u00e0 ajouter les styles et les scripts n\u00e9cessaires pour que notre composant fonctionne correctement.<\/p>\n<h2 id=\"conclusion\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nConclusion <a href=\"#conclusion\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Ce projet fut tr\u00e8s int\u00e9ressant sur de nombreux point.<\/p>\n<p>Tout d&rsquo;abord, je me suis rendu compte que l&rsquo;utilisation de JSX avec Kita comme moteur de rendu \u00e9tait vraiment s\u00e9duisant en comparaison \u00e0 ce qui existe d\u00e9j\u00e0 avec EdgeJS. La capacit\u00e9 \u00e0 proposer des composants facilement r\u00e9utilisables et <em>typescript-friendly<\/em> est vraiment un plus !<\/p>\n<p>Ensuite, j&rsquo;ai pu d\u00e9couvrir les Web Components et leur utilisation avec Preact. M\u00eame si je n&rsquo;ai pas pu exploiter pleinement leur potentiel, j&rsquo;ai pu voir \u00e0 quel point ils \u00e9taient simples \u00e0 mettre en place et \u00e0 utiliser. Cela m&rsquo;a permit de me rendre compte que l&rsquo;utilisation de gros framework en Single-Page-App (tel que React, Vue ou Angular) n&rsquo;\u00e9tait pas une n\u00e9cessit\u00e9 pour avoir de l&rsquo;interactivit\u00e9 sur un site web. Les Web Components peuvent tr\u00e8s bien faire le travail s&rsquo;il est bien utilis\u00e9.<\/p>\n<p>Et pour finir, j&rsquo;ai vraiment \u00e9t\u00e9 surpris par la simplicit\u00e9 d&rsquo;utilisation de la librairie MediaPipe, et la facilit\u00e9 pour mettre cette derni\u00e8re en place dans un projet. M\u00eame si je n&rsquo;ai pas pu exploiter pleinement les capacit\u00e9s de cette librairie, j&rsquo;ai pu voir son potentiel.<\/p>\n<p>Je vous invite \u00e0 aller voir le code de ce projet sur mon <a href=\"https:\/\/github.com\/Bricklou\/media-pipe-demo\/\">Github<\/a> pour voir comment j&rsquo;ai mis en place tout cela.<\/p>"},{"title":"Projet Archipel","link":"https:\/\/bricklou.ovh\/posts\/2023\/11\/06\/projet-archipel\/","pubDate":"Mon, 06 Nov 2023 00:00:00 +0100","guid":"https:\/\/bricklou.ovh\/posts\/2023\/11\/06\/projet-archipel\/","description":"<p>C&rsquo;est parti, premier post de ce blog !<\/p>\n<p>Aujourd&rsquo;hui, nous allons parler d&rsquo;un projet que j&rsquo;ai d\u00e9marr\u00e9 avec une petite \u00e9quipe de gens passionn\u00e9s. Ce projet se nomme <strong>Archipel Project<\/strong>, il consiste \u00e0 r\u00e9impl\u00e9menter un serveur Minecraft en Rust sous forme de micro-services.<\/p>\n<h2 id=\"introduction\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nIntroduction <a href=\"#introduction\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Minecraft est un jeu dans un monde ouvert cr\u00e9\u00e9 en 2011 par Markus &ldquo;Notch&rdquo; Persson et, par la suite, d\u00e9velopp\u00e9 par le studio Mojang. Il fait partie de l&rsquo;un des jeux les plus vendues au monde avec, \u00e0 ce jour, plus de 238 millions de copies vendues, toute plateforme confondues.<\/p>\n<p>L&rsquo;un des principaux attraits \u00e0 ce jeu est la possibilit\u00e9 d&rsquo;agir librement et de laisser cours \u00e0 son imagination. Il n&rsquo;y a ni qu\u00eates, ni sch\u00e9ma narratif, uniquement des blocs g\u00e9n\u00e9r\u00e9s proc\u00e9duralement, des ressources \u00e0 perte de vue, et nous-m\u00eame.<\/p>\n<figure><img src=\"https:\/\/bricklou.ovh\/posts\/2023\/11\/06\/projet-archipel\/screenshot.webp\"\nalt=\"Capture d&#39;\u00e9cran du jeu Minecraft sur une partie en survie.\"><figcaption>\n<p>Partie en survie en solo<\/p>\n<\/figcaption>\n<\/figure>\n<p>Pour en revenir au projet, il fut initi\u00e9 sur un coup de t\u00eate (on ne va pas se le cacher \ud83d\ude02). Malgr\u00e9 le succ\u00e8s du jeu, il est loin de fonctionner aux meilleures performances possibles. Beaucoup de personnes se plaignent de la lourdeur et du manque d&rsquo;optimisation des serveurs Java (mono-threading, grande utilisation de la m\u00e9moire, etc.), \u00e0 tel point que la communaut\u00e9 de modding ont fait leurs propres mods pour corriger cela. C&rsquo;est donc ici que nous allons intervenir, en tentant de proposer une solution, essayant de pallier ces probl\u00e8mes, tout en proposant d&rsquo;autres fonctionnalit\u00e9s.<\/p>\n<h2 id=\"objectif-du-projet\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nObjectif du projet <a href=\"#objectif-du-projet\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Comme cit\u00e9 pr\u00e9c\u00e9demment, notre objectif est de faire une impl\u00e9mentation compl\u00e8te d&rsquo;un serveur Minecraft dans le langage Rust. Cette derni\u00e8re doit pouvoir permettre d&rsquo;avoir un serveur rapide, s\u00e9curis\u00e9 et surtout simple d&rsquo;utilisation (au plus possible en tout cas).<\/p>\n<p>Pour compl\u00e9ter tout cela, nous sommes partis sur une architecture micro-service, dispatchant ainsi la logique du jeu dans plusieurs petits services qui communiqueront les uns avec les autres : certains stockeront les donn\u00e9es du monde, d&rsquo;autres ex\u00e9cuteront la logique du jeu, et d&rsquo;autre s&rsquo;occuperont de g\u00e9rer la connexion des joueurs et de son authentification. Cette ultra-modularit\u00e9 aura comme point fort de permettre aux cr\u00e9ateurs de serveur de n&rsquo;utiliser que ce dont ils ont besoins pour leur installation, le tout en restant compatible avec le client officiel !<\/p>\n<h2 id=\"quest-ce-quun-micro-service-\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nQu&rsquo;est-ce qu&rsquo;un micro-service ? <a href=\"#quest-ce-quun-micro-service-\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Imaginez que vous d\u00e9veloppez une ville num\u00e9rique, o\u00f9 chaque fonctionnalit\u00e9 est un petit b\u00e2timent d\u00e9di\u00e9. Chaque b\u00e2timent s&rsquo;occupe d&rsquo;une t\u00e2che sp\u00e9cifique et fonctionne de mani\u00e8re autonome tout en contribuant au fonctionnement global de la ville. C&rsquo;est exactement ce que sont les micro-services dans le domaine du d\u00e9veloppement informatique.<\/p>\n<p>Un micro-service est une unit\u00e9 logicielle autonome con\u00e7ue pour g\u00e9rer une t\u00e2che sp\u00e9cifique au sein d&rsquo;une application plus large. Prenons l&rsquo;exemple d&rsquo;une application de commerce \u00e9lectronique. Plut\u00f4t que de construire une seule entit\u00e9 complexe pour g\u00e9rer toutes les fonctionnalit\u00e9s, vous divisez l&rsquo;application en plusieurs micro-services distincts, comme l&rsquo;authentification des utilisateurs, la gestion du catalogue de produits, le traitement des paiements, et ainsi de suite.<\/p>\n<p>Chaque micro-service a son propre ensemble d&rsquo;interfaces et sa propre base de donn\u00e9es. De plus, il peut \u00eatre d\u00e9velopp\u00e9, test\u00e9 et d\u00e9ploy\u00e9 ind\u00e9pendamment des autres micro-services. Cela signifie que si des modifications sont n\u00e9cessaires dans une fonctionnalit\u00e9 sp\u00e9cifique, elles peuvent \u00eatre effectu\u00e9es sans impacter le reste de l&rsquo;application. C&rsquo;est comme r\u00e9nover un b\u00e2timent dans votre ville num\u00e9rique sans perturber le fonctionnement global.<\/p>\n<p>L&rsquo;approche des micro-services offre une flexibilit\u00e9 et une \u00e9volutivit\u00e9 exceptionnelles. Chaque micro-service peut \u00eatre ajust\u00e9 en fonction des besoins sans perturber l&rsquo;ensemble de l&rsquo;application. De plus, les \u00e9quipes de d\u00e9veloppement peuvent travailler simultan\u00e9ment sur diff\u00e9rents micro-services, acc\u00e9l\u00e9rant ainsi le processus de d\u00e9veloppement.<\/p>\n<p>En r\u00e9sum\u00e9, les micro-services r\u00e9inventent la fa\u00e7on dont les applications sont con\u00e7ues et construites. Ils permettent la cr\u00e9ation d&rsquo;applications modulaires, flexibles et \u00e9volutives tout en facilitant la gestion, la maintenance et les mises \u00e0 jour continues. \u00c0 l&rsquo;instar des b\u00e2timents sp\u00e9cialis\u00e9s dans une ville, les micro-services sont les \u00e9l\u00e9ments fondamentaux d&rsquo;une architecture moderne et efficace.<\/p>\n<p>En reprenant tous les points expliqu\u00e9s pr\u00e9c\u00e9demment pour les appliquer au projet, chaque entit\u00e9 aura son r\u00f4le \u00e0 jouer dans l&rsquo;ensemble de l&rsquo;infrastructure. Un exemple de service que nous aurons \u00e0 impl\u00e9menter sera un serveur de stockage du monde, un proxy pour la connexion des joueurs ou m\u00eame un serveur d&rsquo;authentification. Chacune de ces parties vont permettre de composer l&rsquo;infrastructure de notre serveur de jeu.<\/p>\n<h2 id=\"conclusion\" class=\"relative group flex flex-row lg:items-center pl-5 md:-left-5\">\nConclusion <a href=\"#conclusion\" class=\"no-underline hidden absolute bottom-2.5 left-0 group-hover:block\">\n<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-4 h-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-link\">\n<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"\/>\n<path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"\/>\n<\/svg>\n<\/a><\/h2>\n<p>Nous esp\u00e9rons que vous appr\u00e9cierez ce projet autant que nous. Nous n&rsquo;en sommes qu&rsquo;au d\u00e9but et il nous reste beaucoup \u00e0 faire dessus. Bien entendu, vous pouvez toujours aller jeter un coup d&rsquo;\u0153il sur la page du projet et m\u00eame y contribuer \u00e0 son d\u00e9veloppement.<\/p>\n<p>Vous pourrez retrouver plus d&rsquo;informations en visitant la page <a href=\"https:\/\/github.com\/archipel-project\">Github<\/a>.<\/p>\n<p>Ainsi que le blog, que nous mettrons \u00e0 jour au fil du d\u00e9veloppement avec de nombreux articles de recherches : <a href=\"https:\/\/archipel-project.github.io\/dev-blog\/\">Archipel - Dev Blog<\/a>.<\/p>"}]}}