TriliumNext: User=0 for keep-id, and our own health check
The first run of this playbook against emily failed, and all three reasons are worth recording because none of them is visible from the files alone. keep-id runs the container *process* as the uid it maps, so UserNS=keep-id:uid=1000,gid=1000 started the container as `node` rather than root -- and the image's start-docker.sh is written to start as root, ending with `exec su -c "node ./main.mjs" node`. `su` from a non-root uid asks for a password the node account does not have, so the container died with "su: Authentication failure" and Restart=always turned that into a crash loop. User=0 forces the process back to root and changes nothing about the mapping: node is still tanshu, so the app is still what writes the data directory and it stays tanshu's. nextcloud.container carries the same pair for the same reason. The health check had to be defined rather than inherited. `latest` floated between the two pulls -- monoco runs v0.95.0 (built 2025-06-15) and emily pulled v0.106.0 (built 2026-09-25) -- and v0.106.0 ships no HEALTHCHECK where v0.95.0 had docker_healthcheck.cjs, so `podman healthcheck run` failed with "no defined healthcheck". The unit now defines HealthCmd= against /api/health-check, the endpoint the app advertises itself in the healthcheck-url file it writes into the data directory, and the image has curl for it (but not wget). The verify and health-check steps are folded in with the start, because they fail the same way and want the same evidence. `systemctl start` reports success as soon as systemd holds the unit, so a container that dies a second later surfaced only as "activating" from `is-active`; the reason -- that "su: Authentication failure" -- was in the journal and nowhere the play looked. The rescue now dumps status, journal and podman logs for any of the three, which is how the su failure was found in the first place. The version float becomes a documented risk rather than a hypothetical: the cutover upgrades the app as well as the runtime, and the first start migrates document.db forward. That is one-way for the copy on emily, so the readme compares digests before the first start, keeps monoco's own tree as the rollback, and notes that pinning a tag here would decouple the two changes. Verified on emily rather than by inspection: the rendered unit was run first as a throwaway Quadlet unit against a scratch volume, then the playbook itself ran to ok=22/changed=6/failed=0 with the mount assertion passing, `healthcheck run` returning 0, podman reporting healthy, and the app's files landing in ~/podman-data/trilium owned by tanshu. The data directory was emptied afterwards and the unit left stopped, ready for the copy from monoco, which has not run yet.
This commit is contained in:
1 parent
17c64cf2f8
commit
3d4ccdd6d1
4 files changed
+161
-64
No files matched your search
@@ -38,6 +38,14 @@ unit_name: "{{ container_name }}.service"
|
||||
# playbook pulled: monoco has been running TriliumNext since June 2025, and its
|
||||
# document.db carries the schema migrations that came with it. Pulling the old
|
||||
# image against that database would not work.
|
||||
#
|
||||
# `latest` has floated, and by more than a patch: monoco runs v0.95.0 (built
|
||||
# 2025-06-15) and the pull on emily is v0.106.0 (2026-09-25). TriliumNext
|
||||
# migrates document.db forward on first start, so the cutover is also an app
|
||||
# upgrade -- one-way for the copy on emily, which is why the readme says to
|
||||
# compare digests before the first start and to leave monoco's own tree alone.
|
||||
# Pin a digest or a version tag here if the migration should move the runtime
|
||||
# only and leave the app version to a separate, deliberate step.
|
||||
image: docker.io/triliumnext/notes:latest
|
||||
|
||||
# The Quadlet file is <network_name>.network. caddy/roles/register pins the
|
||||
@@ -67,6 +75,13 @@ backup_dir: "{{ data_dir }}/backup"
|
||||
# it; nothing is published on the host.
|
||||
container_port: 8080
|
||||
|
||||
# The unit's own HEALTHCHECK, because the image does not ship one: v0.106.0
|
||||
# dropped the docker_healthcheck.cjs that v0.95.0 had, so `podman healthcheck
|
||||
# run` otherwise fails with "no defined healthcheck". /api/health-check is the
|
||||
# endpoint the app advertises itself, writing it to `healthcheck-url` in the data
|
||||
# directory at startup. `curl` is in the image; `wget` is not.
|
||||
health_cmd: "curl -fsS -o /dev/null http://127.0.0.1:{{ container_port }}/api/health-check"
|
||||
|
||||
# The shared Caddy unit and its Caddyfile, both owned by caddy/playbook.yml.
|
||||
caddy_name: caddy
|
||||
caddyfile_path: "{{ podman_data_dir }}/{{ caddy_name }}/conf/Caddyfile"
|
||||
|
||||
Reference in new issue
Block a user