diff --git a/.gitea/workflows/dev-deploy.yaml b/.gitea/workflows/dev-deploy.yaml index 589cd7d..bdbdd5d 100644 --- a/.gitea/workflows/dev-deploy.yaml +++ b/.gitea/workflows/dev-deploy.yaml @@ -104,6 +104,21 @@ jobs: -v "${{ gitea.workspace }}/ui/frontend/build:/src:ro" \ alpine sh -c 'rm -rf /dst/* /dst/.??* 2>/dev/null; cp -a /src/. /dst/' + - name: Seed geoip volume + run: | + # Copy the GeoIP test fixture into a named volume so the + # backend can mount it as /var/lib/galaxy. A bind-mount with + # a relative path would resolve against this runner's + # ephemeral workspace under /home/runner/.cache/act//, + # which the runner deletes once the workflow ends — the next + # `docker restart galaxy-dev-backend` would then fail with + # "not a directory" because the mount source vanished. + docker volume create galaxy-dev-geoip-data >/dev/null + docker run --rm \ + -v galaxy-dev-geoip-data:/dst \ + -v "${{ gitea.workspace }}/pkg/geoip/test-data/test-data:/src:ro" \ + alpine sh -c 'cp /src/GeoIP2-Country-Test.mmdb /dst/geoip.mmdb' + - name: Reap stray dev-deploy containers run: | # Remove any non-running compose-managed containers from diff --git a/tools/dev-deploy/KNOWN-ISSUES.md b/tools/dev-deploy/KNOWN-ISSUES.md index f1f1aad..966ca67 100644 --- a/tools/dev-deploy/KNOWN-ISSUES.md +++ b/tools/dev-deploy/KNOWN-ISSUES.md @@ -162,9 +162,12 @@ redeploys can short-circuit the diagnostic loop. ## `docker restart galaxy-dev-backend` fails after the CI runner cleans up +**Status: fixed (2026-05-19).** Kept here as a postmortem in case +the symptom resurfaces in a different form. + ### Symptom -`docker restart galaxy-dev-backend` from the host fails with: +`docker restart galaxy-dev-backend` from the host failed with: ```text Error response from daemon: ... error mounting @@ -172,36 +175,28 @@ Error response from daemon: ... error mounting to rootfs at "/var/lib/galaxy/geoip.mmdb": ... not a directory ``` -The container ends up `Exited (127)` and never comes back. +The container ended up `Exited (127)` and never came back. ### Cause -`tools/dev-deploy/docker-compose.yml` mounts the geoip database via -a path relative to the compose file +`tools/dev-deploy/docker-compose.yml` used to mount the geoip +database via a path relative to the compose file (`../../pkg/geoip/test-data/test-data/GeoIP2-Country-Test.mmdb`). When -the `dev-deploy.yaml` Gitea runner invokes `docker compose up` it -resolves that relative path against the runner's ephemeral workspace +the `dev-deploy.yaml` Gitea runner invoked `docker compose up`, it +resolved that relative path against the runner's ephemeral workspace under `/home/runner/.cache/act//hostexecutor/tools/dev-deploy/`, -so the bind-mount source baked into the running container points at -that ephemeral path. The runner deletes the workspace once the -workflow ends, the source disappears, and the next `docker restart` -fails to remount it. +so the bind-mount source baked into the running container pointed at +that ephemeral path. The runner deleted the workspace once the +workflow ended, the source disappeared, and the next `docker restart` +failed to remount it. -### Workaround +### Fix -Bring the stack back up from a stable workspace, which re-binds the -mount source to the persistent checkout: - -```sh -make -C tools/dev-deploy up -``` - -This restarts every service (including the broken `galaxy-dev-backend`) -with a stable source path. - -### Status - -Open. The clean fix is either to bake the geoip test fixture into -the backend image (no host bind-mount) or to copy it onto a named -volume during `dev-deploy.yaml` and bind that instead. Either change -removes the runner-workspace dependency entirely. +Replaced the bind-mount with a named volume, +`galaxy-dev-geoip-data`, seeded by the `dev-deploy.yaml` workflow +(and by the new `make seed-geoip` target) at deploy time. The +backend mounts the volume as `/var/lib/galaxy:ro`, so the bind +source is a Docker-managed volume — independent of the runner +workspace — and survives a `docker restart`. See +`.gitea/workflows/dev-deploy.yaml` ("Seed geoip volume" step) and +`tools/dev-deploy/Makefile` (`seed-geoip` target). diff --git a/tools/dev-deploy/Makefile b/tools/dev-deploy/Makefile index e9f1260..30dec77 100644 --- a/tools/dev-deploy/Makefile +++ b/tools/dev-deploy/Makefile @@ -1,4 +1,4 @@ -.PHONY: help up down rebuild logs status clean-data health psql build-engine seed-ui +.PHONY: help up down rebuild logs status clean-data health psql build-engine seed-ui seed-geoip .DEFAULT_GOAL := help @@ -18,10 +18,11 @@ COMPOSE := docker compose help: @echo "Long-lived Galaxy dev environment (https://*.galaxy.lan):" - @echo " make up Build images, ensure engine image, bring stack up" + @echo " make up Build images, ensure engine image, seed geoip, bring stack up" @echo " make rebuild Force rebuild of backend / gateway images and bring up" @echo " make build-engine Build $(ENGINE_IMAGE) from game/Dockerfile (no-op if present)" @echo " make seed-ui Build ui/frontend and load into galaxy-dev-ui-dist volume" + @echo " make seed-geoip Copy GeoIP fixture into galaxy-dev-geoip-data volume" @echo " make down Stop containers, keep named volumes" @echo " make logs Tail all logs" @echo " make status docker compose ps" @@ -35,11 +36,11 @@ help: @echo " - host Caddy proxying *.galaxy.lan into that network" @echo " - game-state dir: $(GALAXY_DEV_GAME_STATE_DIR) (auto-created)" -up: build-engine +up: build-engine seed-geoip mkdir -p "$(GALAXY_DEV_GAME_STATE_DIR)" $(COMPOSE) up -d --wait -rebuild: build-engine +rebuild: build-engine seed-geoip $(COMPOSE) build --no-cache galaxy-backend galaxy-api mkdir -p "$(GALAXY_DEV_GAME_STATE_DIR)" $(COMPOSE) up -d --wait @@ -52,6 +53,19 @@ build-engine: docker build -t $(ENGINE_IMAGE) -f $(REPO_ROOT)/game/Dockerfile $(REPO_ROOT); \ fi +# Copy the GeoIP fixture into a named volume the backend mounts as +# /var/lib/galaxy. Using a volume avoids a bind-mount that would +# resolve against an ephemeral workspace path when compose is driven +# from the Gitea runner (see tools/dev-deploy/KNOWN-ISSUES.md for the +# breakage that bind-mounts caused on `docker restart`). +seed-geoip: + @echo "seeding GeoIP fixture into galaxy-dev-geoip-data…" + docker volume create galaxy-dev-geoip-data >/dev/null + docker run --rm \ + -v galaxy-dev-geoip-data:/dst \ + -v $(REPO_ROOT)/pkg/geoip/test-data/test-data:/src:ro \ + alpine sh -c 'cp /src/GeoIP2-Country-Test.mmdb /dst/geoip.mmdb' + # Build the UI frontend and load the resulting build/ directory into # the named volume Caddy serves from. Used by the dev-deploy workflow # and by anyone bringing the stack up by hand. diff --git a/tools/dev-deploy/README.md b/tools/dev-deploy/README.md index fb308a7..c84a309 100644 --- a/tools/dev-deploy/README.md +++ b/tools/dev-deploy/README.md @@ -153,9 +153,10 @@ The same volume-persistence model applies to `tools/local-dev/`. ## Make targets ```text -make up Build images, ensure engine image, bring stack up (waits for health) +make up Build images, ensure engine image, seed geoip, bring stack up make rebuild Rebuild backend / gateway images (ignores cache), then up make seed-ui pnpm build + load build/ into galaxy-dev-ui-dist volume +make seed-geoip Copy pkg/geoip fixture into galaxy-dev-geoip-data volume make build-engine Build galaxy-engine:dev (no-op if image already present) make down Stop containers, keep named volumes make logs Tail compose logs diff --git a/tools/dev-deploy/docker-compose.yml b/tools/dev-deploy/docker-compose.yml index 8fdfc2b..71a7ee7 100644 --- a/tools/dev-deploy/docker-compose.yml +++ b/tools/dev-deploy/docker-compose.yml @@ -144,7 +144,15 @@ services: target: ${GALAXY_DEV_GAME_STATE_DIR} bind: create_host_path: true - - ../../pkg/geoip/test-data/test-data/GeoIP2-Country-Test.mmdb:/var/lib/galaxy/geoip.mmdb:ro + # The geoip database lives on a named volume seeded by the + # `dev-deploy.yaml` workflow (or by `make seed-geoip` when + # bringing the stack up by hand). A bind-mount with a relative + # path would resolve against the runner's ephemeral workspace + # under /home/runner/.cache/act//, which the runner + # deletes after the workflow ends — and the next + # `docker restart galaxy-dev-backend` would then fail with + # "not a directory" because the mount source vanished. + - galaxy-dev-geoip-data:/var/lib/galaxy:ro networks: - galaxy-internal healthcheck: @@ -258,3 +266,5 @@ volumes: name: galaxy-dev-caddy-data galaxy-dev-ui-dist: name: galaxy-dev-ui-dist + galaxy-dev-geoip-data: + name: galaxy-dev-geoip-data