<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CentOS on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/centos/</link><description>Recent content in CentOS on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Tue, 08 Dec 2020 07:45:00 +0000</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/centos/index.xml" rel="self" type="application/rss+xml"/><item><title>k3os, le reboot de RancherOS à la sauce k3s</title><link>https://blog.zwindler.fr/2020/12/08/k3os-le-reboot-de-rancheros-a-la-sauce-k3s/</link><pubDate>Tue, 08 Dec 2020 07:45:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/12/08/k3os-le-reboot-de-rancheros-a-la-sauce-k3s/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/12/k3s.webp" alt="Featured image of post k3os, le reboot de RancherOS à la sauce k3s" /&gt;&lt;h2 id="k3os-encore-un-produit-rancher-"&gt;k3os, encore un produit Rancher ?
&lt;/h2&gt;&lt;p&gt;Oui, k3os. Je vais donc ENCORE parler d’un produit de Rancher aujourd’hui, et la raison principale est que cet article est plus ou moins la suite logique des deux précédents sur RancherOS et RKE&lt;/p&gt;
&lt;p&gt;Dans &lt;a class="link" href="https://blog.zwindler.fr/2020/10/26/kubernetes-avec-rancheros-et-rke-partie-1/" &gt;Kubernetes avec RancherOS et RKE partie 1&lt;/a&gt;, je vous expliquais que j’avais ENCORE changé d’infra et que pour le fun, j’avais souhaité essayer d’installer &lt;a class="link" href="https://blog.zwindler.fr/2020/10/26/kubernetes-avec-rancheros-et-rke-partie-1/" &gt;RancherOS&lt;/a&gt; puis &lt;a class="link" href="https://blog.zwindler.fr/2020/11/30/kubernetes-avec-rancheros-et-rke-partie-2/" &gt;RKE&lt;/a&gt;, respectivement comme distrib pour mes nodes Kubernetes et comme méthode d’installation de Kubernetes lui même.&lt;/p&gt;
&lt;p&gt;Bon, alors d’abord j’ai pas été super convaincu par RancherOS (pas seulement pour mon usage perso, mais aussi plus globalement) et en plus, j’ai découvert grâce aux commentaires que RancherOS était en fait abandonné.&lt;/p&gt;
&lt;p&gt;Bummer&amp;hellip;&lt;/p&gt;
&lt;h2 id="k3s-pour-mon-usecase-cest-quand-même-mieux"&gt;k3s pour mon usecase c’est quand même mieux
&lt;/h2&gt;&lt;p&gt;Bon en vrai ce n’était pas bien grave, car le but était de tester ces produits dont j’entendais parler depuis un moment. Mais du coup, je n’ai toujours pas de Kubernetes viable pour mes geekeries&amp;hellip;&lt;/p&gt;
&lt;p&gt;Un des outils qui correspond le mieux à mon usecase, là encore chez Rancher, c’est &lt;strong&gt;&lt;a class="link" href="https://k3s.io/" target="_blank" rel="noopener"
&gt;k3s&lt;/a&gt;&lt;/strong&gt;. Un Kubernetes minimaliste qui prend très peu de ressources et qui est simple à installer.&lt;/p&gt;
&lt;p&gt;J’avais d’ailleurs fait quelques articles dessus, notamment pour parler d’un playbook Ansible qui permettait de déployer k3s sur des instances ARM dans le cloud de Scaleway (la bonne époque où ils en proposaient, en tout cas&amp;hellip;).&lt;/p&gt;
&lt;p&gt;Le code est toujours dispo et &lt;strong&gt;n’était pas spécifique à ARM ni à Scaleway&lt;/strong&gt;, si ça vous intéresse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zwindler/ansible-scaleway-k3s" target="_blank" rel="noopener"
&gt;Le code sur Github&lt;/a&gt;&lt;/li&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;L’article pour en parler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="et-k3os-dans-tout-ça-"&gt;Et k3os dans tout ça ?
&lt;/h2&gt;&lt;p&gt;La méthode d’installation de Kubernetes est donc choisie. Mais ça ne répond pas à la seconde question, à savoir, sur quelle distribution je l’installe.&lt;/p&gt;
&lt;p&gt;Je peux l’installer sur n’importe quel OS Linux généraliste (Debian, Ubuntu, CentOS, &amp;hellip; you name it), mais le but, c’est quand même d’installer un Kubernetes le plus léger possible (car je suis radin sur les serveurs que je loue et ils sont peu puissants).&lt;/p&gt;
&lt;p&gt;Qu’à cela ne tienne, me dis-je ! Pourquoi ne pas retenter l’expérience CoreOS et RancherOS avec k3os ?&lt;/p&gt;
&lt;p&gt;Et c’est vraiment une bonne question&amp;hellip;&lt;/p&gt;
&lt;h2 id="k3os-donc"&gt;k3OS donc
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;k3OS is a Linux distribution designed to remove as much OS maintenance as possible in a Kubernetes cluster. It is specifically designed to only have what is needed to run &lt;a class="link" href="https://github.com/rancher/k3s" target="_blank" rel="noopener"
&gt;k3s&lt;/a&gt;. Additionally the OS is designed to be managed by kubectl once a cluster is bootstrapped. Nodes only need to join a cluster and then all aspects of the OS can be managed from Kubernetes. Both k3OS and k3s upgrades are handled by the k3OS operator.
&lt;a class="link" href="https://github.com/rancher/k3os" target="_blank" rel="noopener"
&gt;github.com/rancher/k3os&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;k3os est donc une distribution optimisée par Rancher pour fonctionner avec k3s et consommer le moins de ressources possibles.&lt;/p&gt;
&lt;p&gt;Les avantages mis en avant sont que dès que l’OS est installé, on a un Kubernetes fonctionnel puisque k3s est préinstallé et configuré à l’install de l’OS.&lt;/p&gt;
&lt;p&gt;L’autre avantage mis en avant est que tout la gestion du cycle de vie de l’OS est piloté à l’aide d’un operateur dans Kubernetes (k3OS operator) qui va nous permettre de gérer l’OS depuis Kubernetes directement.&lt;/p&gt;
&lt;p&gt;Mkay, pourquoi pas.&lt;/p&gt;
&lt;h2 id="et-cest-reparti-pour-un-tour"&gt;Et c’est reparti pour un tour
&lt;/h2&gt;&lt;p&gt;Même procédure que pour l’article sur RancherOS, les principes sont très similaires. On va télécharger une image iso, créer une VM et se connecter dessus en liveCD pour installer l’OS sur le disque.&lt;/p&gt;
&lt;p&gt;La page des releases est ici : &lt;a class="link" href="https://github.com/rancher/k3os/releases" target="_blank" rel="noopener"
&gt;github.com/rancher/k3os/releases&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cd /var/lib/vz/template/iso
wget https://github.com/rancher/k3os/releases/download/v0.11.1/k3os-amd64.iso
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;To copy k3OS to local disk, after logging in as rancher run sudo k3os install. Then remove the ISO from the virtual machine and reboot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/12/k3os-0.11.1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STOOOOOP&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Exactement comme dans l’install de RancherOS, si vous partez bille en tête vous risquez de tomber sur un OS (ahah).&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.zwindler.fr/2020/10/26/kubernetes-avec-rancheros-et-rke-partie-1/" &gt;Dans l’article précédent&lt;/a&gt;, j’avais fait l’andouille et lancé la commande, pour me rendre compte qu’une fois installé, je n’avais ni réseau, ni clé SSH pour me connecter sur l’utilisateur rancher post install.&lt;/p&gt;
&lt;p&gt;En vrai, tout doit se faire via cloud-config&amp;hellip;&lt;/p&gt;
&lt;p&gt;Bon, pour être honnête, cette fois-ci, ils ont quand même un peu plus prévu le coup. Si vous ne fournissez pas de cloud-config, cette fois-ci k3os vous propose de rentrer un mot de passe pour votre rancher.&lt;/p&gt;
&lt;p&gt;Mais vous n’aurez pas plus de réseau si comme moi vous n’avez pas mis de DHCP sur votre LAN (cf aparté pour les bolosses qui n’ont pas de DHCP plus tard dans l’article).&lt;/p&gt;
&lt;h2 id="cloud-config"&gt;cloud-config
&lt;/h2&gt;&lt;p&gt;Partons donc pour l’instant du principe que vous avez un DHCP et que vous aurez donc, une fois k3OS installé, accès réseau à votre machine.&lt;/p&gt;
&lt;p&gt;Proxmox a la bonne idée de permettre la création de volume cloud-init directement depuis l’UI.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/12/k3os_cloud-init.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/12/k3os_cloudinit_2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Cependant, j’ai bien l’impression que le format du cloud-init de Proxmox ne correspond pas au format attendu par k3OS&amp;hellip;&lt;/p&gt;
&lt;p&gt;OK, je suis pas fâché.&lt;/p&gt;
&lt;p&gt;On va donc devoir le faire à la mimine et ça tombe bien, car on a ENCORE le souci du clavier Qwerty/Azerty&amp;hellip; (&lt;a class="link" href="https://blog.zwindler.fr/2020/10/26/kubernetes-avec-rancheros-et-rke-partie-1/" &gt;cf Bonus Qwerty&lt;/a&gt;), ce qui est parfait pour copier à la main une clé SSH, c’est bien connu.&lt;/p&gt;
&lt;p&gt;Vous l’aurez compris, on va s’en sortir une fois de plus avec un port série et la console de type xterm.js&amp;hellip;&lt;/p&gt;
&lt;p&gt;Grosso modo, mon cloud config s’est limité à ça.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;gt; config.yml &amp;lt;&amp;lt; EOF
k3os:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQAaaaaaaaaaaaaaaaaaaaaaaaaaaaOF0lZiHOjIZ/27aaHmNTq27Vws2dhzJ9 rancher
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tout ça pour ça me direz-vous ? Oui&amp;hellip;&lt;/p&gt;
&lt;p&gt;Mais bon, une fois qu’on a ça, on peut passer à l’install elle-même, qui est en fait un mini installeur qui vous pose quelques questions un peu triviales comme « rôle du node », « token », « chemin de la clé SSH ».&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;k3os-15121 [~]$ sudo k3os install
Running k3OS configuration
Choose operation
1. Install to disk
2. Configure server or agent
Select Number [1]:
Config system with cloud-init file? [y/N]: y
cloud-init file location (file path or http URL): config.yml
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ces valeurs peuvent d’ailleurs être ajoutées au cloud-config pour vous permettre d’automatiser la totalité de l’opération.&lt;/p&gt;
&lt;p&gt;A l’issue de l’opération&amp;hellip; magie ! vous aurez un Kubernetes tout neuf et tout léger :)&lt;/p&gt;
&lt;h2 id="aparté-pour-les-bolosses-qui-nont-pas-de-dhcp-aka-moi"&gt;Aparté pour les bolosses qui n’ont pas de DHCP (aka. moi)
&lt;/h2&gt;&lt;p&gt;Ça aurait été plus simple de monter un petit serveur DHCP vite fait mais je suis têtu comme pas deux.&lt;/p&gt;
&lt;p&gt;La blague avec k3OS est que, contrairement à RancherOS, il n’est tout simplement pas possible d’installer l’OS en lui spécifiant l’adresse réseau physique qu’il devra avoir post install.&lt;/p&gt;
&lt;p&gt;En fait au début, j’avais copié ce que j’avais fait pour RancherOS. L’installeur de k3OS ne râle pas, mais il ignore simplement le code en trop.&lt;/p&gt;
&lt;p&gt;Et vous ne pourrez plus vous connecter&amp;hellip;&lt;/p&gt;
&lt;p&gt;Mais comme je suis têtu (je me répète), j’ai cherché à tout prix la solution.&lt;/p&gt;
&lt;p&gt;L’idée ici est de feinter l’installeur en ne lui donnant PAS de cloud config. On garde ainsi la possibilité de se loguer à l’utilisateur rancher avec un mot de passe (pas bien ça&amp;hellip;).&lt;/p&gt;
&lt;p&gt;Une fois k3OS installé, on se connecte une nouvelle fois en console (oui, on risque pas de le faire en SSH&amp;hellip;) et on configure la carte réseau.&lt;/p&gt;
&lt;p&gt;k3OS est un dérivé d’Alpine (pour les binaires userspace) avec le kernel d’Ubuntu 20.04 (oh&amp;hellip;kay ?).&lt;/p&gt;
&lt;p&gt;Pour setter le réseau, vous pouvez donc faire :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo connmanctl services
*AR Wired ethernet_c6eb50d8c655_cable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cette commande vous renvoie le nom de la carte réseau virtuelle. Vous pouvez maintenant regarder la configuration par défaut&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo connmanctl services ethernet_c6eb50d8c655_cable
/net/connman/service/ethernet_c6eb50d8c655_cable
Type = ethernet
Security = [ ]
State = ready
Favorite = True
Immutable = False
AutoConnect = True
Name = Wired
Ethernet = [ Method=auto, Interface=eth0, Address=C6:EB:50:D8:C6:55, MTU=1500 ]
IPv4 = [ Method=auto, Address=169.254.126.16, Netmask=255.255.0.0 ]
IPv4.Configuration = [ Method=auto ]
IPv6 = [ ]
IPv6.Configuration = [ Method=auto, Privacy=disabled ]
Nameservers = [ 8.8.8.8 ]
Nameservers.Configuration = [ ]
Timeservers = [ ]
Timeservers.Configuration = [ ]
Domains = [ ]
Domains.Configuration = [ ]
Proxy = [ Method=direct ]
Proxy.Configuration = [ ]
mDNS = False
mDNS.Configuration = False
Provider = [ ]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Grande classe. 8.8.8.8 en DNS&amp;hellip; No comment.&lt;/p&gt;
&lt;p&gt;Et setter votre carte réseau post installation avec cette dernière commande (à remplacer par vos valeurs à vous, hein) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo connmanctl config ethernet_d2416991aa5b_cable --ipv4 manual 192.168.1.15 255.255.255.0 192.168.1.1 --nameservers 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Bon je crois qu’il est temps d’arrêter de se faire du mal&amp;hellip;&lt;/p&gt;
&lt;p&gt;Oui clairement, je me suis mis dans un exemple un peu foireux. Tout le monde de normalement constitué dispose d’un DHCP de nos jours. Surtout que k3OS cible les usages de k3s, à savoir le edge et l’IoT.&lt;/p&gt;
&lt;p&gt;Mais du coup, j’ai l’impression qu’on est vraiment dans le marché de niche de la niche : un OS optimisé pour l’IoT ou l’edge uniquement. Je ne suis clairement pas ciblé par k3OS.&lt;/p&gt;
&lt;p&gt;Ça ne m’a pas vraiment donné envie de regarder plus en détails la partie k3OS operator, qui permet de gérer les mises à jours de l’OS depuis Kube.&lt;/p&gt;
&lt;p&gt;La documentation sur le sujet est disponible ici et ça a l’air d’avoir beaucoup bougé entre la v0.9, la v0.10 et la v0.11, puisqu’il y a des exceptions dans tous les sens&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/rancher/k3os#upgrade-and-maintenance" target="_blank" rel="noopener"
&gt;github.com/rancher/k3os#upgrade-and-maintenance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bref&amp;hellip; il est temps que je m’installe un bête OS généraliste&amp;hellip;&lt;/p&gt;</description></item><item><title>Récupérer les informations sur la distribution avec les facts Ansible</title><link>https://blog.zwindler.fr/2018/11/21/recuperer-les-informations-sur-la-distribution-avec-les-facts-ansible/</link><pubDate>Wed, 21 Nov 2018 12:45:40 +0000</pubDate><guid>https://blog.zwindler.fr/2018/11/21/recuperer-les-informations-sur-la-distribution-avec-les-facts-ansible/</guid><description>&lt;img src="https://blog.zwindler.fr/2018/10/ansible_logo.webp" alt="Featured image of post Récupérer les informations sur la distribution avec les facts Ansible" /&gt;&lt;h2 id="les-facts-dansible"&gt;Les facts d’Ansible
&lt;/h2&gt;&lt;p&gt;Si vous suivez le blog, vous savez que &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ansible" &gt;j’utilise énormément Ansible&lt;/a&gt;. J’ai même été faire un &lt;a class="link" href="https://blog.zwindler.fr/2018/11/09/bdx-i-o-2018-ami-developpeur-deviens-un-ops-sans-effort-avec-ansible" &gt;talk sur le sujet à BDX I/O 2018, à l’ENSEIRB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Aujourd’hui, plutôt que de vous donner un playbook tout fait pour installer sans effort une des multiples applications dont j’ai automatisé le déploiement avec Ansible, je vous propose d’explorer une des features les plus importantes et utiles d’Ansible, les &lt;strong&gt;facts&lt;/strong&gt;, par le biais d’un petit exemple.&lt;/p&gt;
&lt;h2 id="cest-quoi-les-facts-dans-ansible"&gt;C’est quoi les facts dans Ansible
&lt;/h2&gt;&lt;p&gt;Si vous avez déjà lancé un playbook, vous avez sûrement remarqué lors de son exécution, que la première tâche qui est réalisée n’est pas une tâche que vous avez demandée explicitement.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible-playbook -i inventory/prod/blop -u blop --private-key=blop.key configure-blop.yml
[...]]
TASK [Gathering Facts] *********************************************************
ok: [blop-vm1]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cette tâche &lt;strong&gt;[Gathering Facts]&lt;/strong&gt;, qui ne fait à première vue rien, correspond en fait à la connexion à la ou les machines sur lesquelles seront exécutées les playbooks. Si la connexion échoue, le playbook échouera sur cette cible, et continuera éventuellement sur les autres (s’il en reste). Si l’hôte répond, alors Ansible en profite pour récupérer moult informations en rapport avec cette machines et les stockent dans une variable &lt;strong&gt;ansible_facts&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="a-quoi-ça-ressemble-"&gt;A quoi ça ressemble ?
&lt;/h2&gt;&lt;p&gt;Comme je ne disais, à première vue, cette commande de fait rien. Si on ne sait pas qu’elle stocke des informations dans une variables, on ne peut rien en faire.&lt;/p&gt;
&lt;p&gt;Un bon moyen d’avoir un premier aperçu de ce qu’on peut en faire est de les afficher. On peut faire ça avec &lt;a class="link" href="http://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html" target="_blank" rel="noopener"
&gt;le module « setup »&lt;/a&gt;, qui est en réalité le même module qui est appelé lors de l’étape &lt;strong&gt;[Gathering facts]&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Le retour se fera au format JSON, ce qui est certes peu digeste, mais facilitera grandement les manipulations de type « filtre » (via le flag filter intégré ou via l’utilitaire &lt;strong&gt;jq&lt;/strong&gt; par exemple).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible blop-vm1 i inventory/prod/blop -m setup
blop-vm1 | SUCCESS =&amp;gt; {
&amp;#34;ansible_facts&amp;#34;: {
&amp;#34;ansible_all_ipv4_addresses&amp;#34;: [
&amp;#34;10.1.1.10&amp;#34;
],
&amp;#34;ansible_apparmor&amp;#34;: {
&amp;#34;status&amp;#34;: &amp;#34;enabled&amp;#34;
},
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Je ne vous copie-colle pas tout, rien que pour cette machine, j’ai 719 lignes&amp;hellip; La quantité d’informations disponible est impressionnante, et on peut même en venir à se demander à quoi ça va bien pouvoir nous servir.&lt;/p&gt;
&lt;h2 id="ok-on-en-fait-quoi-"&gt;Ok, on en fait quoi ?
&lt;/h2&gt;&lt;p&gt;Du coup je profite de cet article pour faire un tuto tout simple et qui peut être utile dans de nombreux cas, réaliser des opérations différentes en fonction de la distribution de la machine concernée.&lt;/p&gt;
&lt;p&gt;L’information qui va nous intéresser ici concerne donc les remontées en tant que « nom » ou « version » d’une distribution. Je vais vous économiser la lecture de nos 700+ lignes, et vous indiquer que vous pouvez trouver ces informations en filtrant sur les mots clés « ansible_distribution&amp;hellip; » et « ansible_os&amp;hellip; »&lt;/p&gt;
&lt;p&gt;Voilà ce qu’on pourrait obtenir sur une machine CentOS :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible blop-vm1 -m setup -a &amp;#39;filter=ansible_distribution*&amp;#39;
blop-vm1 | SUCCESS =&amp;gt; {
&amp;#34;ansible_facts&amp;#34;: {
&amp;#34;ansible_distribution&amp;#34;: &amp;#34;CentOS&amp;#34;,
&amp;#34;ansible_distribution_major_version&amp;#34;: &amp;#34;7&amp;#34;,
&amp;#34;ansible_distribution_release&amp;#34;: &amp;#34;Core&amp;#34;,
&amp;#34;ansible_distribution_version&amp;#34;: &amp;#34;7.2.1511&amp;#34;
},
&amp;#34;changed&amp;#34;: false
}
ansible blop-vm1 -m setup -a &amp;#39;filter=ansible_os_family&amp;#39;
blop-vm1 | SUCCESS =&amp;gt; {
&amp;#34;ansible_facts&amp;#34;: {
&amp;#34;ansible_os_family&amp;#34;: &amp;#34;RedHat&amp;#34;
},
&amp;#34;changed&amp;#34;: false
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et sur une machine Ubuntu :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible blop-vm2 -m setup -a &amp;#39;filter=ansible_distribution*&amp;#39;
ansible blop-vm2 | SUCCESS =&amp;gt; {
&amp;#34;ansible_facts&amp;#34;: {
&amp;#34;ansible_distribution&amp;#34;: &amp;#34;Ubuntu&amp;#34;,
&amp;#34;ansible_distribution_file_parsed&amp;#34;: true,
&amp;#34;ansible_distribution_file_path&amp;#34;: &amp;#34;/etc/os-release&amp;#34;,
&amp;#34;ansible_distribution_file_variety&amp;#34;: &amp;#34;Debian&amp;#34;,
&amp;#34;ansible_distribution_major_version&amp;#34;: &amp;#34;16&amp;#34;,
&amp;#34;ansible_distribution_release&amp;#34;: &amp;#34;xenial&amp;#34;,
&amp;#34;ansible_distribution_version&amp;#34;: &amp;#34;16.04&amp;#34;
},
&amp;#34;changed&amp;#34;: false
}
ansible blop-vm2 -m setup -a &amp;#39;filter=ansible_os*&amp;#39;
blop-vm2 | SUCCESS =&amp;gt; {
&amp;#34;ansible_facts&amp;#34;: {
&amp;#34;ansible_os_family&amp;#34;: &amp;#34;Debian&amp;#34;
},
&amp;#34;changed&amp;#34;: false
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="utiliser-les-facts-dans-un-playbook"&gt;Utiliser les facts dans un playbook
&lt;/h2&gt;&lt;p&gt;Pour continuer dans l’exemple, on va faire une chose qu’il ne faut jamais faire : désactiver le firewall et SELinux.&lt;/p&gt;
&lt;p&gt;Imaginons que vous souhaitiez quand même le faire. Si vous lancez ce playbook sur tout votre parc et qu’il n’est pas homogène, vous allez tomber sur des groupes de machines Ubuntu, CentOS 5, 6, 7&amp;hellip;&lt;/p&gt;
&lt;p&gt;Un moyen de gérer les cas particuliers pourrait être de les classer tous vos hosts dans des groupes, et de créer un playbook pour chaque OS/version, restreint à un groupe de machines uniquement.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;---
- hosts: rhelcentos6only
tasks:
[…]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ce n’est d’ailleurs pas une mauvaise idée, surtout pour gérer les distrib aussi différentes que RHEL et Ubuntu par exemple.&lt;/p&gt;
&lt;p&gt;En revanche, dans le cas de RHEL, on a des différences qui apparaissent à partir de la RHEL 7, notamment la gestion du Firewall qui passe de IPtables à firewalld.&lt;/p&gt;
&lt;p&gt;On va donc faire appel à la clause &lt;strong&gt;when:&lt;/strong&gt; de ansible, qui conditionne l’exécution d’une tâche (ou d’un rôle ou d’un block) à une validation. Et ça donnerait quelque chose comme ça :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;---
- hosts: rhelcentos6only
tasks:
- name: &amp;#34;shutdown and disable IPtables for RHEL &amp;lt;= 6&amp;#34;
service:
name=iptables
state=stopped
enabled=no
when: (ansible_distribution == &amp;#34;CentOS&amp;#34; or ansible_distribution == &amp;#34;RedHat&amp;#34;) and
(ansible_distribution_major_version &amp;lt;= &amp;#34;6&amp;#34;)
- name: &amp;#34;shutdown and disable firewalld for RHEL &amp;gt;= 7&amp;#34;
service:
name=firewalld
state=stopped
enabled=no
when: (ansible_distribution == &amp;#34;CentOS&amp;#34; or ansible_distribution == &amp;#34;RedHat&amp;#34;) and
(ansible_distribution_major_version &amp;gt;= &amp;#34;7&amp;#34;)
- name: &amp;#34;disable selinux&amp;#34;
selinux:
state=disabled
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Dans cet exemple, lors de l’exécution du playbook, on aura donc, pour chaque VM CentOS ou RHEL, une tâche qui sera exécutée, et l’autre qui sera marquée « skipping » (en bleu clair) et le playbook marchera pour toutes les RHEL, quelque soit leur version.&lt;/p&gt;
&lt;h2 id="aller-plus-loin"&gt;Aller plus loin
&lt;/h2&gt;&lt;p&gt;Il existe une page spécifique sur la documentation d’Ansible pour parler des conditions dans les playbooks, accessible à l’adresse suivante : &lt;a class="link" href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html" target="_blank" rel="noopener"
&gt;https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez aussi utiliser les facts dans les options des tasks, et dans les templates, en encadrant le nom de la variable souhaitée avec des « doubles curly braces » : &lt;code&gt;{{ xxx }}&lt;/code&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;- command: &amp;#34;echo {{ ma_super_variable }}&amp;#34;
&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="http://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html" target="_blank" rel="noopener"
&gt;docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html" target="_blank" rel="noopener"
&gt;docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Installation xwiki 10.6.1 via un playbook Ansible</title><link>https://blog.zwindler.fr/2018/09/05/installation-xwiki-10-6-via-un-playbook-ansible/</link><pubDate>Wed, 05 Sep 2018 11:45:00 +0000</pubDate><guid>https://blog.zwindler.fr/2018/09/05/installation-xwiki-10-6-via-un-playbook-ansible/</guid><description>&lt;img src="https://blog.zwindler.fr/2018/09/xwiki_ansible.webp" alt="Featured image of post Installation xwiki 10.6.1 via un playbook Ansible" /&gt;&lt;h2 id="ansible--xwiki"&gt;Ansible + XWiki
&lt;/h2&gt;&lt;p&gt;Je sais ce que vous vous dites :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ça fait longtemps que zwindler n’a pas écrit un article sur Ansible ou XWiki !&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Non ? Vous ne vous dites pas ça ? Bon tant pis c’est pas grave. Aujourd’hui, je rédige ENFIN l’article pour parler d’un playbook que j’ai déjà rédigé il y a presque un an déjà (et mis à jour et déployé de nombreuses fois). C’est dire si j’ai du retard dans les articles du blog&amp;hellip;&lt;/p&gt;
&lt;h2 id="petit-rappel-des-épisodes-précédents"&gt;Petit rappel des épisodes précédents
&lt;/h2&gt;&lt;p&gt;J’ai déjà rédigé de manière extensive sur XWiki qui est un belle solution open source de gestion de la connaissance. Parmi les articles les plus susceptibles d’intéresser, il y a déjà :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&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;Installer facilement XWiki en 2 lignes de commandes avec Docker compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2016/09/12/migration-mediawiki-vers-xwiki/" &gt;Tutoriel de migration d’un Mediawiki vers XWiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2017/10/24/tutoriel-xwiki-ma-premier-appli-stateful-sur-kubernetes/" &gt;Déploiement d’une application Stateful dans Kubernetes par l’exemple (XWiki + PostgreSQL)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2016/03/12/parametres-caches-de-xwiki-taille/" &gt;Résoudre les erreurs de type « Fichier trop gros » lors de l’import d’un fichier dans XWiki&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il y en a plein d’autre (&lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=xwiki" &gt;voir ici&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id="et-ansible-"&gt;Et Ansible ?
&lt;/h2&gt;&lt;p&gt;Et bien oui. Je vous rabâche aussi les oreilles avec Ansible, l’Infrastructure as Code, et l’Idempotence. (Là encore, &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ansible" &gt;il y en a plein&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Alors pourquoi pas un playbook Ansible pour automatiser l’installation de XWiki, si vous n’avez pas de cluster Kubernetes sous la main et que vous êtes un Gaulois réfractaire à Docker ?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/gaulois.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="ya-quoi-dans-ton-playbook-"&gt;Ya quoi dans ton playbook ?
&lt;/h2&gt;&lt;p&gt;Trêve de suspense, les sources sont disponibles sur &lt;a class="link" href="https://github.com/zwindler/ansible-deploy-xwiki-tomcat-postgresql" target="_blank" rel="noopener"
&gt;Github à cette adresse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce playbook a été testé pour des RHEL/CentOS 7, en particulier de la version 7.2 jusqu’à 7.4. Une installation de RHEL/CentOS en mode minimale, même sans environnement graphique, devrait être suffisante. Je l’ai faite tourner en production sur des environnements Desktop dans des VMs, mais aussi en Minimal sur un container LXC dans Proxmox VE sans aucun souci.&lt;/p&gt;
&lt;p&gt;L’installation n’utilise pas les serveurs web et de bases de données par « défaut » (MySQL), mais Tomcat 8 et PostgreSQL. Pour la version de Tomcat, c’est une version très particulière qu’il faut utiliser car des bugs ont étés introduits dans une version, puis RE-introduits quelques mois plus tard. Vous pouvez modifier la version par défaut qui est une variables de mon playbook (8.5.32) si elle ne vous convient pas. Les instructions d’installation se basent sur &lt;a class="link" href="https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Installation/InstallationWAR/InstallationTomcat/" target="_blank" rel="noopener"
&gt;la documentation officielle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/09/xwiki_warning.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;- tomcat_version: 8.5.32
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vous pouvez également modifier la version de XWiki directement dans le playbook (c’est une variable là aussi) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;- xwiki_version: &amp;#34;10.6.1&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A noter, les vielles versions de XWiki n’étaient pas hébergées sur le même dépôt, qui a changé récemment, d’où les deux URLs dans le playbook.&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;On va utiliser git pour récupérer le playbook et ansible (version de l’OS, rien d’exotique).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum install ansible git
git clone https://github.com/zwindler/ansible-deploy-xwiki-tomcat-postgresql
cd ansible-deploy-xwiki-tomcat-postgresql
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="quand-est-ce-quon-installe-xwiki-"&gt;Quand est ce qu’on installe XWiki ?
&lt;/h2&gt;&lt;p&gt;Maintenant !&lt;/p&gt;
&lt;p&gt;Sur un poste qui dispose de git et Ansible :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible-playbook -l localhost ansible-deploy-xwiki-tomcat-postgresql.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Le playbook devrait vous prompter pour un mot de passe pour l’utilisateur de base de données PostgreSQL, n’hésitez pas à mettre quelque chose de complexe. Vous ne devriez pas en avoir besoin.&lt;/p&gt;
&lt;p&gt;Si vous avez une erreur qui vous dit que localhost est ignoré, vous pouvez l’ajouter à votre fichier d’inventaire global : /etc/ansible/hosts&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;sudo vim /etc/ansible/hosts
[local]
localhost ansible_connection=local
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et Paf ! Vous avez un XWiki installé, disponible à l’adresse &lt;code&gt;http://@IP:8080/&lt;/code&gt;. Il n’y a plus qu’à le configurer :)&lt;/p&gt;</description></item><item><title>Hack : diminuer la taille du VMDK d’une VM Linux LVM</title><link>https://blog.zwindler.fr/2018/03/14/diminuer-la-taille-du-vmdk-dune-vm-linux/</link><pubDate>Wed, 14 Mar 2018 12:45:43 +0000</pubDate><guid>https://blog.zwindler.fr/2018/03/14/diminuer-la-taille-du-vmdk-dune-vm-linux/</guid><description>&lt;img src="https://blog.zwindler.fr/2015/07/vmware2.webp" alt="Featured image of post Hack : diminuer la taille du VMDK d’une VM Linux LVM" /&gt;&lt;h2 id="réduire-un-vmdk"&gt;Réduire un VMDK
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Note : cet article n’est pas écrit par moi mais par mon ami et ancien collègue Steve aka ventreachoux85 (ahahah faut assumer maintenant Steve), que j’héberge avec grand plaisir sur le blog :-)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Note 2: &lt;strong&gt;Comme toute opération sur des disques, des partitions, des filesystems, elles sont à faire avec des backups préalables. Cette opération est dangereuse et est à vos risques et périls =&amp;gt; vous voilà prévenus.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sur un serveur Linux (CentOS 6.9 pour la petite histoire) hébergé sur un serveur VMware, je souhaite réduire la taille de mon disque virtuel de 75 Go car la volumétrie ne va pas bouger. S’il est simple d’agrandir un disque virtuel sous VMware, le réduire est une autre paire de manches !&lt;/p&gt;
&lt;p&gt;Si la machine avait été un serveur Windows, voilà ce que j’aurai fais :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Réduction du volume depuis l’utilitaire de gestion de disques&lt;/li&gt;
&lt;li&gt;Modification de l’&lt;em&gt;extent description&lt;/em&gt; directement sur le fichier .vmdk depuis l’ESXi (en SSH)&lt;/li&gt;
&lt;li&gt;Migration de la VM sur un autre datastore =&amp;gt; elle aurait eu la taille voulue à l’issue de l’opération&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je ne détaille volontairement pas cette procédure car celle qui suit est similaire et nous allons prendre le temps de tout voir.&lt;/p&gt;
&lt;p&gt;Et donc du coup, là c’était pas pour des windows, mais pour des machines sous Linux ! J’ai demandé son avis à zwindler, qui m’a demandé en échange de rédiger une petite procédure pour le blog ;-)&lt;/p&gt;
&lt;h2 id="réduction-du-fs"&gt;Réduction du FS
&lt;/h2&gt;&lt;p&gt;Voilà donc à quoi ressemble les disques de mon serveur avant l’opération :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Dans mon cas, je n’ai pas besoin de réduire les Filesystems, j’ai déjà beaucoup de PE de disponibles. S’il avait fallut le faire, on aurait été obligé de réduire les FS à froid (dans le cas ext*), voire même de passer par un liveCD si on avait du redimensionner « / » ou un autre FS vital pour l’OS.&lt;/p&gt;
&lt;h2 id="réduire-un-vmdk-partitionné-pour-du-lvm"&gt;Réduire un VMDK partitionné pour du LVM
&lt;/h2&gt;&lt;p&gt;Le problème avec la commande &lt;strong&gt;pvs&lt;/strong&gt; est que la taille utilisée et la taille disponible est arrondie pour être au format « human readable » d’Unix. Idéalement, il nous faut une mesure exacte pour redimensionner au plus juste.&lt;/p&gt;
&lt;p&gt;Une des manières simples de le faire est d’utiliser l’unité « secteur » de la commande &lt;strong&gt;pvs&lt;/strong&gt; (512 octets). Il faut faire la différence entre le PSize et le PFree pour avoir la taille définitive du disque :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-1.avif%22"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Après un rapide calcul, si je veux réduire le disque de tous les PE disponibles :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;209453056 – 164757504 = 44695552&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;La nouvelle taille du PV sera de 44965552 secteurs&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note de zwindler : Personnellement j’aurai laissé quelques PE, par habitude (limitations de LVM1 pénibles quand il n’y a plus de PE) et parce que je suis un froussard, mais a priori « ça marche ».&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On redimensionne le disque&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-2.avif%22"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;del&gt;A noter, malgré le fait qu’on ait spécifié qu’il ne devait pas rester de PE de libre, a priori il en reste quand même quelques uns. Je ne sais pas si c’est une sécurité du pvresize ou si c’est lié aux arrondis et à la taille d’un PE sur ce PV.&lt;/del&gt; C’était une erreur de calcul (cf voir les commentaires).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-3.avif%22"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Pour vérifier que tout va bien, un petit &lt;strong&gt;pvscan/vgscan&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-5.avif%22"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-4.avif%22"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="réduire-la-partition"&gt;Réduire la partition
&lt;/h2&gt;&lt;p&gt;A partir de là, ça se corse. On a réduit sans trop de difficulté le PV qui héberge nos LV, mais il nous reste maintenant à réduire la partition qui héberge ce PV. Même si théoriquement on peut le faire à chaud, &lt;strong&gt;zwindler&lt;/strong&gt; m’a conseillé de faire ça à froid.&lt;/p&gt;
&lt;p&gt;Pour autant, si vous vous sentez l’âme d’un aventurier et/ou avec un OS récent et/ou que vous n’avez pas le choix, vous pouvez toujours aller lire ce post sur &lt;a class="link" href="https://askubuntu.com/questions/24027/how-can-i-resize-an-ext-root-partition-at-runtime" target="_blank" rel="noopener"
&gt;Ask Ubuntu&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Le plus safe est quand même d’arrêter la VM puis booter sur un liveCD avec GParted.&lt;/p&gt;
&lt;p&gt;Clic droit sur la partition à modifier – désactiver (sinon impossible de la redimensionner)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-6.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Sélectionner la partition puis Redimensionner / Déplacer&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-7.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Attention : lors du premier redimensionnement, GParted ne prend ne réduit pas au maximum la partition. &lt;strong&gt;Il reste 2 Go qui sont inutilisés&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-8.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;On lance un nouveau redimensionnement pour récupérer la place disponible !!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note de zwindler : moi j’aurai laissé comme ça ;-)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;ATTENTION&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On voit que &lt;strong&gt;/dev/sda2&lt;/strong&gt; fait 21.44 Go après le &lt;strong&gt;pvresize&lt;/strong&gt; (cf. screenshot précédent). En essayant de réduire au maximum la place utilisée, on peut tout casser (expérience vécue !!!). Pour plus de sécurité, je conseille de resizer à l’entier supérieur (donc dans notre exemple 22 Gio soit 22528 Mio)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-9.avif%22"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-10.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-11.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="redimensionner-le-vmdk"&gt;Redimensionner le VMDK
&lt;/h2&gt;&lt;p&gt;Maintenant que le disque est modifié au niveau de l’OS, il faut le redimensionner au niveau de VMware.&lt;/p&gt;
&lt;p&gt;Et là, rebelote : c’est pas « simple » à faire. En effet, &lt;a class="link" href="https://kb.vmware.com/s/article/1002019" target="_blank" rel="noopener"
&gt;VMware ne supporte pas la réduction des VMDK (que ce soit à chaud ou à froid)&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You cannot shrink virtual disks using &lt;strong&gt;vmkfstools&lt;/strong&gt; in ESXi as the hypervisor is not aware of the file system layout and cannot ensure a safe shrink operation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Heureusement, des petits malins ont trouvés la technique depuis bien longtemps :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Se connecter en SSH sur l’ESX qui héberge la VM, se rendre dans le dossier de la VM et faire un &lt;strong&gt;vi&lt;/strong&gt; sur le fichier &lt;em&gt;NomVM.vmdk&lt;/em&gt;, qui est un fichier texte (configuration), contrairement au fichier &lt;em&gt;NomVM-flat.vmdk&lt;/em&gt; qui contient les données réelles.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modifier la valeur suivante :&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Extent description
RW 209715200 VMFS &amp;#34;testsba-flat.vmdk&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;La nouvelle valeur du paramètre &lt;em&gt;extent description&lt;/em&gt; sera « 22 GB = 22 x 1024 x 1024 x 1024 / 512 (octets/secteur) = 46137344 secteurs »&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Extent description
RW 46137344 VMFS &amp;#34;testsba-flat.vmdk&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="déplacer-la-vm-vers-un-autre-datastore"&gt;Déplacer la VM vers un autre Datastore
&lt;/h2&gt;&lt;p&gt;A partir de là, vous vous dites : « cool ! j’ai récupéré l’espace disque ». Et vous êtes déçus car rien ne se passe.&lt;/p&gt;
&lt;p&gt;En effet, ce paramètre n’est pris en compte que lors de la création du disque, lorsque le fichier contenant réellement les données (le fameux &lt;em&gt;NomVM-flat.vmdk&lt;/em&gt; dont je vous ai parlé plus tôt) est créé. Vous pouvez mettre n’importe quoi, ça ne changera rien du tout.&lt;/p&gt;
&lt;p&gt;Cependant, si vous avez la licence qui va bien sur votre cluster, vous pouvez feinter le cluster pour lui faire recréer un disque à chaud de la bonne taille avec un simple &lt;strong&gt;Storage vMotion&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Avant le Storage vMotion :&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-12.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Après le Storage vMotion :&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-13.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="pourquoi-ça-marche-"&gt;Pourquoi ça marche ?
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Petit aparté de zwindler :&lt;/strong&gt; Pour bien comprendre ce qu’il se passe, il faut comprendre comment marche un Storage vMotion. Au moment où vous demandez à VMware de déplacer un disque d’un datastore à l’autre, voici l’enchaînement des opérations :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prise d’un snapshot du disque initial&lt;/li&gt;
&lt;li&gt;Création d’un disque sur le datastore cible. Ce disque est identique au disque initial au moment du snapshot via la commande &lt;strong&gt;vmkfstools&lt;/strong&gt;. Cette commande relis la valeur contenu dans &lt;em&gt;extent description&lt;/em&gt; pour savoir quelle taille le fichier doit faire physiquement, ce qui nous permet de feinter VMware et d’avoir un disque à la bonne taille._&lt;br&gt;
_&lt;/li&gt;
&lt;li&gt;L’ensemble des IO depuis le snapshot sont écrites simultanément sur les deux datastores, ce qui permet d’avoir 2 copies identiques au moment de la fin de la copie du snapshot&lt;/li&gt;
&lt;li&gt;Migration de la VM  sur le nouveau disque&lt;/li&gt;
&lt;li&gt;Suppression de l’ancien disque hébergé par l’ancien datastore&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note de zwindler :&lt;/strong&gt; j’étais persuadé d’avoir fais un article là dessus (et en fait pas du tout) mais &lt;em&gt;il est évidemment possible de faire la même chose à la main sans Storage vMotion&lt;/em&gt;, simplement avec &lt;strong&gt;vmkfstools&lt;/strong&gt; à la main.&lt;/p&gt;
&lt;h2 id="boot-de-la-machine"&gt;Boot de la machine
&lt;/h2&gt;&lt;p&gt;Pour finir, une fois la VM bootée, il reste encore une petite opération de maintenance à réaliser. Il y a une petite différence de nombre de secteurs suite au redimensionnement.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-14.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Il suffit de faire un &lt;strong&gt;pvresize&lt;/strong&gt; avec le nombre de secteurs indiqué par la commande &lt;strong&gt;pvs&lt;/strong&gt; précédente :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-15.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Tout est dorénavant OK :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/03/word-image-16.avif%22"
loading="lazy"
&gt;&lt;/p&gt;</description></item><item><title>Installer un cluster Kubernetes sur des VMs CentOS 7</title><link>https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/</link><pubDate>Wed, 07 Jun 2017 12:00:53 +0000</pubDate><guid>https://blog.zwindler.fr/2017/06/07/installer-cluster-kubernetes-vm-centos/</guid><description>&lt;img src="https://blog.zwindler.fr/2017/06/kubernetes2.webp" alt="Featured image of post Installer un cluster Kubernetes sur des VMs CentOS 7" /&gt;&lt;h2 id="kubernetes-cest-quoi-ça-"&gt;Kubernetes, c’est quoi ça ?
&lt;/h2&gt;&lt;p&gt;Dans cet article, je vais vous guider pour installer pas à pas un cluster Kubernetes sur des serveurs CentOS/RHEL 7. Attention cet article est un gros morceau !&lt;/p&gt;
&lt;p&gt;Pour ceux qui ne connaissent pas Kubernetes, il faut savoir que c’est un des leaders dans le domaine des orchestrateurs de containers Docker ou Rkt.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/06/kubernetes01.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Un bel empilage de couches, pour au final exécuter des applications dans des containers LXC (ou Windows)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour ce qui est de la genèse de Kubernetes, c’est un outil dont le code provient de Borg d’un outil maison de chez Google. Au bout de 10 ans d’utilisation, quand les containers Linux ont commencés à percer, le code source a été légué en 2015 à la &lt;a class="link" href="https://www.cncf.io/" target="_blank" rel="noopener"
&gt;CNCF (Cloud Native Computing Foundation)&lt;/a&gt;. L’outil est donc maintenant open source.&lt;/p&gt;
&lt;p&gt;Sa couverture fonctionnelle est (pour l’instant) supérieure à celle de &lt;a class="link" href="https://blog.zwindler.fr/2017/01/31/premiers-pas-avec-swarm-fr/" &gt;Docker Swarm&lt;/a&gt;, notamment grâce à :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une gestion de la multitenancy via les namespaces&lt;/li&gt;
&lt;li&gt;une gestion des secrets (bien que limitée)&lt;/li&gt;
&lt;li&gt;une gestion des replicas pour un même container, avec scale-up/down&lt;/li&gt;
&lt;li&gt;une gestion native du loadbalancing&lt;/li&gt;
&lt;li&gt;une gestion des rolling upgrades&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Un article sympa d’Octo &lt;a class="link" href="http://blog.octo.com/docker-en-production-la-bataille-sanglante-des-orchestrateurs-de-conteneurs/" target="_blank" rel="noopener"
&gt;résume pas mal l’écosystème et la guerre qui fait rage dans ce domaine&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="prérequis"&gt;Prérequis
&lt;/h2&gt;&lt;p&gt;Avant de commencer le tutoriel, il faut déjà avoir une bonne connaissance de l’écosystème de la containerisation (sujet sur lequel &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=container" &gt;j’ai écris quelques articles&lt;/a&gt; mais qui est bien plus vaste que ça!).&lt;br&gt;
Il faut savoir que Kubernetes est aussi un outil assez complet mais complexe, avec ses propres concepts et sa terminologie associée. Je vous conseille d’abord de vous familiariser avec ces concepts sur &lt;a class="link" href="https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes" target="_blank" rel="noopener"
&gt;un des tutos de Digital Ocean (ils sont souvent très biens fait)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pour ceux qui sont extrêmement pressés, on peut dire brièvement que, dans la terminologie Kubernetes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un &lt;strong&gt;Node&lt;/strong&gt; est un serveur qui exécute les applications&lt;/li&gt;
&lt;li&gt;le &lt;strong&gt;Kubelet&lt;/strong&gt; est un service (au sens démon) présent sur tous les nodes qui leur permet de discuter et de recevoir les ordres&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Pod&lt;/strong&gt;, généralement décrit comme « la plus petite unité de traitement de Kubernetes ». Il est composé d’un ou plusieurs containers et on le caractérise généralement comme « &lt;strong&gt;une&lt;/strong&gt; application »&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Service&lt;/strong&gt; représente un répartiteur de charge qui est conscient de la présence d’un ensemble de containers (backend) et qui permet de rediriger les flux entrants vers eux&lt;/li&gt;
&lt;li&gt;un &lt;strong&gt;Deployment&lt;/strong&gt; est un ensemble de sous éléments (comme les Pods et les Services, mais aussi d’autres que je ne présentent pas) qui permet de déployer une application avec toutes ses caractéristiques (volumes, secrets) et ses contraintes (nombres de réplicas)&lt;/li&gt;
&lt;li&gt;toutes les interactions avec Kubernetes se font avec une seule commande : &lt;strong&gt;kubeadm&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/06/kubernetes02.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Source : kubernetes.io&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="solutions-de-déploiement"&gt;Solutions de déploiement
&lt;/h2&gt;&lt;p&gt;D’abord, la première chose à dire est qu’il existe de nombreuses manières de déployer Kubernetes qui a donc créé un page dédiée à centraliser &lt;a class="link" href="https://kubernetes.io/docs/setup/" target="_blank" rel="noopener"
&gt;l’ensemble des solutions possibles&lt;/a&gt;. Et elle est longue !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/kubernetes2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ceci n’est qu’une fraction des solutions actuellement proposées sur le site. Ça ne rentre pas sur mon écran 29 pouces&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dans mon cas, je suis parti du plus simple pour moi, avec les ressources que j’ai à disposition, c’est à dire 2 machines virtuelles sous CentOS 7.3 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;controlplane01 : 192.168.100.100&lt;/li&gt;
&lt;li&gt;worker01 : 192.168.100.101&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour autant, les solutions avec Vagrant ou sur des clouds publics sont aussi des solutions valables pour commencer si vous maitrisez ces outils. Je vous laisserai regarder la documentation associée si ça vous intéresse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A noter&lt;/strong&gt;, en fonction de la solutions choisie, il existe aussi des considérations réseaux à avoir, et &lt;a class="link" href="https://kubernetes.io/docs/concepts/cluster-administration/networking/" target="_blank" rel="noopener"
&gt;elles sont documentées ici&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="le-plus-simple--minikube"&gt;Le plus simple : Minikube
&lt;/h2&gt;&lt;p&gt;Je ne vais pas m’attarder sur cette méthode mais celle qui me semble vraiment la plus simple si vous voulez commencer rapidement à jouer avec Kubernetes est d’utiliser &lt;strong&gt;minikube&lt;/strong&gt;. Elle utilise de la virtualisation pour déployer l’environnement Kubernetes de manière automatisée sur votre poste et ça fonctionne très bien.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;minikube start
Starting local Kubernetes cluster...
Running pre-create checks...
Creating machine...
Starting local Kubernetes cluster...
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="la-solution-de-larticle--utiliser-kubeadm"&gt;La solution de l’article : Utiliser Kubeadm
&lt;/h2&gt;&lt;p&gt;On ne va pas se le cacher, installer Kubernetes à la main est complexe. Tellement complexe qu’il existe de nombreuses méthodes clé en main pour automatiser le processus.&lt;/p&gt;
&lt;p&gt;La solution que je vous présente ici est un script qui package l’installation des différents composants de Kubernetes. Ces composants sont en fait containerisés pour faciliter leur déploiement.&lt;/p&gt;
&lt;p&gt;La documentation officielle de cette méthode est disponible à l’adresse &lt;a class="link" href="https://kubernetes.io/docs/getting-started-guides/kubeadm/" target="_blank" rel="noopener"
&gt;suivante&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="configuration-des-dépôts"&gt;Configuration des dépôts
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Sur les deux nœuds&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A noter : Dans le cas où vous ne disposeriez pas d’un serveur DNS en propre, le plus simple est de configurer sur vos deux machines leurs noms complets dans le fichier « hosts ». Cela vous évitera des bugs et effets de bords.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;echo &amp;#34;192.168.100.100 controlplane01.example.org
192.168.100.101 worker01.example.org&amp;#34; &amp;gt;&amp;gt; /etc/hosts
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Configurer les repositories officiels :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://yum.kubernetes.io/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
#yum install -y yum-utils
#yum-config-manager \
# --add-repo \
# https://download.docker.com/linux/centos/docker-ce.repo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;J’ai volontairement commenté l’ajout du dépôt de Docker car à date, la dernière version de Kubernetes n’a pas encore complètement validé les dernières versions de Docker (celles depuis le grand renommage, qui sont sur le modèle YY.MM comme la 17.03). C’est pourquoi j’utilise dans ce tutoriel la version packagée par mon OS, la 1.12.6.&lt;/p&gt;
&lt;h3 id="selinux"&gt;SELinux
&lt;/h3&gt;&lt;p&gt;A l’heure actuelle, SELinux est mal supporté par kubelet, le client de Kubernetes présent sur chaque machine. Il est donc malheureusement nécessaire de désactiver cette sécurité pour pouvoir utiliser Kubernetes, pour l’instant.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Disabling SELinux by running setenforce 0 is required in order to allow containers to access the host filesystem, which is required by pod networks for example. You have to do this until SELinux support is improved in the kubelet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Il se peut aussi que le firewall pose des problèmes s’il est activé et mal configuré&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dans le cadre d’un PoC, on pourra éventuellement se permettre de désactiver le firewall et SELinux si on estime que l’environnement est suffisamment sécurisé. C’est bien entendu hors de question pour tout autre environnement non éphémère !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;setenforce 0
vi /etc/selinux/config
[...]
SELINUX=disabled
systemctl disable firewalld
systemctl stop firewalld
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="installation-des-packages"&gt;Installation des packages
&lt;/h3&gt;&lt;p&gt;Comme dit plus haut, j’installe la version Docker de l’OS et non la dernière version. Dans les versions suivantes, Kubernetes aura probablement rattrapé ce retard (si ce n’est pas déjà le cas). On termine par démarrer Docker puis le démon kubelet.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum install -y docker kubelet kubeadm kubectl kubernetes-cni
#yum install -y docker-ce kubelet kubeadm kubectl kubernetes-cni
systemctl enable docker &amp;amp;&amp;amp; systemctl start docker
systemctl enable kubelet &amp;amp;&amp;amp; systemctl start kubelet
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="initialisation-du-cluster"&gt;Initialisation du cluster
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Maintenant que les prérequis sont installés, on peut démarrer Kubernetes. L’ensemble des commandes de Kubernetes utilise le binaire kubeadm et la première à utiliser est kubeadm init.&lt;/p&gt;
&lt;p&gt;Attention cependant, la commande kubeadm init peut nécessiter des arguments complémentaires en fonction du fournisseur de réseau qui sera choisi.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubeadm init
#ou
kubeadm init --pod-network-cidr 10.244.0.0/16 #Si on utilise flannel
#ou
kubeadm init --pod-network-cidr=192.168.0.0/16 #Si on utilise Calico
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si vous avez un proxy chez vous, n’hésitez pas d’exporter la variable http_proxy et à configurer docker pour l’utiliser (voir &lt;a class="link" href="https://stackoverflow.com/questions/23111631/cannot-download-docker-images-behind-a-proxy" target="_blank" rel="noopener"
&gt;ce thread sur stackoverflow&lt;/a&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;export http_proxy=http://@IP_proxy.zwindler.fr:8080/
export no_proxy=localhost,127.0.0.0,[@IP_control_plane]
mkdir /etc/systemd/system/docker.service.d
cat &amp;gt; /etc/systemd/system/docker.service.d/http-proxy.conf &amp;lt;&amp;lt; EOF
[Service]
Environment=&amp;#34;HTTP_PROXY=http://@IP_proxy.zwindler.fr:8080/&amp;#34;
EOF
systemctl daemon-reload
systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On termine l’initialisation côté serveur controlplane avec les commandes suivantes (indiquées dans le retour donné par le kubeadm init) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A noter, en toute fin de retour, kubeadm nous donne la ligne de commande nécessaire pour ajouter des nœuds supplémentaires au cluster via un token. Copiez et conservez cette partie pour plus tard. NE PAS LE FAIRE MAINTENANT !&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#You can now join any number of machines by running the following on each node
#as root:
# kubeadm join --token &amp;lt;token&amp;gt; &amp;lt;ip_controlplane&amp;gt;:6443
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A partir de là, le cluster va s’initialiser et déployer tous les containers nécessaires. Cela peut prendre un certain temps et certains containers peuvent passer par un état Fail, mais au final tout doit être dans l’état « Running », à l’exception des kube-dns*.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system etcd-controlplane01.example.org 1/1 Running 0 13m
kube-system kube-apiserver-controlplane01.example.org 1/1 Running 0 12m
kube-system kube-controller-manager-controlplane01.example.org 1/1 Running 0 13m
kube-system kube-dns-3913472980-gnt72 0/3 Pending 0 13m
kube-system kube-proxy-4m1nd 1/1 Running 0 13m
kube-system kube-scheduler-controlplane01.example.org 1/1 Running 0 13m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vérifiez la présence du controlplane avec la commande :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get nodes
NAME STATUS AGE VERSION
controlplane01.example.org NotReady 12m v1.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A noter : Le Nœud restera à NotReady tant que les containers « kube-dns- » ne seront pas démarrés. Or, les « kube-dns- » ne démarreront pas tant que la configuration des « Network Pods » n’est pas faite (on va voir ça plus loin), ce qui est donc normal pour l’instant.&lt;/p&gt;
&lt;h3 id="waiting-for-the-control-plane-to-become-ready-qui-ne-rend-jamais-la-main"&gt;« waiting for the control plane to become ready » qui ne rend jamais la main
&lt;/h3&gt;&lt;p&gt;En cas de blocage sur l’étape « &lt;em&gt;[apiclient] Created API client, waiting for the control plane to become ready&lt;/em&gt;« , vérifier les logs dans &lt;strong&gt;/var/log/messages&lt;/strong&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Apr 26 16:27:58 controlplane01 kubelet: error: failed to run Kubelet: failed to create kubelet: misconfiguration: kubelet cgroup driver: &amp;#34;cgroupfs&amp;#34; is different from docker cgroup driver: &amp;#34;systemd&amp;#34;
Apr 26 16:27:58 controlplane01 systemd: kubelet.service: main process exited, code=exited, status=1/FAILURE
Apr 26 16:27:58 controlplane01 systemd: Unit kubelet.service entered failed state.
Apr 26 16:27:58 controlplane01 systemd: kubelet.service failed.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ceci est du à un &lt;a class="link" href="https://github.com/kubernetes/kubernetes/issues/43805" target="_blank" rel="noopener"
&gt;bug de kubeadm sur CentOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il n’y a pas vraiment de solution à partir de là. On ne peut pas utiliser « kubeadm reset » pour désinstaller proprement car cela supprime le fichier &lt;strong&gt;10-kubeadm.conf&lt;/strong&gt;, celui qui doit être corrigé/modifié.&lt;br&gt;
La seule possibilité d’est d’interrompre le processus « kubeadm init », de modifier le 10-kubeadm.conf puis de recommencer.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[CTRL-C]
sed -i &amp;#39;s#Environment=&amp;#34;KUBELET_KUBECONFIG_ARGS=-.*#Environment=&amp;#34;KUBELET_KUBECONFIG_ARGS=--kubeconfig=/etc/kubernetes/kubelet.conf --require-kubeconfig=true --cgroup-driver=systemd&amp;#34;#g&amp;#39; /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
systemctl daemon-reload
systemctl restart kubelet
#Puis relancer
kubeadm init #--pod-network-cidr 10.244.0.0/16
[kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters.
[init] Using Kubernetes version: v1.6.2
[init] Using Authorization mode: RBAC
[preflight] Running pre-flight checks
[preflight] WARNING: docker version is greater than the most recently validated version. Docker version: 17.03.1-ce. Max validated version: 1.12
[preflight] Some fatal errors occurred:
/etc/kubernetes/manifests is not empty
[preflight] If you know what you are doing, you can skip pre-flight checks with `--skip-preflight-checks`
kubeadm init --skip-preflight-checks
#Là, ça devrait fonctionner
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="taint-node"&gt;Taint node
&lt;/h3&gt;&lt;p&gt;Par défaut, Kubernetes n’utilise pas le controlplane pour faire tourner des pods. Si vous voulez changer ce comportement, on peut le faire avec la commande suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl taint nodes --all node-role.kubernetes.io/controlplane-
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="configuration-des-network-pods"&gt;Configuration des Network Pods
&lt;/h2&gt;&lt;p&gt;La première chose à configurer sur le cluster est le « Network Pod ». On a le choix entre un certain nombre de modules, dont la liste est disponible sur &lt;a class="link" href="https://kubernetes.io/docs/concepts/cluster-administration/addons/" target="_blank" rel="noopener"
&gt;cette documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="flannel"&gt;Flannel
&lt;/h3&gt;&lt;p&gt;La configuration la plus couramment utilisée semble être flannel (de CoreOS), donc le fichier de configuration yaml est disponible sur Github&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
serviceaccount &amp;#34;flannel&amp;#34; created
configmap &amp;#34;kube-flannel-cfg&amp;#34; created
daemonset &amp;#34;kube-flannel-ds&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="calico"&gt;Calico
&lt;/h3&gt;&lt;p&gt;On peut aussi essayer &lt;a class="link" href="http://docs.projectcalico.org/v2.1/getting-started/kubernetes/installation/hosted/kubeadm/" target="_blank" rel="noopener"
&gt;Calico&lt;/a&gt;. Personnellement j’ai eu des disfonctionnement avec la version Flannel et donc j’utilise Calico.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl apply -f http://docs.projectcalico.org/v2.4/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml
configmap &amp;#34;calico-config&amp;#34; created
daemonset &amp;#34;calico-etcd&amp;#34; created
service &amp;#34;calico-etcd&amp;#34; created
daemonset &amp;#34;calico-node&amp;#34; created
deployment &amp;#34;calico-policy-controller&amp;#34; created
clusterrolebinding &amp;#34;calico-cni-plugin&amp;#34; created
clusterrole &amp;#34;calico-cni-plugin&amp;#34; created
serviceaccount &amp;#34;calico-cni-plugin&amp;#34; created
clusterrolebinding &amp;#34;calico-policy-controller&amp;#34; created
clusterrole &amp;#34;calico-policy-controller&amp;#34; created
serviceaccount &amp;#34;calico-policy-controller&amp;#34; created
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Les pods pour le réseaux se créent. Vérifiez que tout a bien fonctionné avant d’ajouter des nœuds dans le cluster :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get pods --all-namespaces
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="ajout-de-nœuds-supplémentaires"&gt;Ajout de nœuds supplémentaires
&lt;/h2&gt;&lt;p&gt;A partir de cette étape, le cluster Kubernetes fonctionne réellement, tous les composants sont opérationnels, à ceci près que c’est un cluster avec seulement une machine. On peut donc maintenant intégrer les machines supplémentaires.&lt;/p&gt;
&lt;p&gt;Récupérez la commande avec le token que vous avez conservé précédemment (lors du kubeadm init) et exécutez la sur le nœud « worker ».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sur le worker&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubeadm join --token &amp;lt;token&amp;gt; 192.168.100.100:6443
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si on obtient l’erreur suivante, il faut ajouter 2 lignes dans le fichier « sysctl.conf » et appliquer la modification.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[preflight] Some fatal errors occurred:
/proc/sys/net/bridge/bridge-nf-call-iptables contents are not set to 1
[preflight] If you know what you are doing, you can skip pre-flight checks with `--skip-preflight-checks`
echo &amp;#34;net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1&amp;#34; &amp;gt;&amp;gt; /etc/sysctl.conf
sysctl -p
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Sur le controlplane&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Vérifier la présence du controlplane et de son worker avec la commande kubectl :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl get nodes
NAME STATUS AGE VERSION
worker01.example.org NotReady 1m v1.6.2
controlplane01.example.org Ready 33m v1.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="déployer-la-console-web"&gt;Déployer la console web
&lt;/h2&gt;&lt;p&gt;Bravo, votre cluster Kubernetes fonctionne !&lt;/p&gt;
&lt;p&gt;Un bon moyen de débuter est d’installer la WebUI de Kubernetes. Comme tout le reste sur Kubernetes, elle se déploie simplement avec un fichier YAML. La documentation officielle est &lt;a class="link" href="https://kubernetes.io/docs/tasks/web-ui-dashboard/" target="_blank" rel="noopener"
&gt;disponible à cette adresse&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Add kubernetes-dashboard repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Deploy a Helm Release named &amp;#34;kubernetes-dashboard&amp;#34; using the kubernetes-dashboard chart&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --create-namespace --namespace kubernetes-dashboard
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La console est déployée. Elle est accessible de 2 manières.&lt;/p&gt;
&lt;h3 id="kubectl-proxy"&gt;kubectl proxy
&lt;/h3&gt;&lt;p&gt;Cette sous commande kubectl permet de faire un tunnel entre le poste depuis lequel la commande est lancée et le serveur exécutant les pods. Cette commande est pratique pour tester les connexions à des pods sans avoir à travailler sur le serveur (depuis son poste par exemple).&lt;/p&gt;
&lt;p&gt;Le Dashboard deviendra accessible via l’URL :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;http://localhost:8001/ui&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cependant, dans ce cas là, l’interface ne sera disponible que depuis votre poste, ce qui peut ne pas vous convenir.&lt;/p&gt;
&lt;h3 id="via-le-serveur-controlplane"&gt;Via le serveur controlplane
&lt;/h3&gt;&lt;p&gt;On peut également accéder à la console directement depuis l’URL /ui, qui pointe sur le serveur « controlplane » (controlplane01 dans notre cas).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;https://@ip_controlplane]/ui&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La console demandera un login/mdp que l’on peut retrouver avec kubectl&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;kubectl config view
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="le-mot-de-la-fin"&gt;Le mot de la fin
&lt;/h2&gt;&lt;p&gt;Ça y est, vous savez tout.&lt;/p&gt;
&lt;p&gt;Vous êtes maintenant en mesure de déployer vos premières applications avec Kubernetes, et vous amuser à Scale-up &amp;amp; scale-down, faire des rolling upgrades, tester la haute disponibilité et la répartition de charge !&lt;/p&gt;
&lt;p&gt;Have fun :)&lt;/p&gt;</description></item><item><title>Hacker un calendrier javascript (datepicker) avec un scraper python</title><link>https://blog.zwindler.fr/2017/05/09/hacker-calendrier-datepicker-scraper-python/</link><pubDate>Tue, 09 May 2017 12:00:26 +0000</pubDate><guid>https://blog.zwindler.fr/2017/05/09/hacker-calendrier-datepicker-scraper-python/</guid><description>&lt;img src="https://blog.zwindler.fr/2017/05/maitre-gims-scrape-comme-jamais2.webp" alt="Featured image of post Hacker un calendrier javascript (datepicker) avec un scraper python" /&gt;&lt;h2 id="mais-quel-rapport-entre-un-datepicker-javascript-et-un-scraper-python-"&gt;Mais quel rapport entre un datepicker javascript et un scraper python ?
&lt;/h2&gt;&lt;p&gt;Si vous ne savez ni ce qu’est un &lt;em&gt;datepicker&lt;/em&gt; en Javascript ou un &lt;em&gt;scraper python&lt;/em&gt;, je vous ai probablement déjà perdu. Pourtant, dans cet article ultra fun (ok, je suis bizarre), je vous montrerai comme j’ai automatisé via un scraper développé en python la recherche de dates libres dans un calendrier Javascript sur une page web :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;en scriptant la génération de cette page via une ligne de commande&lt;/li&gt;
&lt;li&gt;en simulant un clic pour passer au mois suivant&lt;/li&gt;
&lt;li&gt;et enfin en récupérant les bonnes valeurs (pour me les envoyer par email par exemple)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="commençons-donc-par-un-peu-de-storytelling"&gt;Commençons donc par un peu de storytelling
&lt;/h2&gt;&lt;p&gt;Depuis quelques mois, je vais régulièrement sur un site web un peu artisanal sur lequel je fais des réservations. Pour se faire, ce site web propose une page web simple dans lequel a été intégré un composant calendrier :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/calendrier1.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Rien de particulièrement extraordinaire jusque là.&lt;/p&gt;
&lt;p&gt;Mais (car bien sûr il y a un mais), ce site à l’inconvénient d’être victime de son succès. Pour vous donner une idée, c’est le genre de site web qui tombe 30 secondes après l’ouverture des réservations à 19h00. Et que dès que l’administrateur système le relance entre 20 et 50 minutes plus tard, les réservations sont complètes en quelques minutes.&lt;/p&gt;
&lt;h2 id="méthode-1--f5"&gt;Méthode 1 : F5
&lt;/h2&gt;&lt;p&gt;La première méthode, probablement plébiscité par la plupart des utilisateurs, est à base de refresh frénétique du site web, jusqu’à ce qu’il devienne inopérant&amp;hellip; Une fois que le site est down, on peut continuer à appuyer sur F5 en espérant être le premier quand il reviendra.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/F5.gif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Le souci de cette méthode, c’est que je manque cruellement de patience et que je lâche l’affaire assez vite. Et donc tous les mois, les plus hargneux (ou les plus chanceux) me passent toujours devant car j’ai loupé le moment où le site redevient accessible.&lt;/p&gt;
&lt;h2 id="méthode-2--curl"&gt;Méthode 2 : cURL
&lt;/h2&gt;&lt;p&gt;En bon administrateur système que je suis, je ne pouvais pas me résoudre à en rester là. Mon problème principal étant d’être prévenu lorsque le site devenait à nouveau opérationnel, j’ai sorti ma boîte à outils habituelle : cURL !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cURL&lt;/strong&gt; (abréviation de &lt;em&gt;client URL request library&lt;/em&gt;), est un outil à tout faire quand on veut jouer avec des URL sur un serveur Linux. C’est simple et efficace.&lt;/p&gt;
&lt;p&gt;Dans le cas où le site est tombé suite à la connexion massive des internautes avides de réservations, j’ai donc créé un petit script basé sur ce &lt;em&gt;oneliner&lt;/em&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;curl http://@IP_ou_FQDN/le_chemin_de_la_page/ -I 2&amp;gt;/dev/null | head -n 1
HTTP/1.1 200 OK
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Dès que le code retour passe de 503 à 200, c’est que le site web est de nouveau accessible et je peux me remettre à faire F5 en espérant que les réservations ouvrent.&lt;/p&gt;
&lt;h2 id="méthode-2bis--aller-plus-loin-avec-curl"&gt;Méthode 2bis : aller plus loin avec cURL
&lt;/h2&gt;&lt;p&gt;Bon&amp;hellip; La méthode précédente fonctionne&amp;hellip; mais ce n’est pas encore ça !&lt;/p&gt;
&lt;p&gt;Typiquement, il arrive que l’ouverture des dates soit reportée au lendemain, quand le site est vraiment trop longtemps dans les choux. Du coup le site répond (et mon test me revoie que le site est opérationnel), mais les dates ne sont pas disponibles pour autant&amp;hellip;&lt;/p&gt;
&lt;p&gt;Un rapide coup d’œil aux sources me donne l’info que je cherche. Il n’y a plus qu’à automatiser ça.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/calendrier2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Mais évidemment ça n’est pas si simple&amp;hellip;&lt;/p&gt;
&lt;p&gt;Firefox interprète le Javascript, mais pas cURL, qui ne sait pas &lt;a class="link" href="http://stackoverflow.com/questions/20554113/how-to-get-webcontent-that-is-loaded-by-javascript-using-curl" target="_blank" rel="noopener"
&gt;interpréter le Javascript (cf ce post de Stack Overflow)&lt;/a&gt;. Le retour de ma commande contient donc le code source HTML avec le Javascript brut, mais pas les données que je recherche&amp;hellip;&lt;/p&gt;
&lt;h2 id="méthode-3--un-scraper-"&gt;Méthode 3 : Un scraper ?
&lt;/h2&gt;&lt;p&gt;Je dois écrire un &lt;em&gt;scraper&lt;/em&gt; qui va aller simuler l’action de l’humain qui va ouvrir la page dans un navigateur. Le post de Stack Overflow cite &lt;a class="link" href="http://phantomjs.org/" target="_blank" rel="noopener"
&gt;PhantomJS&lt;/a&gt; qui est probablement une bonne solution.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PhantomJS is a headless WebKit scriptable with a JavaScript API. It has &lt;strong&gt;fast&lt;/strong&gt; and &lt;strong&gt;native&lt;/strong&gt; support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cependant je ne connais pas bien JS (ça fait longtemps on va dire) et je préfère capitaliser sur Python. J’ai donc cherché un module Python pour régler mon problème, et j’en ai trouvé 2 : un module python &lt;strong&gt;selenium&lt;/strong&gt; et un plus simple appelé &lt;strong&gt;dryscrape&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;J’ai installé dryscrape sur un de mes serveurs (un CentOS 7 minimal, sans environnement graphique). La documentation de dryscrape &lt;a class="link" href="http://dryscrape.readthedocs.io/en/latest/installation.html" target="_blank" rel="noopener"
&gt;est disponible ici&lt;/a&gt; et &lt;a class="link" href="https://dryscrape.readthedocs.io/en/stable/usage.html" target="_blank" rel="noopener"
&gt;ici (stable, documentation plus fournie)&lt;/a&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum install -y qt5-qtwebkit-devel gcc-c++
sed -i &amp;#39;s/PATH=$PATH:$HOME\/bin/PATH=$PATH:$HOME\/bin:\/usr\/lib64\/qt5\/bin/&amp;#39; .bash_profile
source .bash_profile
pip install dryscrape
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et j’ai tout de suite voulu tester un bout de code sans trop chercher à comprendre.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;lt;&amp;lt; EOF &amp;gt; test.py
import dryscrape
session = dryscrape.Session()
session.visit(&amp;#39;http://@IP_ou_FQDN/le_chemin_de_la_page/&amp;#39;)
response = session.body()
print response
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;hellip; je me suis donc pris un bon gros Traceback :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Traceback (most recent call last):
File &amp;#34;test.py&amp;#34;, line 3, in &amp;lt;module&amp;gt;;
session = dryscrape.Session()
[...]raise NoX11Error(&amp;#34;Could not connect to X server. &amp;#34;
webkit_server.NoX11Error: Could not connect to X server. Try calling dryscrape.start_xvfb() before creating a session.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ahhhhh oui&amp;hellip; ça !&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;xvfb_ (necessary only if no other X server is available)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En fait il suffit d’ajouter un test pour exécuter dans xvfb si nécessaire.&lt;/p&gt;
&lt;h3 id="un-premier-exemple"&gt;Un premier exemple
&lt;/h3&gt;&lt;p&gt;Le bout de code suivant ne fait que récupérer le code source de la page et l’afficher à l’écran.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;lt;&amp;lt; EOF &amp;gt; simple_scraper.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import dryscrape
if &amp;#39;linux&amp;#39; in sys.platform:
# start xvfb in case no X is running. Make sure xvfb
# is installed, otherwise this won&amp;#39;t work!
dryscrape.start_xvfb()
session = dryscrape.Session()
session.visit(&amp;#39;http://@IP_ou_FQDN/le_chemin_de_la_page/&amp;#39;)
response = session.body()
print response
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Mais la grosse différence avec le cURL précédent, c’est que dans le cas présent, &lt;strong&gt;ici le Javascript est interprété&lt;/strong&gt;. Cette fois ci dans le code source retourné, je retrouve bien mon calendrier&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/datepicky.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A partir de là, il ne me reste donc en théorie qu’à terminer d’écrire un petit bout de script pour extraire les informations qui m’intéressent et à me notifier quand des places sont libres ! On progresse !&lt;/p&gt;
&lt;h2 id="méthode-3--scraper-comme-jamais"&gt;Méthode 3 : Scraper comme jamais
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/maitre-gims-scrape-comme-jamais2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ce montage pourri d’un clip de Maître Gimms avec des logos dans la main vous est offert par Zwindler&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mais je n’étais pas encore satisfait. Mon but est d’être prévenu lorsque des places sont disponibles. Or, les places s’ouvrent le 1er du mois, &lt;strong&gt;pour le mois suivant&lt;/strong&gt;. En revanche, le composant Javascript datepicker a la mauvaise idée de donner les disponibilités &lt;strong&gt;pour le mois en cours&lt;/strong&gt;. Mon script &lt;strong&gt;simple_scraper.py&lt;/strong&gt; ne récupère donc pas les bonnes dates&amp;hellip;&lt;/p&gt;
&lt;p&gt;Pour contourner le problème, il faut aller encore un peu plus loin dans l’automatisation des actions. Il faut simuler le clic de l’utilisateur sur la flèche vers la droite, qui passe au mois suivant.&lt;/p&gt;
&lt;p&gt;C’est possible avec &lt;strong&gt;dryscrape&lt;/strong&gt;, qui propose notamment une fonction pour sélectionner des nodes XPATH et interagir avec. Pour ceux qui ne connaissent pas XPATH, vous pouvez aller sur la doc de dryscrape qui donne quelques exemples, et aussi sur &lt;a class="link" href="https://www.w3schools.com/xml/xpath_intro.asp" target="_blank" rel="noopener"
&gt;le tutoriel de la W3School&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Comme j’ai examiné le code HTML retourné par le datepicker, je sais quoi chercher :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/datepicker3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Pour changer de mois en cours, dans un premier temps j’ai essayé d’utiliser le label « » » mais le module dryscrape ne supporte pas les caractères non ASCII ! Une solution qui fonctionne est de cliquer sur le lien qui contient &lt;em&gt;javascript:void(0)&lt;/em&gt; contenu dans le div de classe &lt;em&gt;datepick-next&lt;/em&gt; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat &amp;lt;&amp;lt; EOF &amp;gt; datepick_scraper.py
#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
import sys
import dryscrape
if &amp;#39;linux&amp;#39; in sys.platform:
# start xvfb in case no X is running. Make sure xvfb
# is installed, otherwise this won&amp;#39;t work!
dryscrape.start_xvfb()
session = dryscrape.Session()
session.visit(&amp;#39;http://@IP_ou_FQDN/le_chemin_de_la_page/&amp;#39;)
datepicknext = session.at_xpath(&amp;#39;//*[@class=&amp;#34;datepick-next&amp;#34;]/a&amp;#39;)
datepicknext.click()
response = session.body()
print response
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Après vérification, cette version du script renvoie bien le tableau avec les date de Juin (quand on est en Mai) !&lt;/p&gt;
&lt;h2 id="le-mot-de-la-fin"&gt;Le mot de la fin
&lt;/h2&gt;&lt;p&gt;A partir du moment où vous en êtes là, il n’y a plus vraiment de limites à ce que vous êtes capable de faire. Dans mon exemple, j’aurai pu aller encore plus loin, extraire les dates disponibles, et même pourquoi pas aller jusqu’à remplir automatiquement le formulaire pour réserver automatiquement une date prédéfinie (voire même toutes les dates disponibles).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/datepickx.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Ce n’est pas mon but : je vais me contenter de m’envoyer un email dès qu’une date se libère. Mais c’est possible !&lt;/p&gt;
&lt;p&gt;Si vous voulez explorer les possibilité de dryscrape, la documentation officielle donne quelques exemples, et notamment celui de l’envoi d’un email depuis Gmail, entièrement automatisé comme si c’était un humain (!)&lt;/p&gt;
&lt;p&gt;De quoi donner des idées, pour &lt;em&gt;&lt;strong&gt;scraper comme jamais&lt;/strong&gt;&lt;/em&gt; !&lt;/p&gt;</description></item><item><title>Comprendre et configurer SELinux sur RHEL</title><link>https://blog.zwindler.fr/2016/10/26/comprendre-configurer-selinux-rhel-7/</link><pubDate>Wed, 26 Oct 2016 12:00:13 +0000</pubDate><guid>https://blog.zwindler.fr/2016/10/26/comprendre-configurer-selinux-rhel-7/</guid><description>&lt;img src="https://blog.zwindler.fr/2016/10/selinux.webp" alt="Featured image of post Comprendre et configurer SELinux sur RHEL" /&gt;&lt;h2 id="présentation"&gt;Présentation
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Security-Enhanced Linux, abrégé SELinux, est un Linux security module (LSM), qui permet de définir une politique de contrôle d’accès obligatoire aux éléments d’un système issu de Linux.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wikipedia&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Des fois, pas la peine de chercher plus loin : les définitions sont techniques sur Wikipedia sont souvent très bonnes et concises.&lt;/p&gt;
&lt;p&gt;Concrètement, SELinux permet de n’autoriser des processus ou des groupes de processus à ne réaliser &lt;strong&gt;que&lt;/strong&gt; des opérations (écrire dans tel FS, ouvrir un port, etc) qui sont légitimes par rapport à leur utilisation. L’avantage : en cas de vulnérabilité sur tel ou tel processus, l’attaquant sera limité aux fonctionnalités normalement utilisées par le processus en question, lui compliquant la tâche.&lt;/p&gt;
&lt;p&gt;Par défaut, SELinux est activé sur tous les serveurs RHEL mais il est souvent désactivé pour pallier certains effets de bords difficilement décelables (charge CPU très importante, plantages de certaines fonctions d’un logiciels).&lt;/p&gt;
&lt;p&gt;Je me souviens avoir lu un jour un fervent défenseur de ce mécanisme de sécurité le qualifier de logiciel le plus incompris de Linux et je suis assez en phase avec cette analyse, tant il est courant de voir comme premier élément d’une procédure d’installation « Désactivez SELinux », même de la part de grandes multinationales comme IBM&amp;hellip;&lt;/p&gt;
&lt;p&gt;Pour autant, comme toute mesure de sécurité, il n’est évidement pas conseillé de le désactiver, même si cela demande effectivement un peu plus de travail ;-). Et comme tout système, il n’est évidemment pas infaillible non plus donc n’allez pas nécessairement vous croire sortir couvert (plusieurs failles ont été remontées).&lt;/p&gt;
&lt;h2 id="commandes-de-gestion-de-selinux"&gt;Commandes de gestion de SELinux
&lt;/h2&gt;&lt;h3 id="afficher-létat-actuel"&gt;Afficher l’état actuel
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;getenforce
Disabled
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SELinux est complètement désactivé&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;getenforce
Permissive
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SELinux n&amp;rsquo;empêche pas les processus de réaliser des actions non préalablement autorisées mais logue tous les accès non autorisés dans &lt;em&gt;/var/log/messages&lt;/em&gt;. Pour autant, certains effets de bords (comme des surcharges CPU) peuvent quand même apparaitre&amp;hellip;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;getenforce
Enforcing
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SELinux est activé. Toutes les actions non préalablement autorisées sont bloquées par sécurité et logué dans &lt;em&gt;/var/log/audit/audit.log&lt;/em&gt; et &lt;em&gt;/var/log/messages&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="ajout-dautorisations-selinux"&gt;Ajout d’autorisations SELinux
&lt;/h3&gt;&lt;p&gt;Par défaut lorsque SELinux est réglé sur &lt;em&gt;Permissive&lt;/em&gt; ou &lt;em&gt;Enforcing&lt;/em&gt;, chaque action non autorisée génère une remontée dans &lt;em&gt;/var/log/messages&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Exemple de message dans &lt;em&gt;messages&lt;/em&gt; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Oct 16 03:43:38 tstbench01 setroubleshoot: SELinux is preventing /usr/bin/bash from getattr access on the file /usr/bin/sudo. For complete SELinux messages. run sealert -l 9a71f3f1-e624-470a-99ae-af04934769e3
Oct 16 03:43:38 tstbench01 python: SELinux is preventing /usr/bin/bash from getattr access on the file /usr/bin/sudo.
***** Plugin catchall (100. confidence) suggests **************************
If you believe that bash should be allowed getattr access on the sudo file by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# grep sh /var/log/audit/audit.log | audit2allow -M mypol
# semodule -i mypol.pp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SELinux a beaucoup évolué et est maintenant relativement simple a administrer. L’ensemble des erreurs provoquées par les modes &lt;em&gt;Enforcing&lt;/em&gt; et &lt;em&gt;Permissive&lt;/em&gt; sont logués dans &lt;em&gt;/var/log/messages&lt;/em&gt; et indiquent la marche à suivre pour corriger le problème.&lt;/p&gt;
&lt;h4 id="exemple-de-résolution-pour-des-plugins-nagios-exécutés-via-nrpe"&gt;Exemple de résolution pour des plugins Nagios exécutés via NRPE
&lt;/h4&gt;&lt;p&gt;Le check &lt;strong&gt;check_cpu_stats&lt;/strong&gt; ne fonctionne pas correctement à cause de SELinux et provoque de fausse alertes sur l’utilisation du CPU. On peut créer un fichier de définitions et le réutiliser pour d’autres serveurs.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;grep check_cpu_stats /var/log/audit/audit.log | audit2allow -M nrpe
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nrpe.pp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La commande &lt;strong&gt;audit2allow&lt;/strong&gt; parse le log &lt;strong&gt;audit.log&lt;/strong&gt; puis consolide les autorisations à ajouter dans un fichier de définitions. On peut directement corriger le problème simplement en exécutant la commande suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;semodule -i nrpe.pp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Si on souhaite savoir quelles autorisations ont été ajoutés, il est possible de consulter les règles en ouvrant le fichier nrpe.te et éventuellement y réaliser des modifications si nécessaire.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat nrpe.te
module nrpe 1.0;
require {
type nrpe_t;
type tmp_t;
type var_lib_t;
class dir { write remove_name add_name };
class file { execute read create getattr execute_no_trans write ioctl unlink open };
}
#============= nrpe_t ==============
allow nrpe_t tmp_t:dir { write remove_name add_name };
allow nrpe_t tmp_t:file { write create unlink open };
allow nrpe_t var_lib_t:file { ioctl execute read open getattr execute_no_trans };
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ici, on voit que le plugin souhaite effectuer des opérations sur /var/lib et /tmp.&lt;/p&gt;
&lt;p&gt;Ce fichier « .te » modifié ne peut pas être directement appliqué sur le serveur. Il devra être compilé avant de pouvoir être appliqué sur les serveurs.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;checkmodule -M -m -o nrpe.mod nrpe.te
semodule_package -o nrpe.pp -m nrpe.mod
semodule -i nrpe.pp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une fois compilé et installé sur le serveur, le fichier « .pp » se retrouve dans un dossier spécifique de SELinux.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;updatedb
locate nrpe
/etc/selinux/targeted/modules/active/modules/nrpe.pp
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On peut ensuite propager ce fichier de définition de sécurité sur tous les serveurs concernés.&lt;/p&gt;
&lt;h3 id="modification-manuelle-de-la-politique-de-sécurité"&gt;Modification manuelle de la politique de sécurité
&lt;/h3&gt;&lt;p&gt;ATTENTION : la commande &lt;strong&gt;setenforce&lt;/strong&gt; ne survie pas au reboot.&lt;/p&gt;
&lt;p&gt;Passer de &lt;em&gt;Enforcing&lt;/em&gt; à &lt;em&gt;Permissive&lt;/em&gt; (pas possible de passer directement à &lt;em&gt;Disabled&lt;/em&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;setenforce 0
getenforce
Permissive
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Passer à &lt;em&gt;Enforcing&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;setenforce 1
getenforce
Enforcing
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Pour faire des modifications permanentes, il est nécessaire de modifier le fichier &lt;strong&gt;/etc/selinux/config&lt;/strong&gt;. La valeur a modifier est &lt;strong&gt;SELINUX=&lt;/strong&gt; avec comme choix &lt;em&gt;enforcing&lt;/em&gt;, &lt;em&gt;permissive&lt;/em&gt; ou &lt;em&gt;disabled.&lt;/em&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinu security policy is enforced.
# permissive - SELinu prints warnings instead of enforcing.
# disabled - No SELinu policy is loaded.
SELINUX=permissive
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;ATTENTION : une erreur dans ce fichier (même une simple faute de frappe) aura pour effet de bloquer la machine au boot. Il faudra passer en mode maintenance ou rescue pour éditer et corriger le fichier. Prudence donc !&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RAPPEL : Comme tout mécanisme de sécurité, il est évidemment fortement déconseillé de désactiver SELinux de façon permanente !&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="désactivation-automatisée"&gt;Désactivation automatisée
&lt;/h3&gt;&lt;p&gt;Pour ceux qui utilisent Ansible, sachez qu’il existe également un module officiel permettant de activer/désactiver SELinux.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat no_selinux.yml
---
# Playbook pour couper SE Linux
- name: &amp;#34;No SE Linux&amp;#34;
hosts: all
remote_user: root
tasks:
- selinux: state=disabled
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="sources"&gt;Sources
&lt;/h2&gt;&lt;p&gt;Un article détaillant de manière plus complète SELinux est disponible sur &lt;a class="link" href="https://wiki.centos.org/HowTos/SELinux" target="_blank" rel="noopener"
&gt;les HowTos de CentOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Et aussi :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.microlinux.fr/selinux" target="_blank" rel="noopener"
&gt;SELinux expliqué aux administrateurs frileux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Le guide de déploiement de CentOS (lien mort, pas dispo sur Internet Archive)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://web.archive.org/web/20220823151858/http://selinux.gave.me.this.remoteshell.org/" target="_blank" rel="noopener"
&gt;Les limites de la sécurité apportée par SELinux (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Bug : unable to execute QEMU command &amp;lsquo;cont’ sous KVM et RHEL/CentOS</title><link>https://blog.zwindler.fr/2015/10/10/bug-unable-to-execute-qemu-command-cont-sous-kvm-et-rhelcentos/</link><pubDate>Sat, 10 Oct 2015 10:30:00 +0000</pubDate><guid>https://blog.zwindler.fr/2015/10/10/bug-unable-to-execute-qemu-command-cont-sous-kvm-et-rhelcentos/</guid><description>&lt;img src="https://blog.zwindler.fr/2015/10/kvm.webp" alt="Featured image of post Bug : unable to execute QEMU command &amp;lsquo;cont’ sous KVM et RHEL/CentOS" /&gt;&lt;p&gt;Cet article est encore un vieil article que je n’ai jamais pris le temps de sortir. Voilà maintenant c’est fait ;-)&lt;/p&gt;
&lt;h2 id="bug-unable-to-execute-qemu-command-cont"&gt;Bug unable to execute QEMU command ‘cont’
&lt;/h2&gt;&lt;p&gt;Aussi rare que cela soit, après ma migration de KVM sur Ubuntu a KVM sur CentOS, je suis tombé sur un bug du Kernel Linux qui affectait directement ma capacité à faire fonctionner des machines virtuelles sous Windows 7 ou Windows 2008 ! Mais toutes les autres fonctionnaient normalement.&lt;/p&gt;
&lt;h3 id="symptôme"&gt;Symptôme
&lt;/h3&gt;&lt;p&gt;Lorsqu’on démarre la VM ou qu’elle démarre seule au boot, elle se met en pause. Si on essaye de la sortir du mode pause on reçoit l’erreur suivante.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Error unpausing domain: internal error unable to execute QEMU command ‘cont’: Resetting the Virtual Machine is required&amp;lt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;L’erreur en elle même n’est pas très explicite. Dans le log de la machine virtuelle en question, on a un message plus long mais guère plus évocateur :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/var/log/libvirt/qemu/[maVM]
kvm: unhandled exit 80000021
kvm_run returned -22
If you’re running a guest on an Intel machine without unrestricted mode
support, the failure can be most likely due to the guest entering an invalid
state for Intel VT. For example, the guest maybe running in big real mode
which is not supported on less recent Intel processors.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bien évidemment, toutes les autres VMs sous Linux fonctionnent parfaitement donc on ne peut pas accuser Qemu de ne pas fonctionner correctement.&lt;/p&gt;
&lt;h3 id="solution"&gt;Solution
&lt;/h3&gt;&lt;p&gt;En théorie, j’ai lu à plusieurs endroits que le bug était censé être corrigés sur des patchs des kernels de CentOS 5 ou 6 (toujours présent en 2.6.32-431.3.1.el6.x86_64 par exemple) et même pour Ubuntu.&lt;br&gt;
Dans la pratique, même en mettant l’OS CentOS à jour, impossible de faire fonctionner cette VM.&lt;br&gt;
La seule vrai solution que j’avais trouvé à l’époque était de forcer le passage à un kernel plus récent, à savoir au moins 3.+.&lt;/p&gt;
&lt;p&gt;Pour ceux qui se sentiraient un peu perdu, le plus simple est de changer de version de CentOS ou d’Ubuntu. Sur les dernière version le bug n’est plus présent.&lt;/p&gt;
&lt;p&gt;Cependant, si vous avez un système en place et qu’une migration n’est pas à l’ordre du jour, voici la marche à suivre pour installer un kernel plus récent. Voici la procédure que j’ai utilisée pour installer un 3.13 sur lequel la VM fonctionne à nouveau (3.11 fonctionne aussi, je ne sais pas avant).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum install gcc ncurses ncurses-devel
yum update
wget https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.13.1.tar.gz
tar xzf linux-3.13.1.tar.gz -C /usr/src/
cd /usr/src/linux-3.13.1/
make menuconfig
make
make modules_install install
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;N’oubliez pas de vérifier que votre kernel est bien choisi en premier dans le boot loader, ce qui n’est souvent pas le cas par défaut (modifier la valeur &lt;strong&gt;default&lt;/strong&gt; dans le &lt;strong&gt;grub.conf&lt;/strong&gt; pour correspondre à la bonne entrée) sinon le problème ne sera pas résolu au reboot.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /etc/grub.conf
default=X
[...]
root (hd0,0)
kernel /vmlinuz-3.13.1 ro root=/dev/mapper/vg_root-lv_root rd_LVM_LV=vg_root/lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_MD_UUID=8f43b4fe:e72ed9aa:2da568b5:5f43b223 SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=fr-latin9 rd_LVM_LV=vg_endeavour/lv_swap rd_NO_DM rhgb quiet
initrd /initramfs-3.13.1.img
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et vous pouvez vérifier que vous êtes sur le bon kernel avec un uname.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;reboot
uname -r
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="erreurbug-error-starting-virt-manager"&gt;Erreur/bug Error starting virt-manager
&lt;/h2&gt;&lt;p&gt;En bonus track, je voudrais aussi ajouter un petit bug de plus pour la route, sur l’utilisation de l’interface graphique virt-manager cette fois ci.&lt;/p&gt;
&lt;p&gt;Pour une raison obscure, lorsque je voulais lancer ma GUI virt-manager, il m’est arrivé une ou deux fois de suivre la procédure décrite sur &lt;a class="link" href="http://nutanix.blogspot.fr/2013/06/kvm-virt-manager-startup-failure.html" target="_blank" rel="noopener"
&gt;le blog de nutanix&lt;/a&gt; lorsque je recevais l’erreur suivante :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Error starting virt-manager&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;dbus-uuidgen --get
cat /var/lib/dbus/machine-id
dbus-uuidgen &amp;gt; /var/lib/dbus/machine-id
&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>