From f8f0951bd562a3630303bfbcd86e66949fe4d5e7 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 May 2026 15:32:36 +0200 Subject: [PATCH] fix(minio): bake bootstrap.sh into image instead of bind-mounting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #506. Under Docker-out-of-Docker (the production Gitea Actions runner), the host daemon resolves the relative bind-mount path against the host filesystem — not the runner container's /workspace. The script is not there, so Docker creates an empty directory at /bootstrap.sh and the entrypoint fails with `/bootstrap.sh: Is a directory`. Bake the script into a tiny derived image (infra/minio/Dockerfile) so there is no runtime path resolution. Works in DooD, regular Docker, and CI. Unblocks the staging / production deploy pipelines from #497 / #499 and turns the Compose Bucket Idempotency CI job green. Verified locally: - `docker compose ... config --quiet` parses - `docker compose ... build create-buckets` builds the image - bootstrap.sh exists as a +x file at /bootstrap.sh inside the image Co-Authored-By: Claude Opus 4.7 --- docker-compose.prod.yml | 10 ++++++---- infra/minio/Dockerfile | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 infra/minio/Dockerfile diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index b66ace54..42203588 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -80,7 +80,12 @@ services: # logic is readable, reviewable, and unit-testable as a script rather # than YAML-escaped shell. create-buckets: - image: minio/mc:RELEASE.2025-08-13T08-35-41Z + # Custom image bakes bootstrap.sh in at build time. A bind-mount fails on + # the Docker-out-of-Docker production runner because the host daemon + # resolves the relative path against the host filesystem, not the + # runner container's CWD. See #506 + infra/minio/Dockerfile. + build: + context: ./infra/minio depends_on: minio: condition: service_healthy @@ -89,9 +94,6 @@ services: environment: MINIO_PASSWORD: ${MINIO_PASSWORD} MINIO_APP_PASSWORD: ${MINIO_APP_PASSWORD} - volumes: - - ./infra/minio/bootstrap.sh:/bootstrap.sh:ro - entrypoint: ["/bin/sh", "/bootstrap.sh"] # Dev-only mail catcher; gated behind the staging profile so production # never starts it. Staging workflow runs with `--profile staging`. diff --git a/infra/minio/Dockerfile b/infra/minio/Dockerfile new file mode 100644 index 00000000..780a6d33 --- /dev/null +++ b/infra/minio/Dockerfile @@ -0,0 +1,16 @@ +# Derived MinIO Client image with the idempotent bootstrap script baked in. +# +# Why a custom image instead of a bind-mount? +# The production Gitea Actions runner is Docker-out-of-Docker. A +# `./infra/minio/bootstrap.sh:/bootstrap.sh:ro` mount resolves the path +# against the HOST filesystem (the host daemon owns the bind), not the +# runner container's `/workspace/...`. The path doesn't exist on the host +# and Docker auto-creates an empty directory at the mount target — the +# entrypoint then fails with `/bootstrap.sh: Is a directory`. Baking the +# script in removes runtime path resolution entirely. See #506. +FROM minio/mc:RELEASE.2025-08-13T08-35-41Z + +COPY bootstrap.sh /bootstrap.sh +RUN chmod +x /bootstrap.sh + +ENTRYPOINT ["/bin/sh", "/bootstrap.sh"]