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.
Options for Highly Available Topology · etcd: failure tolerance
1. Replicas: voldoende kopieën én resterende capaciteit.
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.
spec:
replicas: 3Controle in de praktijkMeet of twee overblijvende replicas de afgesproken piekbelasting verwerken.
2. PodDisruptionBudget: onderhoud begrenzen.
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.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: example-api
namespace: ha-example
spec:
minAvailable: 2
unhealthyPodEvictionPolicy: AlwaysAllow
selector:
matchLabels:
app.kubernetes.io/name: example-apiControle in de praktijkControleer status.disruptionsAllowed. Test een drain met drie gezonde pods, met een ontbrekende pod en met een draaiende pod die niet Ready wordt.
3. Node anti-affinity: kopieën op verschillende hosts.
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.
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: example-api
topologyKey: kubernetes.io/hostnameControle in de praktijkControleer de nodekolom: iedere replica staat op een andere geschikte host.
4. Zonespreiding: ook gedeelde infrastructuur kan uitvallen.
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.
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
nodeAffinityPolicy: Honor
nodeTaintsPolicy: Honor
labelSelector:
matchLabels:
app.kubernetes.io/name: example-apiControle in de praktijkToets zowel resterende capaciteit als Pending-pods bij het wegvallen van één zone.
5. Rolling updates: eerst een bruikbare vervanger.
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.
spec:
minReadySeconds: 10
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
template:
spec:
terminationGracePeriodSeconds: 60Controle in de praktijkVoer een rollout onder belasting uit en meet foutpercentage, latency en beschikbare replicas.
6. Resources: ruimte voor normaal bedrijf én verstoring.
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.
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
memory: 512MiControle in de praktijkMeet startpieken, OOM-kills, throttling en plaatsbaarheid tijdens een verstoring.
Resource Management for Pods and Containers·Horizontal Pod Autoscaling
7. Probes: opstarten, verkeer ontvangen en herstellen scheiden.
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.
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: 3Controle in de praktijkTest trage startup, een NotReady-pod en een externe dependency-storing afzonderlijk.
8. PriorityClass: bewust kiezen bij schaarste.
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.
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-criticalControle in de praktijkToets wachtrijgedrag en Pending-redenen bij schaarste zonder onbedoelde verdringing.
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.
Download de YAML-referentieBekijk het volledige referentiemanifest
# Illustrative stateless API reference, not a ready-to-apply application.
# Replace the placeholder image, health endpoints and resource values.
# Assumptions: three real zone domains and >=4 eligible worker nodes for surge.
# Two surviving replicas must handle the agreed load (verify by load testing).
# Topology-spread node inclusion policies are stable since Kubernetes 1.33.
apiVersion: v1
kind: Namespace
metadata:
name: ha-example
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: example-critical
value: 1000000
globalDefault: false
preemptionPolicy: Never
description: "Explicit application priority without preemption"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-api
namespace: ha-example
spec:
replicas: 3
minReadySeconds: 10
progressDeadlineSeconds: 600
revisionHistoryLimit: 5
selector:
matchLabels:
app.kubernetes.io/name: example-api
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
template:
metadata:
labels:
app.kubernetes.io/name: example-api
spec:
priorityClassName: example-critical
terminationGracePeriodSeconds: 60
securityContext:
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: example-api
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
nodeAffinityPolicy: Honor
nodeTaintsPolicy: Honor
labelSelector:
matchLabels:
app.kubernetes.io/name: example-api
containers:
- name: api
# Placeholder: replace with a reviewed, digest-pinned application image.
image: registry.example.com/team/example-api:1.0.0
ports:
- name: http
containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
memory: 512Mi
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
volumeMounts:
- name: temporary-files
mountPath: /tmp
volumes:
- name: temporary-files
emptyDir:
sizeLimit: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: example-api
namespace: ha-example
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: example-api
ports:
- name: http
port: 80
targetPort: http
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: example-api
namespace: ha-example
spec:
minAvailable: 2
# Healthy pods retain the budget; unhealthy Running pods need not block drain.
unhealthyPodEvictionPolicy: AlwaysAllow
selector:
matchLabels:
app.kubernetes.io/name: example-api
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.
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-apikubectl top geeft huidig verbruik; voor sizing zijn historie en piekmetingen nodig. Plan verstoringstests vooraf in een afgesproken testomgeving, met monitoring en een herstelpad. Leg bij iedere proef de omstandigheden en uitkomst vast.
- 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.
Bespreek een beschikbaarheidsvraagstukBronnen en technische controle
Gecontroleerd op 30 oktober 2026. Raadpleeg de officiële documentatie voor de gebruikte Kubernetes-versie.
- Deployments
- Pod disruptions
- Configure a PodDisruptionBudget
- Assigning Pods to Nodes
- Pod Topology Spread Constraints
- Resource Management for Pods and Containers
- Liveness, Readiness, and Startup Probes
- Pod Priority and Preemption
- Options for Highly Available Topology
- Horizontal Pod Autoscaling
- Pod lifecycle and termination
- etcd: failure tolerance
