diff --git a/.containerignore b/.containerignore index 22be4fd..8bd17b5 100644 --- a/.containerignore +++ b/.containerignore @@ -1,24 +1,40 @@ # Keep the build context small and secret-free. # Read by Podman/Buildah (`.containerignore`) and, as a fallback, Docker. +# +# The build is `git archive HEAD`, so untracked files never reach the context +# anyway; this is belt-and-suspenders for a working-tree build. # VCS / editor / local state .git .gitignore .containerignore .env +.env.* .npm-cache .tmp-pb .podman .vscode +.idea design *.zip -# Node artifacts +# Node artifacts (installed/rebuilt inside the image) +node_modules **/node_modules app/.output +app/.tanstack app/.nitro app/dist +# PocketBase local data & scratch +pb_data +*.db +*.db-shm +*.db-wal + +# Logs +*.log + # Ops assets not needed inside the image ansible Makefile diff --git a/ansible/roles/greatbear/tasks/main.yaml b/ansible/roles/greatbear/tasks/main.yaml index b9bd457..83e30d3 100644 --- a/ansible/roles/greatbear/tasks/main.yaml +++ b/ansible/roles/greatbear/tasks/main.yaml @@ -86,6 +86,15 @@ ansible.builtin.fail: msg: "The Great Bear did not start — see the diagnostics above." +# The unit template notifies "Restart The Great Bear", but handlers otherwise +# run at the very end of the play — after the healthcheck gate below. Flush them +# here so the gate tests the container that has the current HealthCmd; without +# this, a run that only changes the unit would check the stale container and +# fail. On a run where nothing changed, no handler is pending and this is a +# no-op. +- name: Apply pending unit changes before verifying + ansible.builtin.meta: flush_handlers + # Quadlet honours [Install] WantedBy= when it generates the unit, so # `systemctl --user enable` is neither needed nor possible on a generated unit. - name: Verify The Great Bear unit is active @@ -97,8 +106,8 @@ # `is-active` says the unit is running, not that both processes inside the # container are healthy: the entrypoint starts PocketBase, waits for # /api/health, upserts the superuser and seeds content before the site server -# answers. The image ships a HEALTHCHECK covering both; `healthcheck run` forces -# one now and reports its result instead of waiting out the interval. +# answers. The unit's HealthCmd covers both; `healthcheck run` forces one now +# and reports its result instead of waiting out the interval. - name: Wait for the container healthcheck to pass ansible.builtin.command: "podman healthcheck run {{ container_name }}" register: greatbear_health diff --git a/ansible/roles/greatbear/templates/greatbear.container.j2 b/ansible/roles/greatbear/templates/greatbear.container.j2 index 580d9c0..b1bf50d 100644 --- a/ansible/roles/greatbear/templates/greatbear.container.j2 +++ b/ansible/roles/greatbear/templates/greatbear.container.j2 @@ -33,9 +33,14 @@ Volume={{ host_directory }}/pb_data:/app/pb_data # No PublishPort on purpose: the Docker-era deployment had none either, and # Caddy reaches both ports over {{ network_name }}_net. -# The image's own HEALTHCHECK (PocketBase /api/health on {{ pb_port }} and the -# site on {{ site_port }}) is used as is; the playbook gates on -# `podman healthcheck run`. +# podman builds an OCI image by default and drops the Dockerfile's HEALTHCHECK +# instruction, so the same check is declared here and the play gates on it with +# `podman healthcheck run`. curl is in the runner image. +HealthCmd={{ health_cmd }} +HealthInterval=15s +HealthTimeout=3s +HealthRetries=3 +HealthStartPeriod=5s [Service] Restart=always diff --git a/ansible/vars/default.yml b/ansible/vars/default.yml index ccb396b..5a1fdf5 100644 --- a/ansible/vars/default.yml +++ b/ansible/vars/default.yml @@ -41,6 +41,11 @@ host_directory: "{{ podman_data_dir }}/{{ container_name }}" site_port: 3000 pb_port: 8090 +# The Dockerfile's HEALTHCHECK is dropped when podman builds an OCI image (its +# default), so the same check is declared on the Quadlet unit and the play gates +# on `podman healthcheck run`. curl is in the runner image. +health_cmd: "curl -fsS http://127.0.0.1:{{ pb_port }}/api/health > /dev/null && curl -fsS http://127.0.0.1:{{ site_port }} > /dev/null" + # Public hosts for frontend & PocketBase routing. host: www.greatbear.in apex_host: greatbear.in