authentik: boot-persistent quadlet conversion with deploy handler

The compose-era authentik trio died at every boot (rootless podman does not
auto-start bare containers). Convert the trio to Quadlet units installed by
deploy-remote.sh into ~/.config/containers/systemd/, enabled + WantedBy=
default.target:

- 3 unit files under dankclaw/authentik/quadlet/ (postgres -> server -> worker
  ordering via Wants=/After=; secrets stay in the git-ignored host .env,
  expanded by systemd at start time exactly like the gitea units)
- deploy_authentik() handler: install units, daemon-reload, retire stale
  compose-era containers only while units are inactive, enable once, then
  start in dependency order with podman-health gates between stages
- compose.yaml: authentik service definitions retired to a comment pointing at
  the quadlet dir (same pattern as searxng/open-webui/gitea/caddy)
- tests/authentik.bats rewritten from compose assertions to unit-file
  contract assertions (images, Exec roles, ordering, loopback-only publish,
  pg_isready probe, secret hygiene, dispatch routing)
This commit is contained in:
Frank
2026-08-28 03:09:19 -07:00
parent 5829a0bfe8
commit 914e251ebc
6 changed files with 211 additions and 120 deletions
+45 -1
View File
@@ -359,7 +359,7 @@ deploy_compose_service() {
return 0
fi
case "$service" in
comfyui|hermes|hermes-dashboard|hermes-webui|prometheus|grafana|loki|alloy|node-exporter|authentik-postgres|authentik-server|authentik-worker)
comfyui|hermes|hermes-dashboard|hermes-webui|prometheus|grafana|loki|alloy|node-exporter)
case "$service" in
comfyui|loki|alloy)
build_compose_image "$service"
@@ -505,6 +505,47 @@ relink_unit() {
run_privileged ln -sfn "$REMOTE_DIR/scripts/$service.service" "/etc/systemd/system/$service.service"
}
# Authentik runs as three boot-persistent Quadlet units (postgres -> server ->
# worker). The trio deploys as one unit: unit files are installed, stale
# compose-era containers holding the claimed names are retired, then the chain
# starts in dependency order with health gates between stages. Re-running the
# handler on an already-active stack is a deliberate no-op (no DB bounce).
wait_container_healthy() {
local name="$1" limit="$2" status="unknown"
for ((i = 1; i <= limit; i += 5)); do
status="$(podman inspect -f '{{.State.Health.Status}}' "$name" 2>/dev/null || echo missing)"
[[ "$status" == "healthy" ]] && {
echo "$name healthy after approximately ${i}s"
return 0
}
sleep 5
done
echo "FAIL: $name did not become healthy in ${limit}s (status: $status)" >&2
return 1
}
deploy_authentik() {
local unit
mkdir -p "$quadlet_unit_dir"
for unit in authentik-postgres authentik-server authentik-worker; do
cp "dankclaw/authentik/quadlet/$unit.container" "$quadlet_unit_dir/"
done
systemctl --user daemon-reload
# Retire compose-era containers only while the units are not yet active;
# unit-managed containers self-heal via Restart=always.
if ! systemctl --user is-active --quiet authentik-postgres.service; then
podman stop authentik-postgres authentik-server authentik-worker 2>/dev/null || true
podman rm authentik-postgres authentik-server authentik-worker 2>/dev/null || true
fi
systemctl --user enable authentik-postgres.service authentik-server.service authentik-worker.service
systemctl --user start authentik-postgres.service
wait_container_healthy authentik-postgres 120 || return 1
systemctl --user start authentik-server.service
wait_container_healthy authentik-server 300 || return 1
systemctl --user start authentik-worker.service
}
deploy_llm_large() {
relink_unit frank-default-large
# NPU is intentionally not restarted here. It is a separate, retired
@@ -555,6 +596,9 @@ deploy_service() {
pihole) deploy_pihole ;;
gitea-postgres) deploy_gitea_unit gitea-postgres gitea-postgres ;;
gitea-server) deploy_gitea_unit gitea-server gitea-server ;;
authentik-postgres|authentik-server|authentik-worker)
deploy_authentik
;;
frank-default-large) deploy_llm_large ;;
frank-default-small) deploy_llm_small ;;
frank-default-npu) deploy_llm_npu ;;