Files
menu/ansible/readme.md
T
tanshu 2ef044aa45 Let Docker allocate the network subnet again
Reverts the explicit subnets: the pools were freed by deleting five networks, so
the network role is back to its single idempotent task - ensure the network
exists and Caddy is on it - and the Sites no longer declare a subnet. The
deployment readme keeps the note that a new Site needs a config, and therefore a
new tag, but no longer asks for a free /24.

If the pools fill up again the failure is recognisable: 'all predefined address
pools have been fully subnetted', and the choices are deleting stale networks or
declaring a subnet per Site.
2026-09-23 00:21:57 +05:30

95 lines
4.0 KiB
Markdown

# The menu deployment
Lives here, beside the app it deploys. One run deploys a Site: it starts the
app's container and points the Site's web address at it. There is no older
system to keep serving, so there is no staged rollout and nothing to retire —
deploying an earlier tag is the rollback.
**The app's data root is the directory the old static menus were served from**
(`/var/lib/menu.<site>`), on purpose, so the app inherits the location instead of
a second one. The app only reads and writes `data/` and `site.env` inside it. If
you later want the old menu files gone, delete those files — not the directory,
which now holds the live content.
## What lives where
| Thing | Where |
| -------------------------------------- | ---------------------------------------------------------------------- |
| Name, tagline, icon, categories, menus | on the server under `/var/lib/menu.<site>/data` — the admin edits them |
| Theme colours | `config/<site>.site.json` in the repo, baked into the image |
| Admin password hash, session secret | `/var/lib/menu.<site>/site.env` (untracked, mode 600) |
| Which image tag runs | `-e tag=<tag>` |
| Which Site is deployed | the inventory entry in `hosts` |
| The web address it serves | `host:` in `vars/<site>.yml` |
## Deploying
From the repo root:
```sh
./deploy.sh 2026-09-22 # checks, podman build+push, then deploys
SKIP_DEPLOY=1 ./deploy.sh 2026-09-22 # build and push only
```
`deploy.sh` runs `make build-production TAG=<tag>`, which builds a multi-arch
podman manifest (`linux/amd64,linux/arm64`) and pushes `latest` and the tag to
`registry.tanshu.com/menu-admin`. Then it runs this playbook against the Site
named by `SITE` (default `hopsngrains`).
By hand:
```sh
make build-production TAG=2026-09-22
cd ansible
ansible-playbook --inventory=hosts playbook.yml --limit hopsngrains -e tag=2026-09-22
```
Every Site runs on the same box, so `hosts` has one entry per Site pointing at
the same `ansible_host` with its own `var_file`. `ansible_host` is written as the
resolvable name rather than an ssh alias, so the inventory works whatever a
machine's `~/.ssh/config` says. (`ssh` on some machines complains about
`/etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf` being owned by `nobody`; that is
a local file-permission bug whose fix is `sudo chown -R root:root
/etc/ssh/ssh_config.d`, not something this playbook works around.)
Adding a Site is one line in `hosts`, a copy of `vars/hopsngrains.yml`, and a
`config/<site>.site.json`. The image is shared, so the config has to be in it:
a new Site needs a new tag.
## Checking it landed
```sh
npm run check-site -- https://menu.hopsngrains.com
```
Read-only, exits non-zero on failure. Then from a phone: the landing page, a
Section page, the page counter, tap-to-zoom, and signing into `/admin` to
publish something.
## The admin password
The app starts with the admin disabled while `/var/lib/menu.<site>/site.env`
is missing, and the playbook says so rather than failing. Create it once per
Site; run it again with `--force` to reset the password (a fresh session secret
signs everyone out). There is no minimum password length.
```sh
scp scripts/provision-site-env.sh monoco:/tmp/
ssh -t monoco bash /tmp/provision-site-env.sh /var/lib/menu.hopsngrains.com
ssh monoco docker restart menu-app.hopsngrains.com
```
The `-t` matters: the script prompts for the password, and without a terminal on
the remote side the prompt cannot be read, so it would sit there looking frozen.
With no image argument it borrows the one the running container uses.
## Rolling back
Deploy the previous tag:
```sh
./deploy.sh <previous-tag>
```
`docker logs menu-app.<site>` is where a failed container says why.