Le service api clonait le dépôt et compilait le JAR sur le serveur à chaque « docker compose build » (Dockerfile.api + secret ssh_key + CACHEBUST). La prod rebuildait donc ce que la CI avait déjà buildé, sans garantie que les deux partent du même commit — et aucune image publiée n'atteignait jamais la prod. Elle tire maintenant …/bonsai-api:main et porte le label watchtower.enable : le redéploiement suit tout seul chaque merge sur main, comme pour Luz. Le webapp, lui, continue d'être buildé depuis les sources — d'où le secret ssh_key conservé. Prérequis : de quoi tirer les images privées de l'org Bonsai. Le PAT de Watchtower n'a aujourd'hui le scope read:package que sur Luz ; sans extension à Bonsai, le pull échoue en silence (/v1/update répond 200, la prod ne bouge pas). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bonsai — Stack complète
Stack Docker Compose unifiée pour l'application Bonsai : base de données, API et webapp.
Les deux composants ne se déploient pas de la même façon :
api— image tirée du registre Gitea (git.goutailler-olivier.com/bonsai/bonsai-api:main), publiée par la CI du dépôtBonsai-api(.gitea/workflows/images.yml) à chaque merge surmain. Le redéploiement est automatique : le conteneur porte le labelcom.centurylinklabs.watchtower.enable=true, donc Watchtower (../watchtower/) le recrée dès qu'une nouvelle image est publiée. Rien à builder sur le serveur.webapp— toujours buildé depuis les sources de la branchemaindu dépôtBonsai-webapp. La clé SSH est transmise au build via un secret BuildKit — elle n'est jamais gravée dans les couches de l'image.
Services
| Service | Image | Provenance |
|---|---|---|
db |
postgres:16-alpine |
— |
api |
git.goutailler-olivier.com/bonsai/bonsai-api:main |
CI de Bonsai-api (merge sur main) |
webapp |
node:22-alpine → nginx:alpine |
build local depuis Bonsai-webapp (branche main) |
Prérequis
- Docker avec BuildKit activé (Docker 23+)
- Une clé SSH ayant accès au dépôt Gitea (
git.goutailler-olivier.com:2222) — pour le build duwebapp - Réseau Docker externe
proxy(Traefik) - De quoi tirer les images privées de l'org Bonsai : soit un
docker login git.goutailler-olivier.comfait une fois en root sur le serveur, soit lesREPO_USER/REPO_PASSde la stack Watchtower, dont le PAT doit porter le scoperead:packagesur l'org Bonsai. Sans cela, Watchtower échoue silencieusement à tirer l'image (unauthorized: reqPackageAccess) et la prod reste sur l'ancienne version, alors que l'appel à/v1/updaterépond bien 200.
Démarrage
# 1. Configurer les variables d'environnement
cp .env.example .env
# Éditer .env : définir POSTGRES_PASSWORD et SSH_KEY_PATH
# 2. Tirer l'image de l'API + builder le webapp
docker compose pull
docker compose build
# 3. Démarrer la stack
docker compose up -d
Mise à jour
L'API se met à jour toute seule à chaque merge sur main de Bonsai-api (CI → registre → Watchtower). Aucune action ici.
Pour forcer un redéploiement, ou pour rebuilder le webapp depuis le dernier commit de sa branche main :
./deploy.sh
CACHEBUST (posé par le script) invalide uniquement l'étape clone+build du webapp. Les couches précédentes (installation des outils, image de base) restent en cache — le build reste rapide.
Revenir à une version précédente de l'API
Chaque publication pose aussi un tag immuable sha-<court>. Pour épingler un commit :
image: git.goutailler-olivier.com/bonsai/bonsai-api:sha-ccc20bf
puis docker compose up -d api. Watchtower ne touche pas à un tag figé qui ne bouge plus — repasser sur :main pour réactiver le suivi automatique.
Arrêt
docker compose down
Les données PostgreSQL sont persistées dans ~/Applications/data/bonsai/db_data et les fichiers uploadés dans ~/Applications/data/bonsai/uploads.