Compare commits
2
Commits
0c4ee97368
...
049d54e44e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
049d54e44e | ||
|
|
e4764c64e4 |
No files matched your search
+24
-10
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
# Handled by a separate, native (non-Docker) runner registered with the
|
||||
# single "cube-host" label (see docs/deployment.adoc) — it runs directly
|
||||
# on the server, so it has docker/git/etc. from the host, no socket/bind
|
||||
# on the server, so it has podman/git/etc. from the host, no socket/bind
|
||||
# mount tricks needed. The Docker-based runner keeps handling `check`.
|
||||
deploy:
|
||||
needs: check
|
||||
@@ -68,15 +68,15 @@ jobs:
|
||||
# alone too — the glob below doesn't match them — and neither is ever
|
||||
# part of the git checkout in the first place, since both are
|
||||
# gitignored.
|
||||
- name: Sync to /srv/docker/maptool
|
||||
- name: Sync to /srv/podman/maptool
|
||||
run: |
|
||||
mkdir -p /srv/docker/maptool
|
||||
for f in /srv/docker/maptool/*; do
|
||||
mkdir -p /srv/podman/maptool
|
||||
for f in /srv/podman/maptool/*; do
|
||||
[ "$(basename "$f")" = "data" ] && continue
|
||||
rm -rf "$f"
|
||||
done
|
||||
cp -a . /srv/docker/maptool/
|
||||
rm -rf /srv/docker/maptool/.git
|
||||
cp -a . /srv/podman/maptool/
|
||||
rm -rf /srv/podman/maptool/.git
|
||||
|
||||
# Regenerated on every deploy from repo secrets (Settings -> Actions
|
||||
# -> Secrets) rather than created once by hand on the server — see
|
||||
@@ -88,16 +88,30 @@ jobs:
|
||||
# actually reads.
|
||||
- name: Write .env
|
||||
run: |
|
||||
cat > /srv/docker/maptool/.env <<EOF
|
||||
cat > /srv/podman/maptool/.env <<EOF
|
||||
SESSION_SECRET=${{ secrets.SESSION_SECRET }}
|
||||
GITEA_OAUTH_CLIENT_ID=${{ secrets.OAUTH_CLIENT_ID }}
|
||||
GITEA_OAUTH_CLIENT_SECRET=${{ secrets.OAUTH_CLIENT_SECRET }}
|
||||
MAPTOOL_ALLOWED_GITEA_USER=${{ secrets.MAPTOOL_ALLOWED_GITEA_USER }}
|
||||
LIVETRACK_WEBHOOK_SECRET=${{ secrets.LIVETRACK_WEBHOOK_SECRET }}
|
||||
EOF
|
||||
chmod 600 /srv/docker/maptool/.env
|
||||
chmod 600 /srv/podman/maptool/.env
|
||||
|
||||
# podman-compose@maptool.service (/etc/systemd/system/podman-compose@.service)
|
||||
# owns the container lifecycle — its ExecStartPre already tears down
|
||||
# the previous containers/networks/volumes on every start, but not
|
||||
# the built image, and its ExecStart runs a plain `podman compose up`
|
||||
# (deliberately no `--build`), which only builds when the image tag
|
||||
# isn't already present locally. So a bare restart would just
|
||||
# relaunch the previous image; removing that tag first forces a
|
||||
# fresh build from the code just synced above — purely local, no
|
||||
# registry involved (same `maptool:latest` docker-compose.yaml
|
||||
# already builds/tags; podman rmi never talks to a registry for a
|
||||
# locally-built image). sudo is needed since the unit — and thus the
|
||||
# image — is root's, not gitea-runner's own (gitea-runner has
|
||||
# passwordless sudo for this on cube-host).
|
||||
- name: Deploy
|
||||
run: |
|
||||
cd /srv/docker/maptool
|
||||
docker compose -p maptool up --build -d
|
||||
sudo systemctl stop podman-compose@maptool.service
|
||||
sudo podman rmi -f maptool:latest || true
|
||||
sudo systemctl start podman-compose@maptool.service
|
||||
+38
-19
@@ -2,9 +2,10 @@
|
||||
: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:
|
||||
MapTool deploys as a Podman container (via `podman compose`, driven by a
|
||||
`podman-compose@.service` systemd template — see below) 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
|
||||
@@ -24,14 +25,19 @@ whatever's installed on the server.
|
||||
|
||||
== Layout on the server
|
||||
|
||||
`/srv/docker/maptool/` holds:
|
||||
`/srv/podman/maptool/` (`/srv/podman` is a symlink to `/srv/docker`, a
|
||||
leftover from before the Docker → Podman migration — kept around so
|
||||
existing paths/tooling that still assume `/srv/docker` keep working;
|
||||
expect this to flip the other way, `/srv/docker` symlinked to
|
||||
`/srv/podman`, once nothing depends on the old name anymore) holds:
|
||||
|
||||
* A checkout of this repository (kept in sync by the deploy job, see
|
||||
below) — `Dockerfile`, `docker-compose.yaml`, application code.
|
||||
`podman compose` reads the same `docker-compose.yaml` — no
|
||||
Podman-specific compose file needed.
|
||||
* `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.
|
||||
`docker-compose.yaml`), so a redeploy never touches it.
|
||||
|
||||
== The native deploy runner
|
||||
|
||||
@@ -40,8 +46,11 @@ 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`.
|
||||
* Passwordless `sudo` (confirmed via `sudo -l -U gitea-runner`) —
|
||||
`podman-compose@maptool.service` is a root-owned systemd unit (see
|
||||
below), and the image it builds lives in root's Podman storage, so
|
||||
starting/stopping it and removing its image both require root.
|
||||
* Write access to `/srv/podman/maptool`.
|
||||
|
||||
Its `config.yaml` (`/etc/gitea-runner/config.yaml`) declares a single
|
||||
label:
|
||||
@@ -61,20 +70,22 @@ purpose deploy runner needs.
|
||||
|
||||
`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
|
||||
that would make the app unreachable through the 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.
|
||||
`docker-compose.yaml` sets `BIND_HOST="[::]"` to override that for the
|
||||
deployed container specifically — the IPv6 wildcard, which (dual-stack
|
||||
being the Linux default) also accepts IPv4 connections, covering both
|
||||
with a single listener; the compose file's own port publishing
|
||||
(`ports:`) is the network boundary there instead of Puma's bind
|
||||
address.
|
||||
|
||||
== Secrets (`.env`)
|
||||
|
||||
`docker-compose.yaml` reads `SESSION_SECRET`, `GITEA_OAUTH_CLIENT_ID`,
|
||||
`GITEA_OAUTH_CLIENT_SECRET` and `MAPTOOL_ALLOWED_GITEA_USER` from the
|
||||
environment (see `docs/architecture.adoc` for what they're for) —
|
||||
docker compose loads these automatically from a `.env` file next to
|
||||
`docker-compose.yaml`, i.e. `/srv/docker/maptool/.env`. That file is
|
||||
`podman compose` loads these automatically from a `.env` file next to
|
||||
`docker-compose.yaml`, i.e. `/srv/podman/maptool/.env`. That file is
|
||||
gitignored and dockerignored on purpose: nothing here ever puts
|
||||
secrets in the repository or a built image layer.
|
||||
|
||||
@@ -208,9 +219,17 @@ on a push to `main`, with `runs-on: cube-host`:
|
||||
`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`:
|
||||
. Copies the checkout into `/srv/podman/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.
|
||||
. Stops `podman-compose@maptool.service`, force-removes the
|
||||
`maptool:latest` image directly via `podman rmi`, then starts the
|
||||
service again. The service (`/etc/systemd/system/podman-compose@.service`,
|
||||
a systemd template instantiated as `podman-compose@maptool.service`)
|
||||
owns the actual container lifecycle — its `ExecStartPre` tears down
|
||||
the previous containers/networks/volumes on every start, and its
|
||||
`ExecStart` runs a plain `podman compose up` (deliberately no
|
||||
`--build`), which only builds when the image tag isn't already
|
||||
present locally. Removing the tag first is what forces a fresh build
|
||||
from the code just synced above; without it, a restart alone would
|
||||
just relaunch the previous image unchanged.
|
||||
Reference in new issue
Block a user