<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Container on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/container/</link><description>Recent content in Container on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Mon, 13 Jun 2022 08:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/container/index.xml" rel="self" type="application/rss+xml"/><item><title>QNAP débranche LXC sur les NAS ARM : comment contourner ?</title><link>https://blog.zwindler.fr/2022/06/13/qnap-debranche-lxc-workaround/</link><pubDate>Mon, 13 Jun 2022 08:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2022/06/13/qnap-debranche-lxc-workaround/</guid><description>&lt;img src="https://blog.zwindler.fr/2018/01/qnap22.webp" alt="Featured image of post QNAP débranche LXC sur les NAS ARM : comment contourner ?" /&gt;&lt;p&gt;Si vous le suivez sur Twitter ou Masto, vous m&amp;rsquo;avez très probablement lu râler contre la sortie &lt;del&gt;de QTS 5&lt;/del&gt; Container Station v2.4.0.2316, l&amp;rsquo;été dernier.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://preview.redd.it/6bouewrhnze71.png?width=1283&amp;amp;format=png&amp;amp;auto=webp&amp;amp;s=11aacee53bf931b47d1534cc1478b47aa7239701"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Ou plus particulièrement, contre une décision prise lors de ce passage : enlever LXC pour l&amp;rsquo;administration des containers, au profit de LXD. LXD étant juste une couche d&amp;rsquo;administration, LXC est toujours présent et fonctionnel, juste caché.&lt;/p&gt;
&lt;p&gt;Pourquoi je râle ?&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai un &lt;a class="link" href="https://blog.zwindler.fr/2018/01/23/stockage-pour-un-admin-geek-qnap-ts431p2-ou-synology-ds418j" &gt;NAS QNAP TS431P2 depuis 2018 dont je suis pleinement satisfait&lt;/a&gt;, et qui m&amp;rsquo;a permis de passer moins de temps à administrer et ajouter des fonctionnalités à mon NAS ZFS maison, monté initialement en 2011 (merci &lt;em&gt;Dworak_of_sky&lt;/em&gt; pour les souvenirs).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2011/06/29/nasmediacenter-do-it-yourself-or-not/" &gt;NAS/MediaCenter : Do It (the hardware part) Yourself!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2011/08/04/nasmediacenter-do-it-the-software-part-yourself/" &gt;NAS/MediaCenter : Do It (the software part) Yourself!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sauf&lt;/strong&gt; que mon QNAP est un NAS milieu de gamme, fonctionnant avec &lt;em&gt;un processeur ARM&lt;/em&gt; et pas x86 ! Et ces charmantes personnes (grrrr) de chez QNAP &lt;strong&gt;n&amp;rsquo;ont pas porté LXD sur les NAS ARM&lt;/strong&gt; (segmentation artificielle de l&amp;rsquo;offre ? Flemme ?).&lt;/p&gt;
&lt;p&gt;Nous, propriétaires de NAS QNAP ARM, nous retrouvons donc sans solution puisque LXC est désactivé et LXD pas disponible.&lt;/p&gt;
&lt;p&gt;Une fonction hyper pratique pour héberger de petits services à bas coût (autant en performance qu&amp;rsquo;en prix) disparaît. C&amp;rsquo;était un réel différenciant pour ce modèle et je me sens vraiment trahi (ou alors c&amp;rsquo;est ma faute, car je n&amp;rsquo;aurais pas dû leur faire confiance ?).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/06/trahison.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Je ne suis pas près de recommander QNAP comme j&amp;rsquo;ai pu le faire par le passé. #PasContent&lt;/p&gt;
&lt;h2 id="nuance"&gt;Nuance
&lt;/h2&gt;&lt;p&gt;HEUREUSEMENT, les containers LXC ne se sont pas mis à ne plus marcher du jour au lendemain.&lt;/p&gt;
&lt;p&gt;Enfin, encore heureux ! Je n&amp;rsquo;ose imaginer les dégâts en prod !&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est d&amp;rsquo;autant plus vicelard que le message d&amp;rsquo;information pour expliquer qu&amp;rsquo;il n&amp;rsquo;y a plus LXC indique que c&amp;rsquo;est pas grave puisque vous avez LXD à la place. Aucune mention du fait qu&amp;rsquo;en fait, sous ARM, non&amp;hellip;&lt;/p&gt;
&lt;p&gt;Il est toujours possible (&lt;strong&gt;pour l&amp;rsquo;instant&lt;/strong&gt;) de démarrer, arrêter, utiliser et supprimer les containers existants. Mais il n&amp;rsquo;est plus possible d&amp;rsquo;en créer de nouveaux.&lt;/p&gt;
&lt;p&gt;Ça veut donc dire que tout est encore présent pour faire fonctionner la fonctionnalité, ce n&amp;rsquo;est &amp;ldquo;juste&amp;rdquo; plus disponible en UI.&lt;/p&gt;
&lt;h2 id="en-avoir-le-coeur-net"&gt;En avoir le coeur net
&lt;/h2&gt;&lt;p&gt;En farfouillant, je me suis aussi rendu compte qu&amp;rsquo;il était toujours possible d&amp;rsquo;&lt;strong&gt;exporter&lt;/strong&gt; des containers existants et d&amp;rsquo;&lt;strong&gt;importer&lt;/strong&gt; les exports.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/06/qnap_export.avif"
loading="lazy"
&gt;
&lt;img src="https://blog.zwindler.fr/2022/06/qnap_import.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;On peut donc contourner la limitation arbitraire de QNAP via des export / import. J&amp;rsquo;ai l&amp;rsquo;habitude de ce genre de bidouilles, &lt;a class="link" href="https://blog.zwindler.fr/2011/03/20/copier-une-vm-windows-xp-sous-esxi-sans-vcenter/" target="_blank" rel="noopener"
&gt;puisque je faisais déjà ça il y a plus de 10 ans avec les hyperviseurs VMware en licence gratuite&lt;/a&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;A l&amp;rsquo;usage, ça fonctionne mais c&amp;rsquo;est pas satisfaisant. D&amp;rsquo;abord parce que si on a pas, ou plus, de containers sur le NAS, on ne peut pas le faire trivialement.&lt;/p&gt;
&lt;p&gt;Ensuite, parce que le processus et long (l&amp;rsquo;export et l&amp;rsquo;import) et pénible (plusieurs étapes).&lt;/p&gt;
&lt;p&gt;Enfin, parce que les images LXC mises à disposition par QNAP étaient antédiluviennes !&lt;/p&gt;
&lt;p&gt;Ubuntu 14.04 !!! Sauf si vous avez pris le temps de faire le processus d&amp;rsquo;upgrade complet de 14.04 à 20.04 ou 22.04 (et vous devriez), il est probable que vous n&amp;rsquo;ayez pas envie de repartir de ces vieux machins.&lt;/p&gt;
&lt;h2 id="faites-mieux"&gt;&amp;ldquo;Faites mieux&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;Si vous êtes admin, vous avez probablement déjà activé SSH pour vous connecter directement à l&amp;rsquo;OS de votre NAS. (&lt;a class="link" href="https://www.qnap.com/fr-fr/how-to/knowledge-base/article/how-to-access-qnap-nas-by-ssh" target="_blank" rel="noopener"
&gt;Et sinon vous pouvez aller ici pour l&amp;rsquo;activer&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Une fois connecté, on peut sortir du menu TUI et bidouiller l&amp;rsquo;OS comme on en a envie.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/06/qnap_ssh_admin.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~] # id
uid=0(admin) gid=0(administrators)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Je n&amp;rsquo;ai pas fait beaucoup d&amp;rsquo;administration LXC/LXD directement, car j&amp;rsquo;avais toujours une interface à ma disposition pour me &amp;ldquo;cacher&amp;rdquo; la façon dont ça fonctionne vraiment, que ce soit dans le cas de QNAP ou de &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=lxc" target="_blank" rel="noopener"
&gt;Proxmox VE (que j&amp;rsquo;utilise beaucoup pour ça)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En lisant rapidement &lt;a class="link" href="https://doc.ubuntu-fr.org/lxc" target="_blank" rel="noopener"
&gt;la doc sur ubuntu-fr&lt;/a&gt;, j&amp;rsquo;ai compris qu&amp;rsquo;il existait en fait chez Canonical un genre de dépôt d&amp;rsquo;images officielles de pleins d&amp;rsquo;OS, notamment compatible &lt;strong&gt;armhf&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://images.lxd.canonical.com/" target="_blank" rel="noopener"
&gt;images.lxd.canonical.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://images.linuxcontainers.org//meta/1.0/index-system" target="_blank" rel="noopener"
&gt;images.linuxcontainers.org//meta/1.0/index-system&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avec LXC, on peut accéder directement à ces images en ligne de commande avec &lt;code&gt;lxc-download&lt;/code&gt;. Pas de bol, la commande n&amp;rsquo;est pas dispo sur QTS :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[~] # lxc-download
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;-sh: lxc-download: command not found
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(En fait elle n&amp;rsquo;est juste pas dans le PATH, mais je ne le savais pas à ce moment-là)&lt;/p&gt;
&lt;p&gt;Sauf qu&amp;rsquo;on peut aussi appeler directement la commande pour créer des containers &lt;code&gt;lxc-create&lt;/code&gt; avec un flag &amp;ldquo;download&amp;rdquo;. Et ça tombe bien parce que &lt;code&gt;lxc-create&lt;/code&gt; est disponible. Mais la joie sera de courte durée&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;lxc-create -t download -n container_jammy -- -d ubuntu -r jammy -a armhf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;/usr/local/container-station/lxc/share/lxc/templates/lxc-download: line 237: getopt: command not found
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="hack"&gt;Hack&amp;hellip;
&lt;/h2&gt;&lt;p&gt;Note : si vous trouviez que ce qu&amp;rsquo;on était en train de faire n&amp;rsquo;était déjà pas très propre, je tiens à vous prévenir, la suite est vraiment immonde&amp;hellip; Pas merci QNAP de me forcer à faire ça !&lt;/p&gt;
&lt;p&gt;Le script &lt;code&gt;/usr/local/container-station/lxc/share/lxc/templates/lxc-download&lt;/code&gt; est moisi. Il manque la moitié des binaires dans la busybox.&lt;/p&gt;
&lt;p&gt;Pire encore, la procédure que je donne ici semble être écrasée à chaque mise à jour de l&amp;rsquo;application &lt;strong&gt;Container Station&lt;/strong&gt;. Mais, ça fonctionne&amp;hellip;&lt;/p&gt;
&lt;p&gt;La première chose qu&amp;rsquo;on va faire, c&amp;rsquo;est faire une sauvegarde du script &lt;code&gt;lxc-download&lt;/code&gt; par sécurité.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;cp /usr/local/container-station/lxc/share/lxc/templates/lxc-download{,.old}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Le premier message d&amp;rsquo;erreur qu&amp;rsquo;on a &lt;code&gt;getopt: command not found&lt;/code&gt; indique juste que de nombreux binaires &amp;ldquo;classiques&amp;rdquo; ne sont pas disponibles directement dans le shell de QTS.&lt;/p&gt;
&lt;p&gt;Sauf qu&amp;rsquo;en fait, ils sont là, ces binaires. Pas besoin de les télécharger ou de les compiler. Ils ne sont juste &amp;ldquo;pas visibles&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;QTS tourne, comme beaucoup de serveurs Linux minimalistes, avec &lt;a class="link" href="https://fr.wikipedia.org/wiki/BusyBox" target="_blank" rel="noopener"
&gt;l&amp;rsquo;aide de Busybox&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On peut donc &amp;ldquo;magiquement activer&amp;rdquo; les binaires qui nous manquent simplement avec des liens symboliques.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;for binary in getopt xz seq; do
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ln -s /share/CACHEDEV1_DATA/.qpkg/container-station/bin/busybox /share/CACHEDEV1_DATA/.qpkg/container-station/bin/${binary}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;done
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;getopt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;getopt: missing optstring argument
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="-and-slash"&gt;&amp;hellip; and slash!
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;C&amp;rsquo;est bon, mais pas suffisant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;La version du binaire &lt;code&gt;mktemp&lt;/code&gt; de busybox n&amp;rsquo;est malheureusement PAS compatible avec le script &lt;code&gt;lxc-download&lt;/code&gt;. On va devoir le modifier à la main&amp;hellip;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Usage: mktemp [-dq] TEMPLATE
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Le passage problématique se situe autour des lignes 320-325&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;320&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; ! &lt;span class="nb"&gt;command&lt;/span&gt; -V mktemp &amp;gt;/dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;321&lt;/span&gt; &lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmp/lxc-download.&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;322&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;323&lt;/span&gt; &lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp -d&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;324&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En vrai, &lt;code&gt;mktemp&lt;/code&gt; s&amp;rsquo;attend à avoir le path complet, accompagné d&amp;rsquo;un pattern à base de XXXXXX. &lt;code&gt;mktemp&lt;/code&gt; remplace ensuite les caractères XXXXXX par un nombre aléatoire en s&amp;rsquo;assurant que le dossier n&amp;rsquo;existe pas déjà, puis le créé. Par exemple&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mktemp /tmp/mydirXXXXX
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mode bourrin, j&amp;rsquo;ai remplacé la ligne par :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;323&lt;/span&gt; &lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tmpdir&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOWNLOAD_TEMP&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;De toute façon, il est supprimé à la fin de l&amp;rsquo;exécution du script, ce dossier (fonction cleanup dans le shell).&lt;/p&gt;
&lt;h2 id="gpg"&gt;GPG
&lt;/h2&gt;&lt;p&gt;On progresse !&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[~] # lxc-create -t download -n container_jammy -- -d ubuntu -r jammy -a armhf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Setting up the GPG keyring
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;chmod: /var/lib/lxc/container_jammy/tmpdir/gpg: No such file or directory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Error creating container container_jammy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En creusant un peu, la vraie erreur est que je n&amp;rsquo;ai pas le binaire &lt;code&gt;gpgkeys_curl&lt;/code&gt; à l&amp;rsquo;endroit attendu :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;gpg: unable to execute program `/opt/cross-project/arm/linaro/arm-linux-gnueabihf/libc/libexec/gnupg/gpgkeys_curl&amp;#39;: No such file or directory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Voilà un autre point que je n&amp;rsquo;ai pas réussi à corriger correctement.&lt;/p&gt;
&lt;p&gt;Le plus simple est de simplement ignorer la validation avec &lt;code&gt;--no-validate&lt;/code&gt; mais si vous avez une piste, je suis preneur.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;lxc-create -t download -n container_jammy -- -d ubuntu -r jammy -a armhf --no-validate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="des-dossiers-qui-disparaissent-tout-seul-"&gt;Des dossiers qui disparaissent tout seul ???
&lt;/h2&gt;&lt;p&gt;Dernier mystère&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Downloading the image index
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;ERROR: Failed to download http://images.linuxcontainers.org//meta/1.0/index-system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;L&amp;rsquo;erreur n&amp;rsquo;est pas du tout un problème d&amp;rsquo;accès à l&amp;rsquo;URL pour télécharger l&amp;rsquo;index des systèmes disponibles sur &lt;code&gt;images.linuxcontainers.org&lt;/code&gt; (code 302, page redirigée sur &lt;code&gt;uk.lxd.images.canonical.com&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;En réalité, si active les messages d&amp;rsquo;erreurs lors du &lt;code&gt;wget&lt;/code&gt; dans le script, l&amp;rsquo;erreur est que le dossier &lt;code&gt;/var/lib/lxc/container_jammy/tmpdir/&lt;/code&gt; n&amp;rsquo;existe pas !&lt;/p&gt;
&lt;p&gt;Pourtant, ça devrait être corrigé, suite à la modif qu&amp;rsquo;on a faite ligne 323 (voir plus haut)&amp;hellip; trop bizarre :/&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;en ai eu un peu marre de creuser et au bout d&amp;rsquo;un moment, j&amp;rsquo;ai juste fait :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;export CONTAINER_NAME=jammy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;mkdir -p /var/lib/lxc/${CONTAINER_NAME}/tmpdir/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;mkdir -p /var/lib/lxc/${CONTAINER_NAME}/rootfs/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;lxc-create -t download -n ${CONTAINER_NAME} -- -d ubuntu -r jammy -a armhf --no-validate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et croyez-le ou non, mais ça marche ! Le container existe (il n&amp;rsquo;est juste pas visible dans la console pour l&amp;rsquo;instant)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;[...]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;You just created an Ubuntu jammy armhf (20220611_07:42) container.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On a plus qu&amp;rsquo;à redémarrer Container Station, il apparaît&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2022/06/qnap_lxc_jammy.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Si jamais quelqu&amp;rsquo;un de chez QNAP lit ce blogpost&amp;hellip; Arrêtez de vous fiche de nous et :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mettez nous LXD dans nos NAS ARM&lt;/li&gt;
&lt;li&gt;OU si c&amp;rsquo;est trop de boulot (je peux l&amp;rsquo;entendre), remettre LXC en attendant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce genre de hack est indigne et j&amp;rsquo;ai perdu plusieurs heures pour corriger votre m***e. J&amp;rsquo;ai payé pour un NAS compatible LXC, ce n&amp;rsquo;est pas pour que vous retiriez la fonctionnalité 1 an après.&lt;/p&gt;
&lt;p&gt;Ce genre de pratiques est vraiment dégueulasse et je n&amp;rsquo;hésiterais pas à dire tout le mal que je pense de cette décision.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://forum.qnap.com/viewtopic.php?t=159613" target="_blank" rel="noopener"
&gt;Un post sur le Forum QNAP qui m&amp;rsquo;a un peu guidé vers la solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.reddit.com/r/qnap/comments/owkr63/qnap_container_station_loss_of_functionality/" target="_blank" rel="noopener"
&gt;Un fil de discussion Reddit qui en parle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Kubernetes avec RancherOS et RKE – partie 1</title><link>https://blog.zwindler.fr/2020/10/26/kubernetes-avec-rancheros-et-rke-partie-1/</link><pubDate>Mon, 26 Oct 2020 07:45:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/10/26/kubernetes-avec-rancheros-et-rke-partie-1/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/10/rancheros_explained.webp" alt="Featured image of post Kubernetes avec RancherOS et RKE – partie 1" /&gt;&lt;h2 id="rancheros-pour-commencer"&gt;RancherOS pour commencer
&lt;/h2&gt;&lt;p&gt;Pendant l’été, j’ai &lt;em&gt;encore&lt;/em&gt; changé d’infra, avec un passage à un cluster Proxmox VE à 3 nœuds. Je reviendrais la dessus, mais la finalité c’est que j’ai eu (encore) l’envie de m’installer un petit cluster Kubernetes dans mes hyperviseurs.&lt;/p&gt;
&lt;p&gt;Ceux qui me suivent depuis un moment savent que j’en ai déjà déployé des tonnes depuis le temps (&lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=kubernetes" &gt;k3s qui vient également de chez Rancher, mais aussi kubespray, kubeadm, aks, OVH, the hard way de kelsey hightower, &amp;hellip;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Du coup, plutôt que de gagner du temps et refaire quelque chose que je maîtrise déjà, je suis parti dans l’idée de tester quelque chose d’encore nouveau, deux produits de Rancher dont j’ai entendu parler : RancherOS + RKE !&lt;/p&gt;
&lt;p&gt;L’idée dans cette première partie est de découvrir RancherOS, une des nombreuses solutions pour vos workload containerisés proposées par Rancher.&lt;/p&gt;
&lt;h2 id="mais-cest-quoi-rancheros-"&gt;Mais c’est quoi RancherOS ?
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;RancherOS A lightweight, secure Linux distribution, built from containers to run containers well.
RancherOS est donc un OS minimaliste contenant juste ce qu’il faut pour faire du Docker, configuré à l’aide de cloud-init et dans lequel la plupart des opérations de maintenances sont simplifiées.
Quand je lis ça, je ne peux pas m&amp;rsquo;empêcher de repenser à CoreOS, qui faisait (fait) les mêmes promesses.
N’ayant qu’installé et utilisé pendant peu de temps CoreOS, je ne serai pas capable de faire une comparaison des deux produits entre eux, mais la finalité est vraiment la même.
Un point intéressant (je trouve) dans RancherOS est le fait que tous les services &amp;ldquo;techniques&amp;rdquo; nécessaires pour faire fonctionner correctement vos applications containerisés sont également des containers.
RancherOS is the smallest, easiest way to run Docker in production. Every process in RancherOS is a container managed by Docker. This includes system services such as udev and syslog.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/10/rancheros_explained.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;L’idée ici, c’est que tous ces services systèmes tournent dans un démon Docker séparé (pour plus de sécurité et éviter la suppression accidentelle).&lt;/p&gt;
&lt;h2 id="comment-le-déployer-"&gt;Comment le déployer ?
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Ça dépend. Et évidemment, ça dépend, ça dépasse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Rancher a fait le choix (malin) de mettre le paquet pour faciliter le déploiement de leur RancherOS sur le plus de plateformes possibles.&lt;/p&gt;
&lt;p&gt;Ainsi, vous retrouverez des processus de déploiement facilités pour la plupart des clouds providers public, mais aussi des images pour VMware, une image pour Rasberry Pi, Virtual Box ou Docker Machine. Il y a même de quoi booter en PXE pour ceux qui ont encore l’envie de faire ce genre de choses.&lt;/p&gt;
&lt;p&gt;Dans mon cas, la seule solution à ma disposition pour KVM c’est d’&lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/installation/workstation/boot-from-iso/" target="_blank" rel="noopener"
&gt;utiliser l’ISO&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="première-bonne-nouvelle-et-première-déconvenue"&gt;Première bonne nouvelle et première déconvenue
&lt;/h2&gt;&lt;p&gt;LA première bonne nouvelle, c’est qu’il existe un ISO tuné pour Proxmox VE, et ça c’est très cool.&lt;/p&gt;
&lt;p&gt;Donc je DL l’ISO, créé une bête machine virtuelle sur mon cluster, dans lequel l’ISO est monté et roule ma poule ?&lt;/p&gt;
&lt;p&gt;Ouais&amp;hellip; presque !&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You must boot with enough memory which you can refer to &lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/overview/#hardware-requirements" target="_blank" rel="noopener"
&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Un point agaçant avec RancherOS est le &lt;em&gt;minimum requirement&lt;/em&gt; en termes de mémoire. 1.25 Go pour un OS Linux soi-disant minimaliste (passé à 1 Go depuis la 1.5), la pilule a du mal à passer. Ok, je pinaille peut-être un peu, mais 1 Go c’est énorme quand on a prévu de lancer juste quelques petits containers comme des petits nginx ou des petits bouts de code python.&lt;/p&gt;
&lt;p&gt;Il faut dire que Rancher nous a mal habitué avec k3s, leur Kubernetes modifié qui tourne avec quasiment pas de RAM au point de permettre de Kubernetes sur des RPi 1 ou en &lt;em&gt;edge computing&lt;/em&gt;. Et là, avec 2 fois plus de RAM en &lt;em&gt;requirement&lt;/em&gt;, j’ai que le démon Docker, même pas le kube qui va avec&amp;hellip;&lt;/p&gt;
&lt;p&gt;Du coup, le &amp;ldquo;RancherOS is the smallest, easiest way to run Docker in production&amp;rdquo;, bof&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2019/03/21/deployer-en-5-minutes-un-cluster-kubernetes-sur-arm-avec-k3s-et-ansible/" &gt;Déployer en 5 minutes un cluster Kubernetes sur ARM avec k3s et Ansible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rancher essaye de se raccrocher aux branches en vous linkant une &lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/installation/custom-builds/custom-rancheros-iso/#reduce-memory-requirements" target="_blank" rel="noopener"
&gt;doc permettant de construire soi-même une image custom nécessitant moins de RAM&lt;/a&gt;, mais bon&amp;hellip; Le mal est fait, ils m’ont pas motivé à tester&amp;hellip;&lt;/p&gt;
&lt;h2 id="déployer-rancheros-sur-proxmox-ve"&gt;Déployer RancherOS sur Proxmox VE
&lt;/h2&gt;&lt;p&gt;Ok, assez discuté, maintenant on peut rentrer dans le vif du sujet. Sur notre hyperviseur préféré, on récupère l’ISO.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cd /var/lib/vz/template/iso
wget https://releases.rancher.com/os/latest/proxmoxve/rancheros.iso
--2020-08-10 15:00:26-- https://releases.rancher.com/os/latest/proxmoxve/rancheros.iso
Resolving releases.rancher.com (releases.rancher.com)... 104.26.12.240, 172.67.69.133, 104.26.13.240, ...
Connecting to releases.rancher.com (releases.rancher.com)|104.26.12.240|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 160432128 (153M) [application/x-iso9660-image]
Saving to: ‘rancheros.iso’
rancheros.iso 100%[===================&amp;gt;] 153.00M 42.3MB/s in 3.7s
2020-08-10 15:00:36 (40.9 MB/s) - ‘rancheros.iso’ saved [160432128/160432128]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La procédure d’installation officielle est &lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/installation/server/install-to-disk/" target="_blank" rel="noopener"
&gt;disponible ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Grosso modo, on boot la VM, qui va configurer le serveur au minimum et permettre de se connecter avec l’utilisateur rancher&lt;code&gt; sans mot de passe. L’idée est d’utiliser cet utilisateur pour finaliser l’installation avec ros install&lt;/code&gt; une fois la VM configurée.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The ros install` command orchestrates the installation from the rancher/os container. You will need to have already created a cloud-config file and found the target disk.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;STOOOOOP&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Si vous partez bille en tête comme moi et faites un ros install` sans lire la phrase en entier, vous vous retrouverez avec une VM sur laquelle vous ne pourrez pas vous loguer (voire sans réseau si vous n’avez pas de DHCP). C’est con.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The easiest way to log in is to pass a cloud-config.yml file containing your public SSH keys.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="cloud-config"&gt;Cloud config
&lt;/h2&gt;&lt;p&gt;Ok, on va éviter de tous faire la même erreur. Voici maintenant le fameux prérequis, la documentation officielle qui parle de &lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/configuration/#cloud-config" target="_blank" rel="noopener"
&gt;configuration/#cloud-config&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Si vous avez un doute sur certains paramètres, vous pouvez toujours utiliser la commande ros config` qui permet de récupérer les valeurs par défaut puis les setter.&lt;/p&gt;
&lt;p&gt;On finalisera le tout en fusionnant la config actuelle avec un fichier YAML, ou alors on exportera la conf actuelle dans un autre fichier YAML.&lt;/p&gt;
&lt;p&gt;Dans le cas d’un PoC, la plupart des valeurs qui vont nous intéresser sont simplement ce qui permet de setter l’IP et de configurer notre clé SSH pour pouvoir se connecter.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo ros config get rancher.network
dhcp_timeout: 0
dns:
nameservers: []
search: []
http_proxy: &amp;#34;&amp;#34;
https_proxy: &amp;#34;&amp;#34;
interfaces: {}
modem_networks: {}
no_proxy: &amp;#34;&amp;#34;
post_cmds: []
pre_cmds: []
wifi_networks: {}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Donc là, de base, bah ya rien.&lt;/p&gt;
&lt;p&gt;Pourtant, si vous allez voir le fichier /var/lib/rancher/conf/cloud-config.yml, vous remarquerez qu’il y a pleeeeein de choses, plus ou moins utiles.&lt;/p&gt;
&lt;p&gt;La page de doc qui nous intéressera donc dans ce cas est &lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/networking/" target="_blank" rel="noopener"
&gt;networking&lt;/a&gt;. Voici un exemple de commandes pour configurer une IP fixe (à remplacer par des valeurs qui ont du sens dans votre réseau, of course).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo ros config set rancher.network.interfaces.eth0.address 192.168.1.10/24
sudo ros config set rancher.network.interfaces.eth0.gateway 192.168.1.1
sudo ros config set rancher.network.interfaces.eth0.mtu 1500
sudo ros config set rancher.network.interfaces.eth0.dhcp false
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A partir de ce moment là, vous avez accès au réseau depuis votre machine RancherOS, mais les modifications ne seront pas permanentes. On va donc exporter tout ça.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo ros config export
rancher:
environment:
EXTRA_CMDLINE: /init
network:
interfaces:
eth0:
address: 192.168.1.10/24
dhcp: false
gateway: 192.168.1.10
mtu: 1500
ssh_authorized_keys: []
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bon, et là vous voyez qu’il nous manque toujours la clé SSH.&lt;/p&gt;
&lt;h2 id="bonus-clavier-qwerty"&gt;Bonus clavier qwerty
&lt;/h2&gt;&lt;p&gt;Vous connaissez la différence entre un admin systèmes français débutant et un admin système français senior ?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you call yourself a sysadmin and don’t know by heart the qwerty layout on an azerty keyboard, I just assume you are a junior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Pour ceux qui n’ont pas la blague, allez voir ce tweet de _oshell qui a bien backfired (lien mort) dans sa face)&lt;/p&gt;
&lt;p&gt;Le senior, a force de bouffer des consoles à la con qui gèrent mal les différents layouts de claviers (parce que &amp;ldquo;hé, on s’en fout des gens qui ont pas de qwerty, on vient de la Silicon valley&amp;rdquo;), il connaît le qwerty par cœur.&lt;/p&gt;
&lt;p&gt;Et ben là encore, ça n’a pas loupé. La console NoVNC de mon PVE, qui en plus n’avait le partage de presse-papier qui ne marchait pas.&lt;/p&gt;
&lt;p&gt;Je veux bien être à l’aise en &amp;ldquo;blind qwerty sur azerty&amp;rdquo;, mais faut pas déconner, je suis pas senior au point d’être capable de copier une clé publique dans un YAML #trollface.&lt;/p&gt;
&lt;p&gt;Donc pour ceux qui ne connaissent pas l’astuce, il est possible d’affecter temporairement un terminal série à votre VM de la façon suivante (voir &lt;a class="link" href="https://pve.proxmox.com/wiki/Serial_Terminal" target="_blank" rel="noopener"
&gt;doc Proxmox VE&lt;/a&gt;)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# qm set 100 -serial0 socket
update VM 100: -serial0 socket
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A partir de là, vous devriez pouvoir accéder à un nouveau type de console dans Proxmox, qui devrait à la fois résoudre le problème de clavier qwerty ET le problème de presse-papier.&lt;/p&gt;
&lt;h2 id="cloud-config-suite"&gt;Cloud-config, suite
&lt;/h2&gt;&lt;p&gt;On récupère ce qu’on vient d’exporter et on ajoute notre clé comme nous le demande Rancher dans sa doc. Et avant de lancer l’install, on vérifie que notre cloud-config est valide&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo ros config validate -i cloud-config.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si la commande ne renvoie rien, c’est que c’est OK (pas super explicite mais bon why not). On passe donc à l’install :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo ros install -c cloud-config.yml -d /dev/sda
INFO[0000] No install type specified...defaulting to generic
Installing from rancher/os:v0.5.0
Continue [y/N]:
[...]
Continue with reboot [y/N]: y
INFO[0013] Rebooting
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A partir de là, on peut (et on doit) se connecter en SSH sur la machine RancherOS (l’accès console n’est plus possible)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ssh -J proxmoxve rancher@192.168.1.10
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et si tout s’est bien passé, vous devriez pouvoir vous connecter !&lt;/p&gt;
&lt;h2 id="et-maintenant-que-vais-je-fai-reuh-"&gt;Et maintenant, que vais-je fai-reuh ?
&lt;/h2&gt;&lt;p&gt;Ben déjà on peut regarder ce que RancherOS a activé comme &amp;ldquo;services&amp;rdquo; sur notre install Proxmox VE.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo ros service list
disabled amazon-ecs-agent
disabled container-cron
disabled open-iscsi
disabled zfs
disabled kernel-extras
disabled kernel-headers
disabled kernel-headers-system-docker
disabled open-vm-tools
disabled hyperv-vm-tools
enabled qemu-guest-agent
disabled rancher-server
disabled rancher-server-stable
disabled amazon-metadata
disabled volume-cifs
disabled volume-efs
disabled volume-nfs
disabled modem-manager
disabled waagent
disabled virtualbox-tools
disabled pingan-amc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Globalement, pas grand chose. La seule chose activée est le qemu-guest-agent, ce qui est utile puisque nous avons une effectivement une VM QEMU dans ce cas précis.
Quant à vos containers Docker, vous pouvez vérifier qu’ils sont bien séparés des containers docker servant au fonctionnement de RancherOS avec les commandes suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les containers &amp;ldquo;systèmes&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[rancher@rancher ~]$ sudo system-docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e059e78c17e rancher/os-docker:19.03.11 &amp;#34;ros user-docker&amp;#34; 12 minutes ago Up 12 minutes docker
ba43a0648227 rancher/os-qemuguestagent:v2.8.1-2 &amp;#34;/usr/bin/ros entr...&amp;#34; 12 minutes ago Restarting (1) 34 seconds ago qemu-guest-agent
d9ad607221fa rancher/os-console:v1.5.6 &amp;#34;/usr/bin/ros entr...&amp;#34; 12 minutes ago Up 12 minutes console
ad0197c79ff2 rancher/os-base:v1.5.6 &amp;#34;/usr/bin/ros entr...&amp;#34; 12 minutes ago Up 12 minutes ntp
538ccf5eb624 rancher/os-base:v1.5.6 &amp;#34;/usr/bin/ros entr...&amp;#34; 12 minutes ago Up 12 minutes network
f389c6b0b40e rancher/os-base:v1.5.6 &amp;#34;/usr/bin/ros entr...&amp;#34; 12 minutes ago Up 12 minutes udev
b51deb379bf2 rancher/container-crontab:v0.4.0 &amp;#34;container-crontab&amp;#34; 12 minutes ago Up 12 minutes system-cron
59441adcc016 rancher/os-syslog:v1.5.6 &amp;#34;/usr/bin/entrypoi...&amp;#34; 13 minutes ago Up 12 minutes syslog
120df7cc2492 rancher/os-acpid:v1.5.6 &amp;#34;/usr/bin/ros entr...&amp;#34; 13 minutes ago Up 12 minutes acpid
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vos containers :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[rancher@rancher ~]$ docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Les containers &amp;ldquo;systèmes&amp;rdquo; sont bien distincts des containers docker &amp;ldquo;utilisateurs&amp;rdquo;. La promesse d’isolation Docker infra vs Docker appli est bien tenue.&lt;/p&gt;
&lt;h2 id="mon-avis"&gt;Mon avis
&lt;/h2&gt;&lt;p&gt;A voir à l’usage, mais je ne suis pas hyper convaincu.&lt;/p&gt;
&lt;p&gt;D’abord, en termes d’OS minimalistes, on a quand même vu mieux. Et d’ailleurs, &lt;a class="link" href="https://rancher.com/docs/os/v1.x/en/installation/custom-builds/custom-rancheros-iso/#reduce-memory-requirements" target="_blank" rel="noopener"
&gt;les gens chez Rancher le savent puisqu’ils se sentent obligés de s’en justifier&lt;/a&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Plus grave, l’UX est quand même super bof. J’ai l’habitude d’installer des softs mais je me suis quand même pris la tête avec le cloud-config assez moyennement documenté, et en plus, à faire DANS une console (et la galère QWERTY/AZERTY associée).&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Et c’est pas fini&amp;rdquo;, comme dis la pub.&lt;/p&gt;
&lt;p&gt;Je vous l’ai dis, mon objectif est d’avoir un cluster Kubernetes installé par RKE. Or, il n’est pas trivial d’utiliser RancherOS comme OS pour hoster un Kubernetes déployé avec RKE. Vous verrez dans la partie 2 que ça n’a pas été une partie de plaisir&amp;hellip;&lt;/p&gt;
&lt;p&gt;Un comble pour 2 produits de la même boite censé vous simplifier l’administration de Docker/Kube&amp;hellip;&lt;/p&gt;
&lt;p&gt;Et plus grave encore, c’est que j’ai du mal à voir pour qui ce genre de distribs apporte de la valeur. C’est d’ailleurs pour cette même raison pour laquelle je n’avais pas poussé l’expérimentation très loin avec CoreOS. En tant qu’admin, je suis forcément frustré par un OS où je n’ai pas/peu la main.&lt;/p&gt;
&lt;p&gt;J’aime bien ce qu’ils font chez Rancher. Mais je ne sais pas répondre à la question Pourquoi RancherOS ?
On pourrait se dire que pour une équipe de développeurs en mode startup qui doit sortir son MVP en peu de temps, ça peut être cool.&lt;/p&gt;
&lt;p&gt;Mais même là, j’ai des doutes.&lt;/p&gt;
&lt;p&gt;Si ces gens là veulent VRAIMENT s’abstraire d’Ops (voir mon avis sur la question dans &lt;a class="link" href="https://blog.zwindler.fr/2020/07/29/au-secours-le-metier-dops-va-disparaitre/" &gt;Au secours, le métier d’Ops va disparaître !&lt;/a&gt;), ils partiront sur d’autres types de technos (Kubernetes managé, Serverless, No code ?).&lt;/p&gt;
&lt;p&gt;Si vous voyez une raison que j’aurais loupé, n’hésitez pas à venir en parler en commentaire ou via les RS, car là je vois pas&amp;hellip;&lt;/p&gt;
&lt;p&gt;En attendant la partie sur RKE, have fun :)&lt;/p&gt;</description></item><item><title>Stockage distribué et répliqué avec DRBD</title><link>https://blog.zwindler.fr/2020/05/11/stockage-distribue-et-replique-avec-drbd/</link><pubDate>Mon, 11 May 2020 06:35:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/05/11/stockage-distribue-et-replique-avec-drbd/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/04/drbd_infra-2.webp" alt="Featured image of post Stockage distribué et répliqué avec DRBD" /&gt;&lt;h2 id="drbd"&gt;DRBD
&lt;/h2&gt;&lt;p&gt;En 2015, j’avais voulu essayer la solution de stockage distribué DRBD. Et oui, 2015. C’est mon plus vieux brouillon sur le blog que je sors enfin. Vous vous en doutez, j’ai du repasser dessus pour ne pas vous donner de versions antédiluvienne ;-)&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.linbit.com/drbd/" target="_blank" rel="noopener"
&gt;DRBD (pour Distributed Replicated Block Device)&lt;/a&gt; est donc un logiciel disponible sous Linux et Windows qui permet de gérer des périphériques de stockages virtuels utilisables dans des infrastructures.&lt;/p&gt;
&lt;p&gt;Ces périphériques ont la particularité de pouvoir être « distribués » sur plusieurs serveurs sur un réseau de façon synchrone ou asynchrone et disposant de plusieurs méthodes de resynchronisation en cas de perte de lien ou d’incohérences.&lt;/p&gt;
&lt;p&gt;L’avantage de cette solution est qu’elle est robuste (fiabilité éprouvée) et qu’elle permet de répondre à des problématiques de haute disponibilité et de performance que n’offrent pas forcément toutes les solutions de stockage.&lt;/p&gt;
&lt;p&gt;Si cette solution peut paraître de prime abord un peu datée à l’époque des containers et de Kubernetes, sachez que Linbit a fait un effort assez conséquent justement sur cette partie, en essayant de se positionner comme un des acteurs du stockage distribué pour les architectures containerisées et/ou &amp;ldquo;cloud native&amp;rdquo; (surtout trusté par &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ceph" &gt;Ceph/CephFS&lt;/a&gt;, voire &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=gluster" &gt;Gluster&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/linstor.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Pour tester DRBD, vous l’aurez compris, il va nous falloir au minimum deux serveurs. Pour faire simple, je vais utiliser des machines virtuelles (mais évidemment ça fonctionnera mieux sur un serveur physique) sur lesquelles j’ai installé une image Ubuntu 18.04.&lt;/p&gt;
&lt;p&gt;Dans mon cas, j’ai rajouté des disques virtuels de 16Go, pour simuler des disques physiques à synchroniser. De même, j’ai également rajouté des interfaces réseaux supplémentaires pour simuler un réseau dédié « stockage ».&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/drbd_infra-2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="installation-du-logiciel"&gt;Installation du logiciel
&lt;/h2&gt;&lt;p&gt;La société LINBIT qui distribue le logiciel DRBD propose des packages précompilés pour la plupart des distributions Linux classiques. L’ensemble des packages des différentes versions de DRBD sont disponibles sur le site de &lt;a class="link" href="https://www.linbit.com/drbd/" target="_blank" rel="noopener"
&gt;Linbit&lt;/a&gt;. Cependant, ces packages « officiels » précompilés nécessitent d’avoir payé le support.&lt;/p&gt;
&lt;p&gt;Note : Si les packages officiels sont réservés aux personnes qui payent le support, les sources, elles, sont bien entendu disponibles &lt;a class="link" href="https://www.linbit.com/linbit-software-download-page-for-linstor-and-drbd-linux-driver/" target="_blank" rel="noopener"
&gt;sur le site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Heureusement, il est possible d’utiliser tout simplement les packages précompilés de votre distribution.&lt;/p&gt;
&lt;p&gt;A la base, quand j’avais écrit le tutoriel en 2015, j’avais des soucis de compatibilité entre la version du kernel et drbd de ma distribution CentOS (6.3 à l’époque&amp;hellip;). Ma version, 2.6.32-279 alors que les versions 8.3 et 8.4 de DRBD nécessitent le kernel 2.6.32-431. Mais rien ne vous empêche d’installer le kernel demandé pour résoudre ce problème.&lt;/p&gt;
&lt;p&gt;Pour ce tuto, voici les commandes que j’ai dû utiliser pour installer DRBD 9 (la dernière stable même si la 10 arrive bientôt) sur mes Ubuntu 18.04.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo apt update
sudo apt upgrade
sudo apt install software-properties-common
sudo add-apt-repository ppa:linbit/linbit-drbd9-stack
sudo apt-get update
sudo apt install drbd-utils python-drbdmanage drbd-dkms
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une fois que c’est installé, testez que tout fonctionne avec la commande suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo modprobe drbd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si tout se passe bien, elle ne devrait remonter aucune erreur. En revanche, si vous n’avez pas un kernel avec une version compatible, vous devriez avoir une erreur du type &amp;ldquo;file not found&amp;rdquo;. Dans ce cas-là, il faudra compiler DRBD à la main.&lt;/p&gt;
&lt;h2 id="préparation-des-machines"&gt;Préparation des machines
&lt;/h2&gt;&lt;p&gt;Les serveurs doivent évidemment pouvoir se joindre et se résoudre. Le mieux étant bien sûr un DNS correct, on pourra se rabattre dans le cadre d’un test sur &lt;em&gt;a minima&lt;/em&gt; un fichier /etc/hosts contenant les informations nécessaires :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;192.168.100.11 drbd1 drbd1.example.org
192.168.100.12 drbd2 drbd2.example.org
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ensuite, j’ai créé, sur chaque serveur, deux partitions de 8 Go chacun sur le disque de 16. La première sera de type Linux, la seconde sera de type LVM.&lt;/p&gt;
&lt;p&gt;On oublie pas de créer les objets LVM pour pouvoir les utiliser plus tard.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pvcreate /dev/sdb2
vgcreate vg_drbd /dev/sdb2
lvcreate -n lv_drbd -l 2047 vg_drbd
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="configuration"&gt;Configuration
&lt;/h2&gt;&lt;p&gt;Le fichier de configuration global de DRBD est &lt;em&gt;/etc/drbd.conf&lt;/em&gt;. Il définit les fichiers unitaires qui doivent être modifiés. Le fichier &lt;em&gt;/etc/drbd.conf&lt;/em&gt; en lui-même ne doit donc pas être modifié directement ; sauf dans le cas où on souhaite changer les fichiers de configuration inclus de répertoire.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat /etc/drbd.conf
# You can find an example in /usr/share/doc/drbd.../drbd.conf.example
include &amp;#34;drbd.d/global_common.conf&amp;#34;;
include &amp;#34;drbd.d/*.res&amp;#34;;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Le fichier suivant doit contenir les paramètres et les commandes qui sont globaux à toutes les ressources DRBD.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat /etc/drbd.d/global_common.conf
# DRBD is the result of over a decade of development by LINBIT.
# In case you need professional services for DRBD or have
# feature requests visit http://www.linbit.com
global {
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="template-de-ressource"&gt;Template de ressource
&lt;/h3&gt;&lt;p&gt;Pour rendre la configuration lisible, on sépare les fichiers de configuration de manière à faire un fichier texte par ressource, nommé avec la convention r[nombre].res. Ici on prendra l’exemple le plus simple d’une synchronisation synchrone (protocole C, par défaut) dans un modèle actif/passif.
Pour vous aider à créer vos premières ressources, DRBD met à disposition, dans &lt;strong&gt;/etc/drbd.d/drbdctrl.res_template&lt;/strong&gt; un template dans lequel vous n’aurez qu’à modifier les valeurs.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;resource .drbdctrl {
net {
cram-hmac-alg sha1;
shared-secret &amp;#34;&amp;lt;your-shared-secret&amp;gt;&amp;#34;;
}
volume 0 {
device /dev/drbd0 minor 0;
disk /dev/mapper/&amp;lt;vgname&amp;gt;-.drbdctrl;
meta-disk internal;
}
on &amp;lt;node_1&amp;gt; {
node-id 0;
address &amp;lt;ipaddress&amp;gt;:&amp;lt;port&amp;gt;;
}
on &amp;lt;node_n&amp;gt; {
node-id &amp;lt;n&amp;gt;;
address &amp;lt;ipaddress&amp;gt;:&amp;lt;port&amp;gt;;
}
connection-mesh {
hosts &amp;lt;node_1&amp;gt; &amp;lt;node_2&amp;gt; ... &amp;lt;node_n&amp;gt;;
net {
protocol C;
}
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="ressource-pour-un-disque-simple"&gt;Ressource pour un disque &amp;ldquo;simple&amp;rdquo;
&lt;/h3&gt;&lt;p&gt;Ici, c’est l’exemple le plus simple. On va indiquer que notre ressource est distribuée sur 2 serveurs sur un bête partition Linux. Les metadata, elles, sont stockées en local (ce qui n’est pas forcément le mieux, mais pour commencer ça suffira).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /etc/drbd.d/r0.res
resource r0 {
on drbd1 {
device /dev/drbd1;
disk /dev/sdb1;
address 192.168.100.11:7789;
meta-disk internal;
}
on drbd2 {
device /dev/drbd1;
disk /dev/sdb1;
address 192.168.100.12:7789;
meta-disk internal;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note : si le protocole de synchronisation n’est pas spécifié, on est en synchronisation synchrone par défaut.&lt;/p&gt;
&lt;p&gt;Attention : chaque ressource déclarée réserve le port TCP pour la communication de la ressource. Il faut donc incrémenter le numéro du device drbd ET incrémenter le numéro de port à chaque nouvelle ressource (et aussi s’assurer que le port est libre&amp;hellip;).&lt;/p&gt;
&lt;p&gt;Pour mes tests, j’ai également utilisé la possibilité offerte par DRBD d’utiliser des volumes LVM plutôt que des partitions brutes. La configuration est la même à ceci près qu’on pointe sur le LV plutôt que sur une partition.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /etc/drbd.d/r1.res
resource r1 {
on drbd1 {
device /dev/drbd2;
disk /dev/vg_drbd/lv_drbd;
address 192.168.100.11:7790;
meta-disk internal;
}
on drbd2 {
device /dev/drbd2;
disk /dev/vg_drbd/lv_drbd;
address 192.168.100.12:7790;
meta-disk internal;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="initialisation"&gt;Initialisation
&lt;/h2&gt;&lt;p&gt;Maintenant que tout est configuré, on va pouvoir déclencher l’étape d’initialisation des metadata et des ressources nouvellement créées.
Lancez les commandes suivantes sur les deux nœuds :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;drbdadm create-md r0
drbdadm create-md r1
drbdadm up r0
drbdadm up r1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une fois que les commandes sont lancées, on peut afficher les informations sur l’initialisation des disques (état normal) avec &lt;strong&gt;drbdmon&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/drbdmon1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Actuellement, les nœuds sont &lt;strong&gt;Inconsistants&lt;/strong&gt; et en Secondaire/Secondaire, car nous n’avons pas encore désigné le nœud principal. Nous allons &amp;ldquo;forcer&amp;rdquo; le sens dans lequel le disque doit être synchronisé.&lt;/p&gt;
&lt;p&gt;Sélectionner un des nœuds, qu’on va désigner comme &amp;ldquo;serveur primaire&amp;rdquo; et exécuter les commandes suivantes (uniquement sur lui) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@drbd1:~# drbdadm primary --force r0
root@drbd2:~# drbdadm primary --force r1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ATTENTION : dans le cas d’un disque déjà créé, il faut bien ne pas se tromper de sens, au risque d’écraser le disque qui contiendrait les données.&lt;/p&gt;
&lt;p&gt;Une fois la synchronisation terminée, on peut utiliser le disque /dev/drbdX.&lt;/p&gt;
&lt;h2 id="cest-fini-"&gt;C’est fini ?
&lt;/h2&gt;&lt;p&gt;En fait, pas tout à fait. On ne va pas pouvoir utiliser nos disques exactement comme des disques classiques. Si vous formattez ce disque en ext4/xfs/whatever et que vous essayez de le monter sur vos deux serveurs drbd1 et drbd2, vous allez avoir une drôle de surprise.&lt;/p&gt;
&lt;p&gt;En effet, ces filesystems ne savent pas gérer les accès concurrents provenant de deux machines simultanées. On va donc devoir :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;soit utiliser un filesystem capable de gérer les accès concurrents (&lt;a class="link" href="https://en.wikipedia.org/wiki/Clustered_file_system" target="_blank" rel="noopener"
&gt;page Wikipedia listant quelques clustered filesystems&lt;/a&gt;) comme OCFS2 ou GFS2. Si vous publiez les disques DRBD en iSCSI pour votre cluster VMware, vous n’aurez pas de problème non plus car le VMFS le gère très bien aussi.&lt;/li&gt;
&lt;li&gt;soit s’assurer à tout moment que le disque n’est monté que sur un seul serveur à la fois.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Évidemment la 2ème option est à proscrire si vous êtes dans un contexte de production. Cependant, cela reste possible si vous montez un cluster Pacemaker ou &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=RHCS" &gt;RHCS&lt;/a&gt; par exemple, qui va s’assurer que les bascules de stockage se font de manière propre.&lt;/p&gt;
&lt;p&gt;Enjoy !&lt;/p&gt;
&lt;h2 id="bonus--quelques-commandes-utiles"&gt;Bonus : quelques commandes utiles
&lt;/h2&gt;&lt;p&gt;Pour une ressource donnée, afficher le rôle du serveur local&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@drbd1:~# drbdadm role r0
Primary
root@drbd1:~# drbdadm role r1
Secondary
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Afficher de manière concise l’état d’une ressource sur les nœuds&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@drbd1:~# drbdadm dstate r0
UpToDate/UpToDate
root@drbd1:~# drbdadm dstate r1
Inconsistent/UpToDate
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Afficher plus de détails sur une ressource avec &lt;code&gt;drbdadmin&lt;/code&gt; pour un résultat simple ou &lt;code&gt;drbdsetup&lt;/code&gt; pour avoir plus de détails :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/04/drbd_state.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;drbdsetup status r1 --verbose --statistics
r1 node-id:1 role:Secondary suspended:no
write-ordering:flush
volume:0 minor:2 disk:Inconsistent quorum:yes
size:8384220 read:0 written:1972628 al-writes:0 bm-writes:0 upper-pending:0 lower-pending:0 al-suspended:no blocked:no
drbd2 node-id:0 connection:Connected role:Primary congested:no ap-in-flight:0 rs-in-flight:0
volume:0 replication:SyncTarget peer-disk:UpToDate done:23.53 resync-suspended:no
received:1972628 sent:0 out-of-sync:6411740 pending:3 unacked:12 dbdt1:92.39 eta:68
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;En temps normal, toutes les ressources sont actives par défaut. Cependant, on peut les activer ou les désactiver à la main :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;drbdadm up r0
drbdadm down r1
# utiliser le mot clé « all » pour désigner toutes les ressources
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si on modifie les fichiers de configuration global ou un fichier de ressource, il est nécessaire de mettre à jour la configuration sur les deux nœuds. Il est possible de reconfigurer les ressources même si elles sont opérationnelles grâce à la méthode suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;drdbadm adjust r0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Changer le statut du nœud courant (pour le passer en primary s’il est secondary par exemple)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;drbdadm primary r1
drbdadm secondary r0
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="sources"&gt;Sources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.linbit.com/drbd-user-guide/drbd-guide-9_0-en/" target="_blank" rel="noopener"
&gt;User Guide DRBD 9.0 (Anglais)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Exposer des applications containerisées Kubernetes (nginx Ingress Controller)</title><link>https://blog.zwindler.fr/2018/03/06/exposer-des-applications-kubernetes-en-dehors-des-cloud-providers-nginx-ingress-controller/</link><pubDate>Tue, 06 Mar 2018 12:45:47 +0000</pubDate><guid>https://blog.zwindler.fr/2018/03/06/exposer-des-applications-kubernetes-en-dehors-des-cloud-providers-nginx-ingress-controller/</guid><description>&lt;img src="https://blog.zwindler.fr/2018/02/kubernetes_nginx.webp" alt="Featured image of post Exposer des applications containerisées Kubernetes (nginx Ingress Controller)" /&gt;&lt;h2 id="ingress-et-ingress-controller-versus-baremetal"&gt;Ingress et Ingress Controller versus Baremetal
&lt;/h2&gt;&lt;p&gt;Autant le dire tout de suite, cet article s’adresse surtout aux admins qui font du Kubernetes (K8s pour les intimes) et en plus qui font tout eux même. Mais comme je suis sympa j’explique tout et j’ai mis des schémas si vous êtes curieux ;-).&lt;/p&gt;
&lt;p&gt;Je vous plante le décors : &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=Kubernetes" &gt;vous avez suivi un de mes tutos sur Kubernetes&lt;/a&gt; et vous avez maintenant un cluster opérationnel en dehors des gros cloud providers (Amazon, Google, &amp;hellip;) et de leurs solutions clés en main (sur vos propres VMs et/ou serveurs physiques). Vous êtes super contents et il y a de quoi.&lt;/p&gt;
&lt;p&gt;Seulement voilà, maintenant que vous pouvez spawner des containers à tire larigot, vous voulez pouvoir y accéder depuis l’Internet.&lt;/p&gt;
&lt;h2 id="mais-là-comment-faire-"&gt;Mais là, comment faire ?
&lt;/h2&gt;&lt;p&gt;Le premier problème que vous risquez d’avoir est que les applications que vous déployez dans Kubernetes ne sont de base accessibles que DANS Kubernetes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On va être très très vite limité, niveau usecases.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour accéder à un container (ou faire discuter 2 containers comme un serveur web et une base de données), on passe par l’intermédiaire d’un objet appelé &lt;strong&gt;Service&lt;/strong&gt;. C’est cet objet qui permet le service discovery, le scaling aisé de nos applications et la résolution de nom au sein du cluster.&lt;/p&gt;
&lt;p&gt;Cependant, hors du cluster, pas de résolution de nom et/ou d’accès aux ressources par ce biais. Vous allez donc devoir passer par un DNS externe pour spécifier aux clients où sont vos applications et trouver un moyen de différencier quelle requête externe doit aboutir dans quelle container.&lt;/p&gt;
&lt;h2 id="accéder-aux-ressources"&gt;Accéder aux ressources
&lt;/h2&gt;&lt;p&gt;Le premier problème est donc de réussir à accéder à notre service. S’il est possible de créer des &lt;strong&gt;Services&lt;/strong&gt; (les points d’entrées de nos containers) de type &lt;strong&gt;LoadBalancer&lt;/strong&gt; sur AWS, Azure et GCP, qui ont l’avantage de permettre un accès direct au service depuis Internet (magie !), le mieux que l’on puisse faire par défaut sur un cluster Baremetal, c’est un &lt;strong&gt;Service&lt;/strong&gt; de type &lt;strong&gt;NodePort&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Si vous n’êtes pas chez un cloud provider comme nous l’avons dit au départ, vous allez vite vous rendre compte qu’il n’est pas trivial de présenter un container sur HTTP:80 ou HTTPS:443. Car par défaut, les &lt;strong&gt;Services NodePort&lt;/strong&gt; exposent nos container sur un port aléatoire compris entre 30000 et &lt;em&gt;3X000-je-sais-pas-combien&lt;/em&gt; (mate la précision) sur tous les nœuds du clusters.&lt;/p&gt;
&lt;p&gt;Il y a deux choses importantes dans cette dernière phrase :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;D’abord, on va se retrouver avec des URLs du type : &lt;code&gt;http://@IP_node:32251&lt;/code&gt; pour accéder à un serveur web depuis l’extérieur. Pas glop.&lt;/li&gt;
&lt;li&gt;Ensuite, pour un &lt;strong&gt;Service&lt;/strong&gt; de type &lt;strong&gt;NodePort&lt;/strong&gt; donné, le port alloué l’est sur TOUS les membres du cluster, que le container tourne dessus ou pas. Ça veut dire que &lt;em&gt;peu importe quel nœud Kubernetes on interroge&lt;/em&gt;, le 32251 répondra TOUJOURS sur le même container (les requêtes sont forwardé au bon nœud de manière transparente). Ça veut aussi dire qu’il n’y aura qu’un seul service qui aura le privilège d’utiliser le 32251 et aucun autre &lt;strong&gt;Service&lt;/strong&gt; ne pourra le réserver.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/02/Kubernetes1-1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Clairement, c’est tout sauf idéal. On se retrouve donc à différencier les applications simplement avec les numéros des ports qu’on accède.&lt;/p&gt;
&lt;h2 id="le-dns"&gt;Le DNS
&lt;/h2&gt;&lt;p&gt;Et c’est pas fini&amp;hellip;&lt;/p&gt;
&lt;p&gt;Si on prend un cas simple : un site web à exposer sur Internet, on va souvent vouloir relier une URL humainement compréhensible au container qui gère ce site. Cependant cette notion n’a pas vraiment de sens avec Kubernetes.&lt;/p&gt;
&lt;p&gt;Vous ne savez pas &lt;em&gt;a priori&lt;/em&gt; &lt;strong&gt;où&lt;/strong&gt; va être instancié votre container dans le cluster (i.e. sur quelle machine et donc sur quelle IP). Ça sera un des nœuds du cluster, mais lequel ? D’autant que le &lt;strong&gt;Pod&lt;/strong&gt; bouge d’un nœud à l’autre au gré de la vie de l’application (&lt;em&gt;drain&lt;/em&gt; du node pour maintenance ou incident). Difficile donc de donner avec certitude un enregistrement DNS fiable dans le temps.&lt;/p&gt;
&lt;p&gt;Alors bien sûr, vous pouvez toujours fixer en dur l’adresse IP d’un des nœuds Kubernetes dans un enregistrement DNS mais cette méthode trouve très vite sa limite : le moindre arrêt du serveur cause la perte de l’accès à l’application, qui pourtant a probablement été redémarrée sur un nœud du cluster.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/02/Kubernetes2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vous me pardonnerez ce « comic » en mode Draw.io. On s’amuse comme on peut ;-)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A quoi ça sert d’avoir un cluster dans ce cas là ?&lt;/p&gt;
&lt;p&gt;Vous aurez peut être alors l’idée d’utiliser un moyen automatique (&lt;a class="link" href="https://blog.zwindler.fr/2014/09/22/mise-a-jour-de-votre-dns-chez-ovh-avec-dynhost/" &gt;genre ce script qui utilise Dynhost, au hasard&lt;/a&gt;) pour mettre à jour le DNS dès que l’application change de nœud. Mais c’est clairement de la bidouille et on se retrouvera avec pleins d’utilisateurs dont les caches DNS ne sont pas à jour.&lt;/p&gt;
&lt;h2 id="la-méthode-simple"&gt;La méthode simple
&lt;/h2&gt;&lt;p&gt;On peut quand même bosser avec ce qu’on a et présenter à nos gentils utilisateurs des URLs user-friendly sans trop de difficultés, dans la majorité des cas.&lt;/p&gt;
&lt;p&gt;La première chose qu’on peut faire c’est simplement mettre en face de notre cluster Kubernetes un bête reverse proxy et/ou répartiteur de charge. Après tout, c’est ni plus ni moins ce que font AWS et autre avec leur implémentation du &lt;strong&gt;Service&lt;/strong&gt; de type &lt;strong&gt;Loadbalancer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;L’ensemble des requêtes HTTP(S) sont donc dirigées vers le reverse proxy, qui se charge de masquer la complexité de l’URL (l’aiguillage via des ports chelous et le maintiens à jour de l’ensemble des nœud du cluster qu’on arrive à contacter) à l’utilisateur final.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/02/Kubernetes3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Personnellement, &lt;strong&gt;pour mes projets perso&lt;/strong&gt;, ça m’ennuie d’avoir un composant externe au cluster K8s pour faire ça. J’ai déjà investi dans un cluster pour rendre mes applications hautement disponibles (ce qui est déjà overkill), je ne vais pas en plus :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;soit ajouter un SPOF en ajoutant une seule machine pour faire mon reverse proxy&lt;/li&gt;
&lt;li&gt;soit ajouter un cluster de machines rien que pour le reverse proxy&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="et-les-ingress-dans-tout-ça-"&gt;Et les Ingress dans tout ça ?
&lt;/h2&gt;&lt;p&gt;Donc on l’a vu, tout ça c’est pas super propre et on ajoute potentiellement un SPOF, mais ça « marche ». Mais on peut faire mieux :)&lt;/p&gt;
&lt;p&gt;Si vous manipulez un peu Kubernetes, vous avez donc peut être vu qu’il existe un autre type d’objet qui s’appelle les &lt;strong&gt;Ingress&lt;/strong&gt; et les &lt;strong&gt;Ingress Controllers&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Pour ceux qui n’ont pas eu le temps de potasser, un &lt;strong&gt;Ingress&lt;/strong&gt; est une règle qui permet de relier une URL à un &lt;strong&gt;Service&lt;/strong&gt; et un &lt;strong&gt;Ingress Controller&lt;/strong&gt; est un composant qui permet de piloter un reverse-proxy pour implémenter cette règle. C’est &lt;em&gt;LA&lt;/em&gt; méthode propre pour traduire une URL provenant d’un client en requête interne dans le cluster K8s pour atteindre le bon service.&lt;/p&gt;
&lt;p&gt;L’&lt;strong&gt;Ingress Controller&lt;/strong&gt; le plus utilisé est probablement celui pour nginx, mais il existe des &lt;strong&gt;Ingress Controllers&lt;/strong&gt; pour &lt;a class="link" href="https://doc.traefik.io/traefik/reference/install-configuration/providers/kubernetes/kubernetes-ingress/" target="_blank" rel="noopener"
&gt;traefik&lt;/a&gt; ou ha-proxy (ou autre) qui ont été développés et qui sont plus ou moins aboutis.&lt;/p&gt;
&lt;h2 id="helm"&gt;Helm
&lt;/h2&gt;&lt;p&gt;Helm c’est super. &lt;a class="link" href="https://blog.zwindler.fr/2018/02/06/se-simplifier-kubernetes-helm-charts/" &gt;J’en ai parlé dans un autre article il n’y a pas longtemps&lt;/a&gt;, c’est un genre de gestionnaire d’application pour Kubernetes et ça simplifie grandement son utilisation. Mais il faut être honnête, ce n’est pas toujours une super idée&amp;hellip;&lt;/p&gt;
&lt;p&gt;Déjà, la documentation sur &lt;a class="link" href="https://github.com/kubernetes/ingress-nginx" target="_blank" rel="noopener"
&gt;la page d’accueil du Chart est super light&lt;/a&gt;. Si vous ne trouvez pas d’infos sur comment le déployer, c’est normal, c’est parce qu’il faut aller dans le dossier « deploy » du dépôt pour &lt;a class="link" href="https://github.com/kubernetes/ingress-nginx/tree/master/deploy" target="_blank" rel="noopener"
&gt;trouver la doc d’installation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Du coup, confiant, j’y suis allé avant d’avoir trouvé cette page, et je me suis pris ma première claque ;-)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;helm install stable/nginx-ingress --name nginx-ingress
NAME: nginx-ingress
LAST DEPLOYED: Sun Feb 25 16:24:11 2018
NAMESPACE: default
STATUS: DEPLOYED
[...]
NOTES:
The nginx-ingress controller has been installed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Oh cool, ça marché déjà ?&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-7c6f79d45c-jwqkp 0/1 CrashLoopBackOff 14 47m
nginx-ingress-default-backend-6664bc64c9-2zpg4 1/1 Running 0 47m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ah ben non en fait parce que je suis en RBAC (K8s &amp;gt; 1.7.0) ! Il faut créer des autorisations et un compte de service pour l’&lt;strong&gt;Ingress Controller&lt;/strong&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl logs nginx-ingress-controller-7c6f79d45c-jwqkp
-------------------------------------------------------------------------------
NGINX Ingress controller
Release: 0.10.2
Build: git-fd7253a
Repository: https://github.com/kubernetes/ingress-nginx
-------------------------------------------------------------------------------
I0225 16:11:13.374547 7 flags.go:159] Watching for ingress class: nginx
I0225 16:11:13.376659 7 main.go:181] Creating API client for https://10.233.0.1:443
I0225 16:11:13.438774 7 main.go:193] Running in Kubernetes Cluster version v. (v1.9.0+coreos.0) - git (clean) commit 1b69a2a6c01194421b0aa17747a8c1a81738a8dd - platform linux/amd64
F0225 16:11:13.442654 7 main.go:80] &amp;amp;#x2716; It seems the cluster it is running with Authorization enabled (like RBAC) and there is no permissions for the ingress controller. Please check the configuration
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, pas grave&amp;hellip; On supprime et on recommence !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
nginx-ingress 1 Sun Feb 25 16:24:11 2018 DEPLOYED nginx-ingress-0.9.1 default
helm delete nginx-ingress
release &amp;#34;nginx-ingress&amp;#34; deleted
helm install stable/nginx-ingress --name nginx-ingress --set rbac.create=true
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bon, ne vous fatiguez pas. Ça aura l’air de marcher mais en fait, le &lt;em&gt;nginx-ingress-controller&lt;/em&gt; se base sur un &lt;strong&gt;Service&lt;/strong&gt; de type&amp;hellip; &lt;strong&gt;Loadbalancer&lt;/strong&gt; ! Si vous n’êtes pas sur AWS, GCE ou Azure, votre &lt;strong&gt;Service&lt;/strong&gt; restera indéfiniment à l’état &lt;em&gt;Pending&lt;/em&gt; en attente d’une IP publique ;-)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-controller LoadBalancer 10.233.52.122 80:30215/TCP,443:31438/TCP 41m
nginx-ingress-default-backend ClusterIP 10.233.29.8 80/TCP 41m
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="donc-on-laisse-tomber-helm-pour-cette-fois"&gt;Donc on laisse tomber Helm pour cette fois
&lt;/h2&gt;&lt;p&gt;En réalité, le mieux c’est de repartir sur le projet nginx Ingress Controller, qui donne (pour qui trouve la documentation) la bonne marche à suivre pour instancier rapidement son &lt;strong&gt;Ingress Controller&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/ingress-nginx" target="_blank" rel="noopener"
&gt;github.com/kubernetes/ingress-nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md#bare-metal" target="_blank" rel="noopener"
&gt;github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md#bare-metal&lt;/a&gt; (lien mis à jour le 08/10/2018)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Partie à exécuter dans tous les cas&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/namespace.yaml \
| kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/default-backend.yaml \
| kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/configmap.yaml \
| kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/tcp-services-configmap.yaml \
| kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/udp-services-configmap.yaml \
| kubectl apply -f -
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Partie spécifique à ajouter pour déployer l’&lt;strong&gt;Ingress Controller&lt;/strong&gt; dans un environnement de type RBAC (K8s &amp;gt;= 1.7)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/rbac.yaml \
| kubectl apply -f -
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/with-rbac.yaml \
| kubectl apply -f -
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Partie spécifique à ajouter en dernier, dans le cas où on est sur un cluster baremetal (i.e. en dehors des cloud providers).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/provider/baremetal/service-nodeport.yaml \
| kubectl apply -f -
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="ok-on-a-quoi-maintenant-"&gt;OK, on a quoi maintenant ?
&lt;/h2&gt;&lt;p&gt;Et bien, c’est pas encore fini malheureusement&amp;hellip; En fait, tel quel, le dernier fichier YAML qu’on a créé nous créé un service de type NodePort&amp;hellip;&lt;/p&gt;
&lt;p&gt;Oui vous l’avez compris : retour à la case départ ! Nous avons un composant reverse proxy intégré à K8s, mais qui est en écoute sur un port 3XXXX au lieu du 80, et 3YYYY au lieu du 443. Là encore, on aurait pas du tout ce problème si on était chez AWS, car un service de type Loadbalancer (avec une IP publique) aurait été créé pour nous.&lt;/p&gt;
&lt;p&gt;Rassurez vous, il y a des solutions, moyennant un peu de bidouille. J’en ai trouvé 2 dans notre cas.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://medium.com/@olegsmetanin/how-to-setup-baremetal-kubernetes-cluster-with-kubespray-and-deploy-ingress-controller-with-170cdb5ac50d" target="_blank" rel="noopener"
&gt;blog.will3942.com/nginx-kubernetes-bare-metal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;lt;a href=&amp;ldquo;&lt;a class="link" href="https://medium.com/@olegsmetanin/how-to-setup-baremetal-kubernetes-cluster-with-kubespray-and-deploy-ingress-controller-with-170cdb5ac50d%3e" target="_blank" rel="noopener"
&gt;https://medium.com/@olegsmetanin/how-to-setup-baremetal-kubernetes-cluster-with-kubespray-and-deploy-ingress-controller-with-170cdb5ac50d&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour faire simple, la première nécessite juste de modifier unfichier de configuration de Kubernetes pour autoriser le composant &lt;strong&gt;NodePort&lt;/strong&gt; à utiliser des ports en dessous de la limite arbitraire des 30000. Je ne suis pas fan du tout de cette solution mais elle « fonctionne » donc je vous laisse juger.&lt;/p&gt;
&lt;p&gt;En revanche, je trouve la seconde bien plus élégante quoique peut être un peu moins flexible. On peut modifier le &lt;strong&gt;Service&lt;/strong&gt; de l’&lt;strong&gt;Ingress Controller&lt;/strong&gt; en y listant toutes les adresses IPs de tous vos serveurs K8s. Ce n’est pas super confortable dans le cas où ils changent souvent, mais ça à l’effet qu’on recherche, à savoir ouvrir les ports 80 et 443 et rediriger l’ensemble des requêtes HTTP vers les &lt;strong&gt;Ingress&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La modification à réaliser se situe au niveau du champ &lt;strong&gt;externalIPs&lt;/strong&gt; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/cb876766897806ed60b1f2f36564d5f3af8a18c8/deploy/provider/baremetal/service-nodeport.yaml -o ingress-nginx-service-nodeport.yaml
vi ingress-nginx-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
- name: https
port: 443
targetPort: 443
protocol: TCP
externalIPs:
- 10.0.0.1
- 10.0.0.2
- 10.0.0.3
selector:
app: ingress-nginx
kubectl apply -f ingress-nginx-service-nodeport.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Normalement après application de la modification vous devriez avoir la joie (oui oui, carrément) de voir apparaitre sur tous les serveurs (que vous aurez listés) les ports 80 et 443 en écoute !!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ss -lnt
LISTEN 0 128 8.8.8.8:80 *:*
LISTEN 0 128 8.8.8.8:443 *:*
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="super-et-maintenant-cest-bon-mon-container-nginx-est-accessible-"&gt;Super, et maintenant c’est bon, mon container nginx est accessible ?
&lt;/h2&gt;&lt;p&gt;Ah ben non, toujours pas. On a configuré l’&lt;strong&gt;Ingress Controller&lt;/strong&gt;, mais ça fait un moment qu’on parle plus des &lt;strong&gt;Ingress&lt;/strong&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Comme je l’ai dis plus haut, les &lt;strong&gt;Ingress&lt;/strong&gt; sont donc les règles de notre reverse proxy, permettant de mapper les URLs entrant dans le cluster sur les ports 80 et 443 (ou autre si on en définit d’autres) vers les &lt;strong&gt;Services&lt;/strong&gt; définis dans le K8s.&lt;/p&gt;
&lt;p&gt;Heureusement c’est partie est assez simple à configurer. Voici l’exemple minimaliste d’une application dont le &lt;strong&gt;Service&lt;/strong&gt; &lt;em&gt;toto-app-svc&lt;/em&gt; écoute sur le port 8080 à l’intérieur du cluster Kubernetes. Ce service est maintenant accessible pour toute requête HTTP aboutissant sur un des noeuds du cluster et accédé avec l’URL toto.zwindler.fr.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat nginx-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: nginx-ingress
spec:
rules:
- host: toto.zwindler.fr
http:
paths:
- path: /
backend:
serviceName: toto-app-svc
servicePort: 8080
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Point intéressant à noter, il n’est plus nécessaire de faire du &lt;strong&gt;NodePort&lt;/strong&gt; maintenant, on peut se contenter des &lt;strong&gt;ClusterIP&lt;/strong&gt; par défaut. En effet, l’&lt;strong&gt;Ingress Controller&lt;/strong&gt; étant interne au cluster K8s, il sait résoudre les Services sans passer par un port crado en 30000. Autant ne plus les exposer donc et bannir les &lt;strong&gt;NodePorts&lt;/strong&gt; à présent !&lt;/p&gt;
&lt;p&gt;Bon vous avez vu ? Cette dernière étape n’est pas la plus dure qu’on ait fait !&lt;/p&gt;
&lt;p&gt;Et maintenant, à vos &lt;strong&gt;Ingress&lt;/strong&gt; !&lt;/p&gt;</description></item><item><title>[Tutoriel] XWiki, ma premier appli Statefull sur Kubernetes</title><link>https://blog.zwindler.fr/2017/10/24/tutoriel-xwiki-ma-premier-appli-stateful-sur-kubernetes/</link><pubDate>Tue, 24 Oct 2017 11:30:52 +0000</pubDate><guid>https://blog.zwindler.fr/2017/10/24/tutoriel-xwiki-ma-premier-appli-stateful-sur-kubernetes/</guid><description>&lt;img src="https://blog.zwindler.fr/2017/10/xwiki_kubernetes.webp" alt="Featured image of post [Tutoriel] XWiki, ma premier appli Statefull sur Kubernetes" /&gt;&lt;h2 id="pourquoi-déployer-xwiki-sur-kubernetes-"&gt;Pourquoi déployer XWiki sur Kubernetes ?
&lt;/h2&gt;&lt;p&gt;Vous le savez surement maintenant vu le nombre d’article que j’ai écrit sur le sujet, j’aime bien &lt;a class="link" href="http://www.xwiki.org/xwiki/bin/view/Main/WebHome" target="_blank" rel="noopener"
&gt;XWiki&lt;/a&gt;. C’est un super projet mené par des gens passionnés, réactifs et surtout, c’est cet outil qui a permis à mon entreprise d’adopter ENFIN le wiki comme outil de documentation, que ce soit pour documenter les procédures, mais aussi documenter entièrement les concepts de l’outil que nous développons.&lt;/p&gt;
&lt;p&gt;D’un outil quasi-confidentiel utilisés par quelques admins peu motivés (sous Mediawiki), nous sommes donc progressivement passés à un outil utilisé par toutes les équipes, du dev. au support en passant par les ergo. et les CPs, utilisés par plusieurs entités internes et même accepté comme document contractuel par nos prestataires. J’ai d’ailleurs &lt;a class="link" href="https://blog.zwindler.fr/2016/12/12/migration-mediawiki-vers-xwiki/" &gt;documenté la migration sur cet article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2016/12/mediawiki_to_xwiki_logo.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Mais j’aime aussi XWiki car c’est selon moi l’exemple parfait d’une appli 2 ou 3 tiers relativement simple pour explorer l’écosystème Docker (construction des images, les problématiques réseau et stockage, …). Je joue régulièrement avec &lt;a class="link" href="https://hub.docker.com/r/zwindler/xwiki-tomcat8/" target="_blank" rel="noopener"
&gt;ma propre image sur le Dockerhub&lt;/a&gt; pour explorer un peu plus cet écosystème riche (c’est rien de le dire).&lt;/p&gt;
&lt;p&gt;Quelle meilleure application donc pour réellement tester mon tout nouveau cluster Kubernetes (je ne compte pas nginx ou helloworld) ?&lt;/p&gt;
&lt;h2 id="kubernetes-"&gt;Kubernetes ?
&lt;/h2&gt;&lt;p&gt;Pour ceux qui ont besoin d’un rappel sur Kubernetes ou des premiers concepts et/ou comment l’installer, &lt;a class="link" href="https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/" &gt;je vous invite à lire/relire mon article précédent sur le sujet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A noter également (j’ai pas mal communiqué là-dessus sur les réseaux sociaux), la Linux Foundation, qui gère également la Cloud Native Computing Foundation (et qui elle-même gère Kubernetes), a mis à disposition gratuitement un cour en ligne de type MOOC sur edX. Vous pouvez même vous « certifier » à la fin si vous réussissez le QCM, moyennant 100$.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/10/kubernetes_edx.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A l’issue de ces lectures, vous devriez donc avoir :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la connaissance des différents concepts de Kubernetes&lt;/li&gt;
&lt;li&gt;un cluster Kubernetes opérationnel (une ou plusieurs machines, ou simplement un minikube en local)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce sont les prérequis pour la suite de cet article, même si je vais essayer de détailler tout ce qui va suivre.&lt;/p&gt;
&lt;h2 id="plan-de-bataille"&gt;Plan de bataille
&lt;/h2&gt;&lt;p&gt;Je ne vais pas vous le cacher, si on veut tout faire soit même, ce n’est pas « trivial ». Mais en décomposant toutes les étapes, vous allez voir que c’est logique.&lt;/p&gt;
&lt;p&gt;Pour faire tourner mon image Docker &lt;a class="link" href="https://hub.docker.com/r/zwindler/xwiki-tomcat8/" target="_blank" rel="noopener"
&gt;zwindler/xwiki-tomcat8&lt;/a&gt;, j’ai besoin, sur mon cluster Kubernetes, des choses suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un &lt;strong&gt;Deployment&lt;/strong&gt; qui exécute la partie PostgreSQL. Ce &lt;strong&gt;Deployment&lt;/strong&gt; contiendra :
&lt;ul&gt;
&lt;li&gt;un &lt;strong&gt;ReplicaSet&lt;/strong&gt; avec une seule instance car on ne souhaite avoir qu’un seul &lt;strong&gt;Pod&lt;/strong&gt; avec l’image postgresql officielle&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;Service&lt;/strong&gt; de type &lt;strong&gt;ClusterIP&lt;/strong&gt; pour lui permettre de communiquer avec le XWiki mais pas avec le monde extérieur&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;PersistantVolumeClaim&lt;/strong&gt; et son &lt;strong&gt;PersistentVolume&lt;/strong&gt; associé pour stocker les données de la base&lt;/li&gt;
&lt;li&gt;Des &lt;strong&gt;Secrets&lt;/strong&gt; pour permet de configurer les mots de passes de postgres et de l’utilisateur XWiki&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Deployment&lt;/strong&gt; qui exécute la partie XWiki. Ce &lt;strong&gt;Deployment&lt;/strong&gt; contiendra :
&lt;ul&gt;
&lt;li&gt;un &lt;strong&gt;ReplicaSet&lt;/strong&gt; avec une seule instance car on ne fait tourner qu’un seul &lt;strong&gt;Pod&lt;/strong&gt; avec l’image zwindler/xwiki-tomcat8, car on n’utilise qu’un tomcat à la fois pour exécuter XWiki&lt;/li&gt;
&lt;li&gt;Un Service de type &lt;strong&gt;NodePort&lt;/strong&gt; (ou mieux si vous avez des LoadBalancers ou des Ingress à dispo.) qui permettra d’exposer le port interne au cluster Kubernetes vers le monde extérieur&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;PersistantVolumeClaim&lt;/strong&gt; avec le &lt;strong&gt;PersistentVolume&lt;/strong&gt; pour stocker les pièces jointes car mon image Docker utilise l’option filesystem_store pour éviter de surcharger la base pour les PJ&lt;/li&gt;
&lt;li&gt;et aussi le &lt;strong&gt;Secret&lt;/strong&gt; défini précédemment pour accéder à la BDD.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OK.&lt;/p&gt;
&lt;p&gt;Voir ça posé dans une liste comme ça, ça peut faire peur.&lt;/p&gt;
&lt;p&gt;Alors vous allez me dire : « c’est plus facile de lancer ton DockerCompose » (&lt;a class="link" href="https://blog.zwindler.fr/2016/09/15/installer-xwiki-8-2-1-avec-docker-compose-en-2-lignes-de-commandes/" &gt;car j’ai montré qu’avec DockerCompose on peut démarrer une instance XWiki en 2 ou 3 lignes de commandes&lt;/a&gt;). Mais au final, tout ce que j’ai écris ici peut être concaténé dans un seul et même fichier YAML et le résultat est aussi simple dans l’absolu.&lt;/p&gt;
&lt;h2 id="créer-les-secrets"&gt;Créer les Secrets
&lt;/h2&gt;&lt;p&gt;Clairement, c’est un des gros points forts par rapport à la solution plus simple avec juste Docker / DockerCompose : la gestion des Secrets (et des configurations, dans une moindre mesure).&lt;/p&gt;
&lt;p&gt;Ici, plutôt que d’avoir un mot de passe en clair dans mon fichier compose, le mot de passe est renseigné à part, soit via un fichier, soit via l’API. Et ces mots de passes ne pourront plus être consultés via la CLI, mais pourront être utilisés.&lt;/p&gt;
&lt;p&gt;Pour créer un secret dans Kubernetes en CLI, il existe plusieurs méthodes. Soit on utilise la CLI directement depuis le prompt ou depuis un fichier plat (qui va se charger d’encoder le secret en base64 et de générer le YAML pour nous), soit on décide de créer le YAML nous-même. Je vous met les deux méthodes :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;echo -n &amp;#34;xwikidb&amp;#34; &amp;gt; ./POSTGRES_USER.txt
echo -n &amp;#34;xwikipwd&amp;#34; &amp;gt; ./POSTGRES_PASSWORD.txt
kubectl create secret generic postgresql-xwiki-user-password --from-file=POSTGRES_USER.txt --from-file=POSTGRES_PASSWORD.txt
secret &amp;#34;postgresql-xwiki-user-password&amp;#34; created
#ou
cat &amp;gt; postgresql_xwiki_user_password.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: Secret
metadata:
name: postgresql-xwiki-user-password
type: Opaque
data:
username: $(cat POSTGRES_USER.txt| base64 -w 0)
password: $(cat POSTGRES_PASSWORD.txt| base64 -w 0)
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Au final, pour un déploiement unitaire pour vous même, ça ne change pas grand-chose bien sûr. Vous avez renseigné en clair le mot de passe (ou en base64 mais c’est pareil) à un moment donné.&lt;/p&gt;
&lt;p&gt;Cependant, dans le cadre d’un gros projet avec des développeurs qui poussent du code régulièrement d’un côté et des admins qui gèrent de l’autre les utilisateurs et les mots de passes, on peut permettre aux développeurs consommer les mots de passe sans jamais avoir à les connaitre (&lt;strong&gt;et laisser trainer sur Gitlab, ou pire, Github !&lt;/strong&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl describe secret postgresql-xwiki-user-password
Name: postgresql-xwiki-user-password
Namespace: default
Labels: &amp;lt;none&amp;gt;
Annotations:
Type: Opaque
Data
====
password: 8 bytes
username: 7 bytes
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="créer-les-persistent-volumes"&gt;Créer les Persistent Volumes
&lt;/h2&gt;&lt;p&gt;Dans mon infrastructure, j’ai déjà un cluster GlusterFS. GlusterFS étant un SDS, il est particulièrement indiqué comme stockage persistant dans le cadre d’un cluster Kubernetes (comme Ceph, Cinder, S3 ou autre). Ces types de méthodes de stockage peuvent facilement se piloter par API et sont hautement disponibles.&lt;/p&gt;
&lt;p&gt;Création de l’endpoint GlusterFS&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; gluster-endpoints.yaml &amp;lt;&amp;lt;EOF
apiVersion: v1
kind: Endpoints
metadata:
name: gluster-cluster
subsets:
- addresses:
- ip: 10.0.0.1
ports:
- port: 1
protocol: TCP
- addresses:
- ip: 10.0.0.2
ports:
- port: 1
protocol: TCP
EOF
kubectl apply -f gluster-endpoints.yaml
endpoints &amp;#34;gluster-cluster&amp;#34; created
kubectl get endpoints gluster-cluster
NAME ENDPOINTS AGE
gluster-cluster 10.0.0.1:1,10.0.0.2:1 39s
cat &amp;gt; gluster-service.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: Service
metadata:
name: gluster-cluster
spec:
ports:
- port: 1
EOF
kubectl apply -f gluster-service.yaml
service &amp;#34;gluster-cluster&amp;#34; created
kubectl get service gluster-cluster
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
gluster-cluster 10.96.114.181 &amp;lt;none&amp;gt; 1/TCP 1m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La partie GlusterFS a été configurée côté Kubernetes. On peut maintenant s’atteler à la création des PV et PVC associés. D’abord la base de données :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; gluster-pv-xwiki-pg.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: gluster-pv-xwiki-pg
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
glusterfs:
endpoints: gluster-cluster
path: /xwiki-pg-storage
readOnly: false
persistentVolumeReclaimPolicy: Retain
EOF
kubectl create -f gluster-pv-xwiki-pg.yaml
persistentvolume &amp;#34;gluster-pv-xwiki-pg&amp;#34; created
cat &amp;gt; gluster-pvc-xwiki-pg.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gluster-pvc-xwiki-pg
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
EOF
kubectl create -f gluster-pvc-xwiki-pg.yaml
persistentvolumeclaim &amp;#34;gluster-pvc-xwiki-pg&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et maintenant l’application XWiki&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; gluster-pv-xwiki-app.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: gluster-pv-xwiki-app
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
glusterfs:
endpoints: gluster-cluster
path: /xwiki-app-storage
readOnly: false
persistentVolumeReclaimPolicy: Retain
EOF
kubectl create -f gluster-pv-xwiki-app.yaml
persistentvolume &amp;#34;gluster-pv-xwiki-app&amp;#34; created
cat &amp;gt; gluster-pvc-xwiki-app.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gluster-pvc-xwiki-app
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
EOF
kubectl create -f gluster-pvc-xwiki-app.yaml
persistentvolumeclaim &amp;#34;gluster-pvc-xwiki-app&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Dans le cadre d’un test, vous pouvez vous contenter de faire simplement appel à un partage NFS ou même à du stockage local (si vous n’avez qu’un worker) mais sachez que vous n’aurez pas le même niveau de résilience ni les même facilités d’administration.&lt;/p&gt;
&lt;p&gt;Si vous voulez un exemple de &lt;strong&gt;PersistentVolume&lt;/strong&gt; utilisant NFS, je vous conseille cet article qui traite d’un sujet peu plus complexe mais qui donne les étapes de base pour mettre en place le PV et PVC : &lt;a class="link" href="http://blog.kubernetes.io/2017/02/postgresql-clusters-kubernetes-statefulsets.html" target="_blank" rel="noopener"
&gt;Créer un cluster PostgreSQL avec un seul et même Deployment en utilisant les StatefulSets&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="créer-le-deployment-postgresql"&gt;Créer le Deployment postgreSQL
&lt;/h2&gt;&lt;p&gt;Voilà, on a tous les prérequis ! Il ne reste plus qu’à créer dans un premier temps notre base de données, puis notre XWiki. Comme indiqué au début, le &lt;strong&gt;Deployment&lt;/strong&gt; contiendra tous les éléments qu’on a créé plus tôt, dont les &lt;strong&gt;Secrets&lt;/strong&gt; et le &lt;strong&gt;Persistent Volume&lt;/strong&gt;. Il manquera aussi un &lt;strong&gt;Service&lt;/strong&gt;, que nous verrons plus tard.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; xwiki-pg.yaml &amp;lt;&amp;lt; EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: xwiki-pg
labels:
app: xwiki-pg
application: xwiki
spec:
replicas: 1
selector:
matchLabels:
app: xwiki-pg
application: xwiki
template:
metadata:
labels:
app: xwiki-pg
application: xwiki
name: xwiki-pg
spec:
containers:
- image: postgres:9.6
name: xwiki-pg
env:
- name: POSTGRES_DB
value: xwiki
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgresql-xwiki-user-password
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgresql-xwiki-user-password
key: password
ports:
- containerPort: 5432
name: xwiki-pg
volumeMounts:
- name: xwiki-pg-storage
mountPath: /var/lib/postgresql/data/pgdata
volumes:
- name: xwiki-pg-storage
persistentVolumeClaim:
claimName: gluster-pvc-xwiki-pg
EOF
kubectl create -f xwiki-pg.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Normalement, un &lt;strong&gt;Pod&lt;/strong&gt; devrait se créer et monter le disque Gluster, puis s’initialiser avec les variables d’environnement qu’on lui a donné.&lt;/p&gt;
&lt;p&gt;A partir de là, on ne peut cependant pas accéder à la base de données car on a pas encore créé le Service associé au &lt;strong&gt;Deployment&lt;/strong&gt;. Par défaut, on ne donne pas de type, c’est donc un &lt;strong&gt;ClusterIP&lt;/strong&gt;. Pour « savoir » vers quoi le Service doit rediriger, on a ajouté un &lt;strong&gt;Selector&lt;/strong&gt;, qui pointe sur le tag « app » avec la valeur « xwiki-pg » définie plus haut.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; xwiki-pg-svc.yaml &amp;lt;&amp;lt; EOF
apiVersion: v1
kind: Service
metadata:
name: xwiki-pg-svc
labels:
app: xwiki-pg
spec:
ports:
- port: 5432
protocol: TCP
selector:
app: xwiki-pg
EOF
kubectl create -f xwiki-pg-svc.yaml
service &amp;#34;xwiki-pg-svc&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="créer-le-deployment-xwiki"&gt;Créer le Deployment XWiki
&lt;/h2&gt;&lt;p&gt;Youhou ! Plus qu’un ! Ici pas de grosses différences, le principe est le même. On doit créer un &lt;strong&gt;Deployment&lt;/strong&gt; puis un &lt;strong&gt;Service&lt;/strong&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat xwiki-tomcat.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: xwiki-app
labels:
app: xwiki-app
application: xwiki
spec:
replicas: 1
selector:
matchLabels:
app: xwiki-app
application: xwiki
template:
metadata:
labels:
app: xwiki-app
application: xwiki
name: xwiki-app
spec:
containers:
- image: zwindler/xwiki-tomcat8
name: xwiki-app
env:
- name: POSTGRES_INSTANCE
value: xwiki-pg
- name: POSTGRES_DB
value: xwiki
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgresql-xwiki-user-password
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgresql-xwiki-user-password
key: password
ports:
- containerPort: 8080
name: tomcat-port
volumeMounts:
- name: xwiki-app-storage
mountPath: /usr/local/tomcat/work/xwiki
volumes:
- name: xwiki-app-storage
persistentVolumeClaim:
claimName: gluster-pvc-xwiki-app
kubectl apply -f xwiki-tomcat.yaml
deployment &amp;#34;xwiki-app&amp;#34; created
cat xwiki-tomcat-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: xwiki-app-svc
labels:
apps: xwiki-app
spec:
type: NodePort
ports:
- port: 8080
targetPort: tomcat-port
protocol: TCP
selector:
app: xwiki-app
kubectl apply -f xwiki-tomcat-svc.yaml
service &amp;#34;xwiki-app-svc&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="est-ce-que-ça-marche-"&gt;Est-ce que ça marche ?
&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
gluster-cluster 10.96.114.181 &amp;lt;none&amp;gt; 1/TCP 4h
kubernetes 10.96.0.1 &amp;lt;none&amp;gt; 443/TCP 10d
xwiki-app-svc 10.103.218.140 &amp;lt;nodes&amp;gt; 8080:31484/TCP 4m
xwiki-pg-svc 10.108.219.88 &amp;lt;none&amp;gt; 5432/TCP 16m
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="tout-dun-coup"&gt;Tout d’un coup
&lt;/h2&gt;&lt;p&gt;Chose promise chose due ! Je vous ai dit en début d’article que vous pouviez tout déployer en quelques lignes de commandes. Dans l’absolu, vous pourriez tout déployer via un seul fichier. Je préfère découpler la partie stockage (qui va dépendre du stockage que vous allez utiliser) et la partie secret du reste pour les raisons que j’ai énoncé plus haut. Voilà ce que ça donne :&lt;/p&gt;
&lt;p&gt;On récupère les sources sur github&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;git clone https://github.com/zwindler/docker-xwiki
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A adapter en fonction de votre contexte, à minima les adresses IP si vous avez du gluster, et carrément à réécrire si vous utilisez autre chose (NFS ou CEPH par exemple) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f docker-xwiki/kubernetes/gluster-endpoints-service.yaml
endpoints &amp;#34;gluster-cluster&amp;#34; created
service &amp;#34;gluster-cluster&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On injecte ensuite les secrets. A vous de les changer comme on a vu plus haut.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f docker-xwiki/kubernetes/postgresql_xwiki_user_password.yaml
secret &amp;#34;postgresql-xwiki-user-password&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et on fini par&amp;hellip; tout le reste ! Là normalement il n’y a rien à changer à part éventuellement des ports, les seules « variables » dans ce déploiement étant le stockage et les mots de passes (qu’on vient de gérer).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f docker-xwiki/kubernetes/xwiki-tomcat-pg-allinone.yaml
persistentvolume &amp;#34;gluster-pv-xwiki-pg&amp;#34; created
persistentvolume &amp;#34;gluster-pv-xwiki-app&amp;#34; created
deployment &amp;#34;xwiki-pg&amp;#34; created
persistentvolumeclaim &amp;#34;gluster-pvc-xwiki-pg&amp;#34; created
service &amp;#34;xwiki-pg-svc&amp;#34; created
deployment &amp;#34;xwiki-app&amp;#34; created
persistentvolumeclaim &amp;#34;gluster-pvc-xwiki-app&amp;#34; created
service &amp;#34;xwiki-app-svc&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="le-mot-de-la-fin"&gt;Le mot de la fin
&lt;/h2&gt;&lt;p&gt;Voilà, avec ce tutoriel vous avez maintenant une vue détaillée, étape par étape, de ce qu’il faut mettre en place pour gérer « proprement » le déploiement d’une application java + postgreSQL via Kubernetes.&lt;/p&gt;
&lt;p&gt;Clairement, c’est bien plus complexe qu’un simple Docker compose comme j’ai pu le présenté dans l’article sur ce sujet. Pour autant, il faut comparer ce qui est comparable, les deux installations n’ont rien à voir !&lt;/p&gt;
&lt;p&gt;D’un côté, vous avez une application déployée sur un nœud docker simple (éventuellement avec Swarm maintenant que les deux sont compatibles).&lt;/p&gt;
&lt;p&gt;De l’autre, vous avez une application qui est déployée sur un cluster de machines :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Si l’une tombe en panne, la haute disponibilité est gérée : pas seulement sur le runtime, mais aussi sur le stockage !&lt;/li&gt;
&lt;li&gt;Vous pouvez segmenter votre cluster en namespaces, et donner des droits à certains namespace à certains utilisateurs avec un gestion fine des autorisations (RBAC)&lt;/li&gt;
&lt;li&gt;Vous disposez d’un dashboard et d’une API pour automatiser tous les déploiements (via Jenkins par exemple). Si vous voulez faire une mise à jour ou besoin de modifier un paramètre, c’est une simple commande ou un fichier de conf à appliquer à nouveau.&lt;/li&gt;
&lt;li&gt;Vous avez la possibilité de faire du scaling up/down, voire de l’autoscaling.&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La liste est longue ! En bref, vous passez d’une bidouille à la production.&lt;/p&gt;
&lt;h2 id="sources-additionnelles"&gt;Sources additionnelles
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;docs.openshift.org/latest/install_config/storage_examples/gluster_example.html (lien mort, pas dispo sur Internet Archive)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://coderjourney.com/using-kubernetes-persistent-volumes/" target="_blank" rel="noopener"
&gt;coderjourney.com/using-kubernetes-persistent-volumes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.xenonstack.com/blog/how-to-deploy-postgresql-on-kubernetes" target="_blank" rel="noopener"
&gt;www.xenonstack.com/blog/how-to-deploy-postgresql-on-kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Comment j’ai enfin trouvé une excuse pour installer Docker à la maison (Cozy Cloud)</title><link>https://blog.zwindler.fr/2015/09/19/comment-jai-enfin-trouve-une-excuse-pour-installer-docker-a-la-maison-cozy-cloud/</link><pubDate>Sat, 19 Sep 2015 10:30:30 +0000</pubDate><guid>https://blog.zwindler.fr/2015/09/19/comment-jai-enfin-trouve-une-excuse-pour-installer-docker-a-la-maison-cozy-cloud/</guid><description>&lt;img src="https://blog.zwindler.fr/2015/09/docker.webp" alt="Featured image of post Comment j’ai enfin trouvé une excuse pour installer Docker à la maison (Cozy Cloud)" /&gt;&lt;h2 id="docker-cest-hype"&gt;Docker c’est « hype »
&lt;/h2&gt;&lt;p&gt;Ok, j’ai probablement 2 ans de retard sur le fait que Docker soit « hype » dans la communauté IT.&lt;/p&gt;
&lt;p&gt;Les conteneurs sont donc à la mode.&lt;/p&gt;
&lt;p&gt;Surtout chez ceux qui oublient que les conteneurs, c’est une techno archi-ancienne, remise au gout du jour avec « le cloud computing » (lui même un concept remis au gout du jour : comme tout ce qui est &lt;em&gt;hype&lt;/em&gt; ;-)).&lt;/p&gt;
&lt;p&gt;Mais ce n’est pas parce que c’est « à la mode » que je vais décider de ne pas tester. Car après tout, Docker a quand même de gros point forts.&lt;/p&gt;
&lt;p&gt;Il me fallait juste que je me trouve une excuse et me convaincre d’allouer du temps pour tester Docker. Et je l’ai trouvée : Cozy Cloud (voir &lt;a class="link" href="https://blog.zwindler.fr/2015/09/08/decouverte-de-cozy-cloud-personnel/" &gt;mon article précédent&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id="la-simplicité"&gt;La simplicité
&lt;/h2&gt;&lt;p&gt;Enfonçons des portes ouvertes. La grande force des outils comme Docker aujourd’hui, c’est la simplicité de mise en place et d’utilisation. Sincèrement je ne m’attendais pas à ce que ce soit simple à ce point là.&lt;/p&gt;
&lt;p&gt;Je suis parti de la machine que j’avais déjà utilisée pour installer ma première instance de Cozy Cloud, donc un Debian 8 from scratch ou quasiment.&lt;/p&gt;
&lt;p&gt;La première chose à faire pour l’installer sur Debian 8 est d’activer dans les dépôts le « backports ». A priori Docker n’a pas été accepté dans Debian 8 pour des raisons de sécurités non résolues au moment de la sortie ? Vous aurez plus de détails dans la documentation officielle pour Debian : &lt;a class="link" href="https://docs.docker.com/engine/install/debian/" target="_blank" rel="noopener"
&gt;Docker Debian&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo vi /etc/apt/sources.list #ajouter la ligne pour activer les backports
deb http://http.debian.net/debian jessie-backports main
sudo apt-get update
sudo apt-get install docker.io
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et c’est tout. Pas de configuration post installation : ça fonctionne. Si.&lt;/p&gt;
&lt;p&gt;Pour s’en convaincre, on peut télécharger le conteneur hello-world, qui vous imprimera à l’écran un petit message de diagnostic et quelques pistes pour aller plus loin.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo docker run --rm hello-world
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="application-à-cozy"&gt;Application à Cozy
&lt;/h2&gt;&lt;p&gt;Cool, Docker fonctionne. Mais appliquons le maintenant à un cas d’usage utile.&lt;/p&gt;
&lt;p&gt;Cozy, c’est aussi cool que Docker. Aux détails près que :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une instance Cozy est mono utilisateur, impossible de l’utiliser pour une même famille par exemple.&lt;/li&gt;
&lt;li&gt;Tout ce qui est stocké (notamment les fichiers et les photos) est stocké dans Cozy&amp;hellip; impossible pour l’instant de pointer sur un espace partagé (type NFS/SMB) de votre NAS par exemple.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les deux problèmes ont été remontés plusieurs fois et on peut régler le premier avec Docker ; &lt;a class="link" href="https://web.archive.org/web/20161008090232/https://forum.cozy.io/t/more-than-one-user/97" target="_blank" rel="noopener"
&gt;voir ici (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En regardant la documentation d’installation de Cozy Cloud via Docker, on se rend compte de la puissance de Docker en terme de simplification. Déployer Cozy Cloud, ce n’est guère plus compliqué qu’une ligne de commande.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo docker pull cozy/full
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Voilà comment s’économiser les quelques lignes de l’installation classique, déjà relativement simple, pour installer une instance cozy dans un conteneur Docker. Reste à jouer un peu avec les arguments pour que nos instances écoutent sur des ports différents (&lt;a class="link" href="https://docs.cozy.io/en/howTos/dev/runCozyDocker/" target="_blank" rel="noopener"
&gt;voir la documentation officielle&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Mais ça ne résout pas encore totalement le problème du déploiement simplifié lorsqu’on a plusieurs utilisateurs pour une même machine.&lt;/p&gt;
&lt;p&gt;C’est pourquoi un développeur de Cozy a mis en ligne un script qui automatise le déploiement multiple d’instances Cozy sur un même serveur Docker :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://web.archive.org/web/20161008082323/https://forum.cozy.io/t/cozy-deploy-a-tool-to-deploy-and-manage-multiple-cozy-instances/516" target="_blank" rel="noopener"
&gt;forum.cozy.io/t/cozy-deploy-a-tool-to-deploy-and-manage-multiple-cozy-instances/516 (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour vous éviter une lecture de tout le post, le script en question est disponible sur Github à &lt;a class="link" href="https://github.com/cozy-labs/cozy-deploy" target="_blank" rel="noopener"
&gt;cette adresse&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="installation-du-script"&gt;Installation du script
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;wget -qO- https://raw.github.com/cozy-labs/cozy-deploy/master/install.sh | sudo bash #Installation
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si comme moi vous obtenez l’erreur suivant, c’est qu’il vous manque le package lsb-core. Installez le et relancez le script.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;No LSB modules are available.
sudo apt-get install lsb-core
wget -qO- https://raw.github.com/cozy-labs/cozy-deploy/master/install.sh | sudo bash
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="déploiement-des-instances-et-administration"&gt;Déploiement des instances et administration
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;cozy-deploy deploy cozy1.example.org #déploiement d&amp;#39;un premier conteneur
cozy-deploy deploy cozy2.example.org #et de deux !
cozy-deploy list #affichage de tous les conteneurs déployés
DOMAIN RUNNING PORT
cozy2.example.org true 49003
cozy1.example.org true 49002
cozy-deploy status
cozy2.example.org
postfix: up
couch: up
controller: up
data-system: up
home: up
proxy: up
index: up
cozy1.example.org
postfix: up
couch: up
controller: up
data-system: up
home: up
proxy: up
index: up
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vous disposez d’instances distinctes en écoute sur des ports distincts mais accessibles via leur nom complet à l’aide de &lt;strong&gt;nginx&lt;/strong&gt; (qui sert ici uniquement de proxy pour rediriger les requêtes vers le bon port et donc le bon conteneur).&lt;/p&gt;
&lt;p&gt;Le tout sans effort : Problem solved.&lt;/p&gt;
&lt;p&gt;Il ne reste plus que cette histoire de stockage partagé (encore un petit effort, Cozy!).&lt;/p&gt;</description></item></channel></rss>