Je ne suis pas d'Helm (je trouve que c'est rajouter une couche de complexité inutile à la complexité inutile de K8s). Heureusement, on peut tester les descripteurs qu'on génère grâce à ce plugin. Et en plus il semble exister une convention permettant d'avoir de la validation dans le YAML avec VSCode.
Un outil qui vous permet facilement d'attendre qu'un port ou qu'une autre ressource soit dans un état donné. Ca paraît une très bonne idée pour démarrer correctement des services qui ont "des dépendances fortes"
Autre petit déterrage de brouillon. Je sais, quand on bosse sur en tant que Sysadmin, c’est pas spécialement le premier format de données auquel on pense. Mais quand on commence à bosser sur un cluster avec des dizaines de sites web déployés, plus des utilitaires/opérateurs autour, extraire les infos devient un léger sport, pire, quand il faut partager l’info à des gens moins techniques, c’est compliqué. Et donc, le format CSV peut aider, je vous explique.
Quand j’étais encore chez LinkByNet/Accenture, un des clusters Kube que j’avais à gérer était mutualisé entre plusieurs entités d’un client (appelés maisons), les applications étaient identifiées clairement comme telles via un label, mais on a découvert que cet élément d’inventaire, qui permettait la refacturation de la consommation dans le cluster à chaque maison (je vous passe le reste des détails), n’était pas toujours positionné correctement. Avant d’effectuer des corrections il est donc nécessaire de récupérer les informations existantes.
La configuration du label « maison » est splittée dans autant de dépôts git qu’on a de sites déployés, donc on s’évite le truc, et on part du principe qu’on peut récupérer l’information dans le cluster directement. Et pour traiter le résultat, surtout le partager au client, vu le format que ça risque de prendre (un tableau), on pense partager un tableau Excel pour ensuite se voir retourner la version corrigée.
Si vous manipulez régulièrement Kubernetes, vous savez que Excel, et même CSV, ne sont pas des formats supportés pour récupérer les informations, on a que JSON et YAML (en tout cas pour avoir les détails des déploiements/statefulsets/daemonsets, comme les labels), et éventuellement jsonPath pour pré-filtrer les infos. Ceci dit, à partir de JSON il y a potentiellement de quoi faire, en particulier avec jq. J’aime bien jq, même si je rote du sang à chaque fois que j’essaie de l’utiliser. Quelques recherches plus tard, mes intuitions étaient correctes et il s’avère que jq permet de formater les donner en CSV. Mais au fait, c’est quoi le CSV ?
Petit retour sur un format texte simple et pourtant si pratique
CSV ça veut dire Comma Separated Values, soit valeurs séparées par des virgules. Oui, c’est aussi simple que ça en a l’air, dans un fichier texte, la première ligne peut désigner éventuellement les titres des colonnes, et les lignes suivantes les valeurs. Un exemple ?
Vous voyez, c’est assez Simple. Et en vrai on pourrait aussi procéder de la même façon avec la première colonne de description et les suivantes de données, voire les deux. Vous avez remarqué la troisième ligne ? Pour indiquer qu’on ne « remplit » pas la colonne correspondant ici à Profession, on laisse juste un vide avec deux virgules successives. Comme je l’ai dit, simple, efficace.
Reste à savoir comment on obtient ça à partir du JSON que nous retourne kubectl.
Dans le dur
Bien, comme je l’ai dit, jq va nous servir très fort, parce qu’il a justement une fonction dédiée au formatage de données en CSV. Commençons déjà par récupérer ce dont on a besoin. On cherche donc les infos des Deployments, StatefulSets, DaemonSets de tous les namespaces. Sur le papier, j’aurais pu utiliser jsonPath comme sortie pour récupérer les champs que je voulais, mais j’ai noté de déjà passer par jq pour filtrer tout ça et ne garder que ce qui m’intéresse, à savoir le type (Kind), le Namespace, le nodeselector (oui, on a eu une histoire de nodepool à gérer aussi), et le fameux label « maison ». Avec jq j’y suis arrivé plus simplement alors qu’avec jsonPath j’ai toujours buté sur un des points (mais là j’avoue, entre le premier brouillon y’a trois ans et maintenant, j’ai oublié lequel). Bref, tout ça finit dans un fichier json, ça donne quelque chose comme ça :
Pas super simple à lire, mais pas non plus super compliqué à comprendre. Maintenant vient la partie qui permet de structurer notre futur fichier CSV. On commence par les entêtes. Actuellement on a ça dans le fichier json:
La première action va donc être d’extraire les clés. La petite triche ici c’est qu’on est certain qu’on peut se reposer sur la première « ligne » du tableau JSON parce qu’on a exactement les mêmes champs dans toutes les entrées. Et petite subtilité par contre, comme il s’agit des clés, on doit forcer jq à ne pas les trier par ordre alphabétique sinon ça fout la grouille :
Le [0], c’est pour forcer à se baser sur la première ligne uniquement (sinon il sortirait les clés de toutes les lignes et on aurait autant de lignes avec les noms des champs qu’on a d’entrées dans le tableau JSON)
keys_unsorted, comme je l’ai dit, permet de ne pas trier alphabétiquement
le @csv est la fonction magique qui formate le résultat pour nos besoins.
le chevron simple permet de s’assurer que c’est la première ligne du fichier, puisque comme ça tout contenu éventuellement existant est directement supprimé pour être remplacé par notre unique ligne.
C’est pas si compliqué hein ? Reste ensuite à extraire les valeurs, pour toutes les lignes cette fois. La logique reste grosso modo la même, à part que là, et j’ignore pourquoi, pas besoin de forcer à ne pas trier les valeurs, elles restent dans le bon ordre :
À la place de [0] on met [] pour indiquer « toutes les entrées », on mappe les valeurs sinon le filtre csv râle, et on met un double chevron pour mettre le résultat à la suite du contenu existant du fichier.
Et voilà, on peut désormais importer ce CSV dans un tableur pour le présenter de manière intelligible, avec des jolies colonnes qu’on peut filtrer/trier/annoter/corriger, à des gens qui n’ont pas l’habitude de bosser avec du JSON. Au final on aura eu quand même une petite dizaine de sites à corriger, on a donc pu se permettre de le faire manuellement. Sur un plus gros volume, on serait certainement passé par du scripting Python pour modifier les fichiers de values directement dans tous les dépôts Gitlab concernés, en laissant ensuite faire la magie du déploiement continu
Après un retour plutôt positif à ma question de proposer des versions textes de certains sujets abordés pendant certains lives Twitch, on va commencer dans l’ordre avec le plus ancien. Fruit de ma tentative de sauvetage d’un naufrage total du live sur GoDNS, je vous propose donc une solution qui ne nécessite aucun soft dédié (si on met de côté Kubernetes évidemment), et sans avoir besoin de créer une image custom !
C’était mon deuxième live sur YouTube, avant que je ne craque et parte sur Twitch. Je vous remets le lien parce qu’il est moins facile à trouver que les autres, l’ergonomie concernant les lives sur YouTube étant… particulière.
Alors, comme d’hab’, commençons par revenir sur les fondamentaux rapidement, à savoir le DynHost. C’est le nom maison d’OVH pour faire du DNS dynamique. Mais qu’est-ce donc ? Un DNS Dynamique, c’est un dispositif pour mettre fréquemment à jour un enregistrement DNS, notamment un enregistrement A pour une adresse IPv4 qui change fréquemment. Et quand on héberge des trucs chez soi et que votre fournisseur d’accès à Internet ne vous fournit pas d’adresse IPv4 fixe (parce que c’est devenu super rare et super cher), c’est super pratique. Certains connaissent peut-être No-IP, DynDNS, certains fournisseurs étant même directement intégrés dans certains routeurs voire certaines box opérateur.
Bref, c’est donc ce que propose OVH avec son service DynHost. Je vais pas rentrer dans un million de détails, j’ai fait un rôle Ansible à une époque pour gérer le truc avec un service qui s’appelle ddclient, je vous remets l’article que j’avais écrit il y a 4 ans pour comprendre ce qu’il fait, il y a dedans les liens vers les documentations d’OVH sur le sujet.
Le problème pendant le live
En très très gros résumé, je voulais remplacer le ddclient de la VM par un pod Kubernetes (pour l’exercice), mais il y a eu deux gros pépins :
je voulais utiliser goDNS, mais la doc m’a indiqué qu’OVH n’était pas supporté (sérieux !?)
je n’ai jamais réussi à faire fonctionner ddclient plus d’une fois après le démarrage dans mon pod Kubernetes, sans que je sache vraiment pourquoi
Bref, j’ai fini par avoir une idée à la con, mon cerveau fonctionnant toujours malgré les minutes et le stress du live passant : revenir à l’appel de base de l’URL de la doc d’OVH, et utiliser un autre objet Kubernetes de manière originale.
Cronjob et Nixery ?
Un Cronjob Kubernetes permet d’exécuter une tache finie dans le temps à intervalles plus ou moins régulier, à la manière d’une tâche cron sur un serveur classique. Lancer une requête Web avec Curl semble donc très facile à faire avec un cronjob, ce qui veut dire qu’on a pas besoin d’une image de furieux pour le faire fonctionner. Le curl se résume à ça :
Donc on a au final deux curl imbriqués l’un dans l’autre, car il faut bien commencer par déterminer sa propre adresse IP, et des services comme ifconfig.co et ifconfig.me sont très bons pour ça. Et comme on gère une IPv4, on force de faire l’appel en v4 pour s’éviter des problèmes. Et donc le résultat de ce premier appel est utilisé directement pour envoyer la mise à jour chez OVH.
Bref, on a notre « job », on sait comment le planifier, reste l’environnement pour l’exécuter. Et je me rends compte que je n’ai jamais parlé de Nixery ici. J’ai découvert le service grâce à l’incontournable Jérôme Petazzoni. Nixery est un service de fourniture d’images « Docker » (on devrait désormais parler d’images OCI parce qu’il n’y a pas que docker dans la vie), qui ont la particularité de ne pas être statiques, au sens où on l’entend habituellement. Comme vous le savez, les images OCI sont construites sur un modèle de « couches » où une couche contient les modifications par rapport à la couche précédente. La magie de Nixery est de construire une image « à la volée » à partir de couches correspondants aux outils dont on a besoin dans l’image. Dans mon cas, si je demande nixery.dev/arm64/shell/curl, il va me construire une image contenant un busybox et curl, pour une architecture ARM 64bit, mes Raspberry Pi donc. Et c’est tout. Le seul inconvénient, c’est qu’il va mettre un poil plus de temps à répondre pour nous fournir le manifeste. Mais c’est super cool du coup de pas avoir à faire ses images soi-même
On a donc tous les ingrédients. Si on veut faire les choses en quick&dirty, on peut le faire dans un seul fichier que l’on pourrait résumer rapidement comme tel:
Comme c’est un peu cracra de foutre les credentials dans le fichier, pendant le live et par la suite, j’ai peaufiné un chart Helm que j’ai enregistré sur mon Gitea, qui fait un miroir sur GitHub donc je vous partage évidemment le lien. Si d’aventure le README n’est pas suffisamment clair, faites moi signe.
Est-ce qu’on peut faire mieux ?
Probablement, mais déjà pour un quick & dirty réalisé sous stress sans plus de préparation, je suis pas peu fier de moi et depuis les pratiquement deux ans que j’ai mis ça en place, ça fonctionne toujours du feu de dieu. Il manque quand même une bonne partie du setup du DynHost qui se fait majoritairement à la main, mais après tout, ce n’est pas un système qu’on est censé industrialiser en permanence.
Et idéalement tout le monde passe à IPv6 et on peut laisser tomber IPv4. Mais ça, vu que même Github le supporte pas encore, on est pas rendus…
Bon, maintenant, quel autre sujet d’ancien live mériterait un article écrit en complément ?