🚀 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
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.
113 lines
5.3 KiB
YAML
113 lines
5.3 KiB
YAML
name: 🚀 Docker Build and Push
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
# Un push qui ne touche que la doc ne reconstruit rien : aucun Markdown n'entre dans
|
|
# l'image. Un push mêlant code et doc lance toujours la CI.
|
|
paths-ignore:
|
|
- '**.md'
|
|
- 'docs/**'
|
|
# Chaque nuit (heure UTC) : les images publiées sont testées et, si apt leur propose des mises
|
|
# à jour, reconstruites et republiées.
|
|
# Voir docs/decisions/0005-mises-a-jour-nocturnes-pilotees-par-apt.md.
|
|
schedule:
|
|
- cron: '30 3 * * *'
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build-and-push:
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
matrix:
|
|
pg_version: [15, 16, 17, 18]
|
|
# Aucune action externe, construction par le démon Docker du runner (sans Buildx) dont le
|
|
# cache persiste d'une CI à l'autre, et une seule construction par version : l'image testée
|
|
# est celle qui est poussée. Voir docs/decisions/0004-ci-sans-action-externe.md.
|
|
env:
|
|
IMAGE: gitea.killinger.fr/${{ github.repository }}
|
|
PREVIOUS: postgres-ts-vectors-previous:pg${{ matrix.pg_version }}
|
|
steps:
|
|
# Le seul commit poussé, sans historique : c'est tout ce que la construction lit.
|
|
- name: 📥 Checkout code
|
|
env:
|
|
TOKEN: ${{ github.token }}
|
|
run: |
|
|
git init -q .
|
|
git fetch -q --depth 1 "https://oauth2:${TOKEN}@gitea.killinger.fr/${{ github.repository }}.git" "${{ github.sha }}"
|
|
git checkout -q FETCH_HEAD
|
|
|
|
- name: 🔐 Login to Gitea Registry
|
|
env:
|
|
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
|
|
run: echo "$DOCKER_TOKEN" | docker login gitea.killinger.fr -u maxime.killinger --password-stdin
|
|
|
|
# On demande à apt, dans l'image publiée, s'il lui reste des mises à jour :
|
|
# - oui, ou image jamais publiée : nouvelle clé APT_REFRESH, les couches apt sont rejouées ;
|
|
# - non : la clé de l'image publiée (label apt-refresh) est reprise et le cache sert.
|
|
# L'exécution planifiée ne reconstruit ni ne pousse alors rien : elle teste l'image publiée.
|
|
# L'image publiée est gardée sous $PREVIOUS : les tests y créent une base, que l'image
|
|
# reconstruite doit savoir reprendre.
|
|
- name: 🔎 Check for updates
|
|
id: updates
|
|
run: |
|
|
refresh=""; previous=""
|
|
if docker pull -q "$IMAGE:pg${{ matrix.pg_version }}" >/dev/null 2>&1; then
|
|
docker tag "$IMAGE:pg${{ matrix.pg_version }}" "$PREVIOUS"; previous="$PREVIOUS"
|
|
upgrade=$(docker run --rm --entrypoint sh "$PREVIOUS" -c \
|
|
'apt-get update -qq -o APT::Update::Error-Mode=any && apt-get -s upgrade --with-new-pkgs')
|
|
if pending=$(echo "$upgrade" | grep '^Inst'); then
|
|
echo "Mises à jour disponibles :"; echo "$pending"
|
|
else
|
|
refresh=$(docker image inspect -f '{{ index .Config.Labels "fr.killinger.apt-refresh" }}' "$PREVIOUS")
|
|
fi
|
|
fi
|
|
build=true
|
|
if [ -n "$refresh" ] && [ "${{ github.event_name }}" = schedule ]; then
|
|
echo "Image publiée à jour : rien à reconstruire"; build=false; previous=""
|
|
fi
|
|
echo "refresh=${refresh:-$(date -u +%Y%m%dT%H%M%SZ)}" >> "$GITHUB_OUTPUT"
|
|
echo "build=$build" >> "$GITHUB_OUTPUT"
|
|
echo "previous=$previous" >> "$GITHUB_OUTPUT"
|
|
|
|
# `--pull` : l'image de base (tensorchord/vchord-postgres) est vérifiée à chaque construction,
|
|
# pour recevoir une republication sous la même étiquette malgré le cache persistant.
|
|
# Labels OCI propres à la construction ; les labels fixes sont dans le Dockerfile.
|
|
- name: 📦 Build Docker image
|
|
if: steps.updates.outputs.build == 'true'
|
|
run: |
|
|
docker build --pull \
|
|
--build-arg PG_VERSION=${{ matrix.pg_version }} \
|
|
--build-arg APT_REFRESH=${{ steps.updates.outputs.refresh }} \
|
|
--label fr.killinger.apt-refresh=${{ steps.updates.outputs.refresh }} \
|
|
--label org.opencontainers.image.url=https://gitea.killinger.fr/${{ github.repository }} \
|
|
--label org.opencontainers.image.revision=${{ github.sha }} \
|
|
--label org.opencontainers.image.version=pg${{ matrix.pg_version }} \
|
|
--label org.opencontainers.image.created="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
-t "$IMAGE:pg${{ matrix.pg_version }}" .
|
|
|
|
# La même commande qu'en local. Sans reconstruction, c'est l'image publiée qui est testée.
|
|
- name: 🧪 Tests
|
|
run: bash tests.sh "$IMAGE:pg${{ matrix.pg_version }}" ${{ steps.updates.outputs.previous }}
|
|
|
|
# Poussée seulement si les tests sont passés.
|
|
- name: 🚀 Push Docker image
|
|
if: steps.updates.outputs.build == 'true'
|
|
run: docker push -q "$IMAGE:pg${{ matrix.pg_version }}"
|
|
|
|
# Voir docs/decisions/0006-latest-reste-sur-postgresql-17.md.
|
|
- name: 🏷️ Tag latest (PG17 only)
|
|
if: steps.updates.outputs.build == 'true' && matrix.pg_version == 17
|
|
run: |
|
|
docker tag "$IMAGE:pg17" "$IMAGE:latest"
|
|
docker push -q "$IMAGE:latest"
|
|
|
|
# Cache borné : il ne doit pas remplir le disque de Tower.
|
|
- name: 🧹 Cleanup Docker images
|
|
if: always()
|
|
run: |
|
|
docker rmi "$PREVIOUS" >/dev/null 2>&1 || true
|
|
docker builder prune -f --keep-storage 8GB >/dev/null
|
|
docker image prune -f >/dev/null
|