Kubernetes: "Volume Node Affinity Conflict" (PVC Zone Pinning)

A PersistentVolumeClaim exists in one availability zone; the scheduler can only put pods on nodes in that zone. When nodes/pod constraints exclude that zone, pods stay Pending forever. Describe output names the mismatched zone.

What you'll see

Root causes

Zonal volume attached to a pod with conflicting constraints

The PVC's volume physically lives in us-east-1a while the pod's nodeSelector/affinity (or an autoscaler's zone config) excludes 1a. The scheduler cannot satisfy both, so the pod never lands.

StatefulSet replicas or node pool changes stranding volumes

Removing a zone from the node pool or rescheduling a StatefulSet pod that previously pinned a zonal volume: the old volume stays in the now-unavailable zone.

Fix it

  1. Read the conflict zones from the event
    kubectl describe pod <pod> | grep -A 3 'volume node affinity'   # names the volume's zone vs the node zone
  2. Align the pod's constraints with the volume's zone
    kubectl get pvc <pvc> -o jsonpath='{.spec.volumeName}' ; kubectl get pv <pv> -o json | grep -A 3 topology   # find the zone, relax the pod selector to include it
  3. Node pool missing that zone: add a node in the volume's zone (or drain/migrate)
    # cloud node groups: ensure the AZ of the PV has capacity; for StatefulSets, delete the stranded pod after nodes exist in that zone
  4. Future-proof: multi-zone deployments need zone-aware storage
    # use zone-topology StorageClasses (e.g. EBS with WaitForFirstConsumer) so PVs land where the pod schedules

Field note

WaitForFirstConsumer (volumeBindingMode) is THE structural fix: the volume is created in the pod's zone at bind time instead of pinning the pod afterwards. Newly created PVCs should use it by default. This event is the last in a chain — always cross-read with the pod's other scheduling events; a pod with both a topology conflict and a taint issue reports both, and only one shows in most summaries.

Common questions

Why does the same pod work in another namespace/cluster?

Volumes are physical objects in specific zones: a fresh PVC in the new cluster binds in whatever zone the pod actually lands. The old volume can't move — only the constraints can.

Can I move a zonal volume to another AZ?

Not in place — cloud block storage is zone-bound. Migrate data: snapshot/restore to a new PVC with WaitForFirstConsumer, or re-pin the workload to the volume's zone while you plan the migration.

Ship it right the first time

Kustomize base with probes, PDBs, and zero-downtime rollouts already wired.

Kubernetes Production Blueprints — $27 →

One-time. Yours to modify. Instant download from the NinjaOps template store.