Docker : images API et front publiées sur ghcr.io, installation sans cloner le dépôt

Après chaque CI verte sur main (et sur un tag vX.Y.Z), le workflow Images construit
parenthese-api et parenthese-web en amd64 et arm64, les pousse sur ghcr.io, puis teste
une installation dans un dossier vide avec docker-compose.yml et .env pour seuls fichiers.
docker-compose.yml tire ces images (PARENTHESE_VERSION, latest par défaut) et garde le
build depuis les sources en repli. Demande faite sur r/GenealogieFR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
IliesAllaliandClaude Opus 5.5 committed 2026-10-09 14:24:19 +02:00
1 parent 4bdf7aa1f3
commit 3c263a708d
5 files changed
+183 -4

No files matched your search

+5
View File
@@ -34,6 +34,11 @@ CORS_ORIGIN=http://localhost
# MEDIA_QUOTA_PER_TREE_MB=5120
# MEDIA_PENDING_QUOTA_PER_TREE_MB=500
# ── Images ────────────────────────────────────────────────────────────────────
# Version des images ghcr.io/iliesallali/parenthese-api et parenthese-web : latest (dernière
# version de main), ou une version figée, par exemple 1.0.
# PARENTHESE_VERSION=latest
# ── Web ───────────────────────────────────────────────────────────────────────
# Port publié sur la machine hôte (80 = http://localhost sans préciser de port).
WEB_PORT=80
+149
View File
@@ -0,0 +1,149 @@
name: Images
# Publie les images Docker de l'API et du front sur ghcr.io, pour un auto-hébergement sans le code
# source : docker-compose.yml + .env suffisent.
# - après une CI réussie sur un push sur main : tags `latest` et `sha-<commit>`
# - sur un tag de version vX.Y.Z : tags `X.Y.Z` et `X.Y`
# Puis l'installation est testée dans un dossier vide, avec ces deux seuls fichiers.
on:
workflow_run:
workflows:
- CI
types:
- completed
branches:
- main
push:
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: images-${{ github.event.workflow_run.head_sha || github.ref }}
cancel-in-progress: false
jobs:
publish:
name: Build and push (${{ matrix.image }})
if: >-
github.repository == 'IliesAllali/parenthese' &&
(
github.event_name != 'workflow_run' ||
(
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_repository.full_name == 'IliesAllali/parenthese'
)
)
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- image: parenthese-api
context: backend
file: backend/Dockerfile
- image: parenthese-web
context: .
file: Dockerfile.web
steps:
# Sur workflow_run, le commit exact que la CI a validé, pas la tête de main au moment du run.
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
persist-credentials: false
- name: Short commit
id: commit
run: echo "sha=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_OUTPUT"
- uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Tags and labels
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ghcr.io/iliesallali/${{ matrix.image }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable=${{ github.event_name == 'workflow_run' }}
type=raw,value=sha-${{ steps.commit.outputs.sha }}
labels: |
org.opencontainers.image.revision=${{ github.event.workflow_run.head_sha || github.sha }}
org.opencontainers.image.licenses=PolyForm-Noncommercial-1.0.0
- name: Build and push
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: ${{ matrix.context }}
file: ${{ matrix.file }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image }}
cache-to: type=gha,mode=max,scope=${{ matrix.image }}
compose-only:
name: Install from the images only
needs: publish
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
packages: read
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
path: src
persist-credentials: false
# Tant que les paquets ne sont pas publics, le pull demande une connexion.
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Empty folder with docker-compose.yml and .env only
run: |
set -euo pipefail
mkdir parenthese
cp src/docker-compose.yml src/.env.example parenthese/
cd parenthese
cp .env.example .env
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 24)|" .env
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -base64 48)|" .env
echo "PARENTHESE_VERSION=sha-$(git -C ../src rev-parse --short=7 HEAD)" >> .env
ls -A
- name: docker compose up -d (pull, no build)
working-directory: parenthese
run: docker compose up -d --pull always --no-build --wait --wait-timeout 300
- name: Smoke test through the web port
run: bash src/tools/docker-smoke.sh http://localhost
- name: Containers and logs on failure
if: failure()
working-directory: parenthese
run: |
docker compose ps -a
docker compose logs --no-color --timestamps
+12 -2
View File
@@ -32,6 +32,14 @@ cd parenthese
cp .env.example .env
```
Le clone est facultatif. Les images de l'API et du front sont publiées sur le registre de GitHub (`ghcr.io/iliesallali/parenthese-api` et `ghcr.io/iliesallali/parenthese-web`, en amd64 et arm64), deux fichiers suffisent donc :
```bash
mkdir parenthese && cd parenthese
curl -fsSLO https://raw.githubusercontent.com/IliesAllali/parenthese/main/docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/IliesAllali/parenthese/main/.env.example -o .env
```
Ouvrez `.env` et remplissez les deux valeurs vides :
- `POSTGRES_PASSWORD` : un mot de passe pour la base (lettres et chiffres).
@@ -43,7 +51,7 @@ Puis :
docker compose up -d
```
Le premier démarrage construit les images, applique les migrations de la base, puis sert l'application sur [http://localhost](http://localhost). Créez votre compte depuis l'écran d'accueil : le premier compte est un compte comme les autres, il n'y a pas d'administrateur global.
Le premier démarrage télécharge les images (ou les construit depuis les sources si elles sont introuvables), applique les migrations de la base, puis sert l'application sur [http://localhost](http://localhost). Créez votre compte depuis l'écran d'accueil : le premier compte est un compte comme les autres, il n'y a pas d'administrateur global.
Trois conteneurs tournent : `db` (PostgreSQL 16), `api` (l'API Node) et `web` (nginx qui sert le front et relaie l'API). Seul `web` est exposé, sur le port choisi par `WEB_PORT` (80 par défaut). Si ce port est déjà pris, changez `WEB_PORT` dans `.env` et adaptez `CORS_ORIGIN` en conséquence.
@@ -88,9 +96,11 @@ Le script `deploy/backup.sh` fait la même chose (dump PostgreSQL, archive des m
### Mettre à jour
```bash
git pull && docker compose up -d --build
docker compose pull && docker compose up -d
```
`latest` suit la branche main. Pour rester sur une version, renseignez `PARENTHESE_VERSION` dans `.env` (par exemple `1.0`). Depuis un clone, `git pull && docker compose up -d --build` reconstruit depuis les sources.
Les migrations de base de données s'appliquent toutes seules au démarrage de l'API. Faites une sauvegarde avant, par habitude.
## Développer
+12 -2
View File
@@ -38,6 +38,14 @@ cd parenthese
cp .env.example .env
```
You can also skip the clone. The API and front-end images are published on GitHub's registry (`ghcr.io/iliesallali/parenthese-api` and `ghcr.io/iliesallali/parenthese-web`, for amd64 and arm64), so two files are enough:
```bash
mkdir parenthese && cd parenthese
curl -fsSLO https://raw.githubusercontent.com/IliesAllali/parenthese/main/docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/IliesAllali/parenthese/main/.env.example -o .env
```
Open `.env` and fill in the two empty values:
- `POSTGRES_PASSWORD`: a password for the database (letters and digits only).
@@ -49,7 +57,7 @@ Then:
docker compose up -d
```
The first start builds the images, applies the database migrations, then serves the app on [http://localhost](http://localhost). Create your account from the home screen. The first account is an account like any other, there is no global administrator.
The first start downloads the images (or builds them from the source when they can't be pulled), applies the database migrations, then serves the app on [http://localhost](http://localhost). Create your account from the home screen. The first account is an account like any other, there is no global administrator.
Three containers run: `db` (PostgreSQL 16), `api` (the Node API) and `web` (nginx, which serves the front end and proxies the API). Only `web` is exposed, on the port set by `WEB_PORT` (80 by default). If that port is taken, change `WEB_PORT` in `.env` and update `CORS_ORIGIN` to match.
@@ -94,9 +102,11 @@ The `deploy/backup.sh` script does the same (PostgreSQL dump, media archive, che
### Updating
```bash
git pull && docker compose up -d --build
docker compose pull && docker compose up -d
```
`latest` follows the main branch. To stay on a version, set `PARENTHESE_VERSION` in `.env` (for example `1.0`). From a clone, `git pull && docker compose up -d --build` builds from the source instead.
Database migrations apply on their own when the API starts. Make a backup first, as a habit.
## Development
+5
View File
@@ -4,6 +4,9 @@
# docker compose logs -f api suivre l'API
# docker compose down arrêter (les volumes db-data et media sont conservés)
# bash tools/docker-smoke.sh vérifier l'installation
# Les images de l'API et du front sont publiées sur ghcr.io (version choisie par PARENTHESE_VERSION,
# `latest` par défaut) : ce fichier et le .env suffisent, sans le code. Si l'image est introuvable,
# compose la construit depuis les sources (dépôt cloné) ; `--build` force cette construction.
name: parenthese
@@ -24,6 +27,7 @@ services:
retries: 12
api:
image: ghcr.io/iliesallali/parenthese-api:${PARENTHESE_VERSION:-latest}
build: ./backend
restart: unless-stopped
depends_on:
@@ -49,6 +53,7 @@ services:
start_period: 30s
web:
image: ghcr.io/iliesallali/parenthese-web:${PARENTHESE_VERSION:-latest}
build:
context: .
dockerfile: Dockerfile.web