docker: use Dockerfile multi-stage targets in compose

After the multi-stage refactor of Dockerfile, the three separate
Dockerfile.runtime* files are obsolete: every runtime image is
now a stage of the main Dockerfile.

Delete Dockerfile.runtime, Dockerfile.runtime.blogs,
Dockerfile.runtime.api, and rewrite docker-compose.yaml so that
each service points at the corresponding target via build.target:

  web    -> web-runtime    (port 5000)
  api    -> api-runtime    (port 5002)
  blogs  -> blogs-runtime  (port 5004)

The build tag is passed through build.args.BUILD_ENV_TAG, which
the Dockerfile declares as an ARG with the same default as
before.

The shared multi-stage Dockerfile is now the single source of
truth for both the build-env image (used by the APK workflow)
and the three runtime images.
This commit is contained in:
Paul Schneider 2026-06-27 16:32:48 +01:00
commit 4fc0ddb6d4
4 changed files with 21 additions and 145 deletions

View file

@ -1,58 +0,0 @@
# Image runtime pour Yavsc.Org (front web utilisateur-facing).
#
# Construit par-dessus l'image de build (qui produit /app/publish/Yavsc.Org)
# et copie l'artefact publié dans une image ASP.NET minimale.
#
# Le appsettings-org.json n'est PAS commit (le repo n'expose pas la
# configuration de prod). Il est injecté au build via un BuildKit secret
# mount, ex:
#
# docker build \
# --secret id=yavsc_appsettings,src=./appsettings-org.json \
# -f Dockerfile.runtime \
# -t yavsc-org:dev .
#
# En production le secret peut être fourni via le store CI (GitHub Actions
# secrets, etc.). Le chemin du fichier monté (/run/secrets/yavsc_appsettings)
# ne se retrouve PAS dans l'image finale : on le copie dans /app avant
# qu'il ne soit effacé du cache BuildKit.
#
# Pour activer HTTPS en production, monter un volume de certificats
# Letsencrypt (typiquement /etc/letsencrypt) en lecture :
#
# volumes:
# - /etc/letsencrypt:/etc/letsencrypt:ro
#
# et renseigner ASPNETCORE_URLS + Kestrel:Certificates dans la config.
# En dev local, on n'expose que HTTP (5000).
# syntax=docker/dockerfile:1.7
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
# 1. Copier l'artefact publié depuis l'image de build. On référence
# l'image de build par son tag pinné : changer le tag veut dire
# modifier les trois Dockerfile.runtime* en même temps.
COPY --from=pazof/yavsc-build-env:debian12-dotnet10-android36-v1 /app/publish/Yavsc.Org/ ./
# 2. appsettings-org.json : injecté via BuildKit secret mount.
# Le /run/secrets/... est un tmpfs éphémère, on copie dans /app puis
# le secret disparaît avec le cache BuildKit.
RUN --mount=type=secret,id=yavsc_appsettings,dst=/run/secrets/yavsc_appsettings \
cp /run/secrets/yavsc_appsettings /app/appsettings-org.json \
&& chmod 0644 /app/appsettings-org.json
# 3. ASPNETCORE_ENVIRONMENT=Production par défaut ; surchargeable au run.
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000
# Healthcheck simple : on ping /. ASP.NET répond 200 sur la racine en
# mode production ; si le binding échoue, le conteneur est marqué
# unhealthy et docker-compose peut le redémarrer.
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget --quiet --spider http://localhost:5000/ || exit 1
ENTRYPOINT ["dotnet", "Yavsc.Org.dll"]

View file

@ -1,32 +0,0 @@
# Image runtime pour Yavsc.Api (API REST JSON principale, consommée
# par les clients headless : PostIt, intégrations tierces, etc.).
#
# Cf. Dockerfile.runtime pour le pattern appsettings-org.json via
# BuildKit secret mount, et le montage optionnel /etc/letsencrypt
# pour HTTPS en production.
#
# docker build \
# --secret id=yavsc_appsettings,src=./appsettings-org.json \
# -f Dockerfile.runtime.api \
# -t yavsc-api:dev .
# syntax=docker/dockerfile:1.7
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=pazof/yavsc-build-env:debian12-dotnet10-android36-v1 /app/publish/Yavsc.Api/ ./
RUN --mount=type=secret,id=yavsc_appsettings,dst=/run/secrets/yavsc_appsettings \
cp /run/secrets/yavsc_appsettings /app/appsettings-org.json \
&& chmod 0644 /app/appsettings-org.json
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=http://+:5002
EXPOSE 5002
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget --quiet --spider http://localhost:5002/ || exit 1
ENTRYPOINT ["dotnet", "Yavsc.Api.dll"]

View file

@ -1,33 +0,0 @@
# Image runtime pour Yavsc.Blogs (backend API headless des blogs,
# destiné à être déployé sur un sous-domaine dédié en production —
# cf. doc/architecture/decoupage-organisation.md).
#
# Cf. Dockerfile.runtime pour le pattern appsettings-org.json via
# BuildKit secret mount, et le montage optionnel /etc/letsencrypt
# pour HTTPS en production.
#
# docker build \
# --secret id=yavsc_appsettings,src=./appsettings-org.json \
# -f Dockerfile.runtime.blogs \
# -t yavsc-blogs:dev .
# syntax=docker/dockerfile:1.7
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=pazof/yavsc-build-env:debian12-dotnet10-android36-v1 /app/publish/Yavsc.Blogs/ ./
RUN --mount=type=secret,id=yavsc_appsettings,dst=/run/secrets/yavsc_appsettings \
cp /run/secrets/yavsc_appsettings /app/appsettings-org.json \
&& chmod 0644 /app/appsettings-org.json
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=http://+:5004
EXPOSE 5004
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD wget --quiet --spider http://localhost:5004/ || exit 1
ENTRYPOINT ["dotnet", "Yavsc.Blogs.dll"]

View file

@ -1,8 +1,5 @@
services: services:
# ---------- PostgreSQL ---------- # ---------- PostgreSQL ----------
# Image officielle. Les credentials sont repris du .env (jamais commité).
# Healthcheck via pg_isready : web/api/blogs ne démarrent qu'une fois la
# base prête à accepter des connexions.
db: db:
image: postgres:16 image: postgres:16
env_file: .env env_file: .env
@ -18,15 +15,18 @@ services:
start_period: 20s start_period: 20s
# ---------- Yavsc.Org (front web) ---------- # ---------- Yavsc.Org (front web) ----------
# Build depuis Dockerfile.runtime. ASPNETCORE_URLS=http://+:5000 (HTTP seul # Construit depuis le stage `web-runtime` du Dockerfile multi-stage.
# en dev). Pour activer HTTPS en prod, décommenter le montage letsencrypt # ASPNETCORE_URLS=http://+:5000 (HTTP seul en dev). Pour activer
# ci-dessous et renseigner Kestrel:Certificates dans appsettings-org.json. # HTTPS en prod, décommenter le port 5001, monter /etc/letsencrypt
# en volume, et configurer Kestrel:Certificates dans
# appsettings-org.json (cf. CONTRIBUTING.md).
web: web:
build: build:
context: . context: .
dockerfile: Dockerfile.runtime dockerfile: Dockerfile
target: web-runtime
args: args:
BUILD_ENV_IMAGE: pazof/yavsc-build-env:debian12-dotnet10-android36-v1 BUILD_ENV_TAG: debian12-dotnet10-android36-v1
secrets: secrets:
- yavsc_appsettings - yavsc_appsettings
env_file: .env env_file: .env
@ -42,13 +42,14 @@ services:
# volumes: # volumes:
# - /etc/letsencrypt:/etc/letsencrypt:ro # - /etc/letsencrypt:/etc/letsencrypt:ro
# ---------- Yavsc.Api (API REST) ---------- # ---------- Yavsc.Api (API REST principale) ----------
api: api:
build: build:
context: . context: .
dockerfile: Dockerfile.runtime.api dockerfile: Dockerfile
target: api-runtime
args: args:
BUILD_ENV_IMAGE: pazof/yavsc-build-env:debian12-dotnet10-android36-v1 BUILD_ENV_TAG: debian12-dotnet10-android36-v1
secrets: secrets:
- yavsc_appsettings - yavsc_appsettings
env_file: .env env_file: .env
@ -66,14 +67,14 @@ services:
# ---------- Yavsc.Blogs (backend API headless des blogs) ---------- # ---------- Yavsc.Blogs (backend API headless des blogs) ----------
# Déployé sur un sous-domaine dédié en production (ex: blogs.yavsc.example). # Déployé sur un sous-domaine dédié en production (ex: blogs.yavsc.example).
# cf. doc/architecture/decoupage-organisation.md pour la séparation avec # cf. doc/architecture/decoupage-organisation.md.
# le front des blogs (qui reste dans Yavsc.Org).
blogs: blogs:
build: build:
context: . context: .
dockerfile: Dockerfile.runtime.blogs dockerfile: Dockerfile
target: blogs-runtime
args: args:
BUILD_ENV_IMAGE: pazof/yavsc-build-env:debian12-dotnet10-android36-v1 BUILD_ENV_TAG: debian12-dotnet10-android36-v1
secrets: secrets:
- yavsc_appsettings - yavsc_appsettings
env_file: .env env_file: .env
@ -94,17 +95,15 @@ volumes:
networks: networks:
# Réseau interne : seuls les services Yavsc et la base s'y voient. # Réseau interne : seuls les services Yavsc et la base s'y voient.
# Non attaché à l'hôte.
yavsc-internal: yavsc-internal:
internal: false internal: false
# Réseau public : exposé à l'hôte via les ports mappés. Conserver # Réseau public : exposé à l'hôte via les ports mappés.
# les services web/api/blogs ici, PAS la base.
yavsc-public: yavsc-public:
secrets: secrets:
# appsettings-org.json : fichier local non commité. Vit à # appsettings-org.json vit à src/Yavsc.Org/appsettings-org.json
# src/Yavsc.Org/ dans le repo (template : appsettings-org-template.json). # (non commité). BuildKit le monte dans
# BuildKit le monte dans /run/secrets/yavsc_appsettings pendant le # /run/secrets/yavsc_appsettings pendant le build de chaque image
# build de chaque image runtime. # runtime via le Dockerfile multi-stage.
yavsc_appsettings: yavsc_appsettings:
file: ./src/Yavsc.Org/appsettings-org.json file: ./src/Yavsc.Org/appsettings-org.json