QA
Senior LevelDocker & Deployment

How do you execute zero-downtime Kubernetes control plane and worker node upgrades?

❓ Interview Prompt: Explain the Kubernetes version skew policy, control plane upgrade sequence, and safe rolling node drain/upgrade procedures with PodDisruptionBudgets.

Kubernetes cluster upgrades require careful sequencing to maintain availability. Kubernetes version skew policy: components can be at most 2 minor versions apart.

Upgrade Order (Mandatory Sequence):

1
etcd (if managed separately)
2
kube-apiserver
3
kube-controller-manager and kube-scheduler
4
Worker node kubelets (via cordon + drain + upgrade + uncordon)
5
kube-proxy (or Cilium, if kube-proxy is replaced)
6
CNI plugin

Control Plane Upgrade:

With kubeadm: kubeadm upgrade apply v1.30.0 handles components in correct order. With managed services (EKS, GKE, AKS): use the provider's upgrade API — they handle control plane automatically.

Worker Node Rolling Upgrade:

For each node:

1
`kubectl cordon node-X`: Mark unschedulable — no new pods scheduled here.
2
`kubectl drain node-X --ignore-daemonsets --delete-emptydir-data`: Evict all pods (respects PDBs).
3
Upgrade: SSH into node, run apt upgrade kubeadm kubectl kubelet, then kubeadm upgrade node.
4
`kubectl uncordon node-X`: Mark schedulable again — pods return.

PDB Interaction During Drain:

If draining would violate any PDB (e.g., API deployment has minAvailable: 2 but only 2 pods running), drain blocks until pods reschedule elsewhere. This is by design — PDBs prevent zero-downtime guarantees from being violated.

Code Implementation Example

bash
#!/bin/bash
# Zero-downtime rolling node upgrade script

NODES=$(kubectl get nodes -l node-role.kubernetes.io/worker -o name)

for NODE in $NODES; do
  echo "=== Upgrading $NODE ==="
  
  # Step 1: Cordon — mark unschedulable
  kubectl cordon $NODE
  echo "  Cordoned: $NODE"
  
  # Step 2: Drain — evict pods (respects PDBs, waits up to 5min)
  kubectl drain $NODE \
    --ignore-daemonsets \       # don't try to evict DaemonSet pods
    --delete-emptydir-data \   # allow deleting emptyDir volumes
    --grace-period=60 \        # 60s for graceful shutdown
    --timeout=5m                # timeout waiting for evictions
  
  echo "  Drained: $NODE"
  
  # Step 3: SSH + upgrade kubelet (cloud-init, Ansible, or SSM)
  NODE_IP=$(kubectl get $NODE -o jsonpath='{.status.addresses[0].address}')
  ssh ubuntu@$NODE_IP \
    "sudo apt-get update && sudo apt-get install -y kubelet=1.30.0-1.1 \
     && sudo systemctl daemon-reload && sudo systemctl restart kubelet"
  
  # Step 4: Wait for node to become Ready
  kubectl wait --for=condition=Ready $NODE --timeout=5m
  
  # Step 5: Uncordon — allow scheduling again
  kubectl uncordon $NODE
  echo "  Uncordoned: $NODE"
  
  # Wait 30s before upgrading next node (let pods reschedule)
  echo "  Waiting 30s before next node..."
  sleep 30
done
💡Rolling node upgrade: cordon → drain (PDB-aware) → upgrade kubelet → wait Ready → uncordon → next node.
🎯 Interview Key Takeaway

Upgrade control plane first (kube-apiserver → controllers → schedulers), then rolling drain/upgrade worker nodes one-by-one. PDBs block drain if eviction would violate availability guarantees.

#Kubernetes#Cluster Upgrade#Zero-Downtime#Node Drain#PDB#Senior
Back to all Docker & Deployment Questions→

More Docker & Deployment Interview Questions

Beginner LevelDocker & Deployment

How do Docker Multi-Stage Builds minimize image size and improve security?

Beginner LevelDocker & Deployment

What is the difference between a Docker Container and a Virtual Machine (VM)?

Beginner LevelDocker & Deployment

What is the difference between a Docker Image and a Docker Container?