Schedule icon
Commands icon
Docker icon
Script icon
If icon
SlackIncomingWebhook icon
Set icon

ImageWatch - Kubernetes ImagePullBackOff watcher

A Kestra blueprint that watches Kubernetes pods stuck in ImagePullBackOff or ErrImagePull and alerts on Slack with the likely cause, without spamming.

Categories
Infrastructure

How it works

  1. list_pods (io.kestra.plugin.scripts.shell.Commands) dumps the namespace's pods as JSON with kubectl.
  2. find_stuck (io.kestra.plugin.scripts.python.Script) looks at every container state and collects pods stuck in ImagePullBackOff or ErrImagePull. For each one it guesses the cause from the waiting message, the image name, and the pod's pull secrets: registry rate limiting, auth failures, a private registry with no imagePullSecrets, or a probable typo when the image has never been seen. It compares against the KV state so only newly stuck pods alert.
  3. maybe_alert (io.kestra.plugin.core.flow.If) posts the Slack alert only when there is something new, naming the pod, the exact image, how long it has been stuck, and the likely cause.
  4. save_state (io.kestra.plugin.core.kv.Set) writes back the current stuck list. Recovered pods drop out on their own, so getting stuck again alerts again, and steady-state reruns stay quiet.

What you get

  • A five-minute check for the most common "why won't my pod start" failure, no agent to install inside the cluster.
  • Slack alerts that do the first minute of debugging for you: the image, the wait reason, and a likely cause with what to check.
  • No alert spam: the KV-backed memory remembers who was already reported, and forgets pods that recovered.
  • Quiet runs when every pod pulls fine.

Who it's for

Anyone running workloads on Kubernetes who has stared at ImagePullBackOff wondering whether it is a typo, a secret, or the registry. Works on any cluster you can reach with a client certificate: minikube, kind, managed clusters.

Why orchestrate this with Kestra

kubectl get pods shows you the symptom; this flow adds the diagnosis, the memory, and the notification in one scheduled place. Kestra holds the cluster credentials as secrets, keeps every run's findings where you can audit them, and the KV state means the second run does not page you about the same pod again.

Prerequisites

  • A Kubernetes cluster with pods you can list.
  • A kubeconfig client certificate and key with permission to list pods in the target namespace.
  • Kestra with the Docker task runner available (used for the kubectl and Python steps).
  • A Slack Incoming Webhook URL.

Secrets

Secret What it is
CLIENT_CRT base64-encoded client certificate from your kubeconfig
CLIENT_KEY base64-encoded client key from your kubeconfig
MASTERURL base64-encoded Kubernetes API server URL, reachable from inside the Kestra container
SLACK_WEBHOOK base64-encoded Slack Incoming Webhook URL

In Kestra OSS, secrets come from environment variables prefixed with SECRET_ and must be base64-encoded. If the API URL uses 127.0.0.1 or localhost, replace it with host.docker.internal so the Kestra container can reach it.

Quick start

  1. Start Kestra with the four secrets above as SECRET_ environment variables.
  2. Import this flow and run it with your namespace: if a pod is stuck pulling, the Slack alert names it, the image, and the likely cause.
  3. Fix the image or secret and run again: quiet, the pod dropped out of the stuck list.
  4. Break it again: the alert fires once more, because the state only remembers the currently stuck.

How to extend

  • Add more cause hints, like matching the image against a known-good list from your registry.
  • Include the last few lines of kubectl describe output by shelling out per stuck pod.
  • Run across all namespaces by looping the namespace input with a ForEach task.
  • Route alerts to PagerDuty or Opsgenie by swapping the Slack task for another notification task.

Inputs

Input Type Default What it does
namespace STRING default the namespace whose pods to watch
slack_webhook STRING (required) Incoming webhook URL of the Slack channel for alerts

Links

Pitfalls

  • The cause hint is a heuristic, not a diagnosis. "Check for typos" when the registry is actually down will mislead; always confirm with kubectl describe pod.
  • Pod age is used as the stuck duration, which is only accurate if the pod has been stuck since creation. A pod that ran fine for days and then got stuck on a redeploy will show its full age.
  • One alert per pod: if two containers in the same pod are stuck on different images, only the first is reported. The describe command in the alert covers the rest.
  • The flow is strictly read-only. It never deletes pods, pulls images, or touches secrets.
See How

New to Kestra?

Use blueprints to kickstart your first workflows.