Match the deploy system to hops and greatbear
menu-admin was the odd one out: it built from the working directory with a date tag and a multi-arch manifest, deployed with `-e tag=`, and kept the Docker-era container name. The other two apps build from `git archive HEAD` and tag with the commit, so what runs on the host is exactly what git knows about; build only for the architecture emily actually runs; and use one slug for the container, its network and its data directory. The build is now their three lines: `podman build --platform linux/arm64` from `git archive HEAD`, tagged `:<commit>` and `:latest`, pushed with `podman push` rather than a manifest. `deploy.sh` pushes the commit first, then refuses a dirty tracked tree or a HEAD that is not origin/main — which is what makes the commit tag trustworthy — takes the same `--force` and `--no-push`, and ends in the same `-u tanshu ... -e image_tag=<commit>`. Its own lint/typecheck/test gate stays, but behind `--checks`, so a plain deploy behaves as theirs does. The registry credential moves into vars/default.yml and the role logs in, pulls and logs out around it, as their roles do. The image is only pulled at deploy time, so the unit keeps podman's default `Pull=missing` and a reboot never needs the registry. This is the same plaintext credential the other two repos carry. One real bug goes with it: the healthcheck gate ran before the handler that restarts a changed unit, so a run that only changed the unit checked the stale container. `meta: flush_handlers` before the gate is the fix the sibling repos already made. The container, network and data directory are all menu-<site> now. The dotted Docker-era name and the NetworkAlias it needed are gone, so `podman logs menu-<site>` and `systemctl --user status menu-<site>` are the same two commands across all three apps. The Dockerfile keeps its name for the same reason: podman reads it as readily as a Containerfile, and the siblings use that name too.
This commit is contained in:
1 parent
e68f8ab00d
commit
537a4f1e46
21 files changed
+407
-307
No files matched your search
@@ -2,8 +2,9 @@
|
||||
|
||||
Each Site is deployed as a **rootless Podman** container managed by a systemd
|
||||
user unit (Quadlet) on `emily`, reached through the one shared Caddy unit rather
|
||||
than a long-lived rootful Docker container. The image is built by `podman` too,
|
||||
from a `Containerfile`. This matches how every other service on that host is
|
||||
than a long-lived rootful Docker container. The image is built by **Podman** too,
|
||||
from the committed tree, the same way the sibling `hops` and `greatbear` apps are
|
||||
built and deployed. This matches how every other service on that host is
|
||||
deployed, and it takes the deployment off Docker entirely.
|
||||
|
||||
The app owns its whole serving path, so it needed the smallest deployment of the
|
||||
@@ -19,13 +20,15 @@ and never has to be edited when a Site is added or removed.
|
||||
**Considered Options**: staying on rootful Docker on `monoco`, rejected because
|
||||
the fleet is moving and leaving one app behind means two runtimes and two Caddy
|
||||
configs to reason about; running rootful Podman, rejected because it keeps the
|
||||
same root-owned data and loses the plain-backup property; and naming the Quadlet
|
||||
unit after the container (`menu-app.<domain>`), rejected because the dots make
|
||||
the unit name awkward and the name fragile in DNS — the unit is `menu-<site>`
|
||||
while the container keeps its old name for the scripts that look it up.
|
||||
same root-owned data and loses the plain-backup property; and keeping the
|
||||
Docker-era container name `menu-app.<domain>`, rejected because a name with dots
|
||||
in it is a liability in DNS and it would have meant a second name (a network
|
||||
alias) for Caddy to proxy to. The inventory name is now the single slug for
|
||||
everything — container, network and data directory are all `menu-<site>`, so the
|
||||
two commands an operator needs are the same across all three menu apps.
|
||||
|
||||
**Consequences**: the app is not published on a host port at all — only Caddy,
|
||||
on the shared Podman network, can reach it — and deployment, logs and restarts
|
||||
move from `docker` to `systemctl --user` / `podman`. The data root moves to
|
||||
**Consequences**: the app is not published on a host port at all — only Caddy, on
|
||||
the shared Podman network, can reach it — and deployment, logs and restarts move
|
||||
from `docker` to `systemctl --user` / `podman`. The data root moves to
|
||||
`~/podman-data/menu-<site>`, so each Site's content has to be copied across from
|
||||
`/var/lib/menu.<domain>` once, before DNS points at it.
|
||||
+8
-8
@@ -12,7 +12,7 @@ this path.
|
||||
|
||||
| Thing | Where |
|
||||
| --------------- | ----------------------------------------------------------------------------------------- |
|
||||
| The app | user unit `menu-<site>.service` on `emily`, container `menu-app.<site>`, image `registry.tanshu.com/menu-admin:<tag>` |
|
||||
| The app | user unit `menu-<site>.service` on `emily`, container `menu-<site>`, image `registry.tanshu.com/menu-admin:<commit>` |
|
||||
| Menu content | `~/podman-data/menu-<site>/data` — `originals/`, `drafts/`, `published/` |
|
||||
| Admin | `https://<vhost>/admin` |
|
||||
| The password | `~/podman-data/menu-<site>/site.env` (mode 600, never in git) |
|
||||
@@ -52,7 +52,7 @@ HASH=$(printf '%s' "$PW" | node -e "let s='';process.stdin.setEncoding('utf8');p
|
||||
SECRET=$(node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('base64url'))")
|
||||
printf 'ADMIN_PASSWORD_HASH=%s
|
||||
SESSION_SECRET=%s
|
||||
' "$HASH" "$SECRET" | ssh emily "podman run --rm -i --userns=keep-id:uid=1000,gid=1000 -v ~/podman-data/menu-hopsngrains:/data --entrypoint sh registry.tanshu.com/menu-admin:2026-09-22 -c 'umask 077 && cat > /data/site.env'"
|
||||
' "$HASH" "$SECRET" | ssh emily "podman run --rm -i --userns=keep-id:uid=1000,gid=1000 -v ~/podman-data/menu-hopsngrains:/data --entrypoint sh registry.tanshu.com/menu-admin:<commit> -c 'umask 077 && cat > /data/site.env'"
|
||||
ssh emily systemctl --user restart menu-hopsngrains
|
||||
```
|
||||
|
||||
@@ -70,7 +70,7 @@ the icon (under 256 KB; the upload replaces the bundled mark and "Remove the
|
||||
uploaded icon" brings it back). None of this changes your web addresses.
|
||||
|
||||
**Change the colours.** Those are still `config/<site>.site.json`, so they need a
|
||||
rebuild and push (`./deploy.sh <tag>`) and the playbook with the new tag.
|
||||
new build and push (`./deploy.sh`).
|
||||
|
||||
**Fix a missing image.** If a Page's thumbnail or viewing image is lost while its
|
||||
Original survives, the app can rebuild them:
|
||||
@@ -79,7 +79,7 @@ Original survives, the app can rebuild them:
|
||||
podman run --rm --userns=keep-id:uid=1000,gid=1000 -e MENU_ROOT=/data \
|
||||
-e MENU_SITE_CONFIG=/app/config/hopsngrains.site.json \
|
||||
-v ~/podman-data/menu-hopsngrains:/data \
|
||||
--entrypoint node registry.tanshu.com/menu-admin:<tag> src/cli/repair.ts
|
||||
--entrypoint node registry.tanshu.com/menu-admin:<commit> src/cli/repair.ts
|
||||
```
|
||||
|
||||
`src/cli/verify.ts` does the same inventory without changing anything, and is
|
||||
@@ -92,15 +92,15 @@ they would see the files as a different user and fail to write.
|
||||
| --- | --- |
|
||||
| Landing page says the menus are being updated | no Section has a Current Menu Set — publish one in the admin |
|
||||
| A Section 404s | that Section has no Current set, or the URL is misspelled |
|
||||
| Sign-in rejects the right password | `podman logs menu-app.<site>`, then check `site.env` exists and is owned by `tanshu` |
|
||||
| Sign-in rejects the right password | `podman logs menu-<site>`, then check `site.env` exists and is owned by `tanshu` |
|
||||
| Admin is missing entirely | `site.env` was unreadable at boot, so the admin is disabled: run the provision script and `systemctl --user restart menu-<site>` |
|
||||
| A photo uploads but looks wrong | the browser shrinks to 3000px before upload; that is expected, and the Original is kept |
|
||||
| The container will not start | `systemctl --user status menu-<site>` and `podman logs menu-app.<site>` — a fatal integrity problem makes it refuse to serve a data directory it cannot trust |
|
||||
| The container will not start | `systemctl --user status menu-<site>` and `podman logs menu-<site>` — a fatal integrity problem makes it refuse to serve a data directory it cannot trust |
|
||||
| The unit is "not found" | its `.network` file is missing, so Quadlet refused to generate it: check `~/.config/containers/systemd/` |
|
||||
| Caddy reload failed during a deploy | nothing is down: Caddy validates before applying. Read the error in the playbook output |
|
||||
| Everything is slow | check the tag is current; a Viewing image is ~1600px, so a Section page should not be megabytes |
|
||||
|
||||
**Logs.** `podman logs -f menu-app.<site>`, or `journalctl --user -u menu-<site>
|
||||
**Logs.** `podman logs -f menu-<site>`, or `journalctl --user -u menu-<site>
|
||||
-f` for the unit. The app logs JSON lines, one per event, including every upload,
|
||||
publish, restore and failed sign-in.
|
||||
|
||||
@@ -129,7 +129,7 @@ to trip over and no `podman unshare` needed.
|
||||
## Rolling back
|
||||
|
||||
Deploy the previous tag — `./deploy.sh <previous-tag>` — which rebuilds the Site
|
||||
at that version. `podman logs menu-app.<site>` is where a container that will not
|
||||
at that version. `podman logs menu-<site>` is where a container that will not
|
||||
start says why.
|
||||
|
||||
The Docker-era container was left on `monoco`, stopped and not removed, so the
|
||||
|
||||
Reference in new issue
Block a user