diff --git a/.env.example b/.env.example index 64ab2ae..adc2dba 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,9 @@ # Local compose defaults. Copy to .env when you need machine-specific paths. +# Images used by docker-compose.yaml. +READABOOK_REGISTRY=gitea.anthonybouteiller.ovh/blomios/readabook +READABOOK_TAG=latest + # Directory mounted read-only as /library in the API container. READABOOK_LIBRARY_HOST_PATH=./data/library diff --git a/Dockerfile b/Dockerfile index 7eacdb2..c0ccd39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,15 @@ RUN pnpm --filter @readabook/api build RUN pnpm --filter @readabook/api deploy --prod /prod FROM node:22-bookworm-slim AS runtime +ARG OCI_IMAGE_CREATED +ARG OCI_IMAGE_REVISION +ARG OCI_IMAGE_VERSION=latest +LABEL org.opencontainers.image.title="ReadaBook API" \ + org.opencontainers.image.description="ReadaBook NestJS API service" \ + org.opencontainers.image.source="https://gitea.anthonybouteiller.ovh/blomios/ReadaBook" \ + org.opencontainers.image.created="${OCI_IMAGE_CREATED}" \ + org.opencontainers.image.revision="${OCI_IMAGE_REVISION}" \ + org.opencontainers.image.version="${OCI_IMAGE_VERSION}" ENV NODE_ENV=production ENV HOST=0.0.0.0 ENV PORT=3000 diff --git a/README.md b/README.md index 732362d..26a20a8 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ data/ library/ Dossier local à scanner, monté en lecture seule dans compose storage/ Cache backend, notamment couvertures extraites Dockerfile Image API -docker-compose.yaml Services API + web +docker-compose.yaml Services API + web depuis images publiees +docker-compose.build.yaml Override de build local des images API + web pnpm-workspace.yaml Workspace monorepo ``` @@ -72,7 +73,7 @@ Note sandbox constatée : sur Node 24 local, `better-sqlite3` peut nécessiter u ## Docker Compose ```bash -JWT_SECRET="replace-me" docker compose up --build +JWT_SECRET="replace-me" docker compose up ``` Services : @@ -85,6 +86,24 @@ Ports : - Hôte `3000` -> conteneur `web:80`. - L’API est accessible depuis le navigateur via les routes proxifiées par Nginx : `/auth`, `/admin`, `/books`, `/progress`, `/healthz`. +Images par défaut : + +- `${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}/api:${READABOOK_TAG:-latest}` +- `${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}/web:${READABOOK_TAG:-latest}` + +Pour construire localement au lieu de tirer les images publiées : + +```bash +READABOOK_TAG=local docker compose -f docker-compose.yaml -f docker-compose.build.yaml up --build +``` + +Pour publier les images vers le registry Gitea : + +```bash +docker login gitea.anthonybouteiller.ovh +./scripts/publish.sh +``` + ## Frontend PWA Le frontend est accessible sur `http://localhost:3000` en compose. Il expose les routes MVP : @@ -108,6 +127,8 @@ Volumes : Variables principales : +- `READABOOK_REGISTRY` : préfixe registry/repository des images API et web. +- `READABOOK_TAG` : tag d’image utilisé par compose et par `scripts/publish.sh`. - `JWT_SECRET` : secret JWT, à changer hors développement. - `OPEN_LIBRARY_ENABLED=true|false` : active/désactive l’enrichissement distant. - `READABOOK_LIBRARY_HOST_PATH` : dossier hôte monté en lecture seule sur `/library`. diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 2421817..2a31082 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -17,6 +17,15 @@ RUN pnpm --filter @readabook/shared build RUN pnpm --filter @readabook/web build FROM nginx:1.27-alpine AS runtime +ARG OCI_IMAGE_CREATED +ARG OCI_IMAGE_REVISION +ARG OCI_IMAGE_VERSION=latest +LABEL org.opencontainers.image.title="ReadaBook Web" \ + org.opencontainers.image.description="ReadaBook PWA served by Nginx" \ + org.opencontainers.image.source="https://gitea.anthonybouteiller.ovh/blomios/ReadaBook" \ + org.opencontainers.image.created="${OCI_IMAGE_CREATED}" \ + org.opencontainers.image.revision="${OCI_IMAGE_REVISION}" \ + org.opencontainers.image.version="${OCI_IMAGE_VERSION}" COPY apps/web/nginx/default.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/apps/web/dist /usr/share/nginx/html EXPOSE 80 diff --git a/docker-compose.build.yaml b/docker-compose.build.yaml new file mode 100644 index 0000000..076ab02 --- /dev/null +++ b/docker-compose.build.yaml @@ -0,0 +1,20 @@ +services: + api: + build: + context: . + dockerfile: Dockerfile + args: + OCI_IMAGE_CREATED: ${OCI_IMAGE_CREATED:-local} + OCI_IMAGE_REVISION: ${OCI_IMAGE_REVISION:-local} + OCI_IMAGE_VERSION: ${READABOOK_TAG:-local} + image: ${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}/api:${READABOOK_TAG:-local} + + web: + build: + context: . + dockerfile: apps/web/Dockerfile + args: + OCI_IMAGE_CREATED: ${OCI_IMAGE_CREATED:-local} + OCI_IMAGE_REVISION: ${OCI_IMAGE_REVISION:-local} + OCI_IMAGE_VERSION: ${READABOOK_TAG:-local} + image: ${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}/web:${READABOOK_TAG:-local} diff --git a/docker-compose.yaml b/docker-compose.yaml index 6d5691a..b2a3742 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,8 +1,6 @@ services: api: - build: - context: . - dockerfile: Dockerfile + image: ${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}/api:${READABOOK_TAG:-latest} environment: NODE_ENV: production PORT: "3000" @@ -16,7 +14,7 @@ services: INITIAL_ADMIN_PASSWORD: ${INITIAL_ADMIN_PASSWORD:-readabook-admin-change-me} volumes: - ./data:/data - - /home/anthony/Documents/Projects/ReadaBook/Books:/library:ro + - ${READABOOK_LIBRARY_HOST_PATH:-./data/library}:/library:ro healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] interval: 10s @@ -25,9 +23,7 @@ services: start_period: 10s web: - build: - context: . - dockerfile: apps/web/Dockerfile + image: ${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}/web:${READABOOK_TAG:-latest} depends_on: api: condition: service_healthy diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100755 index 0000000..7763ace --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY="${READABOOK_REGISTRY:-gitea.anthonybouteiller.ovh/blomios/readabook}" +TAG="${READABOOK_TAG:-latest}" +REVISION="${OCI_IMAGE_REVISION:-$(git rev-parse HEAD)}" +CREATED="${OCI_IMAGE_CREATED:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}" +PLATFORM="${DOCKER_BUILD_PLATFORM:-}" + +build_args=( + --build-arg "OCI_IMAGE_CREATED=${CREATED}" + --build-arg "OCI_IMAGE_REVISION=${REVISION}" + --build-arg "OCI_IMAGE_VERSION=${TAG}" +) + +platform_args=() +if [[ -n "${PLATFORM}" ]]; then + platform_args=(--platform "${PLATFORM}") +fi + +echo "Publishing ReadaBook images to ${REGISTRY} with tag ${TAG}" + +docker buildx build \ + "${platform_args[@]}" \ + "${build_args[@]}" \ + --tag "${REGISTRY}/api:${TAG}" \ + --push \ + --file Dockerfile \ + . + +docker buildx build \ + "${platform_args[@]}" \ + "${build_args[@]}" \ + --tag "${REGISTRY}/web:${TAG}" \ + --push \ + --file apps/web/Dockerfile \ + . + +echo "Published:" +echo " ${REGISTRY}/api:${TAG}" +echo " ${REGISTRY}/web:${TAG}"