← Back to Projects

Designing for Node Failure on AKS

How one memory-saturated node took down login, and the high-availability baseline that prevents a repeat

Platform: AKS (dedicated node pool)
Type: P1 incident RCA
Focus: Resilience standards
Role: Investigator

Overview

Users of a SaaS product couldn't sign in for roughly half an hour, and two dependent tools failed with it. The service eventually recovered by itself, which made it tempting to move on. I rebuilt the timeline instead, and found three ordinary conditions that together turned one node failure into an outage.

Timeline (relative)

T +Event
0 minLast successful sign-in transaction
~1 minNode memory hits about 94% of allocatable, CPU spikes, the node stops reporting and goes NotReady
1–6 minReplacement auth pod can't schedule: the node pool is at its autoscaler maximum and in scale-up backoff
~6 minPlatform auto-repair reboots the node
~32 minNode Ready, auth pod running again
~33 minSign-ins succeed

Root Cause

Node Amemory saturatedAuth service1 replica on Node AReplacement podPendingAutoscalerat max, backoff
Three ordinary conditions, combined
  1. Single replica: losing one node meant losing authentication completely.
  2. Memory saturation: the node was running hot. Requests were probably set below real usage, which let the scheduler overcommit it.
  3. No room to heal: the autoscaler maximum left nowhere for the evicted pod to go until the same node came back.

Recommended Baseline for Critical Services

ControlStandardWhy
ReplicasAt least 2, or 3 for auth and gatewaysSurvives losing a node
PodDisruptionBudgetminAvailable: 1Survives drains and upgrades
Topology spreadAcross nodes and zonesReplicas never share a failure domain
RequestsSet from observed p95 usagePrevents overcommit
AutoscalerMaximum with headroom, plus a backoff alertLets the cluster reschedule
Node alertsWorking set over 85% of allocatableWarns before NotReady
tier-1 baseline (illustrative)
apiVersion: apps/v1
kind: Deployment
metadata: { name: auth-service }
spec:
  replicas: 3
  template:
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: DoNotSchedule
          labelSelector: { matchLabels: { app: auth-service } }
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: auth-service }
spec:
  minAvailable: 1
  selector: { matchLabels: { app: auth-service } }

Key Outcomes

Lessons Learned

Conclusion

The node failure was ordinary. The configuration around it is what made it an outage. A clear baseline turns the next node failure into a non-event.

Technologies Used

AKSCluster AutoscalerNode Auto-RepairPodDisruptionBudgetsTopology SpreadRequests & LimitsKubernetes Monitoring

About this case study: this write-up is drawn from my hands-on platform engineering experience. Organisation names, system names, figures and timelines have been changed or generalised, and all code, configuration and queries are illustrative examples written for this page.

← Unblocking Batch Jobs: An Admission Webhook BottleneckCrash-Loops with Three DNS Root Causes →
← Back to Projects Get in Touch