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
+40
-31
@@ -5,55 +5,64 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rootless Podman / Quadlet
|
||||
# ---------------------------------------------------------------------------
|
||||
# podman_user is derived from the connection: this play carries no become, so the
|
||||
# Quadlet units belong to whoever Ansible connects as. Requires gather_facts
|
||||
# (set in playbook.yml).
|
||||
#
|
||||
# These three duplicate caddy/vars/default.yml in the ansible-playbooks repo,
|
||||
# which owns the Caddy unit these Sites sit behind. Keep them in sync.
|
||||
# Derived from the connection: this play carries no become, so the Quadlet
|
||||
# units belong to whoever Ansible connects as. Requires gather_facts (set in
|
||||
# playbook.yml). A host that has already run caddy/playbook.yml from the
|
||||
# ansible-playbooks repo has the rootless prerequisites.
|
||||
podman_user: "{{ ansible_facts['user_id'] }}"
|
||||
podman_data_dir: "{{ ansible_facts['user_dir'] }}/podman-data"
|
||||
quadlet_dir: "{{ ansible_facts['user_dir'] }}/.config/containers/systemd"
|
||||
|
||||
# Which Site config inside the image to run, and which web address it serves.
|
||||
# ---------------------------------------------------------------------------
|
||||
# Image
|
||||
# ---------------------------------------------------------------------------
|
||||
registry: registry.tanshu.com
|
||||
registry_username: ta-registry
|
||||
registry_password: ff28a01f00c0f39315d94cd9dcb1e554968dba25676a8ea5f2be34e96a9a099f
|
||||
|
||||
image_name: '{{ registry }}/menu-admin'
|
||||
tag: latest
|
||||
# deploy.sh passes -e image_tag=<commit>; `tag` is the fallback when running the
|
||||
# play by hand. Rollback = -e image_tag=<older-commit>.
|
||||
image: '{{ image_name }}:{{ image_tag | default(tag) }}'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The Site
|
||||
# ---------------------------------------------------------------------------
|
||||
# One image serves every Site; this picks which config inside it to run. The
|
||||
# inventory name is the slug, so the container, its network and its data
|
||||
# directory are all menu-<site>.
|
||||
site: '{{ inventory_hostname }}'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The app
|
||||
# ---------------------------------------------------------------------------
|
||||
image_name: registry.tanshu.com/menu-admin
|
||||
image_tag: "{{ tag | default('latest') }}"
|
||||
|
||||
# The unit file is menu-<site>.container and the Podman network is
|
||||
# menu-<site>_net. The container keeps the Docker-era name, dots and all, because
|
||||
# scripts/provision-site-env.sh and anything an operator types look it up that
|
||||
# way — but a name with dots is a DNS liability, so the Caddyfile proxies to the
|
||||
# dotless NetworkAlias the unit sets beside it.
|
||||
network_name: 'menu-{{ site }}'
|
||||
unit_name: '{{ network_name }}.service'
|
||||
container_name: 'menu-app.{{ host }}'
|
||||
app_name: 'menu-{{ site }}'
|
||||
container_name: '{{ app_name }}'
|
||||
unit_name: '{{ container_name }}.service'
|
||||
network_name: '{{ app_name }}'
|
||||
|
||||
# The image's own account (`node`), which keep-id maps onto podman_user.
|
||||
app_uid: 1000
|
||||
app_gid: 1000
|
||||
|
||||
container_port: 3000
|
||||
# Port inside the container. Caddy proxies to it over menu-<site>_net; nothing
|
||||
# is published on the host.
|
||||
site_port: 3000
|
||||
|
||||
# podman builds an OCI image by default and drops the Containerfile's
|
||||
# HEALTHCHECK instruction, so the unit declares the same check and the play gates
|
||||
# on it. node is in the image and the sh -c podman wraps it in handles the quotes.
|
||||
# podman builds an OCI image by default and drops the Dockerfile's HEALTHCHECK
|
||||
# instruction, so the same check is declared on the Quadlet unit and the play
|
||||
# gates on `podman healthcheck run`. node is in the image, and the sh -c podman
|
||||
# wraps it in handles the quotes.
|
||||
health_cmd: >-
|
||||
node -e "fetch('http://127.0.0.1:{{ container_port }}/healthz').then(r =>
|
||||
node -e "fetch('http://127.0.0.1:{{ site_port }}/healthz').then(r =>
|
||||
process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The shared Caddy unit and its Caddyfile, both owned by the caddy playbook in
|
||||
# ansible-playbooks (caddy/playbook.yml).
|
||||
# Shared Caddy unit (caddy/playbook.yml in the ansible-playbooks repo)
|
||||
# ---------------------------------------------------------------------------
|
||||
caddy_name: caddy
|
||||
caddyfile_path: '{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile'
|
||||
|
||||
caddy_snippet: |
|
||||
# Appended to the shared Caddyfile by roles/caddy. The Site is served from the
|
||||
# container name over menu-<site>_net; no host ports are involved.
|
||||
snippet_block: |
|
||||
{{ host }} {
|
||||
reverse_proxy {{ network_name }}:{{ container_port }}
|
||||
reverse_proxy {{ container_name }}:{{ site_port }}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
# The Great Bear. Its name, tagline, icon, categories and menus live on the
|
||||
# server under app_root and are edited in the admin; config/greatbear.site.json
|
||||
# only seeds the theme and the first category list.
|
||||
# server under host_directory and are edited in the admin;
|
||||
# config/greatbear.site.json only seeds the theme and the first category list.
|
||||
title: greatbear.in
|
||||
host: 'menu.{{ title }}'
|
||||
|
||||
# Everything the app writes — data/ (the content) and site.env (the admin
|
||||
# password hash and session secret). One directory per Site, each of which is
|
||||
# also its own Podman network and its own Caddy upstream.
|
||||
app_root: '{{ podman_data_dir }}/{{ network_name }}'
|
||||
# password hash and session secret). One directory per Site, named for the
|
||||
# container that mounts it.
|
||||
host_directory: '{{ podman_data_dir }}/menu-{{ site }}'
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
# Hops n Grains Mohali. Its name, tagline, icon, categories and menus live on the
|
||||
# server under app_root and are edited in the admin; config/hngmohali.site.json
|
||||
# only seeds the theme and the first category list.
|
||||
# server under host_directory and are edited in the admin;
|
||||
# config/hngmohali.site.json only seeds the theme and the first category list.
|
||||
title: hngmohali.com
|
||||
host: 'menu.{{ title }}'
|
||||
|
||||
# Everything the app writes — data/ (the content) and site.env (the admin
|
||||
# password hash and session secret). One directory per Site, each of which is
|
||||
# also its own Podman network and its own Caddy upstream.
|
||||
app_root: '{{ podman_data_dir }}/{{ network_name }}'
|
||||
# password hash and session secret). One directory per Site, named for the
|
||||
# container that mounts it.
|
||||
host_directory: '{{ podman_data_dir }}/menu-{{ site }}'
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
# Hops n Grains. Its name, tagline, icon, categories and menus live on the server
|
||||
# under app_root and are edited in the admin; config/hopsngrains.site.json only
|
||||
# seeds the theme. This file says where the Site runs and what it answers.
|
||||
# under host_directory and are edited in the admin; config/hopsngrains.site.json
|
||||
# only seeds the theme. This file says where the Site runs and what it answers.
|
||||
#
|
||||
# Every value that interpolates a template is quoted: YAML reads a leading `{`
|
||||
# as a flow mapping, which is the parse error Ansible reports as "missing quotes
|
||||
@@ -10,6 +10,6 @@ title: hopsngrains.com
|
||||
host: 'menu.{{ title }}'
|
||||
|
||||
# Everything the app writes — data/ (the content) and site.env (the admin
|
||||
# password hash and session secret). One directory per Site, each of which is
|
||||
# also its own Podman network and its own Caddy upstream.
|
||||
app_root: '{{ podman_data_dir }}/{{ network_name }}'
|
||||
# password hash and session secret). One directory per Site, named for the
|
||||
# container that mounts it.
|
||||
host_directory: '{{ podman_data_dir }}/menu-{{ site }}'
|
||||
Reference in new issue
Block a user