# kubectl drain: Usage, Options & Common CI Errors

> kubectl drain safely evicts pods from a node before maintenance. DaemonSet and local-data flags, and the PodDisruptionBudget blocks automation hits.

Source: https://latchkey.dev/learn/command-reference/kubectl-drain  
Updated: 2026-06-25

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
```

> Always set `--request-timeout` in CI. Without it an unreachable API server hangs until the job times out, which turns a thirty-second failure into a twenty-minute one.

## FAQ

### 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 ...

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
