The app's health check ran on the target host against the container name, which only resolves inside the Docker network, so the wait could never succeed. Poll the image's HEALTHCHECK instead and fail with a readable message. Also pin site.env to the app user when it exists, and say how to install the provisioning script on the server.
96 lines
3.7 KiB
Markdown
96 lines
3.7 KiB
Markdown
# menu-admin playbook
|
|
|
|
Deploys the menu app for one Site, beside the existing nginx container at first
|
|
and in place of it after cutover. Copy this directory to
|
|
`ansible-playbooks/menu-admin/` and run it from there, so `playbook_dir` and the
|
|
inventory match the other playbooks.
|
|
|
|
This playbook owns the `menu-app` container and the Site's snippet in the shared
|
|
Caddyfile. It does not touch the app's source, the image, or the other Sites'
|
|
containers.
|
|
|
|
## What lives where
|
|
|
|
| Thing | Where |
|
|
| --- | --- |
|
|
| Sections, brand, theme | `config/<site>.site.json` in the app repo, baked into the image |
|
|
| Menu content, Drafts, Originals | `/var/lib/menu-app.<site>/data` on the host |
|
|
| Admin password hash, session secret | `/var/lib/menu-app.<site>/site.env` (untracked, mode 600) |
|
|
| Which image tag runs | `-e tag=<tag>` |
|
|
|
|
Sections are deliberately not editable on the server: changing them is a commit
|
|
to the app repo, a new image, and a redeploy (ADR 0005).
|
|
|
|
## Deploying
|
|
|
|
```sh
|
|
# 1. Build and push from the app repo
|
|
./deploy.sh 2026-09-22 # -> registry.tanshu.com/menu-admin:2026-09-22
|
|
|
|
# 2. First run: a temporary hostname, so the live site keeps serving
|
|
ansible-playbook -l monoco -e site=hopsngrains -e tag=2026-09-22 playbook.yml
|
|
|
|
# 3. The admin needs a password before it can be used. The script lives in the
|
|
# app repo and writes site.env through a container running as the app user,
|
|
# so the SSH user never needs write access to the data root.
|
|
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
|
|
```
|
|
|
|
The first run creates `/var/lib/menu-app.hopsngrains.com`, starts the container
|
|
on the `menu-app.hopsngrains.com_net` network, adds a snippet for
|
|
`menu-new.hopsngrains.com` to the shared Caddyfile, and reloads Caddy. The
|
|
existing `menu.hopsngrains.com` vhost still points at the old nginx container.
|
|
|
|
`site.env` is deliberately not created by Ansible: the password is typed by a
|
|
human on the server. Until it exists the admin is disabled and the playbook says
|
|
so — the public menu still serves.
|
|
|
|
## Checking the parallel run
|
|
|
|
`menu-new.hopsngrains.com` needs a DNS A record pointing at the same address as
|
|
`menu.hopsngrains.com` before this runs: Caddy fetches a certificate for the
|
|
name, which needs it to resolve publicly.
|
|
|
|
Then, from the outside (read-only, exits non-zero on failure):
|
|
|
|
```sh
|
|
npm run check-site -- https://menu-new.hopsngrains.com
|
|
```
|
|
|
|
And from a phone on restaurant wifi, not from the server:
|
|
|
|
- `https://menu-new.hopsngrains.com/` lists the Sections that have a current menu.
|
|
- A Section page scrolls, the pour line tracks, tapping a page opens it full width.
|
|
- The admin signs in, uploads a real photo, reorders, previews, publishes.
|
|
- After publishing, the phone shows the new menu and the old set appears under
|
|
"Older menus".
|
|
|
|
## Cutover
|
|
|
|
```sh
|
|
ansible-playbook -l monoco -e site=hopsngrains -e tag=2026-09-22 \
|
|
-e vhost=menu.hopsngrains.com \
|
|
-e retire_nginx_snippet=true \
|
|
-e retire_nginx_container=true \
|
|
playbook.yml
|
|
```
|
|
|
|
This repoints the real vhost at the app, removes the snippet the old playbook
|
|
wrote for that hostname, and stops the old container. The old container and
|
|
`/var/lib/menu.hopsngrains.com` are kept, not deleted: deleting 319 MB of the
|
|
only copy of the old menus is a human decision, made a week later, once the new
|
|
site has been trusted.
|
|
|
|
## Rolling back
|
|
|
|
```sh
|
|
docker start nginx-menu.hopsngrains.com
|
|
ansible-playbook -l monoco -e site=hopsngrains -e tag=<previous> \
|
|
-e vhost=menu.hopsngrains.com -e retire_nginx_snippet=false playbook.yml
|
|
```
|
|
|
|
Then delete the app's snippet from `/var/lib/caddy/conf/Caddyfile` by hand, or
|
|
set `vhost` back to the temporary name, and reload Caddy.
|