Commit Graph
6 Commits
Author SHA1 Message Date
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
tanshu 01ce0bd609 Create each Site's network with its own subnet
The deploy failed on hngmohali with 'all predefined address pools have been
fully subnetted': every 172.17-172.30/16 is in use, 172.31/16 is the host's own
VPC so Docker will not allocate from it, and all sixteen 192.168.0-240/20 blocks
are taken. Docker therefore refuses a network created without a subnet.

Each Site now names a free network_subnet (10.210.0.0/16, one /24 each), the role
looks the network up first and only creates it when it is absent and with that
subnet, and it fails with an explanation when a Site declares none. Existing
networks are left alone, because Docker cannot change a subnet in place and the
Sites already running have theirs. The test checks every Site declares one, and
the deployment readme says a new Site needs a free subnet.

deploy.sh now deploys every Site by default, with SITE=<name> to narrow it, which
is what the local edit was reaching for.
2026-09-23 00:18:04 +05:30
tanshu c2e499ad87 Declare the healthcheck in Ansible instead of trusting the image
podman builds an OCI image by default and drops Docker's HEALTHCHECK instruction,
so the container had no health at all and the play failed waiting for one. The
check is now declared on the docker_container task - node is in the image and the
exec form needs no shell quoting - which is both what operators see in docker ps
and what an orchestrator would use.

The wait still asks the app directly rather than reading State.Health, because a
container that already exists is only rebuilt when the image tag changes or when
-e recreate_container=true is passed, and a wait must not depend on a container
attribute an existing one may not have.
2026-09-22 23:47:30 +05:30
tanshu 1923c80298 Stop the health wait from failing a healthy deploy, and clear a stale address
The first real deploy left the site on 502 and this is why. podman builds an OCI
image by default and drops the Docker HEALTHCHECK instruction, so the app
container has no State.Health at all; the role waited on that field, exhausted
its retries and failed the play, so the caddy role never ran and Caddy kept
proxying menu.hopsngrains.com to the old nginx container that is now gone.

The wait now asks the app itself: docker exec node -e fetch /healthz, which needs
no healthcheck and no DNS. And because the address may still be claimed by the
snippet the retired nginx-menu playbook wrote, the caddy role drops that marker
before writing its own - two blocks for one address make Caddy refuse the config,
and a refused reload quietly leaves the old proxy in place.

check-site also asked for the font the old design used, so it would have failed a
healthy site; it checks one we ship.
2026-09-22 23:44:54 +05:30
tanshu f2d8058456 Deploy in one run, with nothing older to preserve
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.
2026-09-22 23:27:17 +05:30
tanshu 75b6492493 Move the deployment into the app repo, and build it with podman
The playbook, its roles, its vars and a new inventory now live in ansible/,
beside the app they deploy, the way the other apps on this machine are laid out.
The inventory follows the same shape: one entry per Site, all on the same box,
each naming its own vars file through var_file, so adding a Site is one line and
a file rather than a command-line flag. ansible_host is written as the
resolvable name rather than an ssh alias so the inventory works on any machine.

The image is now built with podman as a multi-arch manifest and pushed to
registry.tanshu.com/menu-admin, mirroring the Makefile used elsewhere on this
machine: build-production, plus build-check and build-check-local for a build
that does not push. deploy.sh runs the checks, builds, pushes, then runs the
playbook for the Site named by SITE, with SKIP_DEPLOY for a push without a
deploy.

ESLint comes out again: this project's typescript@7 has no JavaScript compiler
API, so typescript-eslint cannot install, and linting only the JavaScript was
not worth keeping. Prettier stays, and the README records why ESLint is absent
and what would bring it back.
2026-09-22 23:18:18 +05:30