There is no previous system kept serving, so the playbook no longer knows about one: the retire flags, the temporary web address, the task that removed the old nginx snippet and the task that stopped the old container are gone. One run starts the container and points the Site's web address at it, and deploying an earlier tag is the rollback. The vars lose vhost, retire_nginx_snippet, retire_nginx_container and legacy_container; the Caddy role keeps only the snippet upsert. The deployment readme drops its staged-rollout sections and the glossary of words that no longer exist, and the plan's sequence and the operating notes describe the single run instead.
82 lines
3.2 KiB
Markdown
82 lines
3.2 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.
|
|
|
|
## What lives where
|
|
|
|
| Thing | Where |
|
|
| -------------------------------------- | -------------------------------------------------------------------------- |
|
|
| Name, tagline, icon, categories, menus | on the server under `/var/lib/menu-app.<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-app.<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` and a copy of `vars/hopsngrains.yml`.
|
|
|
|
## 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-app.<site>/site.env`
|
|
is missing, and the playbook says so rather than failing. Create it once per
|
|
Site:
|
|
|
|
```sh
|
|
scp scripts/provision-site-env.sh monoco:/tmp/
|
|
ssh monoco bash /tmp/provision-site-env.sh /var/lib/menu-app.hopsngrains.com
|
|
ssh monoco docker restart menu-app.hopsngrains.com
|
|
```
|
|
|
|
## Rolling back
|
|
|
|
Deploy the previous tag:
|
|
|
|
```sh
|
|
./deploy.sh <previous-tag>
|
|
```
|
|
|
|
`docker logs menu-app.<site>` is where a failed container says why.
|