New to Kestra?
Use blueprints to kickstart your first workflows.
Monitor Portainer-managed Docker containers and alert Slack when one is stuck restarting or has exited.
A container stuck in Docker's restart-backoff loop does not show up anywhere unless someone happens to run docker ps at the right moment. This blueprint authenticates against Portainer on a schedule, lists every container on a Docker endpoint through Portainer's own Docker API proxy, and pages Slack the moment one is crash-looping, has exited, or Portainer itself cannot be reached.
login_to_portainer (io.kestra.plugin.core.http.Request) authenticates against POST /api/auth with a Portainer username and password, returning a jwt. allowFailure: true lets the flow continue into classification instead of aborting on a bad login.list_containers (io.kestra.plugin.core.http.Request) calls GET /api/endpoints/{endpoint_id}/docker/containers/json?all=true with the jwt as a Bearer token, returning Docker's own container list (every container's State: running, restarting, exited, paused, or dead).classify_container_health (io.kestra.plugin.core.debug.Return) checks whether list_containers.body is defined; if not, UNREACHABLE. Otherwise it counts containers with jq by State: any restarting container is CRITICAL (Docker is actively retrying a failing container), any exited container is AT_RISK, otherwise HEALTHY.route_by_container_health (io.kestra.plugin.core.flow.Switch) branches on that string: HEALTHY logs a quiet confirmation, AT_RISK and CRITICAL each page Slack with the specific container names, UNREACHABLE pages Slack separately, and defaults logs the raw outcome.log_audit_status records a status line on every run regardless of branch, so the execution history is a continuous container-health trend.errors block pages Slack separately if the flow itself fails outright.container_health_schedule trigger polls every 5 minutes with explicit input overrides, shipped disabled: true until you point it at a real Portainer instance.status output (HEALTHY / AT_RISK / CRITICAL / UNREACHABLE) you can chart or gate other flows on.Checking docker ps by hand, or on a bare cron job, tells you nothing once the terminal closes. This flow keeps every login, every container snapshot, and every classification in the execution history, turns the health check into a typed output other flows can depend on, and gives you a Switch branch to grow into real remediation (restarting a specific container via the same Docker API proxy, opening a ticket, paging on-call) without rewriting the check itself.
portainer_url. The free, official Docker image (portainer/portainer-ce) is enough to fully test this blueprint locally: docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer-ce:latest.endpoint_id of the Docker environment to check, visible in the Portainer UI under Environments.PORTAINER_USERNAME: Portainer username used to authenticate against /api/auth.PORTAINER_PASSWORD: password for that user.SLACK_WEBHOOK_URL: Slack incoming webhook used for the AT_RISK alert, the CRITICAL alert, the unreachable alert, and the flow-failure alert.SECRET_PORTAINER_USERNAME, SECRET_PORTAINER_PASSWORD, and SECRET_SLACK_WEBHOOK_URL as base64, for example echo -n "<your-value>" | base64.PORTAINER_USERNAME, PORTAINER_PASSWORD, and SLACK_WEBHOOK_URL secrets.portainer_url and endpoint_id to your Docker environment.always) so there is something to detect, run the flow once, and confirm status reads AT_RISK or CRITICAL.container_health_schedule.POST /api/endpoints/{id}/docker/containers/{containerId}/restart as a safe remediation step for AT_RISK containers instead of only alerting.Loop task over list_containers to also surface each container's Image and uptime in the Slack message for faster triage.