# Kubernetes high availability: acht punten die samenwerken

Hoge beschikbaarheid voor applicaties op Kubernetes.

Pascal van der Horst · 2026-10-30

Een node valt uit. De applicatie moet blijven draaien. Daarvoor zijn voldoende replicas nodig, verspreid over nodes en zones, met ruimte voor herstel en updates die verkeer blijven afhandelen.

De acht instellingen in dit artikel zijn uitgewerkt voor één stateless API. Het voorbeeld gebruikt drie replicas en drie zones. De basis van het cluster komt eerst aan bod; daarna volgen de instellingen voor de applicatie. Databases, singletons en batchtaken vragen om eigen keuzes.

Test wat er bij uitval blijft werken. Meet tijdens de verstoring of de applicatie nog voldoende verkeer afhandelt en hoe lang herstel duurt.

## Begin bij de basis van het cluster.

De control plane stuurt het cluster aan; etcd bewaart de clusterstatus. Bij stacked etcd draaien beide op dezelfde nodes. Een gebruikelijke HA-opstelling voor een zelfbeheerd cluster bestaat uit minimaal drie control-plane-nodes achter een redundant API-endpoint. Drie etcd-leden hebben een meerderheid van twee nodig en kunnen daardoor één lid verliezen. Het consensusprotocol zorgt voor die meerderheid.

Bij managed Kubernetes beheert de leverancier een deel van deze basis. Controleer welke onderdelen over zones zijn verdeeld, welke beschikbaarheid is afgesproken en wie verantwoordelijk is voor herstel. Als de control plane uitvalt, kunnen bestaande pods doorwerken. Nieuwe pods plaatsen, configuratie wijzigen en herstel aansturen kan dan worden geblokkeerd.

Controleer ook ingress of Gateway, DNS, het containernetwerk, opslag en externe afhankelijkheden. Een database heeft een eigen beschikbaarheidsontwerp nodig, ook als de operator ervan redundant draait. Zonegebonden volumes kunnen herplaatsing beperken. Zorg daarnaast voor back-ups en een geteste restore.

Spreek af welke uitval het ontwerp moet opvangen. Leg het doel vast in een Service Level Objective (SLO). Benoem ook de gewenste hersteltijd, de Recovery Time Objective (RTO), en het aanvaardbare dataverlies in tijd, de Recovery Point Objective (RPO). Uitval van één zone en uitval van een hele regio zijn verschillende scenario’s.

## 1. Replicas: voldoende kopieën én resterende capaciteit.

Hoeveel instanties blijven bruikbaar als er één wegvalt?

Kies genoeg replicas om de afgesproken belasting ook na uitval af te handelen. In dit voorbeeld draaien drie replicas. Als er één uitvalt, blijven er twee over. Meet of die twee de piekbelasting aankunnen.

Een Deployment legt met spec.replicas het gewenste aantal pods vast. De ReplicaSet probeert dat aantal in stand te houden. De applicatie moet meerdere instanties tegelijk ondersteunen: let op lokale sessies, bestanden, locks en achtergrondtaken. Gedeelde state kan buiten de pods worden opgeslagen; die datastore heeft een eigen beschikbaarheidsontwerp nodig.

Eén replica kan met extra surge-capaciteit soms zonder geplande onderbreking worden bijgewerkt, maar kan de uitval van die ene pod niet opvangen. Kies het aantal op basis van de belasting, het belang van de applicatie en de uitval die moet worden opgevangen. Een oneven aantal replicas geeft een gewone API geen quorum of bescherming tegen split brain.

```yaml
spec:
  replicas: 3
```

**Controle:** Meet of twee overblijvende replicas de afgesproken piekbelasting verwerken.

[Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)

## 2. PodDisruptionBudget: onderhoud begrenzen.

Hoeveel pods mogen via de Eviction API tegelijk verdwijnen?

Beperk hoeveel gezonde pods tijdens onderhoud mogen verdwijnen. Een PodDisruptionBudget (PDB) doet dat voor vrijwillige verstoringen via de Eviction API, bijvoorbeeld bij een node-drain. Met drie gezonde replicas en minAvailable: 2 is normaal één eviction toegestaan. Gebruik minAvailable óf maxUnavailable en selecteer de bedoelde pods met de labelselector.

Het PDB begrenst geen nodecrash, zone-uitval, Deployment-rollout, directe podverwijdering of afschaling via het scale-subresource. Een HorizontalPodAutoscaler (HPA) kan dus terugschalen ondanks het PDB. Stel het minimale aantal replicas apart in.

Bepaal ook wat er met ongezonde pods moet gebeuren. Zonder unhealthyPodEvictionPolicy geldt IfHealthyBudget: een draaiende pod die niet Ready is, mag alleen worden geëvict als currentHealthy minimaal desiredHealthy is. Als dit budget niet wordt gehaald, kan zo’n pod een drain blokkeren.

Het voorbeeld kiest unhealthyPodEvictionPolicy: AlwaysAllow voor deze stateless API. Draaiende, ongezonde pods mogen dan ook bij een tekort aan gezonde pods worden geëvict. Gezonde pods blijven onder het PDB vallen. De afweging: onderhoud hoeft niet op de ongezonde pod te wachten, maar die krijgt ook geen extra kans om op dezelfde node te herstellen. Kies de policy op basis van het herstelgedrag van de applicatie.

```yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: example-api
  namespace: ha-example
spec:
  minAvailable: 2
  unhealthyPodEvictionPolicy: AlwaysAllow
  selector:
    matchLabels:
      app.kubernetes.io/name: example-api
```

**Controle:** Controleer status.disruptionsAllowed. Test een drain met drie gezonde pods, met een ontbrekende pod en met een draaiende pod die niet Ready wordt.

![PodDisruptionBudget: onderhoud begrenzen.](https://horstconsultancy.nl/images/articles/ha/disruptions-nl-light-wide.svg)

[Pod disruptions](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) · [Configure a PodDisruptionBudget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/)

## 3. Node anti-affinity: kopieën op verschillende hosts.

Kan één defecte node meerdere replicas tegelijk raken?

Zet replicas op verschillende nodes, zodat één defecte node niet alle kopieën raakt. Pod anti-affinity regelt dit voor nieuwe pods met hetzelfde applicatielabel. Het voorbeeld gebruikt topologyKey: kubernetes.io/hostname om per host te spreiden.

requiredDuringSchedulingIgnoredDuringExecution is een harde plaatsingsregel; preferredDuringSchedulingIgnoredDuringExecution is een voorkeur. Bij een harde regel blijft een pod Pending als geen node aan de voorwaarden voldoet. Vrije resources, taints, tolerations en node selectors tellen ook mee. Drie replicas vragen hier drie geschikte hosts; een extra surge-pod heeft tijdelijk een vierde nodig.

IgnoredDuringExecution betekent dat de regel bestaande pods niet automatisch verplaatst wanneer labels wijzigen. Controleer daarom de werkelijke plaatsing na een rollout en na onderhoud.

```yaml
affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app.kubernetes.io/name: example-api
        topologyKey: kubernetes.io/hostname
```

**Controle:** Controleer de nodekolom: iedere replica staat op een andere geschikte host.

[Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/)

## 4. Zonespreiding: ook gedeelde infrastructuur kan uitvallen.

Blijft de applicatie bruikbaar wanneer een faaldomein wegvalt?

Verdeel replicas over zones om gedeelde uitval te beperken. Verschillende hosts kunnen nog steeds dezelfde stroomvoorziening of netwerkverbinding delen. topologySpreadConstraints gebruikt het nodelabel topology.kubernetes.io/zone voor die verdeling. De labels moeten echte, onafhankelijke infrastructuur beschrijven.

Met maxSkew: 1 en DoNotSchedule begrenst de scheduler het verschil ten opzichte van de zones die meetellen en de minste pods bevatten. Hij telt pods die bij de labelselector passen, ongeacht hun verwerkingscapaciteit. ScheduleAnyway maakt van de spreiding een voorkeur. Bestaande pods worden niet automatisch verplaatst.

nodeAffinityPolicy en nodeTaintsPolicy bepalen mede welke zones meetellen. Het voorbeeld gebruikt Honor voor beide. minDomains staat bewust niet op 3: die ondergrens kan het plaatsen van vervangers op twee overgebleven zones blokkeren. Zonder dit veld gebruikt de berekening 1. Controleer bij zone-uitval ook taints, tolerations en vrije capaciteit op de resterende nodes.

```yaml
topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    nodeAffinityPolicy: Honor
    nodeTaintsPolicy: Honor
    labelSelector:
      matchLabels:
        app.kubernetes.io/name: example-api
```

**Controle:** Toets zowel resterende capaciteit als Pending-pods bij het wegvallen van één zone.

![Zonespreiding: ook gedeelde infrastructuur kan uitvallen.](https://horstconsultancy.nl/images/articles/ha/placement-nl-light-wide.svg)

[Pod Topology Spread Constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)

## 5. Rolling updates: eerst een bruikbare vervanger.

Kan een nieuwe versie starten voordat oude capaciteit verdwijnt?

Start een bruikbare vervanger voordat oude capaciteit verdwijnt. Bij een gezonde start houdt RollingUpdate met maxUnavailable: 0 de gewenste beschikbare capaciteit aan. maxSurge: 1 laat één extra pod toe. Met minReadySeconds: 10 moet een nieuwe pod tien seconden aaneengesloten Ready blijven voordat die als Available telt.

De Deployment regelt dit los van het PDB. Zonder plek voor de extra pod kan de rollout vastlopen, terwijl oude pods blijven draaien. Pods die nog worden beëindigd, kunnen tijdelijk ook resources gebruiken. Houd daar rekening mee boven op maxSurge. progressDeadlineSeconds markeert een vastgelopen rollout; een rollback moet apart worden geregeld.

Laat oude en nieuwe versies veilig naast elkaar werken, ook met gedeelde data en databaseschema’s. Laat de applicatie bij SIGTERM stoppen met nieuw werk en lopende requests afronden. terminationGracePeriodSeconds omvat de hele beëindiging, inclusief eventuele preStop-hooks. Geef route- en endpointwijzigingen tijd om door te werken en test het resultaat onder belasting.

```yaml
spec:
  minReadySeconds: 10
  progressDeadlineSeconds: 600
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    spec:
      terminationGracePeriodSeconds: 60
```

**Controle:** Voer een rollout onder belasting uit en meet foutpercentage, latency en beschikbare replicas.

![Rolling updates: eerst een bruikbare vervanger.](https://horstconsultancy.nl/images/articles/ha/rollout-nl-light-wide.svg)

[Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) · [Pod lifecycle and termination](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)

## 6. Resources: ruimte voor normaal bedrijf én verstoring.

Passen herstel en een rollout nog wanneer het druk is?

Reserveer ook capaciteit voor uitval en updates. De scheduler gebruikt resource requests om pods te plaatsen. Te lage requests kunnen een node te vol laten lopen bij piekbelasting; te hoge requests houden ruimte bezet die andere pods zouden kunnen gebruiken. Meet normaal verbruik, startpieken en gedrag bij uitval.

CPU-limits kunnen leiden tot throttling: de applicatie krijgt dan minder CPU-tijd. Overschrijding van een geheugenlimiet kan tot een OOM-kill leiden, een beëindiging wegens geheugentekort. Dit voorbeeld laat de CPU-limit weg. Bij gedeeld gebruik, isolatie-eisen of clusterbeleid kan een expliciete CPU-limit wel nodig zijn.

Houd ruimte vrij voor systeemtaken, een extra pod tijdens de rollout en herplaatsing na uitval. Een CPU-gebaseerde HPA vergelijkt het gebruik met de CPU-request. Kies die request daarom op basis van metingen. Met deze requests en alleen een geheugenlimiet krijgt de pod niet de Guaranteed QoS-klasse.

```yaml
resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    memory: 512Mi
```

**Controle:** Meet startpieken, OOM-kills, throttling en plaatsbaarheid tijdens een verstoring.

[Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) · [Horizontal Pod Autoscaling](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/)

## 7. Probes: opstarten, verkeer ontvangen en herstellen scheiden.

Welke controle houdt verkeer tegen, en welke herstart een container?

Geef opstarten, verkeer ontvangen en herstarten elk een eigen controle. Een startupProbe geeft tijd voor initialisatie. Tot die slaagt, starten de liveness- en readiness-controles niet. periodSeconds: 5 en failureThreshold: 24 geven hier grofweg twee minuten opstarttijd; de probeplanning en uitvoering bepalen de werkelijke tijd.

Readiness bepaalt of een pod via een gewone Service verkeer kan ontvangen. Een mislukte readiness-probe herstart de container niet. Liveness is bedoeld voor een proces dat niet zelfstandig herstelt, zoals bij een deadlock. Na voldoende mislukte controles wordt de container herstart. Dat kan ook gebeuren als de startup-probe blijft mislukken.

Houd een externe database of API buiten liveness, zodat een gedeelde storing geen herstartgolf veroorzaakt. Readiness kan essentiële afhankelijkheden controleren. Houd er dan rekening mee dat database-uitval alle replicas NotReady kan maken. Houd de probes licht en kies timeouts en thresholds op basis van gemeten gedrag.

```yaml
startupProbe:
  httpGet: { path: /health/startup, port: http }
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 24
readinessProbe:
  httpGet: { path: /health/ready, port: http }
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 2
livenessProbe:
  httpGet: { path: /health/live, port: http }
  periodSeconds: 10
  timeoutSeconds: 3
  failureThreshold: 3
```

**Controle:** Test trage startup, een NotReady-pod en een externe dependency-storing afzonderlijk.

![Probes: opstarten, verkeer ontvangen en herstellen scheiden.](https://horstconsultancy.nl/images/articles/ha/probes-nl-light-wide.svg)

[Liveness, Readiness, and Startup Probes](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/)

## 8. PriorityClass: bewust kiezen bij schaarste.

Welke workload krijgt voorrang wanneer niet alles past?

Spreek af welke workloads voorrang krijgen als capaciteit schaars is. Een PriorityClass bepaalt de relatieve prioriteit voor scheduling. Het is een clusterbreed object dat vooraf moet bestaan. De pod verwijst ernaar met priorityClassName. Gebruik een afgesproken indeling, zodat de waarde een duidelijke betekenis heeft.

Met preemptionPolicy: Never krijgt de pod voorrang in de schedulingwachtrij, maar verdringt die geen draaiende pods met een lagere prioriteit. De standaardinstelling PreemptLowerPriority kan dat onder voorwaarden wel doen. Daarbij probeert Kubernetes een PDB te respecteren, maar kan het budget toch worden overschreden.

Een PriorityClass reserveert geen CPU, geheugen of nodes. Een pod met hoge prioriteit kan dus Pending blijven door capaciteitstekort of harde plaatsingsregels. Combineer prioriteit met voldoende capaciteit en beperk wie hoge prioriteiten mag gebruiken.

```yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: example-critical
value: 1000000
globalDefault: false
preemptionPolicy: Never
description: "Explicit priority without preemption"
# Pod spec: priorityClassName: example-critical
```

**Controle:** Toets wachtrijgedrag en Pending-redenen bij schaarste zonder onbedoelde verdringing.

[Pod Priority and Preemption](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/)

## Alle acht punten in één manifest.

Het referentiemanifest combineert drie replicas, drie zones, een PDB met minAvailable: 2 en ruimte voor één extra pod tijdens een update. De twee overblijvende replicas moeten de afgesproken belasting aankunnen. De applicatie moet meerdere instanties, de drie probe-endpoints en graceful shutdown ondersteunen.

Door de harde hostname anti-affinity heeft iedere replica een eigen node nodig. Met drie replicas en maxSurge: 1 zijn tijdens een update minimaal vier geschikte worker-nodes nodig. Controleer of zoneplaatsing, taints, requests en quota de extra pod toelaten, ook bij uitval. Maak de namespace en PriorityClass aan voordat de Deployment start.

De image onder registry.example.com is een placeholder. Vervang die door een gecontroleerde image, bij voorkeur gepind op digest. Pas resources, labels, probes en rechten aan op de applicatie. De gebruikte node inclusion policies voor topology spread zijn stabiel vanaf Kubernetes 1.33; controleer of het doelcluster deze ondersteunt.

[YAML reference](https://horstconsultancy.nl/downloads/kubernetes-ha-reference.yaml)

## Stem autoscaling af op herstel en capaciteit.

Een HorizontalPodAutoscaler (HPA) past het aantal replicas aan op gemeten belasting. Bij een CPU-utilization-target vergelijkt de HPA het CPU-gebruik met de CPU-requests van de pods. Daarvoor zijn werkende metrics en passende requests nodig.

De HPA maakt geen nodes aan. Regel voldoende ruimte via vrije capaciteit en passende node-autoscaling en quota. Opschalen kost tijd. Voor het voorbeeld blijft het minimum op drie replicas staan, bijvoorbeeld met minReplicas: 3 in een HPA. Het PDB bepaalt dit minimum niet. Stem bij eventgedreven autoscaling met KEDA dezelfde ondergrens af; terugschalen naar nul past niet bij deze API.

Als de HPA het aantal replicas beheert, moet een GitOps-controller dat veld met rust laten. Stel de diff- en syncconfiguratie daarop in en leg vast welke controller welk veld beheert. Laat geen twee autoscalers onafhankelijk dezelfde workload besturen.

Meet foutpercentage, responstijd en succesvolle requests aan de ingang van de dienst. Gebruik Pending-pods, Ready/Available-replicas, PDB-status, OOM-kills en throttling om de oorzaak van verstoringen te onderzoeken.

## Test wat er bij uitval blijft werken.

Controleer de manifests die daadwerkelijk worden uitgerold en vergelijk die met de live plaatsing. Pods nemen de zonelabels van hun node niet automatisch over. Koppel daarom de nodekolom van de pods aan de zonelabels van de nodes. Deze opdrachten lezen alleen status uit.

```bash
kubectl get nodes -L topology.kubernetes.io/zone
kubectl get pods -n ha-example \
  -l app.kubernetes.io/name=example-api -o wide
kubectl get pdb example-api -n ha-example
kubectl describe pdb example-api -n ha-example
kubectl rollout status deployment/example-api -n ha-example
kubectl top pods -n ha-example \
  -l app.kubernetes.io/name=example-api
```

- **Node-uitval:** Resterende replicas dragen het afgesproken verkeer; fouten en herstelduur blijven binnen doel.

- **Gecontroleerde drain:** Evictions volgen het PDB; herstel maakt verdere onderhoudsstappen mogelijk.

- **Zone-uitval:** Verkeer, compute, opslag en afhankelijkheden worden samen getest; Pending-redenen zijn verklaard.

- **Rollout onder belasting:** Nieuwe pods worden Available, oude requests eindigen netjes en versies kunnen naast elkaar werken.

- **Dependency-storing:** Geen liveness-herstartgolf; gedegradeerd gedrag en herstel zijn voorspelbaar.

- **Herstel van data:** Een uitgevoerde restore toont haalbare RTO/RPO voor de betreffende datastore.

Leg per test vast hoeveel verkeer nog wordt afgehandeld, welke fouten optreden en hoe lang herstel duurt. Vergelijk de uitkomst met het afgesproken doel. Pas daarna replicas, capaciteit of plaatsing aan en herhaal de test.

## Bronnen

Gecontroleerd op 30 oktober 2026. Raadpleeg de officiële documentatie voor de gebruikte Kubernetes-versie.

- [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)

- [Pod disruptions](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/)

- [Configure a PodDisruptionBudget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/)

- [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/)

- [Pod Topology Spread Constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)

- [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)

- [Liveness, Readiness, and Startup Probes](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/)

- [Pod Priority and Preemption](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/)

- [Options for Highly Available Topology](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/ha-topology/)

- [Horizontal Pod Autoscaling](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/)

- [Pod lifecycle and termination](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)

- [etcd: failure tolerance](https://etcd.io/docs/v3.6/faq/#what-is-failure-tolerance)
