Files
postgres-ts-vectors/CLAUDE.md
T
maxime.killinger 7de55c5655
🚀 Docker Build and Push / build-and-push (15) (push) Successful in 5m29s
🚀 Docker Build and Push / build-and-push (16) (push) Successful in 6m10s
🚀 Docker Build and Push / build-and-push (17) (push) Successful in 5m20s
🚀 Docker Build and Push / build-and-push (18) (push) Successful in 5m21s
PG18 de retour, mises à jour nocturnes, tests de reprise et documentation
Image
- Étape `base` commune : tous les paquets sont mis à niveau (PostgreSQL à la
  dernière mineure, pgvector, Debian). L'image de base de VectorChord restait
  figée à la version de sa publication.
- En-têtes du serveur épinglés sur la version du serveur installé. PG18 avait
  été retiré parce que TimescaleDB, compilé avec des en-têtes 18.6, était chargé
  par un serveur 18.3 (`undefined symbol: palloc0_mul`).
- Sonde de santé avec l'utilisateur et la base du conteneur : en `postgres`,
  elle écrivait une erreur FATAL au journal dès que POSTGRES_USER était défini.
- Label `base.name` corrigé : il reprenait la version du paquet au lieu de la
  version majeure.

CI
- PG18 ajouté à la matrice.
- Exécution nocturne : apt est interrogé dans l'image publiée ; elle n'est
  reconstruite et republiée que s'il lui reste des mises à jour, sinon elle est
  seulement testée. Lancement manuel possible.
- `docker-build.yml` supprimé : l'ancien workflow à actions externes tournait
  encore à chaque push, en double de `docker.yml`.
- `paths-ignore` : un push de documentation seule ne lance pas la CI.
- Labels `version`, `url` et `fr.killinger.apt-refresh`.

Tests
- `tests.sh`, la même commande en local et en CI : utilisateur et base autres
  que `postgres`, version majeure du serveur, présence des cinq extensions,
  redémarrage, et reprise d'une base créée par l'image publiée.

Documentation
- README en vitrine, CLAUDE.md, docs/architecture.md,
  docs/exploitation/publication.md, six décisions, docs/a-faire.md.
2026-10-02 17:55:42 +02:00

8.5 KiB

postgres-ts-vectors — consignes

Image Docker de PostgreSQL avec TimescaleDB, VectorChord, pgvector et PostGIS, publiée pour PostgreSQL 15 à 18 dans le registre Gitea. Le dépôt ne contient que la construction de l'image, ses scripts de démarrage et ses tests. Architecture : docs/architecture.md. Choix de conception : docs/decisions/. Points ouverts : docs/a-faire.md.

Commandes

# Construire une version (PG_VERSION : 15, 16, 17 ou 18 ; 18 par défaut)
docker build --build-arg PG_VERSION=17 -t postgres-ts-vectors:pg17 .

# Rejouer la mise à niveau des paquets, que le cache garderait sinon telle quelle
docker build --build-arg PG_VERSION=17 --build-arg APT_REFRESH=$(date +%F) -t postgres-ts-vectors:pg17 .

# Essayer une autre version de TimescaleDB sans toucher au Dockerfile
docker build --build-arg PG_VERSION=17 --build-arg TIMESCALEDB_VERSION=2.30.2 -t postgres-ts-vectors:essai .

# Tests de l'image
./tests.sh postgres-ts-vectors:pg17

# Tests, plus reprise d'une base créée par l'image publiée
docker pull gitea.killinger.fr/maxime.killinger/postgres-ts-vectors:pg17
./tests.sh postgres-ts-vectors:pg17 gitea.killinger.fr/maxime.killinger/postgres-ts-vectors:pg17

# Mises à jour qu'apt propose à une image publiée (ce que la CI regarde chaque nuit)
docker run --rm --entrypoint sh gitea.killinger.fr/maxime.killinger/postgres-ts-vectors:pg17 -c \
  'apt-get update -qq && apt-get -s upgrade --with-new-pkgs | grep ^Inst'
  • Tests : tests.sh IMAGE [IMAGE_PRECEDENTE], en local comme en CI. Il démarre l'image avec un utilisateur et une base autres que postgres, vérifie que le serveur a la version majeure de l'étiquette, joue tests/test-*.sql dans l'ordre, redémarre le serveur, puis, si une image précédente est donnée, crée une base avec elle (tests/reprise-1-semis.sql) et la reprend avec l'image testée (tests/reprise-2-controle.sql). Conteneurs et volume sont jetables.
  • Lint : aucun outil configuré.
  • CI (.gitea/workflows/docker.yml) : construit, teste et publie les quatre versions à chaque push sur main, sauf si tous les fichiers modifiés sont des .md ou sous docs/ (paths-ignore). Chaque nuit, elle teste les images publiées et reconstruit celles qui ont des mises à jour. Détail : docs/exploitation/publication.md.

Conventions

  • Une image par version majeure, construite par le même Dockerfile avec PG_VERSION. Rien n'y est propre à une version : ce qui en dépend se lit dans PG_MAJOR, fourni par l'image de base.
  • Versions épinglées dans le Dockerfile (0003) : TIMESCALEDB_VERSION et VCHORD_VERSION. Les changer suit la procédure de docs/exploitation/publication.md, et met à jour le tableau et les badges du README.md.
  • Le reste vient d'apt, à jour (0002) : PostgreSQL, pgvector, PostGIS, Debian. Aucune version de paquet n'est écrite dans le Dockerfile, sauf les en-têtes du serveur, épinglés sur la version du serveur installé.
  • Nouvelle extension : l'installer dans l'étape finale du Dockerfile, l'ajouter à init-extensions.sh, à la liste contrôlée par tests/test-1-config.sql, lui écrire un tests/test-N-nom.sql, et l'ajouter aux deux fichiers tests/reprise-*.sql.
  • Nouvelle version majeure de PostgreSQL : l'ajouter à la matrice de la CI, au tableau et au badge du README.md, et vérifier le point de montage du volume (docs/architecture.md).
  • Tests SQL : chaque fichier commence par \set ON_ERROR_STOP on et lève une exception quand un contrôle échoue. Ils ne supposent ni l'utilisateur ni la base postgres.
  • CI sans action externe (0004) : des commandes git et docker, jamais de uses:.
  • Commentaires : en français. Le « pourquoi » local reste à côté du code. Les tests SQL tests/test-*.sql et les scripts de démarrage sont encore commentés en anglais : on les traduit quand on les modifie.

Pièges connus

  • Changer la version de TimescaleDB rend une base existante inutilisable jusqu'à sa mise à niveau. L'image ne contient que la bibliothèque de sa version : toute requête échoue avec could not access file "$libdir/timescaledb-2.28.3" tant que ALTER EXTENSION timescaledb UPDATE n'a pas été exécuté, en première instruction d'une session psql -X. pg_isready répond pourtant, et le conteneur paraît sain.
  • Des en-têtes plus récents que le serveur cassent TimescaleDB au chargement (undefined symbol: palloc0_mul), sans erreur à la compilation. C'est ce qui arrive si l'on installe postgresql-server-dev sans mettre le serveur à niveau.
  • La couche apt-get upgrade est mise en cache comme les autres. Une construction locale ne reprend les mises à jour qu'avec un nouvel APT_REFRESH.
  • PG_VERSION a deux sens. Avant le premier FROM, c'est l'argument de construction (18). Dans les étapes, c'est la variable d'environnement de l'image de base, la version du paquet au moment où TensorChord l'a construite (18.3-1.pgdg12+1). Elle reste telle quelle dans l'image publiée, alors que le serveur est mis à niveau : la version du serveur se lit par postgres --version.
  • Le point de montage du volume change avec PostgreSQL 18 (docs/architecture.md). Jusqu'à 17, un volume monté sur /var/lib/postgresql reste vide : les données partent dans un volume anonyme.
  • init-extensions.sh ne s'exécute qu'à l'initialisation d'un volume vide. Une extension ajoutée à l'image n'apparaît pas dans une base existante : il faut l'y créer à la main.
  • Remplacer la commande du conteneur remplace shared_preload_libraries. Sans timescaledb,vchord, les deux extensions ne se chargent pas.
  • L'enveloppe du point d'entrée parcourt tout le volume à chaque démarrage (chown -R) : le démarrage s'allonge avec le nombre de fichiers de la base.
  • Le serveur temporaire de l'initialisation répond déjà aux requêtes, par le socket, avant que les extensions soient créées. Un test qui attend seulement une réponse démarre trop tôt : tests.sh attend aussi PostgreSQL init process complete dans le journal.
  • docker logs … | grep -q échoue sous pipefail alors que le motif est trouvé : grep -q ferme le tube à la première correspondance. tests.sh lit le journal en entier avant de chercher.
  • Une exécution nocturne qui échoue aux tests ne publie rien et recompile la nuit suivante : la clé APT_REFRESH n'est gardée que par l'image publiée.
  • Chaque reconstruction déclenchée par apt recompile TimescaleDB : l'étape de compilation part de l'étape mise à niveau.

Git

  • Messages de commit en français. Jamais de trailer Co-Authored-By.
  • Ne pas pousser sans demande explicite : un push sur main republie les quatre images, dont latest, que d'autres projets utilisent comme base de données.
  • En cas d'échec de push : retenter. Après deux échecs rapprochés, parler d'indisponibilité probablement temporaire de Gitea, sans mettre en cause les identifiants.

Documentation

  • README.md : la vitrine du dépôt. Il résume et renvoie, le détail vit ici et dans docs/.
  • CLAUDE.md : commandes, conventions, pièges connus.
  • docs/architecture.md : étapes de construction, démarrage, données.
  • docs/exploitation/ : CI, mises à jour, changement de version.
  • docs/decisions/ : décisions numérotées et figées.
  • docs/a-faire.md : points ouverts.

Règles :

  1. Un fait, un seul endroit. Ailleurs, un lien, jamais une copie.
  2. La doc décrit le présent. Pas de dates, de « corrigé le », ni de récit. L'historique va dans les messages de commit, le « pourquoi » d'un choix dans une décision.
  3. Une décision est numérotée et figée (0001-titre.md). On ne la modifie pas : une nouvelle décision la remplace et le dit.
  4. a-faire.md ne contient que l'ouvert. Un point terminé est supprimé, pas coché.
  5. La doc est mise à jour dans le même commit que le code qu'elle décrit. Sinon, la tâche n'est pas terminée.
  6. Un commentaire cite un document par son nom de fichier, jamais par un numéro de section.
  7. Un fichier au-delà de ~300 lignes se découpe.