Files
maptool/docs/deployment.adoc
T
randy ae67cc72c7
CI / check (push) Successful in 5m43s
CI / deploy (push) Successful in 2m46s
Move deploy job to a dedicated native runner
The Docker-based runner's own container is too minimal for host-mode
jobs (no rsync, docker CLI, or Node.js) and has no reliable path to
the host filesystem or systemctl otherwise. Register a separate,
native runner (label deploy:host) just for deployment, and point the
deploy job at it.
2026-08-27 16:12:33 +02:00

3.4 KiB
Raw Blame History

Deployment

MapTool deploys as a Docker container on the same server the Gitea Actions runners run on. Two separate runners are registered against the Gitea instance:

  • The existing Docker-based runner (gitea/runner:3), labels ubuntu-latest/ubuntu-24.04/ubuntu-22.04 — runs the check job in a fresh, isolated container per job, same as before.

  • A dedicated native runner, installed directly on the host (no Docker around it), label deploy:host — runs only the deploy job.

They’re separate because the Docker-based runner’s jobs (whether in its usual isolated per-job containers, or tried directly inside its own container via a host-scheme label) have no reliable access to the host’s filesystem, systemctl, or even a full toolset (its own container image is missing rsync, docker CLI, Node.js — it’s built for spawning per-job containers via its docker.sock mount, not for running arbitrary host commands). The native runner sidesteps all of that: it is a host process, so docker, git, etc. are just whatever’s installed on the server.

Layout on the server

/srv/docker/maptool/ holds:

  • A checkout of this repository (kept in sync by the deploy job, see below) — Dockerfile, docker-compose.yaml, application code.

  • data/, not part of that sync — uploaded GPX files and offline.pmtiles. Persisted via a bind mount (./data:/app/data in docker-compose.yaml), so a redeploy (docker compose up --build) never touches it.

The native deploy runner

Installed from the official binary (see https://docs.gitea.com/runner/installation/binary/), running as a systemd service (gitea-runner.service) under a dedicated gitea-runner system user, which needs:

  • Docker access (member of the docker group).

  • Write access to /srv/docker/maptool.

Its config.yaml (/etc/gitea-runner/config.yaml) declares a single label:

runner:
  labels:
    - "deploy:host"

The host scheme means jobs run directly via the runner process’s own shell — no container spawned — which is exactly what a plain, single purpose deploy runner needs.

Puma’s bind address

config/puma.rb binds to 127.0.0.1 by default (see docs/architecture.adoc) — fine for local dev, but inside a container that would make the app unreachable through Docker’s published port (loopback is scoped to the container’s own network namespace). docker-compose.yaml sets BIND_HOST=0.0.0.0 to override that for the deployed container specifically; Docker’s own port publishing (ports: in the compose file) is the network boundary there instead of Puma’s bind address.

CI deploy job

.gitea/workflows/ci.yml’s `deploy job runs after check passes, only on a push to main, with runs-on: deploy:

  1. Checks out the repo with plain git (fetch + checkout, authenticated via a one-off http.extraHeader) rather than actions/checkout@v4 — a leftover from when this job ran in a Node-less container; kept as-is since there’s no reason to bring Node back in for something this already does.

  2. Copies the checkout into /srv/docker/maptool/ using plain cp/rm: clears everything in the target except data/, copies the fresh checkout over, then drops the copied .git.

  3. cd /srv/docker/maptool && docker compose -p maptool up --build -d — rebuilds the image and recreates the container if anything changed; a no-op if nothing did.