Skip to content
LatchkeyLatchkey home

kubectl drain: Usage, Options & Common CI Errors

Evict pods off a node before you take it down.

kubectl drain cordons a node and evicts its pods so it can be rebooted, upgraded, or removed. It respects PodDisruptionBudgets, which is exactly why it sometimes refuses to finish.

What it does

kubectl drain NODE marks the node unschedulable (cordon) and then evicts each pod via the eviction API, honouring PodDisruptionBudgets. DaemonSet pods and bare pods need explicit flags. It blocks until the node is empty (minus DaemonSets), making it safe to combine with node-lifecycle automation.

Common usage

Terminal
kubectl drain ip-10-0-1-5 --ignore-daemonsets
kubectl drain ip-10-0-1-5 --ignore-daemonsets --delete-emptydir-data
kubectl drain ip-10-0-1-5 --grace-period=120 --timeout=5m
# ... do node maintenance ...
kubectl uncordon ip-10-0-1-5

Common errors in CI

"cannot delete DaemonSet-managed Pods" stops the drain until you add --ignore-daemonsets; "cannot delete Pods with local storage" needs --delete-emptydir-data (data in emptyDir is lost - that is the point of the flag). The blocker that hangs automation is a PodDisruptionBudget: "Cannot evict pod ... violates the disruption budget" means evicting would drop the workload below its minAvailable, so drain retries until another replica is Ready or --timeout fires. Set a --timeout so the step fails instead of hanging, and ensure replicas can reschedule before draining.

Using this in CI

A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.

Terminal
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods

# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info

# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes

Frequently asked questions

kubectl drain: Usage, Options & Common CI Errors?
kubectl drain cordons a node and evicts its pods so it can be rebooted, upgraded, or removed. It respects PodDisruptionBudgets, which is exactly why it sometimes refuses to finish.
What it does?
kubectl drain NODE marks the node unschedulable (cordon) and then evicts each pod via the eviction API, honouring PodDisruptionBudgets. DaemonSet pods and bare pods need explicit flags. It blocks until the node is empty (minus DaemonSets), making it safe to combine with node-lifecycle automation.
Common errors in CI?
"cannot delete DaemonSet-managed Pods" stops the drain until you add --ignore-daemonsets; "cannot delete Pods with local storage" needs --delete-emptydir-data (data in emptyDir is lost - that is the point of the flag). The blocker that hangs automation is a PodDisruptionBudget: "Cannot evict pod ...

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card