Kubernetes markeert een node als "Ready" zodra de kubelet draait en het netwerk minimaal werkt. Maar in de praktijk weet iedere platform engineer dat dit lang niet genoeg is. Je CNI-plugin moet initialiseren, GPU-drivers moeten laden, security agents moeten draaien, en toch plant de scheduler vrolijk pods op nodes die nog niet klaar zijn. De Node Readiness Controller (NRR), begin februari 2026 officieel gelanceerd als kubernetes-sigs-project, lost dit probleem op met een declaratief, CRD-gestuurd systeem voor het beheren van node taints op basis van custom health signals. Het project implementeert de ideeën achter KEP 5416 (NodeReadinessGates) als out-of-band oplossing die je vandaag op elk bestaand cluster kunt deployen.
Het probleem dat elke platform engineer herkent
De standaard Ready-conditie van een Kubernetes node is binair: de kubelet werkt, of niet. Maar moderne clusters hebben complexe bootstrapping-vereisten. Een node heeft een functionerende CNI-plugin nodig, misschien NVIDIA GPU-drivers, storage drivers, observability agents of security scanners. De tijd tussen "kubelet is ready" en "alle componenten zijn operationeel" is een gevaarlijke window waarin de scheduler pods plaatst die direct falen.
De gangbare workaround is al jaren dezelfde: je registreert nodes met een NoSchedule-taint via de kubelet-flag --register-with-taints, configureert kritieke DaemonSets om die taint te tolereren, en bouwt een custom controller die de taint verwijdert zodra alles klaar is. Dit werkt, maar het heeft serieuze nadelen. Je moet custom controllers bouwen en onderhouden, die controllers hebben brede nodes/patch RBAC-rechten nodig, er ontstaan race conditions tussen taint-verwijdering en scheduler-beslissingen, en elke organisatie vindt het wiel opnieuw uit. Antonio Ojea, een bekende Kubernetes-contributor, vatte het goed samen in de aankondigingsdiscussie: "Node readiness, especially around network readiness has been always a cause of friction for cluster admins and platform operators."
Hoe de NodeReadinessRule CRD werkt
De NRR introduceert één custom resource: de NodeReadinessRule. Hiermee definieer je declaratief welke condities op een node True moeten zijn voordat een specifieke taint wordt verwijderd. De controller zelf voert geen health checks uit; hij reageert op node conditions die door andere componenten worden gerapporteerd, zoals Node Problem Detector of de meegeleverde Readiness Condition Reporter.
Hier is het CNI-readiness voorbeeld uit de officiële repository:
apiVersion: readiness.node.x-k8s.io/v1alpha1
kind: NodeReadinessRule
metadata:
name: network-readiness-rule
spec:
conditions:
- type: "example.com/CNIReady"
requiredStatus: "True"
taint:
key: "readiness.k8s.io/NetworkReady"
effect: "NoSchedule"
value: "pending"
enforcementMode: "bootstrap-only"
nodeSelector:
matchLabels:
node-role.kubernetes.io/worker: ""
De logica is elegant. Alle nodes met het label node-role.kubernetes.io/worker krijgen de taint readiness.k8s.io/NetworkReady=pending:NoSchedule. Zodra de node condition example.com/CNIReady op True staat, verwijdert de controller de taint en wordt de node schedulable. Meerdere conditions binnen één regel werken als logische AND: alle moeten True zijn.
De volledige CRD-spec heeft deze velden:
| Veld | Type | Beschrijving |
|---|---|---|
spec.conditions[].type |
string | Het type node condition om te monitoren |
spec.conditions[].requiredStatus |
string | De vereiste status (bijv. "True") |
spec.taint.key |
string | De taint key om te beheren |
spec.taint.effect |
string | NoSchedule, NoExecute of PreferNoSchedule |
spec.taint.value |
string | Optionele taint value |
spec.enforcementMode |
string | bootstrap-only of continuous |
spec.nodeSelector |
LabelSelector | Selecteer specifieke node-subsets |
spec.dryRun |
boolean | Simuleer zonder daadwerkelijk taints toe te passen |
Een subtiel maar belangrijk ontwerpdetail: de controller wijzigt niet de Ready-status van de node. Hij beheert uitsluitend taints. De node blijft "Ready" vanuit het perspectief van de kubelet, maar de taint voorkomt dat de scheduler er pods op plaatst totdat alle custom condities zijn vervuld.
Bootstrap-only versus continuous: twee enforcement-modes
De enforcementMode bepaalt fundamenteel hoe de controller zich gedraagt, en de keuze heeft directe impact op je operationele model.
Bootstrap-only is ontworpen voor eenmalige initialisatiestappen. Denk aan het laden van GPU-drivers bij het opstarten van een node, het pre-pullen van grote container images, of het wachten tot een CNI-plugin voor het eerst operationeel is. Zodra alle condities in de regel True zijn, markeert de controller de bootstrap als voltooid en stopt met monitoren voor die specifieke regel op die node. Als de CNI-plugin later crasht, wordt de taint niet opnieuw toegepast. Dit is het juiste gedrag voor provisioning-workflows waar je alleen de initiële opstart wilt gaten.
Continuous monitoring gaat een stap verder. De controller bewaakt de condities gedurende de volledige levensduur van de node. Als een kritieke dependency faalt (bijvoorbeeld een device driver die crasht of een security agent die stopt), wordt de taint direct opnieuw toegepast. Dit fungeert als een "fuse break"-mechanisme: bestaande pods blijven draaien (tenzij je NoExecute gebruikt als taint effect), maar er worden geen nieuwe pods meer geplaatst. Zodra de dependency herstelt, wordt de taint weer verwijderd. Dit is essentieel voor scenario's waar je een continue gezondheidsgarantie nodig hebt.
Meerdere regels, nodeSelector en dry-run
De kracht van de NRR zit in de compositie van meerdere regels. Je kunt onafhankelijke NodeReadinessRule-objecten aanmaken, elk met een eigen taint. Een voorbeeld uit de community-discussie illustreert dit patroon:
- Regel A: vereist
CNIReady→ beheert taintnetwork-not-ready:NoSchedule - Regel B: vereist
GPUReady→ beheert taintgpu-not-ready:NoSchedule
Reguliere workloads tolereren geen van beide taints en wachten dus alleen op netwerk-readiness. GPU-workloads configureer je met een toleration voor de network-not-ready-taint maar niet voor gpu-not-ready, zodat ze wachten tot beide condities vervuld zijn. Een validation webhook voorkomt dat twee regels dezelfde taint proberen te beheren, wat race conditions elimineert.
Met nodeSelector richt je regels op specifieke node-subsets. GPU-readiness hoeft alleen te gelden voor nodes met een GPU-label; CNI-readiness voor alle worker nodes. Dit maakt het mogelijk om heterogene clusters te beheren met verschillende readiness-eisen per node-type, zonder het cluster te partitioneren.
De dry-run mode (dryRun: true) is een onmisbare feature voor productieomgevingen. Wanneer ingeschakeld, logt de controller welke acties hij zou uitvoeren en werkt de status van de regel bij om getroffen nodes te tonen, maar past geen daadwerkelijke taints toe. Dit geeft je de mogelijkheid om nieuwe readiness-eisen te auditen tegen je hele fleet voordat je ze afdwingt. Dat is cruciaal wanneer een verkeerd geconfigureerde regel honderden nodes uit de scheduling-pool kan halen.
De Readiness Condition Reporter en integratie met Node Problem Detector
De controller is bewust ontkoppeld van health checking. Hij reageert op node conditions, maar het rapporteren van die conditions laat hij aan andere componenten over. Dit levert een flexibele architectuur op met drie integratiepaden.
De eerste optie is de meegeleverde Readiness Condition Reporter, een lichtgewicht agent die je als sidecar of DaemonSet deployt. Hij pollt periodiek lokale HTTP health-endpoints en patcht de bijbehorende node conditions via de Kubernetes API. In het CNI-readiness voorbeeld uit de repository wordt deze reporter als sidecar geïnjecteerd in de Calico-deployment via het script examples/cni-readiness/apply-calico.sh. Het project bevat een apart Dockerfile.reporter voor deze agent.
De tweede optie is integratie met Node Problem Detector (NPD). NPD is een bestaande DaemonSet die node-level problemen detecteert en rapporteert als node conditions. Via NPD's Custom Plugin Monitor kun je eigen scripts schrijven die exit code 0 (gezond) of 1 (probleem) retourneren. NPD vertaalt dit naar node conditions die de NRR controller vervolgens bewaakt. Dit is ideaal als je al NPD draait; je hoeft alleen een custom plugin toe te voegen.
De derde optie is een eigen daemon of operator die direct node conditions patcht via de Kubernetes API. Elke component die custom conditions kan schrijven naar node.status.conditions werkt out-of-the-box met de NRR controller.
Hoe NRR zich verhoudt tot NFD, Pod Scheduling Gates en custom controllers
De Kubernetes-ecosysteem heeft meerdere tools die raken aan node-scheduling, maar ze lossen elk een fundamenteel ander probleem op.
Node Feature Discovery (NFD) detecteert hardware- en softwarefeatures op nodes en zet die om in labels. NFD vertelt je wat een node heeft: een NVIDIA GPU, specifieke CPU-instructiesets, bepaalde kernel-versies. De NRR controller vertelt je of wat de node heeft ook daadwerkelijk werkt. NFD labelt een node met feature.node.kubernetes.io/pci-10de.present: "true" (NVIDIA GPU aanwezig); NRR zorgt ervoor dat de GPU-driver ook daadwerkelijk geladen en functioneel is voordat er GPU-workloads worden geplaatst. Ze zijn complementair: NFD voor capability discovery, NRR voor readiness enforcement.
Pod Scheduling Readiness Gates (GA sinds Kubernetes v1.30) werken op pod-niveau. Met schedulingGates in de pod-spec kun je individuele pods vasthouden totdat een externe controller de gate verwijdert. Dit is nuttig voor scenario's als dynamisch quotabeheer of pre-deployment checks. NRR werkt op node-niveau: het gaat niet om de vraag "is deze pod klaar om gescheduled te worden?" maar "is deze node klaar om pods te ontvangen?" Beide mechanismen vullen elkaar aan.
Custom taint-management controllers (de huidige workaround) doen in essentie hetzelfde als NRR, maar ad hoc en zonder standaardisatie. De NRR controller vervangt deze met een declaratief, gestandaardiseerd systeem dat minder RBAC-privileges vereist en geen custom code nodig heeft. Het elimineert de operationele last van het bouwen, testen en onderhouden van eigen controllers.
Praktijkscenario's: van CNI tot GPU tot autoscaling
CNI-readiness is het meest voor de hand liggende scenario. Wanneer een nieuwe node joint aan een cluster met Calico of Cilium, duurt het even voordat de CNI-plugin volledig operationeel is. Gedurende die window kan de node "Ready" zijn terwijl pod-networking niet werkt. Met een NodeReadinessRule in bootstrap-only mode houd je de node getaint totdat de CNI-agent gezondheid rapporteert. Het officiële voorbeeld in de repository demonstreert precies dit scenario met Calico.
GPU-nodes kennen het "False Ready"-probleem: Kubernetes markeert de node als schedulable, maar GPU-resources zijn nog niet geadverteerd door de device plugin. De scheduler plaatst GPU-pods die direct falen met UnexpectedAdmissionError. Een NRR-regel die wacht op een GPUReady-conditie, gecombineerd met een nodeSelector voor GPU-gelabelde nodes, voorkomt dit volledig.
Autoscaling-scenario's worden expliciet ondersteund. De test suite demonstreert hoe de controller automatisch taints toepast op nieuwe nodes die door een autoscaler worden toegevoegd. Zodra de benodigde componenten op de nieuwe node draaien en gezondheid rapporteren, wordt de taint verwijderd. Dit maakt de NRR bijzonder waardevol voor cluster autoscaler-integraties waar nodes dynamisch komen en gaan.
Multi-tenant platforms profiteren van de combinatie van meerdere regels en nodeSelectors. Verschillende teams kunnen verschillende readiness-eisen hebben: het ene team vereist een functionerende service mesh, het andere team specifieke storage drivers. Met gescheiden regels en taints per node-pool kun je dit granulaire enforcement bieden zonder complexe custom logic.
KEP 5416 en waarom dit een out-of-band oplossing is
De Node Readiness Controller implementeert de concepten uit KEP 5416 (NodeReadinessGates) zonder wijzigingen aan core Kubernetes te vereisen. Het oorspronkelijke KEP-voorstel, getrackt als kubernetes/enhancements#5233, stelt voor om een readinessGates-veld toe te voegen aan de NodeSpec, vergelijkbaar met hoe PodSpec.ReadinessGates werkt. In die upstream-visie zou de kubelet bij self-registratie de readiness gates in de node-spec zetten, en zou de scheduler pas pods plaatsen als alle gate-condities True zijn.
Het probleem met de upstream-aanpak is dat het wijzigingen vereist aan de kubelet, de scheduler en de Node API. Dat is een lang KEP-graduatietraject. De NRR controller omzeilt dit door bestaande Kubernetes-primitieven te gebruiken: node conditions voor health signals en taints voor scheduling-controle. Het resultaat is functioneel equivalent, maar deployable op elk bestaand cluster vandaag. Zodra KEP 5416 eventueel in core Kubernetes landt, biedt het een elegantere oplossing zonder taints, maar tot die tijd biedt de NRR controller dezelfde mogelijkheden als out-of-tree oplossing.
Community en wat komen gaat
Het project wordt onderhouden door Ajay Sundar Karuppasamy (Google) onder de paraplu van SIG Node. De community is actief op het #sig-node-readiness-controller Slack-kanaal op kubernetes.slack.com. Op de roadmap staan metrics- en alerting-integratie, verbeterde logging, performance-optimalisaties en scale testing voor meer dan 1000 nodes.
Een belangrijk moment wordt KubeCon + CloudNativeCon Europe 2026 in Amsterdam (23-26 maart), waar een maintainer track sessie is gepland: "Addressing Non-Deterministic Scheduling: Introducing the Node Readiness Controller". Voor Nederlandse DevOps-engineers een uitgelezen kans om het project in actie te zien en direct met de maintainers te spreken.
Conclusie
De Node Readiness Controller vult een gat dat jarenlang door ad-hoc scripts en custom controllers werd gedicht. De declaratieve aanpak via de NodeReadinessRule CRD vervangt fragiele, zelfgebouwde taint-management met een gestandaardiseerd systeem dat composeert met bestaande tools als NPD en NFD. De twee enforcement-modes (bootstrap-only voor provisioning, continuous voor runtime-gezondheid) dekken de twee meest voorkomende scenario's af. Het project is alpha, maar de timing is goed: vroege adoptie geeft je invloed op de API-richting en bereidt je team voor op een toekomst waarin node readiness een eersteklas Kubernetes-concept wordt. Wil je starten, begin dan met het CNI-readiness voorbeeld op een Kind-cluster en bouw van daaruit op.