Node Cordon & Drain

Cordon a Kubernetes node and drain its pods safely, respecting PodDisruptionBudgets, before maintenance or decommissioning.

Node Cordon & Drain lets an admin mark a node unschedulable and move its pods off before maintenance, a resize, or decommissioning it. This is available on the Enterprise plan, and is Kubernetes-only: Docker has no node or scheduler concept, so there's no equivalent action for Docker agents.

Kubernetes has no built-in way to move a specific pod to a specific node. Draining evicts pods and lets the Kubernetes scheduler decide where each one lands among your remaining nodes, the same behavior as `kubectl drain`. There's no way to choose a destination.

What it does

Cordon marks a node unschedulable. This has no effect on pods already running there. It only stops new pods from being scheduled onto it.

Drain cordons the node, then evicts its pods one at a time using Kubernetes' eviction API, which is what actually respects any PodDisruptionBudgets you've configured. If a PDB would be violated, that eviction is retried automatically with backoff rather than forced through. Two kinds of pods are handled specially:

  • DaemonSet-managed pods are always skipped. They'd simply be recreated on the same node regardless, so evicting them accomplishes nothing.
  • Pods using an emptyDir volume lose that data permanently on eviction. The dashboard warns you about this and requires you to acknowledge it before a drain proceeds if any such pods are present.

Uncordon reverses a cordon, making the node schedulable again.

Enabling it

Add this to your helm upgrade/helm install:

--set rbac.allowCordonDrainNodes=true

This is off by default and independent of every other RBAC opt-in. Once enabled, open a node's detail page and use the Cordon/Uncordon/Drain controls there.

Approval

Every cordon, uncordon, and drain request needs approval from an admin (any admin, including the one who requested it) before it's applied. Draining in particular can affect many workloads at once, so it goes through the same approval step as editing or deleting a Deployment. Pending and completed requests are listed on the Nodes page, along with a per-pod result summary (evicted, skipped, and failed counts) once a drain finishes.

Limitations

  • This is cordon and drain only. There's no way to move a workload to a specific destination node (see the note above on why).
  • A bare pod with no owning controller (Deployment, StatefulSet, DaemonSet, etc.) can't be "moved" by any mechanism. Evicting one just removes it permanently, since nothing recreates it elsewhere.
  • Draining can take longer than a moment when PodDisruptionBudgets are tight and evictions have to be retried. The dashboard reports the drain as accepted immediately and updates with the final result once it completes.