This script was vibe-coded with gpt-5.5. Quality assessment: "It works for me". I've only tested it via a per-user runit serivce, the turnstile implementation is untested.
⚠️ While this works, I'm now using a custom build of podman instead: https://github.com/ar-jan/podman#podman-runit-healthcheck
podman-healthcheckd is a small supervised runner for Podman healthchecks on non-systemd systems.
It periodically executes:
podman healthcheck run CONTAINERfor selected running containers, so Podman's stored health state can advance from starting to healthy or unhealthy.
The main use case is Docker Compose used through podman compose on systems where Podman was built without systemd healthcheck timer support.
Docker Compose can wait for depends_on: condition: service_healthy, but it can only observe the health state reported by the container engine.
The default mode checks every running container visible to the user that has an enabled healthcheck command.
To require explicit opt-in by label, set PODMAN_HC_MODE=label:
services:
db:
labels:
podman-healthcheckd.enable: "true"The daemon reads configuration from environment variables:
| Variable | Default | Description |
|---|---|---|
PODMAN |
podman |
Podman executable to run. |
PODMAN_HC_MODE |
all |
label or all. |
PODMAN_HC_LABEL |
podman-healthcheckd.enable=true |
Label filter used in label mode. |
PODMAN_HC_TICK |
1 |
Main loop sleep interval in seconds. |
PODMAN_HC_MIN_INTERVAL |
1 |
Minimum per-container healthcheck interval in seconds. |
PODMAN_HC_STATE_DIR |
unset | Override runtime state directory. |
PODMAN_HC_ONESHOT |
0 |
Set to 1 to run one scan and exit. |
PODMAN_HC_DEBUG |
0 |
Set to 1 to log healthcheck runs and actionable diagnostics. |
The runner should run as the same Unix user that owns the rootless Podman containers.
When XDG_RUNTIME_DIR is unset and /run/user/$(id -u) exists, the daemon exports that value for Podman and uses it for its default state directory. PODMAN_HC_STATE_DIR only overrides the daemon's lock and interval state location.
podman-healthcheckd exits cleanly on TERM, INT, and HUP, so sv restart podman-healthcheckd should stop the daemon without waiting for a timeout.
To verify the daemon and Podman's stored health state:
SVDIR=~/.config/service sv status podman-healthcheckd
podman ps --format '{{.ID}} {{.Names}} {{.Status}}'
podman inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}no-health-state{{end}}' CONTAINER
podman healthcheck run CONTAINERPODMAN_HC_DEBUG=1 logs healthcheck runs and actionable diagnostics, but runit only preserves that output if your user runsvdir captures service stdout/stderr.
To add persistent runit logs using the shipped svlogd example:
cd ~/.config/service/podman-healthcheckd
mkdir -p log/main
cp /usr/share/examples/podman-healthcheckd/runit/user/log/run log/run
chmod +x log/run
SVDIR=~/.config/service sv exit podman-healthcheckd
sleep 1
SVDIR=~/.config/service sv status podman-healthcheckd
sv status ~/.config/service/podman-healthcheckd/log
tail -f ~/.config/service/podman-healthcheckd/log/main/currentFor foreground diagnosis, run one daemon pass from the service directory:
cd ~/.config/service/podman-healthcheckd
PODMAN_HC_DEBUG=1 PODMAN_HC_ONESHOT=1 ./runTo confirm the daemon is active even when logs are quiet:
ls -l /run/user/$(id -u)/podman-healthcheckd/last-*
podman ps --format '{{.Names}} {{.Status}}'make install PREFIX=/usrTo copy the full runit user service example after installing:
mkdir -p ~/.config/service/podman-healthcheckd
cp -a /usr/share/examples/podman-healthcheckd/runit/user/. ~/.config/service/podman-healthcheckd/make check