Podman Quadlet and systemd restart policy conflict during healthcheck failures
0 reputation · 17 Feb 2022, 21:24 UTC
0 reputation · 17 Feb 2022, 21:24 UTC
If a container fails a defined healthcheck, Podman may attempt a restart based on internal logic. However, if the generated systemd unit also has a Restart= policy defined, it is unclear how the two managers arbitrate a restart triggered by a healthcheck failure versus a process-level exit. This overlap can lead to unpredictable restart loops or suppressed recovery if the KillMode or unit type are not perfectly aligned between the two layers.
35775 reputation · 18 Feb 2022, 04:54 UTC
Systemd does not prioritize a restart request based on a Podman healthcheck failure if the container process remains running. Because systemd monitors the process state (the PID of the container engine/shim) rather than the application state (the healthcheck status), a container marked as "unhealthy" by Podman is still seen as "active" by systemd. Consequently, systemd will not trigger a Restart= policy unless the container process actually exits.
The ambiguity arises when both Podman's internal restart policies (e.g., --restart always) and systemd's Restart= directives are active. In a Quadlet-managed environment, the generated unit file is the primary authority. If a healthcheck failure leads to a process crash, both managers may attempt to intervene. This overlap often results in restart loops or race conditions where systemd kills the container to restart it just as Podman is attempting an internal recovery.
To ensure systemd handles the lifecycle without conflict, delegate all restart logic to the systemd unit and disable Podman's internal policies. In your .container file, use the following approach:
Restart= or --restart flags from the Container= or Exec= lines.[Service] section of the Quadlet file to ensure systemd is the sole orchestrator.[Container]
Image=quay.io/example/app:latest
HealthCmd=curl -f http://localhost:8080/health
[Service]
Restart=on-failure
RestartSec=5s
To verify that systemd is managing the recovery and not Podman's internal engine, use these commands:
systemctl cat container-app.servicepodman inspect <container_id> --format '{{.HostConfig.RestartPolicy.Name}}'journalctl -u container-app.service -fMissing Diagnostic: Are you using a custom healthcheck script that explicitly calls exit 1 to terminate the container process upon failure? If the process does not exit, systemd will never trigger a restart regardless of the health status.
Use comments to ask for clarification. Post a solution as an answer.
35,775 reputation · 18 Feb 2022, 07:22 UTC
To build on the previous point, it is important to clarify that Podman's HealthCmd is purely diagnostic; it changes the container status to unhealthy but does not send a termination signal to the process. Since systemd only reacts to process exits or signals, a container can remain unhealthy indefinitely while systemd reports it as active (running).
If you require a restart specifically triggered by a healthcheck failure, you cannot rely on Restart=on-failure alone. You must implement an external trigger. A common pattern is using a sidecar container or a simple systemd timer that runs a script to check the status:
# Example logic for a monitoring script
if [ "$(podman inspect --format='{{.State.Health.Status}}' container_name)" == "unhealthy" ]; then
systemctl restart container-name.service
fi
When verifying this behavior, check systemctl status to see if the Main PID has changed. If the PID remains the same despite an unhealthy status, systemd is correctly ignoring the application-level failure.