Skip to main content

vCluster Brought Karpenter to Bare Metal. Here's What Actually Changes for a Cluster-API Fleet

8 min readDora NodaDora Noda
Share
On this page

For eight years, if your Kubernetes nodes lived on hardware you owned instead of a hyperscaler's account, you had exactly one mature autoscaler: Cluster Autoscaler. Karpenter, AWS's faster, workload-aware replacement, only ever worked where a cloud provider exposed an API that could hand back an exact-shape instance in seconds — EC2, and eventually a handful of managed clouds that copied the model. Bare metal never had that primitive. Provisioning a dedicated server has always meant hours, not seconds, and inventory you can reserve, not an API you can call on demand.

In September 2025, vCluster shipped Auto Nodes, embedding a Karpenter operator inside every virtual cluster's control plane and wiring it to node providers for public cloud, private cloud, and — for the first time — bare metal, via KubeVirt and NVIDIA Base Command Manager. The pitch is that Karpenter's "provision the exact shape a pending pod needs, in seconds" model finally reaches owned hardware.

For a fleet running Cluster API on owned Hetzner machines, that's a real question, not a marketing one: does Auto Nodes actually replace Cluster Autoscaler's job, or does it solve a different problem while adding a control-plane layer you now have to run and pay for? Here's the concrete answer, mechanics first.

Why Cluster Autoscaler Was the Only Option, Structurally

Karpenter's speed comes from bypassing infrastructure abstractions entirely — it calls a cloud provider's fleet API directly (RunInstances on EC2, its equivalents elsewhere), picks from a database of hundreds of instance shapes, and gets a running node back in under a minute. That only works because AWS, and later GCP and Azure, expose an API where "give me this exact CPU/RAM/GPU shape, right now" is a normal, few-second operation.

Bare metal and dedicated servers never exposed that primitive. Hetzner's own dedicated line (the Robot/Server Auction inventory, not Cloud) is physical hardware sitting in a rack; provisioning one has always meant picking from what's currently in stock and waiting for it to be racked and imaged — an hour or more, not the sub-minute loop Karpenter is built around. There was nothing for a Karpenter bare-metal provider to call. Cluster Autoscaler, by contrast, doesn't need that primitive — it just watches MachineDeployment/MachineSet/MachinePool objects carrying two annotations, cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size and -max-size, and adjusts replica counts within those bounds against whatever pool of machines your Cluster API infrastructure provider already manages. That's why it was the only mature option on owned hardware: it doesn't require instant provisioning underneath it, only a controller loop and a set of machines to point at.

The Mechanics, Side by Side

Cluster Autoscaler's loop: poll every ~10 seconds, simulate scheduling against pending pods, and if nothing fits, bump the MachineDeployment replica count within its min/max annotations. Cluster API's machine controller then reconciles that count through the infrastructure provider — for a Hetzner fleet, that's CAPH, Cluster API Provider Hetzner — which creates the actual HetznerMachine and calls the Hetzner API. Node-ready time is typically a few minutes, most of it Cluster Autoscaler's own poll-and-simulate cadence plus however long the underlying Hetzner resource takes to boot.

Auto Nodes' loop is different in shape, not just speed: an unschedulable pod triggers the Karpenter operator embedded in the vCluster control plane, which creates a NodeClaim describing the exact CPU/RAM/GPU shape needed; the vCluster Platform fulfills that claim through whichever Node Provider is configured (Terraform/OpenTofu, KubeVirt, or NVIDIA BCM); the node then attaches directly to the vCluster's control plane as a "private node," without ever joining a shared host cluster. vCluster's own walkthrough clocks a node going from NodeClaim to ready in the host environment at 117 seconds. The architectural difference that matters: Cluster Autoscaler scales pre-defined node groups up and down; Karpenter (and by extension Auto Nodes) picks the node shape per pending pod and bin-packs continuously, consolidating workloads onto fewer nodes as demand drops — Cluster Autoscaler doesn't repack existing nodes at all.

What "Bare Metal" Actually Means for Each, on Hetzner

This is where the title's premise needs a correction, and it's the part a self-hosted fleet needs to get right before switching anything. Neither model conjures a new physical server out of thin air on a timescale anywhere close to Karpenter speeds — because that primitive still doesn't exist for dedicated hardware, on Hetzner or anywhere else.

On Hetzner Cloud (the virtualized product, not dedicated iron), both models genuinely get elastic, API-driven provisioning: Cloud servers spin up in seconds via API call, and CAPH's HetznerMachine reconciliation against Cluster Autoscaler's replica bumps rides that same speed. Auto Nodes' Terraform/OpenTofu node provider hits the identical Hetzner Cloud API. Neither has an edge here — they're both fundamentally "call the Cloud API and wait roughly the same number of seconds."

On Hetzner dedicated/Robot servers — the hardware a self-hosting-for-cost fleet actually cares about, since that's where the per-core economics beat Cloud pricing — there is no elastic supply on either side. Auto Nodes' bare-metal story here is KubeVirt: it slices right-sized VMs out of a pool of already-racked, already-provisioned dedicated machines running the KubeVirt hypervisor layer. That's real and useful, but it is not new physical capacity appearing in 117 seconds — it's fast reallocation of capacity you already bought and racked, the same way CAPH's Cluster Autoscaler integration is fast reallocation of whatever MachineDeployment pool you already provisioned.

NVIDIA BCM follows the same pattern for DGX-class GPU pods: it manages elastic allocation across an existing physical fleet, not on-demand physical procurement. So on the resource that actually matters for a cost-driven owned-hardware fleet, both tools are doing the same job — subdividing a pre-provisioned pool — and the 117-second number is a bin-packing/VM-slicing speed, not a new-hardware-materializes speed.

The Added Control-Plane Layer: What You Actually Pay For It

Cluster Autoscaler running against CAPH costs you one extra Deployment inside a cluster you're already operating — no new control plane, no new etcd, no new upgrade surface. Auto Nodes buys its speed and per-pod bin-packing by putting a full virtual Kubernetes control plane in front of every tenant that wants it, and that control plane isn't free:

Virtual cluster sizeCPU requestMemory request
Small (< 10 workloads)50–100m128–256Mi
Medium (10–50 workloads)100–500m256Mi–1Gi
Large (50+ workloads)500m–1000m1–2Gi

That's on top of an embedded etcd instance per vCluster (a modest ~20m CPU / ~150Mi memory on its own, but it's another stateful component to back up, upgrade, and watch), and — if the workloads underneath run as KubeVirt VMs rather than bare pods — a per-VM libvirtd process with roughly 32Mi of fixed memory overhead per instance for the virtualization layer itself. None of these individual numbers is large. The point is additive: a fleet running ten tenant vClusters at medium size is carrying ten extra control planes, ten extra etcd instances, and a KubeVirt hypervisor layer across every bare-metal box that hosts them — real resources, real upgrade surface, real failure domains that a flat CAPI cluster with one Cluster Autoscaler Deployment simply doesn't have.

Decision Framework

The two tools aren't actually competing for the same job once the bare-metal reality above is priced in. Cluster Autoscaler plus CAPH scales a shared pool of machines up and down for workloads that all trust the same cluster. Auto Nodes' value isn't "faster new bare-metal supply" — it's isolation plus fast reallocation within a pool of capacity you already own, delivered per-tenant with its own control plane.

  • Running your own apps on your own owned Hetzner fleet, one trust boundary, no need to hand out isolated clusters to separate customers or teams? Stay CAPI-native. Cluster Autoscaler against CAPH's MachineDeployment gets you the same underlying elastic-on-Cloud / pre-provisioned-on-dedicated reality, for the cost of one extra Deployment — no additional control planes to run.
  • Operating a platform that hands multiple tenants their own isolated Kubernetes-like environment carved out of shared bare-metal capacity — the shape of a multi-tenant PaaS control plane, not a single application fleet — Auto Nodes' per-tenant control plane and KubeVirt-based VM slicing is solving a real problem: isolation with fast internal reallocation. The extra etcd/control-plane/hypervisor overhead per tenant is the isolation tax, and it's the right trade when isolation is the actual requirement.

A platform like Bex.co — an open-source, AI-native Render alternative that runs on machines you own via Cluster API — sits in the first bucket by design: one Cluster-API-managed fleet, workloads scheduled directly onto it, no per-tenant control-plane layer to multiply. That's the same reason it doesn't chase Karpenter-style bare-metal supply that doesn't exist yet — the honest win on owned hardware is a thin, CAPI-native autoscaling loop against machines you already provisioned, not a new control-plane tax for a problem you don't have.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Sources

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex