The first deploy put all three Sites up serving and permanently unhealthy: every healthcheck run died with `/bin/sh: syntax error: unterminated quoted string`. The unit file carried the closing quote, but podman's stored config did not. Quadlet's parser strips a trailing double quote, so `node -e "fetch(...)"` reached the container as an unterminated shell string. The sibling apps never hit this because their HealthCmd is a bare `curl`. The check is now `wget -q -O /dev/null http://127.0.0.1:<port>/healthz` — busybox wget, no quoting, non-zero on anything but a 2xx — and the Dockerfile's own HEALTHCHECK says the same thing. The vars comment, the unit template and the deployment readme all say why it has to stay quote-free. Found from the running container rather than the play output: `podman healthcheck run` returned 1, `.State.Health.Log` held the sh error, and the app log showed it listening on 127.0.0.1:3000 the whole time.
73 lines
3.2 KiB
YAML
73 lines
3.2 KiB
YAML
---
|
|
# Defaults shared by every Site. Each Site's own file is named by the `var_file`
|
|
# in ansible/hosts, and its slug is its inventory name.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Rootless Podman / Quadlet
|
|
# ---------------------------------------------------------------------------
|
|
# 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"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 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 }}'
|
|
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
|
|
|
|
# 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 Dockerfile's HEALTHCHECK
|
|
# instruction, so the same check is declared on the Quadlet unit and the play
|
|
# gates on `podman healthcheck run`.
|
|
#
|
|
# The command must not contain quotes. Quadlet's parser strips a trailing double
|
|
# quote from HealthCmd, so `node -e "fetch(...)"` reaches podman as an
|
|
# unterminated string and every check dies with "/bin/sh: syntax error:
|
|
# unterminated quoted string" — the container serves, and is permanently
|
|
# unhealthy. wget is busybox's, needs no quoting, and exits non-zero on anything
|
|
# but a 2xx.
|
|
health_cmd: 'wget -q -O /dev/null http://127.0.0.1:{{ site_port }}/healthz'
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Shared Caddy unit (caddy/playbook.yml in the ansible-playbooks repo)
|
|
# ---------------------------------------------------------------------------
|
|
caddy_name: caddy
|
|
caddyfile_path: '{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile'
|
|
|
|
# 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 {{ container_name }}:{{ site_port }}
|
|
}
|