Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
file: images/OAUFMT.webp
|
||||
title: Illustration par DALL·E
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 246 KiB |
@@ -0,0 +1,200 @@
|
||||
---
|
||||
cover: images/OAUFMT.webp
|
||||
date: "2024-05-04T22:32:09+02:00"
|
||||
title: Maintenance terminée
|
||||
---
|
||||
|
||||
Anticiper les problèmes ne signifie pas que l'on connaisse systématiquement à l'avance le genre de problèmes que l'on va rencontrer.
|
||||
Et, évidemment, j'ai connu un problème majeur pendant ma dernière [maintenance planifiée](/interets/informatique/2024/04/30/maintenance-planifiee/).
|
||||
|
||||
## Contexte
|
||||
|
||||
<details class="read-more"><summary>Voir aussi</summary>
|
||||
|
||||
- [/interets/informatique/2021/03/09/mon-reseau/](/interets/informatique/2021/03/09/mon-reseau/)
|
||||
|
||||
</details>
|
||||
|
||||
Le but ultime de la maintenance était d'intégrer mon Mac mini M1 au réseau en tant que serveur principal, en remplacement de mon minisforum U-820.
|
||||
Du coup, j'ai vu une opportunité d'utiliser ce dernier en tant que routeur à la place du Awow AK-34, qui deviendrait mon reverse-proxy.
|
||||
|
||||
### Mac mini M1
|
||||
|
||||
Depuis que je dispose du M2, je me gardais le M1 au chaud pour l'intégrer au réseau en tant que serveur principal, c'est-à-dire celui qui stocke tous mes fichiers dans [ma forge](https://git.dern.ovh/) [Gitea](https://about.gitea.com), en plus d'héberger tous mes services.
|
||||
Remplacer le minisforum U820 par le Mac mini m'offrirait un gain de performances (même si le U820 était loin d'être surmené) sans compromettre ma consommation d'énergie.
|
||||
|
||||
En outre, je voulais tester deux configurations : l'une où [nix](https://nixos.org) serait installé dans macOS, et l'autre où j'effectuerais une [installation native de NixOS](https://wiki.nixos.org/wiki/NixOS_on_ARM/Apple_Silicon_Macs).
|
||||
Contre toute attente, la première configuration s'est révélée peu pratique à l'usage, alors que la seconde a été plus facile que prévu...
|
||||
Il m'a suffi de suivre consciencieusement la [documentation](https://github.com/tpwrules/nixos-apple-silicon/blob/main/docs/uefi-standalone.md) pour que je me retrouve avec un environnement serveur familier.
|
||||
|
||||
> Je dispose d'un Mac mini M2 en plus du M1 : si j'avais fait une connerie, j'aurais pu la [rattraper](https://github.com/libimobiledevice/idevicerestore).
|
||||
> Je décline toute responsabilité si vous décidez d'installer NixOS sur un Mac avec cette méthode.
|
||||
|
||||
### Awow AK-34
|
||||
|
||||
Cette machine a toujours été mon routeur ; je l'ai achetée pour ça.
|
||||
Mais avec le temps (et mes envies du moment), je me suis rendu compte que c'était le "maillon faible" de mon réseau.
|
||||
En effet, activer l'IPS/IDS ([Suricata](https://suricata.io)) faisait considérablement chuter mon débit maximal atteignable sur le réseau.
|
||||
|
||||
L'exemple le plus frappant est lors de l'installation d'un jeu : sans Suricata, je sature le lien gigabit.
|
||||
Avec Suricata, je plafonne au tiers (environ 300Mb/s).
|
||||
Je n'aime pas l'idée de ne pas pouvoir utiliser mon matériel "à fond"...
|
||||
|
||||
Son petit [Celeron N3450](https://ark.intel.com/content/www/fr/fr/ark/products/95596/intel-celeron-processor-n3450-2m-cache-up-to-2-2-ghz.html) se trouve bien plus à l'aise dans son nouveau rôle de reverse-proxy.
|
||||
La création de ce rôle est peut-être l'élément le plus significatif de cette maintenance (après l'intégration du Mac mini évidemment) : jusqu'à présent, puisque le serveur principal centralisait cette fonctionnalité spécifique, il suffisait d'un reboot pour que plusieurs services dépendant d'un serveur web soient momentanément inaccessibles, même si je ne changeais rien au serveur web.
|
||||
|
||||
Le plus embêtant était sans doute [Home Assistant](https://www.home-assistant.io), hébergé sur une autre machine physique mais proxifié pour un accès extérieur, et, [ma station météo](/interets/informatique/2023/09/15/mise-a-jour-de-ma-station-meteo/) qui a besoin d'envoyer ses données à un nom de domaine et non à une adresse IP.
|
||||
Donc, si, en pleine nuit, je bidouillais mon serveur web, je risquais de me retrouver dans le noir parce que ma station météo devenait incapable de contacter Home Assistant, qui en retour était incapable de connaître la luminance extérieure et ainsi éteignait les lumières...
|
||||
|
||||
Du coup, insérer un reverse-proxy dans la chaîne me permet de faire toutes les bidouilles que je veux sur le serveur principal, sans risquer un effet de bord qui entraînerait la panne d'un service qui n'a rien à voir avec ma bidouille.
|
||||
Je touche moins souvent au reverse-proxy : une fois configuré, je peux l'oublier.
|
||||
|
||||
### Minisforum U-820
|
||||
|
||||
Je le désignais jusqu'alors comme mon "serveur préféré", notamment en raison de sa puissance ([Core i5 8259U](https://www.intel.fr/content/www/fr/fr/products/sku/135935/intel-core-i58259u-processor-6m-cache-up-to-3-80-ghz/specifications.html), 4 cœurs/8 threads), et il s'est montré largement à la hauteur de mes attentes (et de son prix puisqu'à l'époque, je l'ai payé plus de 500€).
|
||||
|
||||
Il est doté d'un port ethernet 2.5Gb/s.
|
||||
En pratique, ça ne me sert absolument à rien : c'est le seul élément de mon réseau avec la [freebox Pop](https://www.free.fr/freebox/) à pouvoir atteindre ces vitesses.
|
||||
Mais c'est surtout son CPU qui m'intéresse pour le rôle de routeur.
|
||||
Et là encore, il se montre redoutable puisque, même avec Suricata actif, je peux saturer tranquillement mon lien réseau en toute circonstance, et sans entraîner de charge CPU.
|
||||
C'est assez bluffant de voir à quel point, dans ce contexte précis, le Core i5 surpasse le Celeron.
|
||||
|
||||
Une telle puissance va m'ouvrir la porte à davantage d'expérimentations avec [OPNsense](https://opnsense.org).
|
||||
Je rêve déjà à l'installation d'un pare-feu applicatif et autres améliorations en termes de sécurité.
|
||||
|
||||
J'ai eu la surprise, à la réinstallation d'OPNsense, de voir qu'un paquet était disponible pour installer mon serveur Web fétiche : [Caddy](https://caddyserver.com).
|
||||
Malheureusement, mes tentatives de configuration se sont révélées infructueuses pour le moment.
|
||||
Trop de paramètres modifiés en une seule fois : je verrai ça plus tard.
|
||||
L'essentiel étant que ce Minisforum va vivre une deuxième vie en tant que routeur, et vu les performances et sa consommation contenue, il va durer longtemps à ce poste.
|
||||
|
||||
## Implications
|
||||
|
||||
L'intégration d'une seule machine va m'imposer d'en (ré)installer trois en même temps.
|
||||
Inutile d'être un expert en sysadmin pour comprendre que c'est risqué et déconseillé.
|
||||
Mais il faut bien comprendre que :
|
||||
|
||||
- je ne gagne pas d'argent avec mon réseau
|
||||
- si je fais une connerie, je perds essentiellement du temps (et parfois des données)
|
||||
- quoi qu'il arrive, j'apprends de nouvelles choses
|
||||
|
||||
Je ne ferai jamais quelque chose d'aussi "tête-brûlée" en entreprise, mais à la maison, je m'en fous.
|
||||
Je m'en fous d'autant que j'ai des backups dans tous les coins.
|
||||
|
||||
Oui, sauf que, si mes backups sont foutues...
|
||||
|
||||
## C'est la cata
|
||||
|
||||
Tout content que je suis d'avoir tout installé et que tout fonctionne extrêmement bien (en apparence), j'ai eu un gros moment de panique en voyant des erreurs quand j'essayais d'accéder à certains fichiers depuis Gitea.
|
||||
De grosses erreurs 500, concernant manifestement [LFS](https://git-lfs.com).
|
||||
Sauf que dans les copies locales de mes dépôts, celles-là même que j'ai utilisé pour restaurer les dépôts sur Gitea, mes fichiers sont parfaitement lisibles.
|
||||
|
||||
Je vous passe les détails parce que je ne me souviens plus de tout ce que j'ai fait, mais mes tentatives de mise à jour de mes dépôts sur Gitea se sont soldées par une corruption de mes dépôts locaux.
|
||||
En gros, certains "vrais" fichiers ont été simplement remplacés par leur pointeur LFS, sauf que dans la panique, les "vrais" fichiers n'existaient plus.
|
||||
Je n'ai pas la moindre idée si j'emploie le bon vocabulaire, et je ne saurai pas vous expliquer plus en détails ce qu'il s'est réellement passé, mais une chose est sûre : j'ai fait une grosse connerie, et j'ai flingué mes dépôts locaux.
|
||||
|
||||
Pas de problème, je vais piocher dans une sauvegarde.
|
||||
|
||||
Ah, bah non en fait.
|
||||
La connerie que j'ai faite avec LFS ne date pas de ma maintenance, mais d'il y a bien plus longtemps.
|
||||
Trop longtemps.
|
||||
|
||||
Les experts de git et de LFS ne comprendront sans doute pas ce que j'ai pu faire pour ne jamais m'en rendre compte, et je ne peux pas les blâmer pour ça.
|
||||
C'est passé inaperçu, c'est tout, c'est comme ça.
|
||||
Et le pire, c'est que plus j'essaye de trouver une solution, plus je risque de corrompre de nouveaux fichiers.
|
||||
|
||||
Pour vous donner une idée du volume que ça représente, j'ai plus d'une cinquantaine de dépôts, et plusieurs dizaines de milliers de fichiers stockés avec LFS.
|
||||
Donc à chaque tentative de restauration, je fais monter la pression d'un cran...
|
||||
|
||||
À ce stade, on essaye de mesurer l'étendue des dégâts, et, fort heureusement, seuls trois dépôts ont été impactés, dont deux où seuls quelques fichiers ont été perdus (mais il m'est possible de les recréer facilement).
|
||||
|
||||
Un dépôt en revanche a morflé : celui de mon blog.
|
||||
5900 fichiers d'images irrémédiablement corrompus.
|
||||
En vrai, deux tiers de ces fichiers sont simplement des miniatures de différentes tailles, mais pour les re-générer, il me faut les fichiers d'origine...
|
||||
|
||||
## Résolution du problème
|
||||
|
||||
Il m'a fallu quitter l'écran quelques heures pour trouver une solution : il "suffit" de récupérer les fichiers depuis l'instance publiée de mon blog.
|
||||
Non, il ne s'agit pas de faire de simples copier/coller.
|
||||
|
||||
Dans le markdown de mes articles, j'utilise un composant [Blade](https://laravel.com/docs/11.x/blade) pour insérer une pièce jointe, auquel je passe un attribut `ref` contenant une chaîne aléatoire de six caractères.
|
||||
|
||||
Dans le système de métadonnées que j'ai créé, il suffit de déposer un fichier dans le bon dossier pour que mon application génère automatiquement tout ce dont j'ai besoin.
|
||||
Au moment du rendu HTML du markdown source, ce composant Blade est transformé en un autre, approprié au type de fichier.
|
||||
L'instanciation de ce nouveau composant déclenche la copie des fichiers liés (c'est-à-dire, l'image d'origine et les différentes miniatures) dans le répertoire de stockage de [Laravel](https://laravel.com/).
|
||||
Mais, afin de ne pas avoir à gérer des chemins relatifs (ce qui me serait difficilement faisable pour différentes raisons) et pour éviter de stocker des fichiers en double, je calcule le md5 de chaque fichier et le place dans une arborescence où chaque dossier correspond à quatre caractères de ce hash.
|
||||
|
||||
Ce système est très efficace, ce n'est pas pour rien que je l'utilise depuis des années dans différents projets.
|
||||
Il présente par contre un inconvénient : si le fichier d'origine n'existe plus, on ne peut pas calculer son md5, et donc on ne peut pas retrouver où il est stocké.
|
||||
_Note pour plus tard : stocker le md5 dans les métadonnées..._
|
||||
|
||||
Par contre, j'ai eu la bonne idée d'organiser mes markdown exactement de la même façon que comme ils sont présentés : l'article `blog/2024/05/04/maintenance-terminee` est généré de sorte que son HTML se trouve dans `blog/2024/05/04/maintenance-terminee/index.html`.
|
||||
Du coup, si j'inspecte le HTML des pages de mon blog en production, je peux savoir à quel article appartiennent les fichiers qui existent dans cette page.
|
||||
Il me suffit de rechercher les balises `<figure>`, et d'y chercher les fichiers dont l'URL commence par `/storage`.
|
||||
[DomDocument](https://www.php.net/manual/en/class.domdocument.php) et [xpath](https://www.php.net/manual/en/class.domxpath.php) ont considérablement aidé pour cette tâche et l'ont rendue presque triviale.
|
||||
|
||||
En comparant l'ordre dans lequel ces fichiers apparaissent avec l'ordre dans lequel j'ai créé mes balises `x-attachment` dans mon markdown, et en prenant en considération que l'image d'en-tête n'y figure pas (pas plus que certaines images additionnelles), j'ai fini par pouvoir associer un fichier spécifique à sa référence dans mes métadonnées.
|
||||
De là, il n'y avait plus qu'à copier le fichier de mon blog en production vers son emplacement attendu dans les sources de l'article correspondant.
|
||||
Ensuite, une "petite" réparation des articles (consistant essentiellement en la recréation des miniatures), et "le tour est joué".
|
||||
|
||||
## Post-mortem
|
||||
|
||||
Maintenant que la crise est passée, je me dis qu'il y a eu plus de peur que de mal.
|
||||
Le moment où l'on constate la perte irrévocable de données est glaçant, terrifiant.
|
||||
Mais après ce moment, on commence à réfléchir.
|
||||
Et, souvent, on arrive à faire preuve d'astuce.
|
||||
|
||||
J'ai abondamment utilisé [ChatGPT](https://chat.openai.com/) au cours de cette "crise".
|
||||
Il m'a été d'une aide précieuse, pertinente et adaptée.
|
||||
Il m'a permis d'écrire une grosse partie du code "trivial" qui allait me "sauver la vie", un code que j'aurai pu écrire moi-même si la panique n'avait pas été aussi forte.
|
||||
Il m'a aussi permis de sauver une grosse partie des données que je pensais corrompues, afin que je n'aie à déplorer que la perte de quelques fichiers de moindre importance dans seulement deux dépôts.
|
||||
Sans ChatGPT, j'aurai peut-être tellement paniqué que j'aurai perdu bien plus que ça.
|
||||
Sans ChatGPT et donc sans les gens qui ont produit les documents qui l'ont alimenté.
|
||||
|
||||
Mais il m'a aussi avoué ses limites : l'idée de créer un script de récupération à partir de mon blog en production m'est venue au moment où il se confondait en excuses devant son incapacité de me suggérer autre chose que l'acceptation de la perte définitive de mes données.
|
||||
Un moment en pleine [vallée de l'étrange](https://fr.wikipedia.org/wiki/Vallée_de_l'étrange) d'ailleurs, un instant suspendu entre l'appréciation de sa compassion et le rappel que ce n'est qu'un algorithme.
|
||||
|
||||
Je ne vais pas me faire donneur de leçon parce que, moi-même, je suis incapable de suivre ce conseil simple : **ne jamais travailler sur plusieurs machines en même temps**.
|
||||
Toutefois, il aurait été difficile de faire autrement dans ce cas précis, où l'on interverti les rôles d'au moins deux machines.
|
||||
On pourra toujours me suggérer des choses : virtualiser, dockeriser, héberger dans le cloud, etc.
|
||||
Acheter une nouvelle machine ou utiliser une vieille machine de façon temporaire, ou que sais-je encore.
|
||||
Oui, dans un contexte pro.
|
||||
À la maison, on fait avec ce qu'on a.
|
||||
|
||||
Un autre mémo que je pourrais faire concerne les sauvegardes.
|
||||
On ne le répètera jamais assez, et, pourtant, c'est plus compliqué qu'il n'y parait : **il faut tester ses sauvegardes**.
|
||||
Et, là encore, on me donnera l'argument de la virtualisation, de la dockerisation ou de la cloudification, afin d'avoir une infra qu'on peut péter à volonté.
|
||||
Oui, dans un contexte pro.
|
||||
À la maison, je suis un bidouilleur.
|
||||
Si, un jour, je gagne de l'argent avec mon blog, on verra pour quelque chose de plus robuste.
|
||||
En attendant, je bidouille parce que ça me plaît, pas parce que j'en ai l'obligation.
|
||||
|
||||
Donc, oui, je m'expose à plein de choses qui empêcheraient certains de dormir.
|
||||
Oui, je fais des choses que certains considèrent comme de l'overengineering.
|
||||
Non, je ne respecte pas toujours les bonnes pratiques en termes de sysadmin (essentiellement par manque de moyens techniques).
|
||||
Mais je m'amuse, parfois je panique, mais je trouve des solutions, je progresse, j'apprends.
|
||||
Je fais des choses que personne ne fait, je tombe sur des problèmes que personne ne rencontre.
|
||||
Je résous des énigmes.
|
||||
C'est ça qui me plaît.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Je suis passé par un moment assez chargé en émotion, puis par un travail de longue haleine pour tout restaurer correctement.
|
||||
Mais je suis content du résultat.
|
||||
|
||||
En termes de consommation d'énergie, l'intégralité du réseau consomme moins de 60W en charge.
|
||||
En termes de performances, rien à dire : c'est parfait.
|
||||
Et en termes de maintenabilité, je gagne en flexibilité : je peux héberger temporairement un service sur le reverse-proxy le temps que je tripatouille le serveur principal, sans engendrer de coupure.
|
||||
|
||||
J'ai encore des petites choses à faire, comme rendre quelques dépôts git publics (mais je veux d'abord vérifier qu'ils soient présentables), m'assurer du paramétrage de quelques services un peu obscurs, etc.
|
||||
|
||||
En outre, il y a encore quelques trucs que j'aimerais mettre en place un jour :
|
||||
|
||||
- IPv6 : j'ai encore profité de l'occasion de tout réinstaller pour tenter de le mettre en place, sans succès. Ça fait partie des choses que je ne m'explique pas : comment peut-on à la fois être dans l'urgence de passer à IPv6 et rendre ça aussi compliqué...
|
||||
- Reverse-proxy sur OPNsense : pareil, c'est tellement sur-compliqué... C'est hyper-paramétrable, mais franchement pas accessible...
|
||||
- Miroir de Gitea : j'aimerais mettre en place sur une deuxième machine un miroir exhaustif de mon instance de Gitea pour parer à toute éventualité. Je dispose désormais de l'infra matérielle pour ça, mais j'aimerais que ce soit propre et que cela nécessite le minimum de maintenance en cas de création/suppression de dépôt
|
||||
|
||||
Enfin, il faudrait que je me mette sérieusement à la newsletter, mais depuis le premier envoi, je bosse non-stop sur un gros refactoring de mon blog, et là sur le réseau depuis trois jours.
|
||||
Je manque donc un peu de temps pour la newsletter.
|
||||
|
||||
Mais, la bonne nouvelle, c'est que le refactoring de mon blog est terminé, et la maintenance de mon réseau aussi.
|
||||
Je vais donc pouvoir m'y mettre...
|
||||
@@ -0,0 +1,3 @@
|
||||
file: images/ZOPNhT.png
|
||||
title: Le plan de la formation *Elements of AI*. Cliquez pour afficher l'image à sa
|
||||
taille réelle.
|
||||
@@ -0,0 +1 @@
|
||||
file: images/ceFyBS.png
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 334 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 350 KiB |
@@ -0,0 +1,132 @@
|
||||
---
|
||||
cover: images/ceFyBS.png
|
||||
date: '2024-05-05T23:51:47+02:00'
|
||||
title: 'Elements of AI : pour en finir avec l''ultracrépidarianisme'
|
||||
---
|
||||
|
||||
Souvent, je critique.
|
||||
Et, après coup, je m'informe.
|
||||
On fait — presque tous — cela.
|
||||
|
||||
Il m'arrive d'avoir tort, ou, en tout cas, de changer d'opinion après m'être renseigné.
|
||||
Honnêtement, c'est assez rare, mais ça arrive.
|
||||
Le meilleur exemple que je puisse vous donner est aussi le plus récent : alors que je critiquais vertement l'Intelligence Artificielle à travers plusieurs articles, j'ai fini par utiliser ChatGPT avec un enthousiasme non dissimulé.
|
||||
|
||||
<details class="read-more"><summary>Voir aussi</summary>
|
||||
|
||||
- [/interets/informatique/2022/12/24/l-ia-pose-la-question-de-l-identite/](/interets/informatique/2022/12/24/l-ia-pose-la-question-de-l-identite/)
|
||||
- [/interets/informatique/2023/05/26/reflexion-ia-et-moteurs-de-recherche/](/interets/informatique/2023/05/26/reflexion-ia-et-moteurs-de-recherche/)
|
||||
- [/interets/informatique/2023/08/16/reflexion-ia-et-licences/](/interets/informatique/2023/08/16/reflexion-ia-et-licences/)
|
||||
- [/interets/informatique/2024/02/19/j-ai-discute-avec-chatgpt/](/interets/informatique/2024/02/19/j-ai-discute-avec-chatgpt/)
|
||||
- [/interets/informatique/2024/03/03/reflexions-leonardo-ai/](/interets/informatique/2024/03/03/reflexions-leonardo-ai/)
|
||||
- [/interets/informatique/2024/03/10/j-ai-pris-un-abonnement-a-chatgpt/](/interets/informatique/2024/03/10/j-ai-pris-un-abonnement-a-chatgpt/)
|
||||
|
||||
</details>
|
||||
|
||||
Mais, fondamentalement, ma culture générale concernant l'IA est relativement limitée.
|
||||
Discuter avec ChatGPT ou me faire conseiller par lui sur des sujets techniques, c'est vrai que c'est bien utile (surtout [quand on fait n'importe quoi](/interets/informatique/2024/05/04/maintenance-terminee/)), mais ça ne me dit rien sur son fonctionnement.
|
||||
Et, si j'étais un véritable profane, j'entendrais beaucoup parler d'[algorithmes](https://fr.wikipedia.org/wiki/Algorithme) sans vraiment savoir ce dont il s'agit.
|
||||
|
||||
Me refusant à être l'un de ces profanes, et toujours désireux d'étendre mes connaissances, je me suis mis en quête d'une formation consacrée à l'IA.
|
||||
Une *vraie* formation, dispensée par un organisme reconnu.
|
||||
J'étais prêt à casser mon [CPF](https://www.moncompteformation.gouv.fr/) pour ça : forcément, une formation sur une technologie moderne doit coûter une certaine somme.
|
||||
|
||||
Mais, en fin de compte, je suis tombé sur une excellente formation dont je voulais absolument vous parler, et qui ne m'a rien coûté.
|
||||
|
||||
## Sorbonne, Helsinki et compagnie
|
||||
|
||||
C'est par l'intermédiaire du [portail de la transformation numérique des entreprises](https://www.francenum.gouv.fr/formations/comment-se-former-lintelligence-artificielle) que je suis tombé dessus.
|
||||
Initialement dispensée par l'[Université d'Helsinki](https://www.helsinki.fi/), la formation est réalisable en français grâce à un partenariat avec la [Sorbonne](https://www.sorbonne-universite.fr/).
|
||||
|
||||
Il s'agit d'une formation **certifiante**, dont j'ignore totalement la valeur sur le marché de l'emploi.
|
||||
Tout ce que je peux vous dire de mon expérience personnelle, c'est que je l'ai trouvée très enrichissante.
|
||||
Comme 950 000 autres étudiants à travers le monde, excusez du peu.
|
||||
|
||||
Après avoir complété les six chapitres, on se retrouve gratifié d'un joli certificat tout ce qu'il y a de plus officiel, et tout ce qu'il y a de plus gratuit.
|
||||
|
||||
## La formation
|
||||
|
||||
### Plan
|
||||
|
||||
Elle est entièrement faisable à distance, et aucun rythme n'est imposé.
|
||||
Ils évoquent une durée de 30 heures pour les six chapitres, divisés en deux ou trois cours.
|
||||
J'y ai passé une heure par semaine et par chapitre, mais je ne suis précisément pas un profane, et je suis très motivé.
|
||||
|
||||
Comme dit, les six chapitres sont divisés en deux ou trois cours, et chaque cours peut faire l'objet d'un ou plusieurs exercices.
|
||||
Mais que l'on ne s'imagine pas des exercices "comme à l'école" : l'objectif est évidemment d'apprendre, mais en s'amusant.
|
||||
|
||||
Que cela soit par l'esthétique pop et colorée, par l'humour latent ou par les références de geeks, l'environnement d'apprentissage qui nous est offert est très plaisant, rassurant et engageant.
|
||||
C'est visuellement agréable, tant dans les couleurs, les images, la présentation du texte et les interactions.
|
||||
Et ces dernières sont assez nombreuses et diversifiées.
|
||||
|
||||
[Tous les cours sont accessibles](https://course.elementsofai.com/fr), même sans avoir créé un compte.
|
||||
Bien sûr, un compte reste nécessaire pour répondre aux questions, avoir un suivi, et obtenir le certificat.
|
||||
|
||||
Voici le plan de la formation :
|
||||
|
||||

|
||||
|
||||
Comme vous pouvez le constater, la formation offre une vue d'ensemble sur l'Intelligence Artificielle : on aura assurément quelques cours assez techniques, requérant de se rappeler quelques notions simples de mathématiques, mais on aura aussi des cours plus réflexifs, voire franchement philosophiques.
|
||||
Et j'apprécie, et même très fortement, la **neutralité** de la formation.
|
||||
|
||||
### Contenu et interactions
|
||||
|
||||
C'est d'ailleurs ce qui m'a le plus motivé pour la réaliser.
|
||||
L'accent est mis sur l'accès à une culture universelle : tout le monde peut participer à cette formation, même sans aucun bagage technique, simplement pour savoir de quoi on parle, sans pour autant verser ni dans l'alarmisme primaire, ni dans l'exubérance des technologies "émergentes".
|
||||
|
||||
Du coup, les exercices aussi sont variés, bien que relativement peu nombreux : il y a 25 questions en tout, réparties sur les six chapitres.
|
||||
Il y a pas mal de questions ouvertes où l'on nous incite à la réflexion et à la philosophie.
|
||||
L'occasion d'être évalué par nos pairs : d'autres étudiants vont pouvoir lire et donner leur point de vue sur notre réflexion et vice-versa.
|
||||
Il n'y a pas de communication directe, mais on n'a pas l'impression de donner des réponses dans le vide : savoir que l'on sera lu devrait être incitatif à élaborer, et si on élabore, on réfléchit, et c'est tout le propos de cette formation.
|
||||
|
||||
Au-delà de ces quelques questions philosophiques, il y a des exercices plus fondamentaux, dont la difficulté est globalement très accessible.
|
||||
Occasionnellement, la formulation du problème d'un exercice peut prêter à confusion si l'on se précipite.
|
||||
Il faut bien lire le cours, parce que tout est dedans.
|
||||
Je n'irai pas jusqu'à dire qu'il faut faire du copier-coller (les exercices sont assez intelligemment posés pour ne pas le permettre), mais il faut **lire et prendre son temps**.
|
||||
Je sais que plus personne ne fait ni l'un ni l'autre, mais bon...
|
||||
|
||||
En outre, les exercices ne se limitent pas à répondre à des QCM : on aura aussi l'occasion de manipuler des graphiques, d'étudier des tableaux, poser des équations, et même, parfois, sortir un crayon et du papier.
|
||||
Et oui les jeunes, les technos du siècle dernier restent utiles...
|
||||
Enfin, vous me direz, on peut remplacer le crayon et le papier par un stylet et une tablette, mais le fait est que c'est une façon supplémentaire pour cette formation de nous inciter à nous poser et réfléchir.
|
||||
|
||||
### Interprétation du contenu
|
||||
|
||||
Cette formation nous permet donc de combler quelques lacunes culturelles au sujet de l'IA, sans rentrer dans trop de détails techniques.
|
||||
Oui, on aborde la classification bayésienne et les réseaux de neurones, mais pas de façon académique.
|
||||
L'apprentissage a vocation, encore une fois, à apporter une culture générale, afin de pouvoir débattre de la question de manière éclairée.
|
||||
|
||||
Tout le projet pédagogique est sincèrement brillamment mis en œuvre.
|
||||
Ce n'est pas la gamification qu'on voit partout, ni l'industrialisation de l'apprentissage, ni l'avalanche d'informations universitaires.
|
||||
On avance tranquillement de cours en cours, on rate des exercices, mais ça ne fait rien parce qu'on apprend.
|
||||
Pour la première fois de ma vie, je suis une formation où être le premier de la classe ne compte pas, et même, où cela signifierait qu'on n'avait pas besoin de cette formation.
|
||||
|
||||
J'ai obtenu un score — que j'estime — très bas (par rapport à mes autres diplômes "académique", eux) : 65% de réponses justes seulement.
|
||||
Et, là aussi, pour la première fois de ma vie, je ne suis pas meurtri par un score aussi faible.
|
||||
Mon égo est habitué à faire la gueule quand il lui manque un point ou un demi-point pour avoir le score maximal, parce que c'est généralement dû à un prof qui saque (ça m'est arrivé sur la conception d'une méthode de validation d'une adresse email... elle était parfaite, mais hors sujet : paf, 2 points en moins...), ou une petite erreur d'inattention en raison du haut particulièrement moulant de la copine de classe (ou de la prof...), bref, dans ce genre de contexte, je suis en roues libres, je plane au-dessus de mes pairs, je les regarde de là-haut, insupportable je-sais-tout qui plie le match à chaque fois que la prof sort ses copies.
|
||||
|
||||
Là, l'ambiance est tellement loin des cours scolaires, et ne pas voir, ni les étudiants, ni les profs, est salvateur.
|
||||
On est face à soi-même, nous devons nous juger par rapport à ce que nous croyons savoir.
|
||||
Un exercice que personne ne fait "dans la vraie vie".
|
||||
Personne, à part les 950 000 étudiants de tous horizons.
|
||||
Des Français qui jugeront vos écrits, des jeunes, puisque vous avez probablement le double de leur âge.
|
||||
Des anglophones aussi, et des Finlandais, et d'autres encore.
|
||||
Un tel cosmopolite en devint enivrant : j'en aurais voulu plus, de ces intégrations.
|
||||
Moi, l'autiste misanthrope !
|
||||
|
||||
Alors, 65% parce que je suis allé trop vite, pour une formation où j'ai appris une foultitude de choses intéressantes et préparatoires, je considère que c'est un succès autant pour moi que pour l'université d'Helsinki.
|
||||
Je n'ai pas participé pour rien, les mains dans les poches.
|
||||
Et le fait de ne pas avoir obtenu 100% est un rappel que j'ai encore des choses à apprendre, et ça, dans mon état actuel, c'est une aubaine.
|
||||
|
||||
D'autant que la formation nous quitte, certes, sur un certificat, mais aussi sur un cliffhanger : ce que l'on vient de faire n'est que la première étape.
|
||||
|
||||
### Et après ?
|
||||
|
||||
Car la conclusion de la formation nous offre plusieurs ressources à visiter pour étendre encore notre culture, et notamment une deuxième formation, toujours dispensée par l'Université d'Helsinki, où, cette fois-ci, l'objectif est a priori de *développer* une IA, notamment à l'aide de [python](https://fr.wikipedia.org/wiki/Python_(langage)) mais aussi d'outils plus théoriques, accessibles aux non-devs.
|
||||
Elements of AI se révèle n'être que le premier volet d'une duologie, dont la séquelle, elle aussi gratuite, s'annonce diablement intéressante.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Que vous ayez peur de l'IA ou que vous en rêviez la nuit, que vous pensez qu'elle va nous exterminer ou voler votre travail, qu'elle puise dans nos ressources naturelles ou qu'elle amènera la paix sur terre, cette formation va vous donner une piqûre de rappel à la réalité.
|
||||
Plus de gens y assisteront, moins il y en aura pour faire de l'ultracrépidarianisme.
|
||||
|
||||
Je suis heureux et fier de l'avoir fait, et c'est avec enthousiasme que je vais m'atteler au deuxième volet.
|
||||
@@ -0,0 +1,2 @@
|
||||
file: images/DTaMGE.webp
|
||||
title: Illustration par DALL·E
|
||||
@@ -0,0 +1,2 @@
|
||||
file: images/mMfOpQ.png
|
||||
title: Utilisez le bouton "Brut" pour obtenir l'URL du fichier à rajouter à blocky
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
@@ -0,0 +1,429 @@
|
||||
---
|
||||
cover: images/DTaMGE.webp
|
||||
date: "2024-05-21T00:10:53+02:00"
|
||||
title: Blocky et Unbound sous NixOS
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
### Hardware
|
||||
|
||||
J'en ai marre des Raspberry Pi.
|
||||
Ça fait depuis longtemps que [je le dis](/interets/informatique/2021/02/28/rant-raspberry-pi-4/), et le temps n'a malheureusement pas corrigé certains défauts.
|
||||
Je vais oser l'affirmation :
|
||||
|
||||
**Il est impossible d'avoir un uptime décent pour faire un serveur d'un Raspberry Pi**, peu importe le type de serveur ou la génération de Raspberry Pi dont on parle.
|
||||
Ce sont des machines d'_expérimentation_, et malgré les soins que je leur apporte, je ne peux pas les utiliser comme des serveurs pour deux raisons :
|
||||
|
||||
- le réseau est instable (en particulier en Wifi mais c'est aussi vrai en ethernet pour les RPi qui en sont dotés, en tout cas le 4 comme on va le voir)
|
||||
- le système de stockage aux fraises (je ne parle pas des cartes SD mais du stockage USB)
|
||||
|
||||
Pour les caméras, ce n'est pas trop grave si l'une d'elles se déconnecte pendant quelques minutes.
|
||||
C'est beaucoup plus embêtant pour un serveur DNS, en substance [pi-hole](https://pi-hole.net/), hébergé depuis quelque temps sur un [Raspberry Pi 4](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/).
|
||||
La machine utilise l'[ISO officielle](https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit) de la fondation et il n'y a que pi-hole qui y soit installé.
|
||||
**Aucune configuration supplémentaire** n'est faite sur la machine.
|
||||
L'installation est parfaitement _vanilla_, sauf ce qui est installé par pi-hole.
|
||||
|
||||
Le Pi 4 est connecté en ethernet, et il boote depuis un SSD SATA en USB3.
|
||||
Je ne me fous pas de la gueule de cette machine quand même.
|
||||
|
||||
Occasionnellement, une fois par semaine ou peut-être plus, la machine _disparaît_ du réseau.
|
||||
Comme ça : pouf, plus de Raspberry Pi.
|
||||
Plus de DNS.
|
||||
Plus de SSH.
|
||||
Plus de pi-hole.
|
||||
Plus _rien_.
|
||||
Sans explication : pas de log, rien, que dalle, _peanuts_.
|
||||
|
||||
### Software
|
||||
|
||||
J'adore pi-hole.
|
||||
L'application fonctionne exactement comme je veux qu'elle le fasse.
|
||||
Je vois en temps réel les domaines demandés par le réseau, je peux black/whitelister un domaine en un clic, c'est très frugal, ça répond bien, bref, c'est un excellent logiciel.
|
||||
|
||||
Malgré ces éloges, j'ai trois "problèmes" :
|
||||
|
||||
- installer un upstream récursif sur la même machine n'est pas "simple" (c'est-à-dire que [c'est facile de copier/coller des commandes](https://docs.pi-hole.net/guides/dns/unbound/), mais les comprendre — et surtout comprendre pourquoi ça ne fonctionne pas — est une autre histoire)
|
||||
- installer un cluster de pi-hole est tout sauf trivial ([il y a moyen](https://discourse.pi-hole.net/t/clustered-pihole-ive-done-it/12716/7) mais ce n'est absolument pas propre)
|
||||
- pas d'installation sous NixOS (selon ma politique personnelle, docker n'est pas une option)
|
||||
|
||||
## Perdre pour gagner avec Blocky, Unbound et NixOS
|
||||
|
||||
Hors de question de re-tenter le coup avec AdGuard Home pour les raisons que j'ai déjà détaillées [ici](/interets/informatique/2023/06/21/migration-de-pi-hole-vers-adguard-home-et-digression/).
|
||||
Une alternative (parmi d'autres) est [blocky](https://github.com/0xERR0R/blocky).
|
||||
Une "petite" application écrite en Go, qui fait office de proxy DNS et de blocklist.
|
||||
Avec unbound en upstream, on obtient une solution _similaire_ à pi-hole.
|
||||
C'est la "stack" que l'on va installer sur un "vrai" serveur.
|
||||
|
||||
_Similaire_ parce que, "malheureusement", on va perdre l'UI, mais est-ce que ça sera vraiment un problème ?
|
||||
Pour l'instant, je ne sais pas...
|
||||
|
||||
### Pré-requis
|
||||
|
||||
Partons du principe qu'on a un serveur DNS fonctionnel sur le réseau (typiquement, le routeur ou le serveur DNS à remplacer).
|
||||
|
||||
On va installer Blocky et Unbound sur un serveur sous [NixOS](https://nixos.org/).
|
||||
|
||||
### Unbound
|
||||
|
||||
```nix
|
||||
{
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
resolveLocalQueries = false;
|
||||
|
||||
settings = {
|
||||
server = {
|
||||
interface = "127.0.0.1@5353";
|
||||
access-control = [ "127.0.0.1/0 allow" ];
|
||||
verbosity = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
On passe `resolveLocalQueries` à `false` pour qu'unbound ne pirate pas le `resolv.conf` : étant donné qu'il n'écoute pas sur le port standard, si on ne met pas cette directive, NixOS ne pourra plus résoudre des domaines après l'installation d'unbound.
|
||||
|
||||
`interface` et `access-control` ne servent respectivement qu'à indiquer comment le serveur doit écouter (en l'occurrence, uniquement depuis `127.0.0.1` sur le port `5353`) et n'autoriser que la machine locale à l'utiliser.
|
||||
|
||||
- [Consulter toutes les directives de configuration d'unbound pour NixOS](https://search.nixos.org/options?channel=23.11&from=0&size=50&sort=alpha_asc&type=packages&query=services.unbound).
|
||||
|
||||
Et c'est **tout** : tous les autres paramètres par défaut sont suffisants, nous n'avons besoin de rien d'autre.
|
||||
|
||||
```shell
|
||||
nix-os rebuild switch
|
||||
```
|
||||
|
||||
Et on s'assure que ça fonctionne :
|
||||
|
||||
```shell
|
||||
nix-shell -p dig # Shell temporaire pour lancer dig
|
||||
dig free.fr @127.0.0.1 -p 5353
|
||||
```
|
||||
|
||||
<pre><samp>
|
||||
; <<>> DiG 9.18.26 <<>> free.fr @127.0.0.1 -p 5353
|
||||
;; global options: +cmd
|
||||
;; Got answer:
|
||||
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22474
|
||||
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
|
||||
|
||||
;; OPT PSEUDOSECTION:
|
||||
; EDNS: version: 0, flags:; udp: 1232
|
||||
;; QUESTION SECTION:
|
||||
;free.fr. IN A
|
||||
|
||||
;; ANSWER SECTION:
|
||||
free.fr. 600 IN A 212.27.48.10
|
||||
|
||||
;; Query time: 67 msec
|
||||
;; SERVER: 127.0.0.1#5353(127.0.0.1) (UDP)
|
||||
;; WHEN: Mon May 20 00:49:10 CEST 2024
|
||||
;; MSG SIZE rcvd: 52
|
||||
</samp></pre>
|
||||
|
||||
On peut passer à la suite.
|
||||
|
||||
L'avantage avec NixOS (et plus généralement, les distros du même genre) c'est qu'à ce stade, si ça ne fonctionne pas, ça ne vient pas de la configuration 😁
|
||||
|
||||
### Blocky
|
||||
|
||||
```nix
|
||||
{
|
||||
services.blocky = {
|
||||
enable = true;
|
||||
settings = {
|
||||
# On peut utiliser plusieurs upstreams dans plusieurs groupes...
|
||||
upstreams = {
|
||||
groups = {
|
||||
default = [
|
||||
# Mais en l'occurrence, on va se contenter d'utiliser notre unbound
|
||||
"127.0.0.1:5353"
|
||||
];
|
||||
};
|
||||
};
|
||||
conditional = {
|
||||
# Si Blocky n'a pas déjà résolu un domaine, il demande à l'upstream.
|
||||
# Si on mettait false, on obtiendrait une erreur de résolution.
|
||||
fallbackUpstream = true;
|
||||
mapping = {
|
||||
# Ça c'est personnel : c'est 10.0.0.1 qui répond pour le domaine
|
||||
# home.arpa sur mon réseau parce que c'est le DHCP et qu'il stocke les
|
||||
# noms d'hôtes du réseau local
|
||||
"home.arpa" = "10.0.0.1";
|
||||
};
|
||||
};
|
||||
blocking = {
|
||||
blackLists = {
|
||||
ads = [
|
||||
# Là on ajoute les listes que l'on veut, à commencer par la plus
|
||||
# célèbre
|
||||
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
];
|
||||
};
|
||||
clientGroupsBlock = {
|
||||
default = [
|
||||
# Sans cette ligne, rien ne sera bloqué, tout sera envoyé à
|
||||
# l'upstream. Le nom doit correspondre à au moins une liste créée
|
||||
# dans `blackLists`
|
||||
"ads"
|
||||
];
|
||||
};
|
||||
};
|
||||
# Les ports d'écoute
|
||||
ports = {
|
||||
dns = 53;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Voyez que si l'on virait les lignes ne servant qu'à ouvrir et fermer des blocs de config, on n'aurait moins d'une dizaine de lignes de configuration.
|
||||
Si vous préférez quelque chose de plus condensé :
|
||||
|
||||
```nix
|
||||
{
|
||||
services.blocky.enable = true;
|
||||
services.blocky.settings.upstreams.groups.default = [ "127.0.0.1:5353" ];
|
||||
services.blocky.settings.conditional.fallbackUpstream = true;
|
||||
services.blocky.settings.conditional.mapping."home.arpa" = "10.0.0.1";
|
||||
services.blocky.settings.blocking.blackLists.ads = [
|
||||
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
];
|
||||
services.blocky.settings.clientGroupsBlock.default = [ "ads" ];
|
||||
services.blocky.settings.ports.dns = 53;
|
||||
}
|
||||
```
|
||||
|
||||
**On répète exactement la même configuration sur un deuxième serveur.**
|
||||
On obtient deux serveurs DNS capables de bloquer des domaines sur le réseau, mais, pour obtenir un véritable effet "cluster", il faut aller un peu plus loin.
|
||||
|
||||
Les directives de configuration de Blocky pour NixOS se résument à `enable` et `settings`, cette dernière acceptant une notation équivalent à celle de Blocky.
|
||||
On pourra donc utiliser "directement" [la documentation de Blocky](https://0xerr0r.github.io/blocky/v0.23/configuration/) pour le configurer dans NixOS.
|
||||
|
||||
### redis
|
||||
|
||||
J'utilise de toute façon redis sur mon serveur web, ce n'est pas bien compliqué de l'installer sur le reverse-proxy (qui est aussi une machine sous NixOS).
|
||||
|
||||
Je vais d'ailleurs considérer que le redis du serveur web (`10.0.2.2`) sera le maître du réseau, tandis que celui du reverse-proxy (`10.0.2.1`) sera l'esclave.
|
||||
|
||||
Le redis maître sera configuré comme suit :
|
||||
|
||||
```nix
|
||||
{
|
||||
services.redis.vmOverCommit = true;
|
||||
|
||||
services.redis.servers.blocky = {
|
||||
enable = true;
|
||||
bind = "0.0.0.0";
|
||||
port = 16379
|
||||
masterAuth = "secret";
|
||||
requirePass = "secret";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Notons que nous créons un service redis spécialement dédié à blocky.
|
||||
On applique [la modification que redis recommande](https://redis.io/docs/latest/develop/get-started/faq/#background-saving-fails-with-a-fork-error-on-linux) avec `services.redis.vmOverCommit = true;`.
|
||||
En outre, on fait écouter ce serveur sur un port différent du port original (`6379`) pour pouvoir continuer d'utiliser une autre instance de redis dédiée à d'autres usages.
|
||||
|
||||
Enfin, n'oubliez pas de changer le mot de passe (`secret`).
|
||||
|
||||
Et l'esclave :
|
||||
|
||||
```nix
|
||||
{
|
||||
services.redis.vmOverCommit = true;
|
||||
|
||||
services.redis.servers.blocky = {
|
||||
enable = true;
|
||||
bind = "0.0.0.0";
|
||||
masterAuth = "secret";
|
||||
requirePass = "secret";
|
||||
|
||||
slaveOf = {
|
||||
ip = "10.0.2.2";
|
||||
port = 16379;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Même configuration, mais en précisant simplement quel est le serveur maître.
|
||||
|
||||
Après quelques `nixos rebuild switch`, on devrait voir la sortie suivante sur le serveur maître :
|
||||
|
||||
```shell
|
||||
journalctl -u redis-blocky.service -f
|
||||
```
|
||||
|
||||
<pre><samp>
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: Running mode=standalone, port=16379.
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: Server initialized
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: Loading RDB produced by version 7.2.4
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: RDB age 0 seconds
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: RDB memory usage when created 0.98 Mb
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: Done loading RDB, keys loaded: 0, keys expired: 0.
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: DB loaded from disk: 0.000 seconds
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: Ready to accept connections tcp
|
||||
May 20 10:27:08 mac-mini-m1-de-richard redis[97580]: Ready to accept connections unix
|
||||
May 20 10:27:08 mac-mini-m1-de-richard systemd[1]: Started Redis Server - redis-blocky.
|
||||
May 20 10:27:42 mac-mini-m1-de-richard redis[97580]: Replica 10.0.2.1:16379 asks for synchronization
|
||||
May 20 10:27:42 mac-mini-m1-de-richard redis[97580]: Partial resynchronization request from 10.0.2.1:16379 accepted. Sending 0 bytes of backlog starting from offset 2087.
|
||||
</samp></pre>
|
||||
|
||||
Et sur l'esclave :
|
||||
|
||||
```shell
|
||||
journalctl -u redis-blocky.service -f
|
||||
```
|
||||
|
||||
<pre><samp>
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Ready to accept connections unix
|
||||
May 20 10:27:42 reverse-proxy systemd[1]: Started Redis Server - redis-blocky.
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Connecting to MASTER 10.0.2.2:16379
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: MASTER <-> REPLICA sync started
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Non blocking connect for SYNC fired the event.
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Master replied to PING, replication can continue...
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Trying a partial resynchronization (request c55ad3ed1037641cbbf6f8cc36a7e76bc64b59e5:2087).
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Successful partial resynchronization with master.
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: Master replication ID changed to 00484c469b8a3de337df088cadefc5e2687f2338
|
||||
May 20 10:27:42 reverse-proxy redis[48394]: MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
|
||||
</samp></pre>
|
||||
|
||||
Donc, a priori tout fonctionne.
|
||||
|
||||
Il ne reste plus qu'à intégrer redis à Blocky en modifiant sa configuration sur les deux serveurs :
|
||||
|
||||
```nix
|
||||
{
|
||||
services.blocky = {
|
||||
enable = true;
|
||||
settings = {
|
||||
# [...]
|
||||
redis = {
|
||||
address = "127.0.0.1:16379";
|
||||
password = "secret";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Dans un monde idéal, on aurait trois serveurs redis et on utiliserait [sentinel](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/), mais dans le cas présent, un système maître/esclave devrait suffire : c'est pourquoi on indique à chaque serveur blocky d'utiliser son propre serveur redis qui sera de toute façon répliqué sur l'autre serveur physique.
|
||||
|
||||
Après quelques instants, on devrait pouvoir voir la base de données de redis se remplir :
|
||||
|
||||
```shell
|
||||
redis-cli -p 16379 -a secret
|
||||
```
|
||||
|
||||
```ansi
|
||||
127.0.0.1:16379> KEYS *
|
||||
1) "blocky:cache:\x00\x01hosts.tweedge.net"
|
||||
2) "blocky:cache:\x00\x01blocklistproject.github.io"
|
||||
3) "blocky:cache:\x00\x1cgit.dern.ovh"
|
||||
4) "blocky:cache:\x00\x01git.dern.ovh"
|
||||
5) "blocky:cache:\x00\x1craw.githubusercontent.com"
|
||||
6) "blocky:cache:\x00\x1cblocklistproject.github.io"
|
||||
7) "blocky:cache:\x00\x01raw.githubusercontent.com"
|
||||
8) "blocky:cache:\x00\x1chosts.tweedge.net"
|
||||
```
|
||||
|
||||
Et on devrait voir plus ou moins la même chose sur les deux serveurs.
|
||||
|
||||
### Blacklist/whitelist personnelles
|
||||
|
||||
Évidemment, on peut modifier la configuration de Blocky pour ajouter ses propres black/whitelists :
|
||||
|
||||
```nix
|
||||
{
|
||||
services.blocky = {
|
||||
enable = true;
|
||||
settings = {
|
||||
# [...]
|
||||
blocking = {
|
||||
blackLists = {
|
||||
ads = [
|
||||
"someadsdomain.com"
|
||||
# [...]
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Mais cela impose de modifier les deux serveurs à chaque fois, puis `nixos rebuild switch`, etc.
|
||||
C'est chiant.
|
||||
Donc, la solution, c'est d'héberger ses listes dans un dépôt git.
|
||||
Du coup, on peut faire ça :
|
||||
|
||||
```nix
|
||||
{
|
||||
services.blocky = {
|
||||
enable = true;
|
||||
settings = {
|
||||
# [...]
|
||||
blocking = {
|
||||
blackLists = {
|
||||
externalLists = [
|
||||
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
];
|
||||
internalLists = [
|
||||
https://git.dern.ovh/Infrastructure/dns/raw/branch/main/blacklist.txt
|
||||
];
|
||||
};
|
||||
whiteLists = {
|
||||
internalLists = [
|
||||
https://git.dern.ovh/Infrastructure/dns/raw/branch/main/whitelist.txt
|
||||
];
|
||||
};
|
||||
};
|
||||
# [...]
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Il n'y a qu'à mettre à jour le dépôt git pour que, ponctuellement, Blocky mette à jour ses listes.
|
||||
Et si on est vraiment pressé, on peut toujours faire `systemctl restart blocky.service`.
|
||||
|
||||
On écrira alors notre blacklist comme un fichier `hosts` :
|
||||
|
||||
```txt
|
||||
0.0.0.0 cache.consentframework.com
|
||||
0.0.0.0 cdn.stripcash.com.c.footprint.net
|
||||
0.0.0.0 consentframework.com
|
||||
0.0.0.0 cookieless-data.com
|
||||
# etc
|
||||
```
|
||||
|
||||
Alors que la whitelist contiendra un domaine par ligne, tout simplement.
|
||||
|
||||
On utilisera alors le chemin vers le fichier brut, fourni par notre forge logicielle.
|
||||
|
||||

|
||||
|
||||
Il y a d'autres façons de faire : blocky peut aussi interpréter des fichiers locaux[^1].
|
||||
Mais j'ai estimé que pour mon cas d'usage, stocker mes black/whitelists dans Gitea était plus intéressant.
|
||||
|
||||
[^1]: <https://0xerr0r.github.io/blocky/v0.23/configuration/#blocking-and-whitelisting>
|
||||
|
||||
Je regrette juste de ne pas encore avoir compris s'il était possible de fournir à blocky la liste des listes à parser : j'aurais aimé stocker dans Gitea un fichier qui contient une liste d'URLs (contenant notamment <https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts> mentionné dans mes exemples, mais pas seulement), mais je n'ai pas — encore — compris comment faire ni même si c'était possible.
|
||||
|
||||
## Conclusion
|
||||
|
||||
La gestion des black/whitelists est un peu plus pénible que sous pi-hole : je ne peux plus afficher en temps réel la liste des domaines demandés, et cliquer sur l'un d'eux pour le (dé)bloquer.
|
||||
Il est possible de partiellement remédier à cela en installant une stack [Prometheus/Grafana](https://0xerr0r.github.io/blocky/v0.23/prometheus_grafana/), ce que je n'ai pas envie de faire pour le moment, pas juste pour blocky.
|
||||
|
||||
Pour le moment, cette solution me satisfait, et, finalement, l'interface web ne me manque pas.
|
||||
Après tout, une fois que tout est en place, on ne touche plus à rien, et la supervision se fait aussi bien en ligne de commande.
|
||||
Et je ne trifouille pas tous les jours les black/whitelists.
|
||||
|
||||
Notons tout de même que tout cela est bien plus simple et rapide à installer, et surtout [à sauvegarder et à restaurer](/interets/informatique/2024/05/04/maintenance-terminee/) que pi-hole sur un Raspberry Pi.
|
||||
|
||||
Deux instances de blocky couplées à deux instances de redis sur deux serveurs physiques "fiables" devraient m'éviter quelques déconvenues à l'avenir...
|
||||
Reference in New Issue
Block a user