Fractal Techware

Alert runbooks /

KubeNodeCordoned

A node has been cordoned (no new pods allowed) for much longer than a normal maintenance window, most likely by accident.

   
Severity info
Source kube-state-metrics v2.x
Key metric kube_node_spec_unschedulable (label node)

What it means

kubectl cordon and kubectl drain set spec.unschedulable on a node. Existing pods keep running, but nothing new is scheduled there. The alert fires once a node has stayed cordoned for a long stretch.

It is informational because nothing is broken yet. The cost is quiet: you pay for capacity you cannot use, the remaining nodes run hotter, and the next node failure hurts more than it should.

Common causes

First checks

  1. See how much of the fleet is cordoned and since when (graph over a few days):
    sum(kube_node_spec_unschedulable) / count(kube_node_spec_unschedulable)
    

    That gives the share of nodes cordoned; to name them:

    kubectl get nodes | grep SchedulingDisabled
    
  2. Find out who cordoned it. The field manager tells you whether it was kubectl, an upgrade tool or an autoscaler:
    kubectl get node <node> --show-managed-fields -o yaml | grep -B8 "f:unschedulable"
    
  3. Check taints and annotations left by maintenance tooling:
    kubectl get node <node> -o jsonpath='{.spec.taints}{"\n"}{.metadata.annotations}{"\n"}'
    
  4. See what is still running and whether a PodDisruptionBudget blocks eviction:
    kubectl get pods -A --field-selector spec.nodeName=<node> -o wide
    kubectl get pdb -A
    

Fixing it

Ask the owner (from step 2) whether the work is done. If the node is healthy, kubectl uncordon <node>. If maintenance is still needed, finish the drain: resolve the blocking PodDisruptionBudget (scale the workload up so it tolerates one disruption), then complete the work and uncordon. If the node was quarantined for a hardware or kernel issue, drain it and replace it instead of leaving it half in service.