Every few months, some Hacker News thread rediscovers the same thesis: Kubernetes was never really about orchestrating containers — it is a vendor-neutral PaaS layer, and its killer feature is portability. Build on plain K8s constructs and your app runs anywhere those constructs exist, no cloud-proprietary services required. "Portability is THE killer feature of kubernetes," as one commenter put it in the Future of Kubernetes thread. "Kubernetes is a portability platform, that happen to -also- orchestrate containers," as another put it in Nomad vs. Kubernetes.
The verdict up front: the thesis is half right, and the half it gets right is genuinely valuable. Workload manifests really do port across providers in a way nothing before Kubernetes achieved. But the thread consistently skips the other half of the invoice — somebody operates the control plane, the upgrades, the networking, and the node lifecycle underneath those portable manifests, and that bill lands somewhere no matter how portable your YAML is. Here is the ports-vs-doesn't-port table first, the ops ledger second, and the honest version of the thesis at the end.
| Your app's manifest set | Ports unchanged across providers? |
|---|---|
| Deployment, Service (ClusterIP), ConfigMap, Secrets | Yes — the stable core API |
| StatefulSet + PVC definitions | YAML ports, data does not follow |
| StorageClass names and CSI behavior | No — per-cluster, must be remapped |
| Service type LoadBalancer | No — each provider provisions something different |
| Ingress + ingress controller annotations | Mostly no — controller-specific |
| NetworkPolicy semantics | Depends on the CNI — same YAML, different enforcement |
| Cloud IAM bindings (IRSA, workload identity) | No — provider-proprietary by design |
And the preview of the ops half, so nobody reads the table above as the whole story: platform teams lose an average of 34 workdays a year to Kubernetes troubleshooting and incidents (Komodor 2025), a typical 14-component platform absorbs 2–5 major upgrades, 43–52 minor ones, and 276–327 patches every year (CNCF, January 2026), and Kubernetes' three-releases-a-year cadence with a roughly twelve-month support window means every cluster gets a mandatory major upgrade about once a year whether anything is broken or not. Portability never exempted anyone from any of that.
What the thread got right: the workload layer really is portable
Take a deliberately ordinary app — an API Deployment, a ClusterIP Service, a Postgres StatefulSet with a PVC, a ConfigMap — and apply the same manifest set to EKS, to GKE, and to a Cluster API-provisioned cluster on Hetzner. What happens is the thesis working as advertised: the Deployment rolls out, the Service resolves, the StatefulSet orders its pods, the ConfigMap mounts. The one asterisk — the StorageClass behind that PVC, and the data inside the volume — gets its own section below, because it is where the thesis starts leaking. The core workload API is the most stable cross-vendor compute contract our industry has ever had, and the set of providers honoring it keeps growing downward in cost and complexity, not just upward.
Lightweight distros are the existence proof at the bottom end: k0s ships as a single ~160 MB binary with zero host OS dependencies, runs on anything from a bare-metal server to a 1 GB edge box, carries CNCF certification, and now underpins even Mirantis's own enterprise engine (MKE 4 rebuilt its core on k0s). The portability story no longer bottoms out at "whichever managed cloud" — it bottoms out at hardware you own outright.
This is a real break from the past, and the thread is right to treat it as one. Before Kubernetes, moving a production app between providers meant rewriting the deployment layer: new instance templates, new load balancer wiring, new service discovery, new secret injection, new health-check plumbing. The app container might survive, but everything around it was provider-shaped. Kubernetes moved all of that into declarative objects served by a uniform API, so the description of the system ports even when the substrate changes.
France's national railway operator is the large-scale receipt: SNCF's March 2026 CNCF case study describes reaching "strategic autonomy" by running standard Kubernetes on-premises under Cluster API and ArgoCD, with every cluster in the fleet updated monthly to a zero-drift posture. Same manifests, no hyperscaler. Portability at national-infrastructure scale, audited by a third party.
Note what made SNCF's version work, because it previews the catch: Cluster API is the machine layer underneath the portable workloads. Portable manifests answer "how does my app run on any cluster." They never answered "where does the cluster come from" — and CAPI answers that second question the same declarative way, turning cluster lifecycle itself into reconcilable objects. The full thesis, steelmanned, is really two layers: Kubernetes for portable workloads, Cluster API for reproducible clusters. That stack genuinely ports further than anything that came before it.
Where portability leaks: the platform layer under your manifests
Now the fine print, demonstrated with the most load-bearing row in the table: Service of type LoadBalancer. Apply that one object on three clusters and watch the thesis wobble. On EKS, the cloud controller provisions an NLB, wires target groups, and hands you a hostname. On a Hetzner cluster, the Hetzner Cloud Controller Manager provisions a Hetzner LB with different annotations, different health-check semantics, and different pricing. On bare metal with no cloud controller at all, the Service sits in Pending forever until somebody installs MetalLB or an equivalent — the YAML was valid everywhere and sufficient nowhere by itself. Same manifest, three different load balancers, one of them nonexistent.
That is not portability failing; it is portability ending exactly where the platform layer begins.
The leaks form a pattern worth naming, because every one of them has the same shape — the object ports, the implementation doesn't:
- Storage. Your PVC definition applies anywhere, but it references a StorageClass that is a per-cluster name for a per-provider CSI driver with per-provider performance and snapshot behavior. Porting the YAML without remapping the class gets you either the wrong storage or no binding at all — and the data inside the volume never ported in the first place. StatefulSet YAML is portable; state is a migration project.
- Ingress. The Ingress object is standard; everything that makes it do something — the controller, its annotations, its TLS and rate-limit behavior — is controller-specific. Moving from ingress-nginx to Traefik to a cloud L7 is a rewrite of the annotations that carry the actual behavior.
- NetworkPolicy. Same YAML, different enforcement depending on the CNI — and some CNIs historically ignored policies entirely. A policy you never tested on the destination cluster is a comment, not a firewall.
- Cloud IAM. IRSA annotations, workload-identity bindings, and secret-store CSI providers are provider-proprietary by design. They are the exact "rent each cloud's proprietary services" dependency the thesis tells you to avoid — and teams adopt them anyway, because the portable alternative (hand-rolled credential injection) is worse. Every such binding is a line item in your future migration.
None of this refutes the thesis; it scopes it. The honest version: Kubernetes standardizes the workload description layer, not the platform implementation layer. A disciplined fleet narrows the leaks by standardizing the platform side too — one CNI, one ingress controller, one storage story per fleet, pinned across every cluster — so the portable manifests land on identical ground everywhere. But notice who does that standardizing and maintaining. Which brings us to the skipped half.
What the thread skipped: the ops ledger
Here is the sentence the portability thread never prices: somebody operates etcd upgrades, the Kubernetes version treadmill, the CNI, the CSI drivers, node lifecycle, and certificate rotation for every cluster those portable manifests land on. The manifests being portable does not make the clusters self-driving.
The numbers above bear repeating with their teeth showing: three Kubernetes releases a year on a roughly twelve-month support window means skipping upgrades is not an option — fall more than a year behind and you are running unsupported control-plane software with no security patches. Across a typical platform's fourteen integrated open-source components, that compounds into dozens of minor upgrades and hundreds of patches a year. And the 34 lost workdays a year is the average troubleshooting load — the Tuesday-afternoon kind, when a network policy silently blocks traffic or a CSI driver stops binding volumes on one node pool.
The way to read this ledger is as a burden looking for an owner. Every team running Kubernetes picks exactly one of three owners:
| Ops burden | Managed control plane (EKS/GKE/AKS) | Self-run CAPI fleet | PaaS-on-K8s absorbing the surface |
|---|---|---|---|
| K8s version upgrades | Vendor runs the control-plane half; you still drain/upgrade every node | You run all of it, on your schedule | Platform runs it; you see a changelog |
| etcd backup, restore, quorum | Vendor-operated, vendor-priced | Your quorum, your 3 AM | Invisible to you |
| CNI / CSI / ingress lifecycle | Partly managed, partly your add-ons | Your standard fleet-wide stack to maintain | Chosen and maintained once per fleet |
| Node lifecycle and OS patching | Managed node groups or your Karpenter | Your machine images, your rollout | Your git push; machines are the platform's problem |
| Cost shape | Per-cluster fee + cloud-priced nodes | Flat hardware + your engineers' time | One subscription covering both |
No row in that table is free; each column just moves the cost between vendor fees and engineering payroll. SNCF picked the middle column deliberately and staffed for it — a dedicated platform organization running monthly fleet-wide reconciliation is what "self-run at scale" actually costs, and it is a rational trade for a national railway. A five-person SaaS team picking the middle column without SNCF's headcount is how the 34 lost workdays happen. And the left column is not an escape hatch either: managed control planes still hand you node upgrades, add-on compatibility matrices, and per-cluster fees — they halve the ledger, they don't erase it.
This is the precise sense in which the HN thesis hand-waves: it prices the migration (cheap, thanks to portable manifests) and ignores the operation (permanent, and due every year forever). "If you want to create a PaaS, Kubernetes is an excellent foundation," as the You might not need Kubernetes thread put it — and the second half of that sentence, left unsaid, is that somebody then has to operate the PaaS. The operations surface is exactly what a PaaS-shaped platform exists to absorb: the upgrades, the etcd, the CNI, the node images, the cert rotation — done once per fleet by people whose job it is, instead of once per team by people whose job it isn't.
The synthesis: Kubernetes is the portable substrate, the PaaS is the operator
So here is the thesis rewritten to survive contact with the ledger: Kubernetes is the most portable substrate we have, and portability decides how cheaply you can move — but a substrate is not a service, and the service half is who operates the clusters. The two halves compose rather than compete. Portable manifests plus Cluster API-provisioned clusters is the best answer our industry has to "run anywhere without rewriting." A PaaS-shaped operator on top of that stack is the best answer to "never think about etcd upgrades again."
Teams should pick the combination consciously: adopt the portable substrate always, then choose your operator by headcount — managed control planes when you have some platform capacity, self-run CAPI when operating fleets is your product, and a PaaS layer when your product is anything else and the 34 workdays belong to your roadmap, not your runbook.
Look forward one release cycle and the split only sharpens. The substrate keeps getting more portable — lighter certified distros, wider CAPI provider coverage, conformance programs pinning down what "standard Kubernetes" even means — while the operation keeps getting no simpler, because each new capability (GPU scheduling, checkpoint/restore, workload-aware placement) is a new component in the ledger. The teams that thrive will be the ones that stop treating those as one decision: standardize on the portable layer, then be deliberate — and honest about headcount — in choosing who operates it.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with the control plane operated as part of the platform instead of handed to you as homework. Star the repo on GitHub or deploy your first app today.



