Vue normale

Reçu avant avant-hierLe blog de Seboss666

Gérer son DynHost OVH grâce à Kubernetes et Nixery

15 janvier 2025 à 18:19

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 :

#
curl -s -u $CREDENTIALS "https://www.ovh.com/nic/update?system=dyndns&hostname=$DOMAIN&myip=$(curl -s -4 ifconfig.me/ip)"
#

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:

---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: dynhost-ovh-cron
  labels:
    app.kubernetes.io/name: dynhost-ovh-cron
spec:
  schedule: "*/5 * * * *"
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app.kubernetes.io/name: dynhost-ovh-cron
        spec:
          containers:
          - name: dynhost
            image: "nixery.dev/arm64/shell/curl:latest"
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - curl -s -u $CREDENTIALS "https://www.ovh.com/nic/update?system=dyndns&hostname=$DOMAIN&myip=$(curl -s -4 ifconfig.me/ip)"
            env:
            - name: CREDENTIALS
              value: <BasicAuth>
            - name: DOMAIN
              value: <Dynhost.Domain.tld>
          restartPolicy: OnFailure

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 ?

Utiliser Varnish pour injecter du contenu sans toucher au backend

18 décembre 2024 à 17:37

Varnish, en voilà une techno qu’on ne voit pas tous les jours sur les plateformes modernes d’hébergement, et pourtant, ça se déploie même dans Kubernetes 😛 Et si je vous dis que j’ai eu à gérer un cas de fourniture de contenu dans un contexte plus que particulier, avec du Varnish en frontal, et que je ne pouvais pas passer par le serveur web ? Allez, je vous explique.

Varnish, un logiciel méconnu, mais très puissant

Varnish est un serveur « cache », qui fonctionne comme un « proxy » entre votre site web et ses visiteurs. Son rôle est de garder en mémoire temporairement le résultat de la construction des pages de votre site. En effet, quand vous visitez un site comme le mien par exemple, le moteur WordPress, qui doit être chargé en premier lieu, doit construire l’intégralité du code HTML de la page, avec les références aux feuilles de style, aux scripts JavaScript des différents plugins, et le contenu de la page en question, ce qui implique des appels à la base de données. Bref, un paquet d’activités à rejouer pour chaque visiteur, chaque page visitée. Si le contenu d’une page n’a pas à bouger pendant un certain temps, on peut se dire que générer une fois la page, et servir le résultat X fois pendant ledit certain temps, est un gain de ressources et donc de performances non négligeable. C’est un des points forts des CDN, allié à l’aspect géographique de ce type de service.

Varnish est reconnu pour son empreinte minimaliste, et ses performances redoutables. Il est aussi connu pour la mentalité des développeurs du projet concernant la sécurité (ils se sont réjoui le jour où ils ont ouvert une section « security advisory », après 10 ans d’existence). Il est aussi devenu un peu pénible à utiliser depuis que le HTTPS s’est généralisé, parce que les développeurs ont pris le parti de ne pas l’implémenter, ce qui a réduit un peu son intérêt. L’usage des CDNs étant une autre raison du désamour croissant.

Le contexte particulier qui nous intéresse

Particulier, c’est bien le mot : le site sur lequel je dois intervenir est déployé avec Docker, un container avec Varnish en frontal, un container avec Apache/PHP derrière. Mais j’ai plusieurs problèmes avec cette plateforme. Les containers sont déployés avec docker-compose, mais je n’ai pas accès au fichier, tout est construit et déployé avec un pipeline Jenkins, jusque là rien que de très commun me direz-vous. Sauf que le serveur Jenkins n’existe plus non plus, je n’ai accès à aucune source ni aucun support de l’agence web d’origine (plus de contrat). Le bonheur de tout sysadmin.

On me demande de mettre à jour le « merchant ID » d’Apple pour le site web (un identifiant qui sert pour Apple Pay), et ça passe par un fichier spécial qui doit être joignable avec une URI de la forme /.well-known/apple-developer-merchantid-domain-association. Pas de bol, le container avec le site web est en lecture seule (comprendre, l’utilisateur du container n’est pas le propriétaire du « DocumentRoot », le dossier qui contient le site web). Mais, le Varnish 5 présent en front, lui, il l’est, d’autant plus qu’on a accès à son compte root !

On est donc tout équipé pour tenter une greffe à chaud sans anesthésie.

Opération à cœur ouvert

J’identifie le fichier « VCL » qui contient la configuration relative au site, et j’attaque la première tentative. On rajoute un test dans la section vcl_recv{} :

sub vcl_recv {
if (req.url ~ "^/.well-known/apple-developer-merchantid-domain-association") {
return (synth(200,"7C227073704964223B2236304337424..."));
}

return (synth(() est la méthode à utiliser si on veut renvoyer du contenu qui ne vient pas du backend. Il faut par contre définir quelques propriétés dans la section vcl_synth{} pour qu’il ne renvoie pas du HTML par défaut mais du texte brut :

sub vcl_synth {
set resp.http.Content-Type = "text/plain; charset=utf-8";
set resp.body = resp.reason;
return(deliver);
}

Vient ensuite l’injection à chaud de la configuration. C’est un truc que j’aime bien avec Varnish, on peut lui demander de charger plusieurs configurations en parallèle et basculer entres celles-ci en fonction des besoins. En gros, voilà ce que je fais :

bash-5.0# varnishadm
200
-----------------------------
Varnish Cache CLI 1.0
-----------------------------
Linux,3.10.0-1160.83.1.el7.x86_64,x86_64,-junix,-smalloc,-sdefault,-hcritbit
varnish-6.2.1 revision 9f8588e4ab785244e06c3446fe09bf9db5dd8753

Type 'help' for command list.
Type 'quit' to close CLI session.

varnish> vcl.list
200
active warm warm 2 boot

varnish> vcl.load apple /var/varnish-docker/dockerized.apple.vcl
200
VCL compiled.

varnish> vcl.list
200
active warm warm 2 boot
available auto warm 0 apple

varnish> vcl.use apple
200
VCL 'apple' now active
varnish> quit
500
Closing CLI connection
bash-5.0# curl -s http://127.0.0.1:6081/.well-known/apple-developer-merchantid-domain-association
7C227073704964223B2236304337424(...)

Le détail du fonctionnement des commandes Varnish se trouve dans la documentation.

Hourra ! Enfin presque, parce qu’après avoir informé le client, ce dernier me dit que c’est toujours pas bon. Et là, le gaillard qui travaille sur l’intégration Apple Pay m’indique qu’il y a un souci avec le checksum (première fois que c’est mentionné dans nos échanges). La documentation que l’on ne m’avait évidemment pas fourni indiquait bien de livrer le fichier et de ne pas copier son contenu. Je vous le donne en mille, il manque un retour à la ligne à la fin.

J’ai donc bossé sur une alternative. La doc de Varnish me renvoie vers un std.fileread(). Je copie donc le fichier dans le même répertoire que le VCL, et j’en profite pour faire une syntaxe un poil plus propre au niveau de ce dernier, la voici.

sub vcl_recv {
    if (req.url ~ "^/.well-known/apple-developer-merchantid-domain-association") {
        return (synth(200,"apple"));
    }
(...)
}

sub vcl_synth {
(...)
if (resp.reason == "apple") {
    set resp.http.Content-Type = "text/plain; charset=utf-8";
    set resp.body = std.fileread("/var/varnish-docker/apple-developer-merchantid-domain-association");
    return(deliver);
  }
}

Et là, j’ai bien le bon checksum (franchement, pour un retour à la ligne…). À noter qu’il faut bien faire attention aux permissions du fichier qu’il doit lire – même si dans le cas présent on est root-, et que le contenu n’est pas lu dynamiquement, mais mis en cache au chargement à l’instar du reste de la configuration, il faut donc jouer avec use/discard/load/use de varnishadm pour jouer avec les configs (ou charger avec un nom différent à chaque fois, mais c’est un peu plus dégueu).

Dans mon cas, vu le peu de persistance nécessaire je me suis arrêté là. Le site était en cours de refonte et c’est d’ailleurs ce qui a motivé le choix de l’ajout du fichier en premier lieu sur cette plateforme, vu qu’elle répondait déjà au domaine. Je n’avais pas le temps de tenter un reverse des images pour la jouer au niveau du serveur web, et c’était cool au final de bosser avec Varnish, que je vous recommande de découvrir rien que pour comprendre comment fonctionnent certains CDNs.

Amusez-vous bien 🙂

Stream youtube sans navigateur, dur, mais faisable !

9 août 2021 à 16:30

Quand je ne suis pas en réunion/call/conférence Teams, et même en dehors du boulot, j’ai une tendance facile à laisser traîner un live youtube en mode « radio » (il en existe une foultitude). Mais l’âge du PC, la lourdeur de YouTube (son manque d’optimisation « standard »), font que je cherchais une solution plus légère. J’ai trouvé une solution de geek évidemment…

Ma machine date technologiquement : un Intel Core i5 6300U, ça reste encore vaillant, mais face à l’agression constante d’un Microsoft Teams, et d’un Firefox aux dizaines d’onglets ouverts, certains particulièrement consommateurs (consoles de cloud providers, entre autres), malgré les 16Go de RAM et le Crucial P2, certains moments deviennent pénible. Ajoutez que sous Linux, l’accélération vidéo dans les navigateurs reste problématique, et que malgré les solutions apportées sur le papier, j’ai toujours pas réussi personnellement alors que les plateformes Intel sont pourtant réputées faciles à exploiter. Le load s’envole à tout va, les latences dans la moindre action devient problématique, la seule chose qui reste constante, c’est le shell.

Je n’ai pas de capture d’écran à partager, mais voilà, lors d’un test « au repos », avec juste un onglet Youtube d’ouvert sur une des radios que j’écoute, le load atteint vite les 4/5 avec tous les cœurs à 100%, sur une machine qui n’a que deux cœurs physiques avec HyperTreading. Teams est déjà une purge quand il est tout seul, pareil pour Firefox avec tous les sites qui ne sont maintenant validés qu’avec Chrome (l’impression d’un retour en arrière de 20 ans, mais en remplaçant Microsoft par Google, on se sentirait presque Bill Murray). Je me suis donc mis en tête de chercher des alternatives plus légères, d’autant plus que seul l’audio est ma cible.

Une flopée de déceptions

VLC en tête d’ailleurs. C’est le seul logiciel à qui j’ai pu faire avaler le moteur de décodage vidéo du GPU intégré Intel, il portait donc beaucoup d’espoir. Mais depuis un certain temps, alors que pas mal d’articles, certains datant même de plusieurs années, ou parlant de la version de développement, mentionnent qu’il suffit normalement de lui passer l’URL d’une vidéo pour qu’il s’en charge, pas moyen ici de lui faire avaler celle de mon flux favori.

D’autres recherches m’ont envoyées vers différents logiciels de différents niveaux de finition. Une fois encore, la facilité apportée par AUR dans l’installation des logiciels et de leurs dépendance rend l’expérience de test beaucoup plus simple et rapide. Mais pas le résultat. Certains logiciels ne fonctionnaient pas du tout, d’autres étaient encore plus lourds qu’un navigateur. J’avais pourtant déjà exclus d’emblée toute application Electron, parce que bon, si c’est pour lancer un Chromium et ouvrir un site, autant utiliser Chromium qui est déjà fréquemment ouvert (j’avais déjà parlé de ça dans l’utilisation des proxy Socks). Ce n’est cependant pas ce que je cherchais.

Il y a une application qui a tenu deux minutes avant que je la supprime. Elle paraissait intéressante, mais elle ne supporte pas correctement les flux « stream », et changeait de vidéo au bout de 10 secondes. C’est particulièrement frustrant. Au total ce sont quatre ou cinq applications qui sont passées sur le grill et qui n’ont pas tenu l’objectif. Avec en plus des recherches entrecoupées d’actions liées purement au boulot, et des appels fréquents en ce moment (vacances, départs, on devient vite « seul au monde »), je désespérais de trouver une solution.

Le Graal encore une fois en « console »

Je finis sur une discussion qui parle de youtube-viewer. Quand on cherche juste youtube-viewer sur un moteur de recherche, on tombe sur plusieurs projets, mais celui-ci est en perl (ouais, je troll souvent sur le langage, mais voilà, parfois, ça fait le taf). C’est finalement un gros script, il n’est là que pour manipuler les API YouTube, et passer la vidéo à un lecteur adapté. Les premiers essais avec mplayer échouent (j’ai suivi les exemples dans la discussion), un rapide coup d’œil dans les issues github me confirment que le lecteur n’est plus supporté et que mpv doit lui être préféré; un coup de yay plus tard j’entends enfin mon premier son stable pendant plus d’une minute !

Je ne vais pas détailler toutes les possibilités de youtube-viewer, sachez que si vous comptez exploiter la recherche de vidéos, il faudra générer une clé d’API sur… votre compte YouTube/Google. Eh ouais, l’utilisation en mode « anonyme » ne peut se faire que via le navigateur ou les applications officielles, histoire de bien enregistrer le moindre de vos faits et gestes… Dans mon cas, vu que je passe l’URL directe du flux, ça n’est pas nécessaire, la documentation devrait vous aider.

Le dernier point qui me dérangeait, c’était que ça prenait un onglet dans Guake, et j’en ouvre déjà beaucoup trop 😀 j’ai donc monté un petit prototype de script qui ne sert pas à grand chose à part démarrer youtube-viewer en mode « arrière-plan » :

#!/bin/bash

screen -dmS mpv-youtube youtube-viewer --video-player=mpv --no-video $@

Ah oui, ce n’est pas mentionné, mais il faut installer youtube-dl pour que l’extraction des flux d’une URL fonctionne, il n’est qu’en dépendance optionnelle sur le paquet AUR. Et pour screen, c’est pas non plus installé par défaut. L’avantage, c’est que sous Manjaro/Arch, c’est d’une facilité déconcertante à installer.

C’est du prototype hein, donc ça se limite à dire « lance youtube-viewer, avec le lecteur mpv, sans aucun décodage vidéo, avec l’URL fournie au lancement du script. Le tout dans un screen pour rendre la main à la console. Les plus alertes auront compris qu’il n’y a aucun contrôle de lecture ou de volume du coup. En effet, pour couper le son pendant les appels, je me repose sur pulseaudio, qui a aussi le bon goût de pouvoir envoyer la lecture d’mpv sur la sortie « enceintes » du laptop, pour laisser le casque à Teams. Je n’ai pas besoin de contrôler la lecture, pour une bonne et simple raison…

Réduction du load : achievement unlocked

Je me suis remis dans la configuration du test initial pour mesurer le load : moins de 2, avec mêmes des descentes à presque 1. Le CPU respire et les latences sont réduites dans plusieurs situations, j’ai donc moins de frustrations à l’accumulation de ces micro-attentes qui se répètent à longueur de journée. Par conséquent, le manque de contrôle de la lecture n’est pas un problème fondamental, dans la mesure ou il n’y a plus qu’à couper le son pour ne pas être dérangé, la lecture peut continuer sans avoir d’impact important sur mon quotidien.

Voilà, une grosse astuce qui méritait un peu plus qu’une petite place dans un « astuces diverses » (on vient de dépasser les 1000 mots). Et oui, j’ai encore trouvé une solution qui n’est pas à la portée de tout le monde, mais quand les outils pour monsieur tout le monde deviennent trop pénibles, la console nous sauve tous. Et il n’est pas dit que j’aurais pu trouver une solution simple sous Windows (bon ceci dit, l’accélération vidéo sous Windows, ça fonctionne mieux, alors…).

Quelques astuces diverses, vingtième

1 août 2021 à 08:30

Quoi, ce blog est encore en vie ? Oui, c’est une première je pense aussi longtemps sans billet. Le problème, c’est la motivation et la satisfaction de ce que je peux écrire, pour que ça parvienne jusqu’au partage. Malgré tout, et histoire d’enlever quelques toiles d’araignées, on va repartir sur ces bonnes vieilles astuces !

ipcalc pour IPv6 ?

Historiquement, sur Manjaro j’utilise le paquet ipcalc tout court pour valider/vérifier des subnet réseaux. Mais il est limité à IPv4, et si on veut IPv6, AUR vient à notre rescousse en nous mettant à disposition le fork maintenu par RedhHat :

$ ipcalc 2001:41d0:304:200::9bb4/64
Full Address:	2001:41d0:0304:0200:0000:0000:0000:9bb4
Address:	2001:41d0:304:200::9bb4
Full Network:	2001:41d0:0304:0200:0000:0000:0000:0000/64
Network:	2001:41d0:304:200::/64
Netmask:	ffff:ffff:ffff:ffff:: = 64

Address space:	Global Unicast
HostMin:	2001:41d0:304:200::
HostMax:	2001:41d0:304:200:ffff:ffff:ffff:ffff
Hosts/Net:	2^(64) = 18446744073709551616

Autre alternative, sur Ubuntu par exemple, sipcalc vous aidera :

$ sipcalc 2001:41d0:304:200::9bb4/64
-[ipv6 : 2001:41d0:304:200::9bb4/64] - 0

[IPV6 INFO]
Expanded Address	- 2001:41d0:0304:0200:0000:0000:0000:9bb4
Compressed address	- 2001:41d0:304:200::9bb4
Subnet prefix (masked)	- 2001:41d0:304:200:0:0:0:0/64
Address ID (masked)	- 0:0:0:0:0:0:0:9bb4/64
Prefix address		- ffff:ffff:ffff:ffff:0:0:0:0
Prefix length		- 64
Address type		- Aggregatable Global Unicast Addresses
Network range		- 2001:41d0:0304:0200:0000:0000:0000:0000 -
			  2001:41d0:0304:0200:ffff:ffff:ffff:ffff

Des sons de vague dans le terminal ?

Non pas que les baignades me manquent, mais tout de même, sans être accro à la mer, un son de vague, c’est toujours apaisant (limite je m’endors avec). Alors jouer un son de vagues via le terminal, ça coûte moins cher en ressources qu’une vidéo YouTube 😛

play -n synth brownnoise synth pinknoise mix synth 0 0 0 15 40 80 trapezium amod 0.2 20

Il faut le mentionner, play est une commande qu’on retrouve dans le paquet « sox », disponible dans toutes les bonnes crèmeries/distributions.

OpenSSH et format de clé privée « legacy »

Ah oui tiens, une belle surprise qui m’est arrivée au taf. Mise en place d’un Rundeck qui, pour le SSH a décidé d’utiliser une bibliothèque Java de mes deux plutôt que le SSH natif de l’hôte (du container en l’occurrence, mais on s’en fout). Souci, quand on génère la clé SSH sur un système récent, voilà le résultat de l’entête de la clé :

$ ssh-keygen -t rsa -b 2048 -f private.key
$cat private.key
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEb
(...)

Et l’implémentation en Java ne supporte que l’ancien format « RSA ». L’astuce, c’est de changer le format de la clé en modifiant la passphrase, et donc le format au passage (ouais c’est pas trivial comme méthode) :

$ ssh-keygen -p -N "" -m pem -f /path/to/key

-N vide si pas de passphrase, sinon mettez la votre ou une autre si vous souhaitez la changer par la même occasion.

Liveness Probe sur container php-fpm dans Kubernetes ?

Eh oui, il arrive dans certains contextes qu’on sépare l’exécution de php-fpm du serveur web (quand c’est Nginx par exemple le serveur web, et non on met pas tout dans le même container, bandes de gros dégueulasses). Pour vérifier son état de santé, on peut lancer la commande suivante en guise de Liveness Probe :

readinessProbe:
          exec:
            command:
            - sh
            - "-c"
            - "SCRIPT_FILENAME=/ping /usr/bin/cgi-fcgi -bind -connect localhost:9000"

On aura pris soin évidemment de configurer le ping dans le pool fpm embarqué :

pm.status_path=/status
ping.path=/ping
ping.response=pong

Obtenir l’uptime d’un container ?

Comme le brouillon a trainé pendant un temps beaucoup trop long et que j’ai pas pris suffisamment de notes, je n’ai plus de contexte particulier (j’aime bien avoir le contexte, pourtant). Enfin bref, j’ai eu à un moment donné besoin d’avoir l’uptime d’un container, vu par l’hôte, sans accès au runtime. Ben si on cherche bien, on peut récupérer l’uptime du processus démarré par le container via des options de ps :

$ ps -eo pid,comm,lstart
  PID COMMAND                          STARTED
    1 init            Sat Jul 31 11:15:54 2021
    2 init            Sat Jul 31 11:15:54 2021
    3 bash            Sat Jul 31 11:15:54 2021
    4 terminator      Sat Jul 31 11:15:54 2021
   32 dbus-launch     Sat Jul 31 11:15:54 2021
   33 dbus-daemon     Sat Jul 31 11:15:54 2021
   35 at-spi-bus-laun Sat Jul 31 11:15:54 2021

Faire le total des pages des supports PDF en ligne de commande

Pendant ma préparation à la certification Google Cloud Professional Architect (que j’ai eu, champagne ! Bon c’était en Décembre dernier déjà, mais c’est pas grave), j’ai accumulé les supports PDF des formations préparatoires à la certification. C’était assez touffu — 65h de formations prévues, ateliers compris–, et en discutant d’un éventuel partage des documents, j’ai voulu savoir à quel point c’était dense. Avec tous les PDFs dans le même dossier, et grâce à qpdf, voilà à quoi on peut s’attendre :

$ find . -name "*.pdf" -exec qpdf --show-npages {} \; | awk '{s+=$1} END {print s}'
1032

Oui, c’est dense, très dense. Et le pire, c’est que ça couvre pas toutes les questions posées à l’examen, il faut quand même un cerveau !

MongoDB est un con

J’avoue, j’étais un peu énervé. Déjà que je suis pas spécialement fan (parce que je pratique pas assez, certainement), mais là, quand même… Sur mysql/mariadb, dans un dump vous avez à disposition moultes métadonnées très pratiques pour savoir si ça peut bien ou mal se passer à l’importation, Dedans, la version du serveur et de l’outil de dump utilisé.

Apparemment ce n’est pas le cas avec mongoDB, en voulant transférer les utilisateurs, voilà ce que j’ai eu comme erreur pendant la restauration :

#commande du duump
$mongodump --db admin --collection system.users

#commande de restauration
$ mongorestore -d admin admin
2021-01-20T10:47:23.897+0100 the --db and --collection args should only be used when restoring from a BSON file. Other uses are deprecated and will not exist in the future; use --nsInclude instead
2021-01-20T10:47:23.897+0100 building a list of collections to restore from admin dir
2021-01-20T10:47:23.897+0100 assuming users in the dump directory are from <= 2.4 (auth version 1)
2021-01-20T10:47:23.898+0100 Failed: the users and roles collections in the dump have an incompatible auth version with target server: cannot restore users of auth version 1 to a server of auth version 5

La solution, dumper la collection « system.version » avec celle des utilisateurs parce que sinon il l’inclut pas de lui-même !!!

$ mongodump --db admin --collection system.users --collection system.version

Vérifier les services en erreurs

Après l’incendie d’OVH et surtout le redémarrage du serveur, je me suis retrouvée face à une VM redémarrée mais plusieurs services en échec à cause de la lenteur (systemd arrête généralement ses actions au bout d’1m30s). Pour afficher la liste des services HS, c’est simple :

[root@vox ~ ]# systemctl list-units --failed
  UNIT                         LOAD   ACTIVE SUB    DESCRIPTION
● b3.service                   loaded failed failed LSB: Starts b3 Server Daemon
● certbot.service              loaded failed failed Certbot
● systemd-modules-load.service loaded failed failed Load Kernel Modules
● webmin.service               loaded failed failed LSB: Start or stop the Webmin server

Et hop, on est bon pour des start manuels (et découvrir quelques services zombie du passé qui n’ont rien plus à faire là aussi, mais ça, c’est une autre histoire :D).

Pas de dig ? Les alternatives !

Eh oui, dig ne fait pas partie des commandes de bases dans toutes les distributions, il fait souvent partie d’un paquet « dns-utils » (ou dnsutils, ou dns-tools, aucune distrib n’utilise le même nom !!), et pour des raisons fréquentes d’optimisation, c’est encore moins souvent ajouté dans des images docker. Il est donc possible de reposer sur certaines alternatives.

La commande host est embarquée dans bind9-host, qui peut être souvent installée en dépendance d’un autre package. Idem pour getent, beaucoup plus facile à trouver, puisqu’il est fourni par libc-bin, du assez bas niveau cette fois :

$ getent hosts blog.seboss666.info
91.121.61.180   blog.seboss666.info

$ host blog.seboss666.info
blog.seboss666.info has address 91.121.61.180

Après on en convient, pour du débug de résolution DNS plus avancée, dig reste une très bonne trousse à outils 🙂

Ansible : environnement conditionné !

Que j’en ai chié pour ça. Je devais travailler dans un environnement particulièrement contraint où les machines n’ont pas de réseau public, pas d’accès au réseau extérieur, et même pour joindre nos propres outils, un proxy spécifique dans le réseau privé a été mis en place. Et je travaille sur deux datacenters différents, l’un en France, l’autre en Belgique, donc avec des proxy différents.

Je peux passer les proxys en variables d’environnement, mais il faut pouvoir identifier si l’on se trouve en France ou en Belgique. Par chance les domaines des machines permettent facilement d’identifier leur localisation, et c’est là-dessus que je joue avec Ansible, et des groupes de variables :

vars:
  proxy_fr_env:
    http_proxy: "http://proxy_fr.domain.tld:3128"
    https_proxy: "http://proxy_fr.domain.tld:3128"
  proxy_be_env:
    http_proxy: "http://proxy_be.domain.tld:3128"
    https_proxy: "http://proxy_be.domain.tld:3128"

tasks:

  - name: force chef-client configuration
    shell: "chef-client -c {{ chef_path }}/client.rb -o lin-chef-client"
    environment:
      "{{ proxy_be_env if 'belgium' in inventory_hostname else proxy_fr_env }}"

Ici, je met l’environnement au niveau des tâches qui en ont besoin, mais si vous pensez que c’est plus simple de foutre l’environnement au niveau global, ça fonctionne aussi 🙂

Ubuntu et WSL : mais c’est quoi ce masque ?

Je vais pas revenir sur mon setup WSL, vous le connaissez (sinon c’est à relire par ici). Un truc qui m’a fait chier pendant un bon moment sans que je me penche sur le problème avant trop longtemps, c’est le masque par défaut, umask de son petit nom. En effet, sur une installation fraiche d’Ubuntu WSL, si on vérifie c’est moche :

$ umask -S
u=rwx,g=rwx,o=rwx

Ce qui veut dire que tous les fichiers et dossiers seront avec des permissions pas du tout adaptées au schéma habituel des distributions dans le reste du monde (des vraies installations de Linux, en gros), c’est à dire que c’est open bar pour tous les utilisateurs de l’installation (666 pour les fichiers, 777 pour les dossiers). Tout ça parce que sous Ubuntu, le masque par défaut est géré par un plugin pam_umask, mais pam n’est pas exploité par défaut dans ce cadre précis de WSL. Du coup, faut aller soi-même ajouter le correctif dans /etc/profile.d/umask.sh (à créer évidemment) :

umask 022

Et on peut lancer la commande à chaud si on en a besoin tout de suite sans relancer tout le bousin. On peut aussi adapter le masque si on veut du fichier privé par défaut (le masque sera alors 077).


Bon, est-ce que ça va permettre de décoincer un peu les sorties sur le blog ? l’avenir nous le dira. J’ai les mains actuellement dans les migrations, VPS tout d’abord, big serveur ensuite, et surtout l’ansiblisation de toute ça, sachant qu’il va y avoir Debian 11 bientôt dans l’affaire, sait-on jamais, y’aurait peut-être quelque chose à en dire !

❌