Skip to main content

Kubero vs a Cluster-API PaaS: Two Kubernetes-Native Bets on "Heroku Without the Monthly Bill"

7 min readDora NodaDora Noda
Share

Both projects promise the same thing: Heroku's git push experience, minus Heroku's invoice. Kubero pitches itself as a free, self-hosted PaaS you drop onto any Kubernetes cluster. A Cluster-API-based PaaS pitches the same git-push experience, but built on a control plane that also provisions the cluster underneath it. That difference sounds cosmetic until you ask a much more concrete question: what has to exist before your first deploy, and who's still paying whom after it succeeds?

Kubero replaces one layer of the Heroku bill — the app-deployment layer. A Cluster-API PaaS replaces two — app deployment and the managed-Kubernetes control plane sitting underneath it. That's not a marketing nuance; it shows up directly in each project's CRDs, in what you need in hand before kubectl apply does anything useful, and in which invoice line items survive the migration.

What Kubero Actually Owns

Kubero ships as two containerskubero-ui and an operator — installed onto a Kubernetes cluster you already have. Its own docs are explicit about this: bring a cluster from Kind, Minikube, k3s, or MicroK8s for local use, or point its CLI at a managed offering (EKS, GKE, DigitalOcean, and others) for production. Kubero never creates the cluster itself; it assumes one exists and layers a developer experience on top.

That developer experience is genuinely complete at its own layer. The kubero-operator defines two CRDs — KuberoApp and KuberoPipeline — and reconciles them into the Deployments, Services, Ingress rules, and HPA objects a Heroku user never has to think about. All state lives in the cluster's own etcd; there's no external database to back up. Pipelines get up to four staging environments, GitOps review apps spin up and tear down on pull-request open/close, and v3 (a full rewrite onto NestJS, with roughly 500 new Jest tests and about 85% coverage) adds JWT-based auth and a more modular backend. Redis, Postgres, MongoDB, and half a dozen other addons install through the same UI via their own operators.

None of that CRD graph — KuberoApp, KuberoPipeline — says anything about where a node comes from, what happens when one dies, or who's paying for the control plane reconciling them. That's a different layer, running somewhere Kubero doesn't reach.

What a Cluster-API PaaS Owns

Cluster API (CAPI) operates one layer further down. Its CRDs — Cluster, Machine, MachineDeployment, KubeadmControlPlane — don't describe an application; they describe the fleet of machines a cluster runs on, provisioned through a pluggable InfrastructureProvider. CAPD (the in-tree reference provider) fakes those machines as Docker containers for local dev; CAPH provisions real Hetzner Cloud VMs or dedicated Robot bare-metal servers for production, via HetznerBareMetalHost and HetznerBareMetalMachine objects (see our CAPD-vs-CAPH walkthrough for the full lifecycle). Scale a MachineDeployment, and CAPI provisions or decommissions actual servers — not app pods.

A PaaS built on CAPI folds both layers into one declarative object graph: the same control plane that provisions the bare-metal node your app runs on also reconciles the App-equivalent resource that deploys your service onto it. Kubero and a CAPI PaaS aren't reading from the same CRD vocabulary at all — one starts at KuberoApp, the other starts a rung lower, at Machine.

The Concrete Prerequisites Checklist

Here's what actually has to exist before either system will turn a git push into a running URL.

Kubero, on a managed cluster:

  1. Provision a cluster somewhere — EKS, GKE, or equivalent. On EKS that's a $0.10/hour control-plane fee (about $73/month, before a single node runs), per AWS's own pricing.
  2. Provision the node group(s) that back it — a separate, ongoing compute bill.
  3. Install kubero-ui and the operator onto that cluster.
  4. Register your Git provider and define a KuberoPipeline.

A Cluster-API PaaS, on owned Hetzner bare metal (via CAPH):

  1. Create a Hetzner Robot web-service user (a credential separate from your normal login).
  2. Generate and register an SSH keypair with Hetzner.
  3. Create the hetzner and robot-ssh secrets in a management cluster, then define HetznerBareMetalHost objects pointing at real server IDs.
  4. clusterctl init --infrastructure hetzner, apply a Cluster/MachineDeployment manifest, and the same control plane that just provisioned the server reconciles your app onto it.

Neither checklist is trivial. But only one of them has a recurring per-hour fee for a control plane you don't operate — and it isn't the CAPI one.

What Happens When a Node Dies

This is where the two CRD graphs diverge in practice, not just in principle. Kubero has no object for "a node just died" — that failure is entirely the concern of whatever produced the cluster in the first place: EKS's managed node groups, a manual k3s reinstall, or a page to whoever's on call. Kubero's reconciliation loop keeps your KuberoApp correctly deployed onto whatever nodes the cluster reports as ready; it has no opinion on how a missing node gets replaced.

A Cluster-API PaaS answers this with the same object graph that deployed the app: a MachineHealthCheck watches node conditions, and CAPI's MachineDeployment controller replaces an unhealthy machine the same way it would scale one up — a real CAPH-managed dedicated server gets flagged, deprovisioned, and a HetznerBareMetalHost re-claimed, no separate cloud-vendor node group involved.

The Cost Line Kubero Can't Remove — and the One Cluster API Can't Either

Run Kubero on EKS and its own excellent UI never touches the ~$73/month control-plane fee, because that fee belongs to a layer Kubero doesn't reach. However good Kubero's pipelines or review apps get, that line item is structural, not a configuration choice — it's baked into being one layer up from the machines.

A CAPI PaaS on owned Hetzner bare metal removes that specific line item: there's no separate per-hour managed-control-plane charge, because CAPI-provisioned bare metal is the control plane. But it would be dishonest to call that "no bill" — it's a different bill. Someone still has to bootstrap and secure the management cluster the CAPI controllers run in, execute kubeadm upgrades across the workload cluster's control-plane nodes, and keep CAPI/CAPH's own controllers patched and healthy. EKS's $73/month is explicitly a fee for not doing that work yourself; a self-managed CAPI cluster trades that fee for operational labor. The honest comparison isn't "CAPI is free and EKS costs money" — it's "EKS externalizes control-plane operations for a fixed hourly rate, and CAPI internalizes them for whoever's running the platform," which is exactly the tradeoff a platform team (or an AI agent operating one) needs to price correctly before picking either.

Which Problem Each Is Actually Solving

Kubero and a Cluster-API PaaS aren't really competing for the same job. Kubero solves app-deployment ergonomics on top of infrastructure someone else already secured — hand it a cluster, and it gives you Heroku-grade pipelines, review apps, and addon management for free, with no opinion on where the nodes came from. A Cluster-API PaaS solves a bigger problem: machine lifecycle and app deployment as one declarative API, so the same reconciliation loop that heals a dead bare-metal node also ships your next release.

They're not even mutually exclusive — nothing stops Kubero from running as the app layer on top of a CAPI-provisioned cluster, getting Kubero's pipeline UI and CAPI's node-lifecycle guarantees at once. The real question isn't "which PaaS is better," it's "which layer of the stack do you still want someone else operating for you" — and that answer determines whether your bill has a recurring managed-control-plane line, or a recurring operations one.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, backed by Cluster API's declarative fleet management instead of a hand-managed server pool or a separate managed-control-plane bill. 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