Kubernetes can make a very persuasive promise: a Pod cannot fit, so the cluster adds a node. That sentence is almost true on a hyperscaler, where an API can usually turn a request into a VM. On bare metal, it conceals the only question that matters during a burst: what system can turn this NodeClaim into a healthy machine before the workload’s deadline?
vCluster Auto Nodes is an important answer to the integration problem. It places Karpenter’s constraint-aware scheduling behind a virtual cluster and can fulfill requests with Terraform/OpenTofu, KubeVirt, or NVIDIA Base Command Manager. But it does not make a rack of already-owned machines behave like an infinite VM API. It makes the boundary explicit—and that is exactly what a platform team needs to design well.
The answer first: a NodeClaim selects capacity; a provider delivers it
Here is the boundary to keep in mind. vCluster’s Auto Nodes documentation describes Karpenter watching unschedulable Pods, creating a Karpenter NodeClaim, then having vCluster Platform create a platform NodeClaim that a node provider fulfills. Those are deliberately different jobs.
| Stage | What it can decide | What it cannot guarantee |
|---|---|---|
| Karpenter | Which allowed node type satisfies resource requests, labels, taints, affinities, topology rules, and pool limits | That the selected machine exists, can be acquired, or will join in time |
| vCluster Platform | Which configured provider and node type should fulfill the claim | That the provider has quota, stock, working credentials, or a valid image |
| Terraform/OpenTofu, KubeVirt, BCM, or another provider | Create a VM, activate a prepared host, or run the infrastructure workflow | That bootstrap succeeds, the network works, or kubelet becomes Ready |
| Kubernetes | Schedule the Pod after the worker is registered and Ready | That an emergency workload can wait through procurement or a reimage |
That distinction applies to every node autoscaler. Kubernetes’ own node-autoscaling overview says autoscalers need an integration with an infrastructure provider to create and delete the resources backing Nodes. Karpenter is better thought of as a highly capable capacity-selection engine, not as a source of capacity.
Follow three pending workloads through a real inventory
Make the discussion reproducible. Imagine a tenant cluster with this ready inventory; all quantities are allocatable capacity available to new Pods, not the machines’ total specifications.
| Ready worker | Free capacity and traits |
|---|---|
general-a | 8 vCPU, 28 GiB memory |
general-b | 8 vCPU, 28 GiB memory |
gpu-a | 16 vCPU, 120 GiB memory, one free A100; labelled accelerator=nvidia-a100 |
Now three demands arrive together:
| Workload | Pod constraints | Outcome before any new machine | If it needs a NodeClaim |
| --- | --- | --- |
| Web burst | six Pods, each 1 vCPU/2 GiB | Fits on the two general workers; no NodeClaim is necessary | Nothing should be provisioned. Correct requests let the scheduler use capacity already paid for. |
| Batch job | one Pod, 20 vCPU/40 GiB | Cannot fit on a single current worker | Karpenter can select an allowed 32-vCPU general node type and emit a NodeClaim. |
| GPU inference | two Pods, each 8 vCPU/32 GiB and accelerator=nvidia-a100 | The first fits on gpu-a; the second cannot share its only free GPU | Karpenter can request a node type offering an A100, provided the NodePool permits it. |
The NodeClaim is a valuable improvement over a simple “add one more node from pool X” response. It incorporates the actual shape of the unschedulable Pod and excludes types that cannot satisfy it. vCluster documents that it passes fitting, cost-sorted node types and requested resources to the platform, which then selects a type and invokes its configured provider. That is useful bin packing.
But each claim takes one of four very different physical paths:
| Supply state for the selected type | Batch-job result | Second GPU-job result | Illustrative time budget |
|---|---|---|---|
| Matching worker is already Ready | It should have scheduled without a claim; investigate stale capacity/request accounting | Same | Scheduler latency, not provisioning time |
| Warm, pre-prepared worker or an immediately available VM | Provider attaches or creates it, bootstrap joins it, readiness gate passes | Same, if a warm A100 host exists | Usually minutes; test the actual image, network, and join path |
| Bare-metal spare needs PXE boot or reimage | Claim may be fulfilled, but it is a slow burst path | Same, plus GPU-driver validation | Commonly tens of minutes in a well-run operation; measure your own path |
| No matching spare, provider quota, or vendor stock | Pod stays pending despite a valid NodeClaim | Pod stays pending | Days or weeks if acquisition/delivery is required—outside an autoscaler’s control |
Those are operational bands, not Karpenter service-level guarantees. The important consequence is practical: a 30-second web spike cannot be rescued by a 30-minute bare-metal reimage. A warm reserve, a virtualisation layer, or a capacity buffer handles that spike; Karpenter simply makes the request for the next worker more precise.
The sensitivity test: when bin packing changes the outcome
Before enabling dynamic provisioning, run the same workload table against the variables that change its outcome. This prevents a demo where an autoscaler looks impressive because the difficult part—supply—was quietly pre-arranged.
| Variable | What changes in the example | Operational implication |
|---|---|---|
| Warm matching inventory | A prepared 32-vCPU host makes the batch claim practical; a prepared A100 host makes the second GPU claim practical | Keep a measured reserve for the workload’s recovery objective, or accept pending Pods. |
| Request-to-Ready time | A five-minute VM workflow may be fine for an asynchronous job, while a 30-minute physical workflow is not | Set workload deadlines and capacity policy together; do not call every delayed path “elastic.” |
| Provider quota or stock | A NodeClaim can select a node type that the provider cannot issue | Monitor quota and inventory as production dependencies; a controller cannot bargain for unavailable hardware. |
| Resource-request accuracy | Understated requests may pack Pods onto a node that later throttles or OOMs; overstated requests create unnecessary claims | Autoscaling is only as truthful as the requests it models. Profile workloads and retain headroom for DaemonSets. |
| Consolidation budget | Aggressive consolidation may evict a node that took a long time to prepare; restrictive budgets retain expensive idle capacity | Use disruption budgets and consolidateAfter as availability policy, not merely as a cost switch. |
vCluster exposes Karpenter-style disruption configuration, including consolidation policy, delay, and budgets. The default it documents can consolidate empty or underutilized nodes after 30 seconds. That default is a sensible cloud starting point, but it deserves deliberate review on bare metal: a node that took half an hour to reimage should not necessarily be treated like a disposable VM.
What the fulfillment contract needs beneath Karpenter
“Karpenter on bare metal” becomes honest only when every row below has an owner and a tested failure mode.
| Required capability | Why it exists | Auto Nodes mapping |
|---|---|---|
| A provider adapter with scoped credentials | Something must create, activate, or release the machine | A configured vCluster node provider; supported paths include Terraform, KubeVirt, and NVIDIA BCM. |
| A typed hardware catalog | Karpenter needs CPU, memory, GPU, zone, and custom properties to rule types in or out | Node types become claim requirements such as instance type or region. |
| Capacity source | Selection is pointless if nothing can satisfy it | Cloud API capacity, virtualised hosts, or physical hosts already prepared for activation. |
| Immutable bootstrap and join | A created server is not yet a worker | Image/user data install the runtime and join with short-lived credentials. |
| Serialized, idempotent infrastructure state | Two claims must not race to claim the same machine | Terraform/OpenTofu state needs a locking backend; Terraform’s documentation explains that locking prevents concurrent writers from corrupting state. |
| Readiness and health gates | Kubelet Ready alone may be too early for CNI, storage, or GPU drivers | Mark the claim successful only when the required node services are actually ready. |
| Safe deprovisioning | Consolidation must not turn into data loss or a surprise outage | Cordon, drain within disruption budgets, release the machine, and reconcile stranded resources. |
The chain is therefore: unschedulable Pod → Karpenter NodeClaim → platform NodeClaim → provider action → bootstrap → joined Node → readiness gate → scheduled Pod. Instrument each arrow separately. “Node provisioning is slow” is not a usable incident diagnosis; “state lock held,” “PXE failed,” “GPU driver gate failed,” and “provider quota exhausted” are.
Cluster Autoscaler remains the simpler baseline for many CAPI fleets
Karpenter is not the only valid response to pending Pods. Kubernetes distinguishes its model from Cluster Autoscaler: Cluster Autoscaler grows and shrinks preconfigured node groups; Karpenter uses operator-provided constraints to auto-provision suitable nodes. Both can consolidate nodes, and both still require an infrastructure integration.
| Question | Cluster Autoscaler with Cluster API | Karpenter through vCluster Auto Nodes |
|---|---|---|
| Capacity definition | Operator declares homogeneous MachineDeployment/node groups and min/max sizes | Operator declares allowed node types, requirements, limits, and disruption policy in NodePools |
| Scale action | Adjusts the size of an existing group | Selects a fitting type and creates a NodeClaim |
| Best operational shape | A small, stable menu of worker pools with clear reservations | Diverse workload shapes where the provider can fulfill constrained choices quickly |
| Bare-metal dependency | Machine deployment still needs an automatable provider and available hosts | NodeClaim still needs an automatable provider and available hosts |
| Cluster API integration | Uses Cluster Autoscaler’s Cluster API provider to manage worker Machines | Is not a replacement for CAPI’s lifecycle/health controls; it adds tenant-scoped selection and fulfillment machinery |
The Cluster API Book’s autoscaling guide documents the Cluster Autoscaler provider as managing worker-machine provisioning and deprovisioning through Cluster API. That is an attractive, boring default when a fleet has, for example, general and GPU MachineDeployments with well-understood minimums and maximums.
The key difference is not “old autoscaler versus new autoscaler.” It is whether the variability Karpenter can model—different hardware traits, zones, and workload requirements—outweighs the extra provider and fulfillment system required to execute the choice.
The Hetzner boundary: Cloud API capacity and physical stock are different products
A Hetzner-backed CAPI fleet needs to name which kind of Hetzner capacity it is using. Hetzner Cloud offers an API-facing VM capacity interface. For stable worker shapes and predictable demand, Cluster Autoscaler’s named-pool model keeps that interface simple: CAPI reconciles the chosen MachineDeployment, while the autoscaler changes its desired size.
Auto Nodes becomes materially different when virtual clusters need to choose among a broad, fast-to-fulfill catalog—say, general CPU, high-memory, and GPU types—with constraints that would otherwise cause an explosion of static pools. The provider must still be able to honor those choices quickly enough for the workload. That is a supply-chain condition, not a Karpenter feature.
Dedicated servers and true bare-metal inventory have a harder boundary. If the operation has warm, matching hosts or a virtualisation layer, Auto Nodes can make that reserve available to the right tenant workload without manually choosing a pool. If it does not, a valid NodeClaim merely records an unmet need. A planned fixed pool plus a consciously sized reserve is the truthful capacity policy until the physical activation path meets the workload’s tolerance.
That is not a limitation to hide. It is the design decision a self-hosted platform gets to own: choose where the buffer lives, expose the relevant inventory and readiness state, and let automation act only inside those boundaries.
Make the promise measurable
The useful promise of Karpenter-enabled bare-metal autoscaling is not “hardware appears on demand.” It is: the platform can select the right capacity, invoke an owned fulfillment path, and tell you exactly where that path failed.
For a platform such as Bex, that separation is healthy. A Git-push PaaS can keep ordinary applications on predictable worker pools while exposing enough machine and workload state for an operator—or an AI agent—to identify whether a pending deployment needs a new node, a quota change, a warmed spare, or a different workload request. The system becomes more autonomous without pretending the physical world is an API call.
Bex.co is the open-source, AI-native Render alternative: push a Git repo and get a running HTTPS service on machines you own. Its Cluster API-based approach is a natural place to keep machine lifecycle and application intent explicit rather than hiding capacity limits behind a hosted-platform abstraction.



