Skip to main content

SNCF Cut Kubernetes Provisioning From a Month to 30 Minutes With Cluster API

10 min readDora NodaDora Noda
Share
On this page

France's national railway operator just told the CNCF that it cut Kubernetes cluster provisioning from a month to thirty minutes — and did it by handing the job to Cluster API. SNCF now runs its Kubernetes estate, more than 200 clusters spanning Azure, AWS, and its own datacenters, on a platform where Cluster API's OpenStack provider is the thing actually turning nodes on and off. That's not a startup's weekend project. It's a company that moves millions of passengers a day, operating under a security posture serious enough that engineers describe a 200-page internal manifesto governing it.

Metric (on-prem CAPI platform)BeforeAfter
Cluster provisioning time~1 month~30 minutes
Clusters delivered14 in 4 years10 in 6 months
Production incidents (IaaS → CaaS)baseline90% fewer
Maintenance effortbaseline66% less
Update cadencead hocmonthly, fleet-wide

Those numbers describe SNCF's on-prem OpenStack-plus-Cluster-API platform specifically — the piece of its roughly 200-cluster, multi-cloud estate this case study is actually about. They're also a useful stress test for a claim bex has made about its own architecture: that Cluster API's declarative machine-lifecycle model — the same CAPH-for-Hetzner, CAPD-for-local-Docker pairing bex runs underneath every tenant deploy — holds up outside cloud-native startups, on infrastructure that answers to its own uptime and compliance obligations. SNCF is about as far from a Cluster-API-native startup as production infrastructure gets. Its numbers are worth reading closely for exactly that reason.

The four-year detour before Cluster API

SNCF didn't arrive at Cluster API on the first attempt. Between 2018 and 2024, the team ran Kubernetes on-prem using Ubuntu and RKE2 — a conventional enough stack — and it stalled. Four years in, the platform had delivered fourteen clusters total. A new cluster took as long as a month to provision, long enough that teams treated a new environment as a project, not infrastructure. Each cluster tended to drift from every other one: manually patched, manually upgraded, a "snowflake" the platform team had to remember rather than a state the platform enforced.

Two things made the stall worse than ordinary growing pains. SNCF's legacy IT operations teams weren't the ones running the new platform, and rather than force a retraining effort across an organization with decades of established process, SNCF stood up a separate cloud-native team and let the two operating models coexist. That solved the organizational friction but didn't solve the technical one.

The new team still didn't have node autoscaling, upgrade automation, or any of the things a public-cloud managed Kubernetes offering hands a team for free. Those capabilities existed for SNCF's Azure and AWS clusters. They didn't exist in SNCF's own datacenters.

The team spent roughly two years evaluating alternatives — bare-metal-only approaches among them — before settling on the architecture it runs today: OpenStack (via Canonical) as the private-cloud IaaS layer, Talos Linux as the node operating system, and Cluster API as the control plane gluing the two together. SNCF's own retrospective is candid that the research phase ran longer than it needed to; a platform engineer estimated the team could have made the same call six to twelve months earlier with more openness to changing course. That's a detail worth sitting with before assuming an evaluation phase this long is normal — it's a cautionary note from SNCF itself, not a template.

What Cluster API actually turned on

The architecture that came out the other side is specific enough to describe in full. OpenStack provides compute, networking, and storage primitives. Talos Linux — the API-driven, SSH-free, immutable OS built by Sidero Labs — runs on every node, eliminating the manual shell access and hand-edited config files that caused drift in the RKE2 era. Cluster API, using its OpenStack infrastructure provider plus Sidero's own Talos bootstrap and control-plane providers, treats every cluster as a Kubernetes resource: declare the desired Cluster and MachineDeployment objects, and a reconciliation loop keeps the running fleet matched to that declaration. Cilium handles eBPF-based networking and observability; Kyverno enforces policy-as-code; ArgoCD drives GitOps across the hybrid fleet, with ORAS managing the OCI artifacts for CAPI's own providers.

The specific capability that made this worth the two-year search: node autoscaling. Yann Rotilio, senior staff engineer on SNCF's Kubernetes team, put it plainly in the CNCF case study — Cluster API "gave us node autoscaling in datacenters, something previously exclusive to AKS or EKS." That's the capability gap that defined the RKE2 era: a public-cloud managed Kubernetes service scales a node pool up and down against demand as a baseline feature. Rolling your own Kubernetes on-prem historically meant rolling your own answer to that problem too, usually badly. Cluster API's Machine and MachineDeployment abstraction is what let SNCF wire the cluster autoscaler to real infrastructure lifecycle events in its own datacenter instead of a public cloud API — spin up a Machine, let the autoscaler request it, let CAPI's OpenStack provider actually provision the VM, all through the same declarative model the fleet's baseline nodes already used.

The zero-drift posture is the second-order effect. Because every cluster's state lives in a Cluster / MachineDeployment spec instead of in a person's memory of what they last did to a box, SNCF's platform team now pushes updates to its entire fleet monthly — every cluster, on a predictable cadence, without the upgrade being a special one-off project. Thomas Comtet, head of SNCF's container and cloud-native platforms group, frames the result directly: "We built a platform competing with AKS/EKS in our own datacenters using CNCF ecosystem tools — metrics demonstrate success."

Predictable, schedule-driven load — not a bursty-traffic story

Here's the part most Cluster-API autoscaling writeups skip, because most of them are written around a web-application mental model: a consumer app gets featured somewhere, traffic spikes 10x in twenty minutes, and the cluster autoscaler either keeps up or the app falls over. That's a real scenario, but it's not SNCF's scenario, and the difference matters for anyone reading a rail operator's autoscaling numbers and trying to map them onto their own workload.

SNCF's infrastructure ingests real-time train geolocation continuously from trackside beacons — a system called BREHAT logs an observation every time a train passes a beacon, timestamped to the second, building up a decade of positional history that today feeds live tracking. That's a workload with a shape: it tracks the train timetable, which is itself a known, published schedule. Ticketing and booking demand follows a similarly legible pattern — spikes around commuter peak hours, around holiday travel windows, around fare-change announcements — all things a platform team can see coming days or weeks in advance, not something that erupts without warning the way a viral social post does. Overnight batch jobs (settlement, reporting, schedule reconciliation) are, definitionally, scheduled.

That predictability is a real operational advantage, and it's plausibly part of why SNCF's platform team feels comfortable running monthly fleet-wide updates against a known load curve — a cadence that would be a much harder sell against a workload where the next spike's timing and magnitude are both unknown. But it's worth being precise about what the SNCF case study does and doesn't demonstrate.

It's public evidence that Cluster API's node-autoscaling model works at production scale against a diurnal, schedule-driven signal. It is not evidence — because it isn't the scenario being tested — of how CAPI's reconciliation loop and infrastructure-provider API calls hold up against a true bursty, unpredictable spike, the kind a consumer SaaS or a platform hosting other people's unpredictable apps has to survive. A rail operator's autoscaler has the luxury of mostly knowing what's coming; a multi-tenant PaaS, where any one tenant's app can go viral with zero notice, does not. That's a meaningfully different stress profile, and SNCF's numbers only speak to the one it actually faced.

What it validates for a Hetzner-fleet, multi-tenant PaaS

Set SNCF's architecture next to bex's and the parallels are direct, not analogical. Both run Cluster API against a single infrastructure provider — SNCF's OpenStack provider, bex's CAPH against Hetzner in production and CAPD against local Docker in development — rather than trying to span multiple clouds inside one cluster. Both run one Cluster API management plane whose cost is amortized across a fleet, not stood up fresh per workload: SNCF's management cluster reconciles Machines across its whole on-prem estate, and bex's does the same across every tenant's app on the shared worker pool. Both lean on GitOps (SNCF's ArgoCD, bex's own deploy pipeline) to keep the fleet's actual state matched to a declared one, so an upgrade is a scheduled, monthly, boring event instead of a per-cluster fire drill.

There's one structural difference worth naming plainly rather than glossing over: SNCF is one organization running roughly 200 clusters to serve its own several thousand applications. bex is one or a handful of clusters, shared by many separate tenants who never see the Cluster API layer underneath their git push. That's a different topology — many-clusters-one-tenant versus few-clusters-many-tenants — and it means SNCF's numbers don't directly transfer as bex's numbers.

What they do transfer is the more basic claim underneath both architectures: that Cluster API's declarative Machine/MachineDeployment model is durable enough, at real production scale, for a team whose infrastructure carries someone else's uptime and compliance stakes — not just for a startup with the latitude to treat an outage as a learning experience. SNCF's security manifesto, its incident-reduction numbers, and its monthly update cadence are what that durability looks like when the operator is a national railway instead of a Kubernetes-native startup. That's the validation a bare CAPI GitHub README can't provide on its own.

Where this points next

SNCF's own platform team isn't done. The case study notes they're now evaluating KCP and Crossplane as a further abstraction layer on top of what Cluster API already gives them — one more indication that "declarative infrastructure lifecycle" is treated as a foundation to build on, not a finished product. For a platform like bex, built on the same CAPH/CAPD foundation, the read-through is less about copying SNCF's next move and more about the pattern: the provider model held up long enough, and cleanly enough, that the team's next problem is what to build on top of it, not whether to keep it underneath.

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