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.
87 lines
3.4 KiB
Plaintext
87 lines
3.4 KiB
Plaintext
= Deployment
|
|
:toc:
|
|
:toclevels: 2
|
|
|
|
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:
|
|
|
|
[source,yaml]
|
|
----
|
|
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`:
|
|
|
|
. 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.
|
|
. 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`.
|
|
. `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.
|