
Filtre actif, cliquez pour en enlever un tag :
Cliquez sur un ou plusieurs tags pour appliquer un filtre sur la liste des notes de type "Journaux" :
Résultat de la recherche (23 notes) :
Lundi 23 juin 2025
Journal du lundi 23 juin 2025 à 11:49
Dans la slide 18 de la conférence "Nubo: the French government sovereign cloud" du FOSDEM 2025, j'ai découvert l'article "Un logiciel libre est un produit et un projet" (https://bzg.fr/fr/logiciel-produit-projet/).
Je viens de réaliser une lecture active de cet article. Je l'ai trouvé très intéressant. Je vais garder à l'esprit cette distinction "produit / projet".
Voici quelques extraits de cet article.
La popularité de GitHub crée des attentes sur ce qu'est un logiciel « open source » (comme disent les jeunes) ou « libre » (comme disent les vrais). Il s'agit d'un dépôt de code avec une licence, une page de présentation (souvent nommée README), un endroit où remonter des problèmes (les issues), un autre où proposer corrections et évolutions (les pull requests) et, parfois, d'autres aspects : un espace de discussion, des actions lancées à chaque changement, un lien vers le site web officiel, etc.
Je trouve que ce paragraphe décrit très bien les fonctions remplies par un dépôt GitHub :
Pourquoi distinguer produit et projet ?
Cette distinction permet d'abord de décrire une tension inhérente à tout logiciel libre : d'un côté les coûts de distribution du produit sont quasi-nuls, mais de l'autre, l'énergie à dépenser pour maintenir le projet est élevée. Lorsque le nombre d'utilisateurs augmente, la valeur du produit augmente aussi, de même que la charge qui pèse sur le projet. C'est un peu comme l'amour et l'attention : le premier se multiplie facilement, mais le deuxième ne peut que se diviser.
Je partage cet avis 👍️.
C'est d'ailleurs cette tension qu'on trouve illustrée dans l'opposition entre les deux sens de fork. Dans le sens technique, forker un code source ne coûte rien. Dans le sens humain, forker un projet demande beaucoup d'effort : il faut recréer la structure porteuse, à la fois techniquement (hébergement du code, site web, etc.), juridiquement (éventuelle structure pour les droits, etc.) et humainement (attirer les utilisateurs et les contributeurs vers le projet forké.)
J'approuve 👍️.
Côté morale, il y a les principes et les valeurs. Les principes sont des règles que nous nous donnons pour les suivre ; les valeurs expriment ce qui nous tient à coeur. Les deux guident notre action.
Intéressant 🤔
Un logiciel libre est un produit qui suit un principe, celui d'octroyer aux utilisateurs les quatre libertés. Il est porté par un projet ayant des valeurs, dont voici des exemples : l'importance de ne pas utiliser des plateformes dont le code source n'est pas libre pour publier un code source libre, celle d'utiliser des outils libres pour communiquer, de produire un logiciel accessible et bien documenté, d'être à l'état de l'art technique, d'être inclusif dans les contributions recherchées, d'avoir des règles pour prendre des décisions collectivement, de contribuer à la paix dans le monde, etc.
Je trouve cela très bien exprimé 👍️.
Jeudi 12 juin 2025
Journal du jeudi 12 juin 2025 à 15:51
Je viens de publier : Projet 30 - "Setup une instance personnelle d'Open WebUI connectée à OpenRouter".
Jeudi 5 juin 2025
Liste d'issues pour gibbon-replay de juin 2025
Mon objectif dans cette note est de rassembler une liste d'issues que j'ai à l'esprit pour le projet gibbon-replay.
Dans cette note, les issues sont décrites en moins de 280 caractères, de manière approximative et sans doute un peu idiosyncrasique. Elles sont présentées dans un ordre quelconque.
- Dans le README, expliquer pourquoi j’ai créé ce projet et son ambition. Indiquer clairement que l’objectif est de rester simple à déployer (architecture monolithique) et que les utilisateurs plus ambitieux peuvent se tourner vers des solutions comme Posthog ou OpenReplay.
- Toujours dans le README, indiquer comme dans l'introduction de SilverBullet : « gibbon-replay is optimized for people with a hacker mindset ».
- [x] En tant qu'utilisateur, je peux visualiser l'espace mémoire total utilisé par l'ensemble des sessions. Issue GitHub : #4.
- [x] En tant qu'utilisateur, je peux visualiser l'espace mémoire consommé par chaque session individuellement.
- [x] En tant qu'utilisateur, je peux visualiser la durée de chaque session. Issue Github : #3.
- [x] En tant qu'utilisateur, je peux consulter, session par session, la présence ou non des actions utilisateur. Issue GitHub : #6.
- [ ] Optimiser la densité d'affichage de la liste des sessions en regroupant plusieurs données dans des cellules multilignes.
- En tant qu'utilisateur, dans la page liste des sessions, je peux appliquer un filtre sur les champs suivants : durée, taille mémoire ou mouvement de souris.
- En tant qu'utilisateur, dans la page détail d'une session, je peux visualiser les titres et les URLs des pages décrivant le parcours effectué par l'utilisateur.
- En tant qu'utilisateur, je peux visualiser un résumé textuel, du parcours utilisateur d'une session, rédigé par un agent conversationnel de petite taille.
- En tant qu'utilisateur avancé, je peux effectuer des recherches avancées sur le contenu des URLs présentes dans le parcours utilisateur. Par exemple, l'utilisateur peut saisir du code JavaScript qui permet de tester une condition sur toutes les URLs parcourues lors d'une session. Si la condition est positive, alors le résultat doit être sauvegardé dans un champ json de la session.
- En tant qu'utilisateur avancé, je peux rechercher des informations spécifiques dans le contenu des URLs présentes dans le parcours d'une session. Par exemple, je peux saisir un code JavaScript personnalisé pour tester une condition (comme la présence d'un
utm_source
oucampaign
) sur toutes les URLs parcourues. Si cette condition est vérifiée, les résultats correspondants sont stockés dans un champ json dans la session, permettant d'effectuer par la suite un filtre sur la liste des sessions. - User Story qui ressemble à la précédente : en tant qu'utilisateur avancé, je peux rechercher les balises HTML qui ont déclenché un événement "click" durant un parcours de session. Pour ce faire, il peut saisir du code JavaScript personnalisé pour tester une condition spécifique (comme la présence d'un attribut, d'une classe, etc.) sur ces balises. Les résultats de cette recherche sont enregistrés dans un champ JSON associé à la session, permettant d'effectuer par la suite un filtre sur la liste des sessions.
- En tant qu'utilisateur, je peux activer / désactiver l'envoi de notifications web sur des filtres de session, filtres avancés inclus.
- Permettre à une instance gibbon-replay d'enregistrer et de gérer plusieurs sites en même temps, en single-tenant.
- Ajouter un support multiutilisateurs — toujours en mode single-tenant. Permettre l'authentification par magic link et par username et password.
- Permettre la gestion des utilisateurs par API REST.
- Permettre de supprimer automatiquement des sessions en fonction de critères de filtres.
- En tant qu'utilisateur, je peux supprimer des sessions en mode batch.
Prochaine étape : créer ces issues plus détaillé dans : https://github.com/stephane-klein/gibbon-replay/issues
Mercredi 28 mai 2025
Bilan de poc-sveltekit-custom-server
Contexte et objectifs
Dans le projet gibbon-replay, j'ai besoin d'exécuter une tâche une fois par jour pour supprimer des anciennes sessions.
gibbon-replay utilise une base de données SQLite qui ne dispose pas nativement de fonctionnalité de type Time To Live, comme on peut trouver dans Clickhouse.
SQLite ne propose pas non plus d'équivalent à pg_cron — ce qui est tout à fait normal étant donnée que SQLite est une librairie et non pas un service à part entière.
Le projet gibbon-replay est un monolith (j'aime les monoliths !) et je souhaite conserver ce choix.
Face à ces contraintes, une solution consiste à intégrer une solution comme Cron for Node.js directement dans l'application gibbon-replay.
Je pense que je dois implémenter cela dans un SvelteKit Custom Server, ce qui me permettrait d'exécuter cette tâche de purge à intervalles réguliers tout en conservant l'architecture monolithique.
Il y a quelques jours, j'ai décidé de tester cette idée dans un POC nommé : poc-sveltekit-custom-server
.
J'ai aussi décidé d'expérimenter un objectif supplémentaire dans ce POC : lancer la migration du modèle de données dès le lancement du monolith et non plus lors de la première requête HTTP reçue par le service.
Enfin, je souhaitais ne pas dégrader l'expérience développeur (DX), c'est à dire, je souhaitais pouvoir continuer à simplement utiliser :
$ pnpm run dev
ou
$ pnpm run build
$ pnpm run preview
sans différence avec un projet SvelteKit "vanilla".
Résultats du POC et enseignements
Tout d'abord, le POC fonctionne parfaitement 🙂, sans dégrader l'expérience développeur (DX), qui ressemble à ceci :
$ mise install
$ pnpm install
$ pnpm run load-seed-data
Start data model migration…
Data model migration completed
Start load seed data...
seed data loaded
Lancement du projet en mode développement :
$ pnpm run dev
Start data model migration…
Data model migration completed
Server started on http://localhost:5173 in development mode
Lancement du projet "buildé" :
$ pnpm run build
$ pnpm run preview
Start data model migration…
Data model migration completed
Server started on http://localhost:3000 in production mode
Les migrations et les données "seed.sql" se trouvent dans le dossier /sqls/
.
Le SvelteKit Custom Server est implémenté dans le fichier src/server.js
et il ressemble à ceci :
import express from 'express';
import cron from 'node-cron';
import db, { migrate } from '@lib/server/db.js';
const isDev = process.env.ENV !== 'production';
migrate(); // Lancement de la migration du modèle de donnée dès de lancement du serveur
// Configuration d'une tâche exécuté toutes les heures
cron.schedule(
'0 * * * *',
async () => {
console.log('Start task...');
console.log(db().query('SELECT * FROM posts'));
console.log('Task executed');
}
);
async function createServer() {
const app = express();
...
Personnellement, je trouve cela simple et minimaliste.
Point de difficulté
SvelteKit utilise des "module alias", comme par exemple $lib
.
Problème, par défaut, ces "module alias" ne sont pas configurés lors de l'exécution de node src/server.js
.
Pour me permettre d'importer dans src/server.js
des modules de src/lib/server/*
comme :
import db, { migrate } from '@lib/server/db.js';
j'ai utilisé la librairie esm-module-alias
.
Ceci complexifie un peu le projet, j'ai dû configurer ceci dans /package.json
:
{
"scripts": {
"dev": "ENV=development node --loader esm-module-alias/loader --no-warnings src/server.js",
"preview": "ENV=production node --loader esm-module-alias/loader --no-warnings build/server.js",
...
"aliases": {
"@lib": "src/lib/"
}
}
- ajout de
--loader esm-module-alias/loader --no-warnings
- et la section
aliases
Et dans /vite.config.js
:
export default defineConfig({
plugins: [sveltekit()],
resolve: {
alias: {
'@lib': path.resolve('./src/lib')
}
}
});
- ajout de
alias
Le fichier src/server.js
contient du code spécifique en fonction de son contexte d'exécution ("dev" ou "buildé") :
if (isDev) {
const { createServer: createViteServer } = await import('vite');
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom'
});
app.use(vite.middlewares);
} else {
const { handler } = await import('./handler.js');
app.use(handler);
}
En mode "dev" il utilise Vite et en "buildé" il utilise le fichier build/handler.js
généré par SvelteKit build en mode SSR.
Le fichier src/server.js
est copié vers le dossier /build/
lors de l'exécution de pnpm run build
.
J'ai testé le bon fonctionnement du POC dans un container Docker.
J'ai intégré au projet un deployment-playground : https://github.com/stephane-klein/poc-sveltekit-custom-server/tree/main/deployment-playground.
La suite...
Je souhaite rédiger cette note en anglais et la publier sur https://github.com/sveltejs/kit/discussions et https://old.reddit.com/r/sveltejs/ afin :
- d'avoir des retours d'expérience
- de découvrir des méthodes alternatives
- et partager la méthode que j'ai utilisée, qui sera peut-être utile à d'autres développeurs Svelte 🙂
Update du 2025-05-29 à 00:07 - Je viens de publier ceci :
- https://github.com/sveltejs/kit/discussions/13841
- https://old.reddit.com/r/sveltejs/comments/1kxtz1u/custom_sveltekit_server_dev_production_with/?
2025-05-29 : voir J'ai découvert la fonctionnalité SvelteKit Shared hooks init
Mardi 20 mai 2025
Journal du mardi 20 mai 2025 à 17:03
#JaiLu la discussion GitHub du projet nginx-proxy : "How can we scapre metrics from nginx-proxy container".
J'y ai découvert le Prometheus exporter : nginx-prometheus-exporter (https://github.com/nginx/nginx-prometheus-exporter). Il semble être l'exporter officiel de nginx pour Prometheus.
Je pense tester son installation et sa configuration d'ici à quelques jours.
Liste des éléments que je souhaite étudier :
- Est-ce qu'il existe un dashboard Grafana qui permet de consulter par domaine et peut-être par URLs :
- le temps moyen de réponse
- la mediane de temps de réponse
- le temps de réponse au 90ème percentile (p90)
- le temps de réponse au 95ème percentile (p95)
Je pense que la metric nginxplus_upstream_server_response_time
me permettra peut-être d'obtenir cette information.
J'ai identifié ce dashboard Grafana mais il ne semble pas afficher les informations dont j'ai besoin.
Mercredi 14 mai 2025
Journal du mercredi 14 mai 2025 à 13:25
Depuis que j'ai commencé ma mission chez la DINUM, je me retrouve à rencontrer de nombreuses personnes en présentiel.
En ligne — sur Internet, le partage d'informations personnelles est simple et fluide. Je peux facilement communiquer mon prénom, mon nom, et des URLs avec précision. C'est pourquoi j'ai créé https://sklein.xyz, porte d'entrée vers toutes les informations me concernant.
Quand une rencontre s'effectue en présentiel, les choses sont plus compliquées.
Il y a deux semaines, par exemple, j'échangeais avec un collègue assis en face de moi. Après plusieurs minutes, il a lancé la discussion et a cherché à mieux me connaître. Ma présentation a été maladroite et je doute qu'il ait retenu mon prénom ou mon nom...
Lorsque j'ai commencé à l'interroger à mon tour, j'ai découvert qu'il était l'un des deux créateurs du projet Open Food Facts, un projet que j'admire depuis plusieurs années.
Cette expérience m'a fait prendre conscience une nouvelle fois de deux choses : j'aurais vraiment apprécié avoir des cartes de visite à partager, et si je n'avais pas posé de questions, j'aurais manqué l'opportunité d'échanger pendant près d'une heure sur un projet qui me passionne.
Suite à cela, j'ai pour objectif :
- Concevoir une carte de visite personnelle
- Créer un sticker personnalisé à apposer sur le capot de mon Thinkpad T14s
Par le passé, j'avais le sticker suivant sur mon laptop, acheté chez Redbubble :
Ce dessin suscitait des discussions autour du Yak shaving à presque chacune de mes nouvelles rencontres. Je trouvais cela à la fois amusant et efficace pour briser la glace.
Informations que je souhaite intégrer sur ces supports :
- Simplement l'URL : https://sklein.xyz
- Et mon https://notes.sklein.xyz/avatar_stephane-512x512.jpg
Rien de plus.
Pour me permettre d'analyser les sources de connexion (tracking), je souhaite :
- Imprimer l'URL https://sklein.xyz/1/ sur le sticker de laptop
- Imprimer l'URL https://sklein.xyz/2/ sur les cartes de visite
Samedi 26 avril 2025
Journal du samedi 26 avril 2025 à 22:43
J'ai publié une première version du Projet 28 - "Publier un repository playground de déploiement de Open WebUI basé sur docker-compose.yml".
https://github.com/stephane-klein/open-webui-deployment-playground/
Je vais maintenant attaquer le Projet 29 - "Publier un repository playground de déploiement de Open WebUI sur un cluster Kubernetes".
Vendredi 25 avril 2025
Journal du vendredi 25 avril 2025 à 18:33
Au mois de janvier, j'ai écrit :
Voici mes prochaines #intentions d'amélioration de ma workstation :
- ...
- Essayer de remplacer les services ChatGPT ou Claude.ia par Open WebUI.
- ...
Le hasard de la vie fait que je commence une mission professionnelle pour la DINUM en lien avec Open WebUI : Ablert Conversation.
Au mois de décembre, j'ai déjà installé et testé rapidement Open WebUI connecté à Scaleway Generative APIs, mais je n'ai pas pris le temps de le faire avec rigueur.
Dans les prochains jours, je souhaite réaliser les projets suivants :
Lundi 14 avril 2025
J'ai publié le projet "pg_back-docker-sidecar"
Je viens de terminer une première itération de travail sur Projet 27 - "Créer un POC de pg_back".
Le résultat se trouve dans le repository GitHub : pg_back-docker-sidecar
J'ai passé en tout 17 h 30 sur ce projet, écriture de notes incluse.
Ce projet a évolué par rapport à mon objectif initial :
Initialement, dans ce dépôt, je voulais tester l'implémentation de
pg_back
déployé dans un conteneur Docker comme un « sidecar » pour sauvegarder une base de données PostgreSQL déployée via Docker.Et progressivement, j'ai changé l'objectif de ce projet. Il contient maintenant
- le code source pour construire une image Docker Sidecar nommée
stephaneklein/pg_back-docker-sidecar:2.5.0-delete-local-file-after-upload
- un tutoriel étape par étape qui présente tous les aspects de l'utilisation de ce conteneur
- un espace de travail qui me permet de contribuer au projet pg_back en amont :
./src/
Voici tous les éléments testés dans le tutoriel :
pg_back
est dépolyé dans un Docker sidecar- L'instance PostgreSQL est sauvegardée dans une instance Minio
- Les archives sont chiffrées avec age
- Les archives sont générées au format
custom
- J'ai documenté une méthode pour télécharger une archive dans un dossier du workspace du développeur
- J'ai documenté une méthode pour restaurer l'archive dans un serveur PostgreSQL déployé via Docker
- J'ai testé le fonctionnement du système d'expiration des archives
- J'ai testé la fonctionnalité de "purge" automatique
Éléments que j'ai implémentés
L'image Docker proposée par pg_back ne contient pas de scheduler de type cron et ne suit pas les recommandations The Twelve-Factors App.
J'ai décidé d'implémenter ma propre image Docker stephaneklein/pg_back-docker-sidecar:2.5.0-delete-local-file-after-upload
avec les ajouts suivants :
- Support de configuration basé sur des variables d'environnement, par exemple :
pg_back:
image: stephaneklein/pg_back-docker-sidecar:2.5.0-delete-local-file-after-upload
environment:
POSTGRES_HOST: postgres1
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
POSTGRES_DBNAME: postgres
POSTGRES_PASSWORD: password
BACKUP_CRON: ${BACKUP_CRON:-0 3 * * *}
UPLOAD: "s3"
UPLOAD_PREFIX: "foobar"
...
- Intégration de Supercronic pour exécuter pg_back régulièrement, une fonctionnalité de type cron
Patch envoyé en upstream
J'ai proposé deux patchs à pg_back :
- Add upload_prefix option to pg_back.conf example file
- Add the --delete-local-file-after-upload to delete local file after upload
Le premier patch est totalement mineur.
Dans la version actuelle 2.5.0
de pg_back, les archives dump ne sont pas supprimées du filesystem de container après l'upload vers l'Object Storage.
Ce choix me perturbe, car je préfère éviter de surcharger le disque avec des fichiers d'archives volumineux qui risquent de saturer l'espace disponible.
Pour éviter cela, j'ai implémenté "Add the --delete-local-file-after-upload to delete local file after upload" qui permet de supprimer les fichiers intermédiaires après upload.
Bilan
J'ai réussi à effectuer un cycle complet de la sauvegarde à la restauration.
J'ai décidé d'utiliser pg_back pour mes sauvegardes PostgreSQL automatique vers Object Storage.
J'ai déprécié le projet restic-pg_dump-docker
pour inviter à utiliser pg_back.
Idée d'amélioration
#JaimeraisUnJour créer et implémenter les issues suivantes.
1.
Implémenter une commande pg_back snapshots
pour lister les snapshots sous une forme facilement lisible par un humain. Actuellement, le retour de la commande ressemble à ceci :
$ pg_back --list-remote s3
foobar/hba_file_2025-04-14T14:58:08Z.out.age
foobar/hba_file_2025-04-14T14:58:39Z.out.age
foobar/ident_file_2025-04-14T14:58:08Z.out.age
foobar/ident_file_2025-04-14T14:58:39Z.out.age
foobar/pg_globals_2025-04-14T14:58:08Z.sql.age
foobar/pg_globals_2025-04-14T14:58:39Z.sql.age
foobar/pg_settings_2025-04-14T14:58:08Z.out.age
foobar/pg_settings_2025-04-14T14:58:39Z.out.age
foobar/postgres_2025-04-14T14:58:08Z.dump.age
foobar/postgres_2025-04-14T14:58:39Z.dump.age
Je ne trouve pas ce rendu agréable à lire. J'aimerais afficher quelque chose qui ressemble à la sortie de restic. Par exemple :
$ pg_back snapshots
ID Date Folder
---------------------------------------
40dc1520 2025-04-14 14:58:08 foobar
79766175 2025-04-14 14:58:39 foobar
2.
Implémenter un système de suppressions des archives basé sur des règles plus avancées, comme celle de restic
3.
Implémenter un refactoring vers cobra pour utiliser des sous-commandes (subcommands) et éviter le mélange entre paramètres et commandes.
Vendredi 11 avril 2025
Journal du vendredi 11 avril 2025 à 10:24
Suite à 2025-04-10_2034, je viens de créer le Projet 27 - "Créer un POC de pg_back".
Jeudi 10 avril 2025
Journal du jeudi 10 avril 2025 à 20:34
Je me relance sur mes sujets de backup de PostgreSQL.
Au mois de février dernier, j'ai initié le « Projet 23 - "Ajouter le support pg_basebackup incremental à restic-pg_dump-docker" ».
J'ai ensuite publié les notes suivantes à ce sujet :
À ce jour, je n'ai pas fini mes POC suivants :
poc-pg_basebackup_incremental est la seule méthode que j'ai réussi à faire fonctionner totalement.
#JaimeraisUnJour terminer ces POC.
Aujourd'hui, je m'interroge sur les motivations qui m'ont conduit en 2020 à intégrer restic dans mon projet restic-pg_dump-docker
. Avec le recul, l'utilisation de cet outil pour la simple sauvegarde d'archives pg_dump me semble désormais moins évidente qu'à l'époque.
J'ai fait ce choix peut-être pour bénéficier directement du support des fonctionnalités suivantes :
- Uploader vers différents Object Storage : S3-compatible Storage
- Le système de rétention : Removing snapshots according to a policy
- Le chiffrement : Encryption
- Et naïvement, je pensais peut-être pouvoir utiliser le système de déduplication des données : Backups and Deduplication
Après réflexion, je pense que pour la sauvegarde d'archives pg_dump, les fonctionnalités de déduplication et de sauvegarde incrémentale offertes par restic génèrent en réalité une surconsommation d'espace disque et de ressources CPU sans apporter aucun bénéfice.
J'ai ensuite effectué quelques recherches pour savoir s'il existait un système de sauvegarde PostgreSQL basé sur pg_dump et un système d'upload vers Object Storage et #JaiDécouvert pg_back (https://github.com/orgrim/pg_back/).
En 2020, quand j'ai créé restic-pg_dump-docker
, je pense que je n'avais pas retenu pg_back car celui-ci était minimaliste et ne supportait pas encore l'upload vers de l'Object Storage.
En 2025, pg_back supporte toutes les fonctionnalités dont j'ai besoin :
pg_back is a dump tool for PostgreSQL. The goal is to dump all or some databases with globals at once in the format you want, because a simple call to pg_dumpall only dumps databases in the plain SQL format.
Behind the scene, pg_back uses pg_dumpall to dump roles and tablespaces definitions, pg_dump to dump all or each selected database to a separate file in the custom format. ...
Features
- ...
- Choose the format of the dump for each database
- ...
- Dump databases concurrently
- ...
- Purge based on age and number of dumps to keep
- Dump from a hot standby by pausing replication replay
- Encrypt and decrypt dumps and other files
- Upload and download dumps to S3, GCS, Azure, B2 or a remote host with SFTP
Je souhaite :
- Créer et publier un playground pour tester pg_back
- Si le résultat est positif, alors je souhaite ajouter une note en introduction de
restic-pg_dump-docker
pour inviter à ne pas utiliser ce projet et renvoyer les lecteurs vers le projet pg_back.
Lundi 17 mars 2025
Expérimentation de migration de deux utilisateurs grand public vers des laptops sous Fedora
J'envisage de proposer à ma mère et à ma compagne de se prêter à une expérimentation : une transition en douceur vers des portables sous GNU/Linux, avec mon assistance complète durant tout le processus.
Leur situation actuelle :
- Pour ma compagne : d'un Macbook Air 13" 3ième génération, modèle de 2015, acheté en 2018 à moins de 1000 €, qui tourne bien entendu sous MacOS. Usage principal : navigation web.
- Pour ma maman : un laptop de plus de 10 ans sous MS Windows. Usage principal : Microsoft Word, Microsoft Excel, impression, navigation web.
Choix de la distribution Linux : une Fedora version n-1 (voir la note 2024-01-29 pour plus d'informations sur ce choix).
Plus précisément, j'envisage d'utiliser l'édition Fedora Silverblue, une variante immutable (ou « atomic ») de Fedora Workstation qui propose l'environnement de bureau GNOME.
Je souhaite configurer et rendre très facilement accessibles les applications Signal et RustDesk :
- Signal pour facilement échanger avec moi en cas de difficulté ;
- RustDesk pour me permettre de prendre directement le contrôle du desktop à distance, pour les aider.
Pour ma maman, je souhaite lui faire tester Libre Office. Pour éviter de la perturber avec les formats de fichier, je souhaite configurer Libre Office pour qu'il enregistre par défaut au format de Microsoft Word et Microsoft Excel.
Je souhaite installer quelques extensions GNOME pour que l'environnement Linux ressemble au maximum à MS Windows, par exemple :
Je souhaite leur proposer un laptop qui répond aux caractéristiques suivantes :
- si possible à moins de 1000 € ;
- entre 14 et 15 pouces, avec une résolution verticale de 1200 pixels minimum ;
- 16Go de RAM ;
- un trackpad et un châssis avec un maximum de qualité ;
- idéalement convertible en 2 en 1 ou 3 en 1 ;
- silencieux ;
- support GNU/Linux parfait ;
Pour le moment, j'ai identifié les modèles suivants :
Dimanche 9 février 2025
Journal du dimanche 09 février 2025 à 17:05
J'utilise depuis 2019 les containers Docker suivant en sidecar pour sauvegarder automatiquement et régulièrement directement un volume Docker et un volume PostgreSQL :
restic-pg_dump-docker est très pratique et facile d'usage, voici un exemple d'utilisation dans un docker-compose.yml
:
restic-pg-dump:
image: stephaneklein/restic-pg_dump:latest
environment:
AWS_ACCESS_KEY_ID: "admin"
AWS_SECRET_ACCESS_KEY: "password"
RESTIC_REPOSITORY: "s3:http://minio:9000/bucket1"
RESTIC_PASSWORD: secret
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_HOST: postgres
POSTGRES_DB: postgres
postgres:
image: postgres:16.1
environment:
POSTGRES_USER: postgres
POSTGRES_DB: postgres
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- ./volumes/postgres/:/var/lib/postgresql/data/
healthcheck:
test: ["CMD", "sh", "-c", "pg_isready -U $$POSTGRES_USER -h $$(hostname -i)"]
interval: 10s
start_period: 30s
Il suffit de configurer les paramètres d'accès à l'instance PostgreSQL à sauvegarder et ceux de l'Object Storage où uploader les backups. Rien de plus, 😉.
Pour plus de paramètres, voir la section Configuration du README.md.
Cependant, je ne suis pas totalement satisfait de restic-pg_dump-docker. Cet outil effectue seulement des sauvegardes complètes de la base de données.
Ceci ne pose généralement pas trop de problème quand la base de données est d'une taille modeste, mais c'est bien plus compliqué dès que celle-ci fait, par exemple, plusieurs centaines de mégas.
Pour faire face à ce problème, j'ai exploré fin 2023 une solution basée sur pgBackRest : Implémenter un POC de pgBackRest.
Je suis plus ou moins arrivé au bout de ce POC mais je n'ai pas été satisfait du résultat.
Je n'ai pas réussi à configurer pgBackRest en "pure Docker sidecar".
De plus, j'ai trouvé la restauration du backup difficile à exécuter.
Un élément a changé depuis septembre 2024. Comme je le disais dans cette note 2024-11-03_1151, la version 17 de PostgreSQL propose de nouvelles options de sauvegarde :
- l'outil pg_basebackup qui permet de réaliser les sauvegardes incrémentales,
- et un nouvel utilitaire, pg_combinebackup, qui permet de reconstituer une sauvegarde complète à partir de sauvegardes incrémentales.
Cette nouvelle méthode semble apporter certains avantages par rapport aux solutions basées sur WAL comme pgBackRest ou barman.
Une consommation d'espace réduite :
In this mailing list thread on the Postgres-hackers mailing list, Jakub from EDB ran a test. This is a pgbench test. The idea is that the data size doesn't really change much throughout this test. This is a 24 hour long test. At the start the database is 3.3GB. At the end, the database is 4.3GB. Then, as it's running, it's continuously running pgbench workloads. In those 24 hours, if you looked at the WAL archive, there were 77 GB of WAL produced.
That's a lot of WAL to replay if you wanted to restore to a particular point in time within that timeframe!
Jakub ran one full backup in the beginning and then incremental backups every two hours. The full backup in the beginning is 3.4 GB, but then all the 11 other backups are 3.5 in total, they're essentially one 10th of a full backup size.
Une vitesse de restauration grandement accélérée :
A 10x time safe
What Jakub tested then was the restore to a particular point in time. Previously, to restore to a particular point in time would take more than an hour to replay the WAL versus in this case because we have more frequent, incremental backups, it's going to be much, much faster to restore. In this particular test case 78 minutes compared to 4 minutes. This is a more than a 10 times improvement in recovery time. Of course you won't necessarily always see this amount of benefit, but I think this shows why you might want to do this. It is because you want to enable more frequent backups and incremental backups are the way to do that.
Nombre 2024 j'ai passé un peu de temps à étudier les solutions de backup qui utilisent la nouvelle fonctionnalité de PostgreSQL 17, mais je n'avais rien trouvé
Je viens à nouveau de chercher dans les archives de Postgre Weely, sur GitHub, sur le forum de Restic, etc., et je n'ai rien trouvé d'intéressant.
#JaiDécidé de prendre les choses en main et de faire évoluer le projet restic-pg_dump-docker pour y ajouter le support du backup incrémental de PostgreSQL 17.
Voir : Projet 23 - "Ajouter le support pg_basebackup incremental à restic-pg_dump-docker".
Dimanche 12 janvier 2025
Journal du dimanche 12 janvier 2025 à 12:56
Je viens de publier : Projet 21 - "Rechercher un AI code assistant qui ressemble à Cursor mais pour Neovim".
Lundi 18 novembre 2024
Journal du lundi 18 novembre 2024 à 21:47
Je viens de créer les projets suivants :
Lundi 14 octobre 2024
Journal du lundi 14 octobre 2024 à 11:23
J'ai commencé le projet Projet 14 - Script de base d'installation d'un serveur Ubuntu LTS.
Samedi 21 septembre 2024
Journal du samedi 21 septembre 2024 à 11:42
Je souhaite essayer de créer un #playground qui intègre UnoCSS et qui permet de builder un fichier HTML qui contient toutes les dépendances.
Mercredi 11 septembre 2024
Journal du mercredi 11 septembre 2024 à 11:14
Dans la branche gibbon-replay-js
du projet Idée d'un outil de session recoding web minimaliste basé sur rrweb, j'ai essayé sans succès d'extraire du code dans un package Javascript.
Pour le moment l'import suivant ne fonctionne pas :
import gibbonReplayJs from 'gibbon-replay-js';
Quand je lance pnpm run build
, j'ai l'erreur suivante :
$ pnpm run build
...
x Build failed in 336ms
error during build:
src/routes/(record)/+layout.svelte (2:11): "default" is not exported by "packages/gibbon-replay-js/dist/index.js", imported by "src/routes/(record)/+layout.svelte".
file: /home/stephane/git/github.com/stephane-klein/gibbon-replay-poc/src/routes/(record)/+layout.svelte:2:11
1: <script>
2: import gibbonReplayJs from 'gibbon-replay-js';
Et quand je lance pnpm run dev
, j'ai l'erreur suivante :
$ pnpm run dev
...
11:21:21 [vite] Error when evaluating SSR module /packages/gibbon-replay-js/dist/index.js:
|- ReferenceError: exports is not defined
at eval (/home/stephane/git/github.com/stephane-klein/gibbon-replay-poc/packages/gibbon-replay-js/dist/index.js:5:23)
at instantiateModule (file:///home/stephane/git/github.com/stephane-klein/gibbon-replay-poc/node_modules/.pnpm/vite@5.4.3/node_modules/vite/dist/node/chunks/dep-BaOMuo4I.js:52904:11)
11:21:21 [vite] Error when evaluating SSR module /src/routes/(record)/+layout.svelte:
|- ReferenceError: exports is not defined
at eval (/home/stephane/git/github.com/stephane-klein/gibbon-replay-poc/packages/gibbon-replay-js/dist/index.js:5:23)
at instantiateModule (file:///home/stephane/git/github.com/stephane-klein/gibbon-replay-poc/node_modules/.pnpm/vite@5.4.3/node_modules/vite/dist/node/chunks/dep-BaOMuo4I.js:52904:11)
Suite à cette frustration, j'ai envie de créer un projet, sans doute nommé javascript-package-playground
dans lequel je souhaite étudier les sujets suivants :
- mise en place d'une librairie
/packages/lib1/
qui contient une librairie javascript, qui peut être importé avec la méthode ECMAScript Modules ; - mise en place d'une app NodeJS dans
/services/app1_nodejs/
qui utiliselib1
; - mise en place d'une app SvelteKit dans
/services/app2_sveltekit/
qui utiliselib1
dans un fichier coté server et dans une page web coté browser ; - mise en place d'une librairie
/packages/lib2
qui utiliselib1
Je souhaite décliner ces 2 libs et 2 apps sous plusieurs déclinaisons d'implémentation :
- avec le build basé sur tsc
- avec le build basé sur esbuild
- avec le build basé sur Babel (Javascript)
- et sans build
Et le tout encore dans deux déclinaisons : Javascript et TypeScript.
Je ne souhaite pas supporter CommonJS qui est sur le déclin, remplacé par ECMAScript Modules.
Dans ce playground, je souhaite aussi me perfectionner dans l'usage de pnpm link
et pnpm workspace.
#JeMeDemande si ces connaissances sont totalement maitrisées et évidentes chez mes amis développeurs Javascript 🤔 et s'ils les considèrent comme "basiques".
Jeudi 29 août 2024
Journal du jeudi 29 août 2024 à 13:23
Voici les nouveautés depuis ma dernière itération du Projet 11 - "Première version d'un moteur web PKM".
Ce commit contient le résultat du travail du Projet 13, c'est-à-dire le refactoring de PostgreSQL vers Elasticsearch ainsi que la page /src/routes/search
qui permet à la fois d'effectuer une recherche sur le contenu des notes et un filtrage de type and
sur les tags.
Une démo est visible ici https://notes.develop.sklein.xyz/
Ma Developer eXperience avec Elasticsearch est excellente. J'ai trouvé toutes les fonctionnalités dont j'avais besoin.
Je pense que mon utilisation des Fleeting Note n'est pas la bonne. Je pense que les notes que je qualifie de Fleeting Note sont en réalité des Diary notes ou Journal notes.
J'ai donc décidé de :
- [x] Renommer partout
fleeting_note
enjournal_notes
Après implémentation, j'ai réalisé que j'ai fait l'erreur de mélanger l'implémentation de le page qui affiche la liste des notes antéchronologiques et la page de recherche.
Pour être efficace, le résultat de la page recherche doit être affiché en fonction du scoring de la recherche, alors que les pages listes de notes par date de publication.
J'ai donc décidé de :
- [x] Implémenter une page
/diaries/
(pour la cohérence des path en anglais, je préfère "diaries" à "journaux") qui affiche une liste de notes de type Diary notes ;- [x] Cette page doit permettre un filtrage par tags
- [x] Implémenter une page
/notes/
qui affiche une liste des notes qui ne sont pas de type Diary notes, comme des Evergreen Note, Hub note…- [x] Contrairement à la page liste des Diary notes, cette page de liste ne doit pas afficher le contenu des notes, mais seulement le titre des notes ;
- [x] Je propose de classer ces titres de notes par ordre alphabétique ;
- [x] Je propose aussi de séparer ces notes par lettre,
A
,B
… c'est-à-dire un index alphabétique. - [x] Cette page doit permettre un filtrage par tags
- [x] Refactoring la page
/search/
pour ordonner le résultat de la recherche par scoring.- [x] Cette page doit afficher le contenu des notes avec highligthing ;
- [x] Cette page doit permettre un filtrage sur les types de notes, pour le moment Diary notes et Evergreen Note.
- [x] Cette page doit permettre un filtrage par tags
Au moment où j'écris ces lignes, je ne sais pas encore comment je vais gérer les opérateurs or
, (
.
Pour le moment, le filtrage multi tags est effectué avec des and
.
Samedi 17 août 2024
Journal du samedi 17 août 2024 à 16:09
Je viens de créer Projet 13 - "POC Elasticsearch sur un PKM".
Mardi 30 juillet 2024
Journal du mardi 30 juillet 2024 à 14:55
Je viens de créer Projet 12 - "Implémentation nodemailer-scaleway-transport".
Mercredi 10 juillet 2024
Journal du mercredi 10 juillet 2024 à 09:41
Suite à 2024-07-09_0846 (Projet 5) et suite à la publication de poc-meilisearch-blog-sveltekit
en 2023, je souhaite tester l'intégration de Typesense à obsidian-vault-to-apache-age-poc
en complément de pg_search.
J'ai bien conscience que Typesense fait doublon avec pg_search, mais mon objectif dans ce projet est de comparer les résultats de Typesense avec ceux de pg_search.
J'espère que cet environnement de travail me permettra d'itérer afin de répondre à cette question.
Idéalement, j'aimerais uniquement utiliser pg_search afin de mettre en œuvre un seul serveur de base de données et de bénéficier de la mise à jour automatique de l'index du moteur de recherche :
A BM25 index must be created over a table before it can be searched. This index is strongly consistent, which means that new data is immediately searchable across all connections. Once an index is created, it automatically stays in sync with the underlying table as the data changes. (from)
Lundi 21 août 2023
Journal du lundi 21 août 2023 à 11:57
Pour le moment, j'ai passé 17h sur le Projet GH-289 - Créer un simulateur de manque à gagner suite à une rupture conventionnelle, licenciement économique ou licenciement simple.
Je ne comprends pas comment j'ai fait pour y passer autant de temps.
Peut-être le cumul de la recherche d'information juridique, le refactoring UX de la page 🤔.
À noter que je ne suis pas satisfait de cette version de l'UX.
Le projet est déployé sur Vercel à l'adresse suivante : https://comparateur-rupture-conventionnelle-cdi.sklein.xyz/
Fin de la liste des notes.