Skip to content

How Flui works across providers

Every later chapter about infrastructure (clusters, networks, firewalls, DNS, credentials) builds on the abstraction described here.

The problem

Two cloud providers can look similar and behave very differently.

  • What sits next to a server varies widely. One provider offers managed DNS, firewalls, private networks, load balancers and snapshots through the same API. Another gives you a server and almost nothing else. Building a platform on each takes very different work.
  • Billing models differ. One provider bills by the hour and stops charging the moment you delete the resource. Another bills monthly under contract. Some mix both in the same catalogue.
  • The same idea has different names. A server can live in a location, a zone or a region depending on the provider. The words are not interchangeable: each carries its own meaning about scope, redundancy and pricing.
  • SSH keys, firewalls, private networks and DNS are each modelled differently. The same concept comes with a different API and a different shape on each provider.

Even one vendor can ship two compute products that look interchangeable and behave very differently, and only one of them may suit the elastic, autoscaling workloads Flui is built for.

A naive integration ends up with provider-specific branches scattered across the CLI, the API and the dashboard. The cost grows with every new provider, feature and edge case, until adding a third provider is a project of its own.

What Flui does instead

Flui’s goal is to get your applications online quickly, on the cloud provider you choose, and let you scale without rewriting your platform as traffic, team or workloads grow. That matters most on providers that do not ship a managed platform of their own, and also on providers that do, when portability across clouds matters more than one vendor’s stack.

To do this across providers that vary so much, Flui puts a single abstraction layer between the rest of the system and the cloud provider. The layer has two properties:

  1. No lowest common denominator. When a provider lacks a capability, Flui says so, and may simulate it, fall back or degrade gracefully, instead of pretending the capability does not exist.
  2. Capability awareness. Each provider declares which of a fixed set of capabilities it supports, and the rest of Flui adapts its behaviour, without provider-specific branches in user-facing code.

The result is a two-layer architecture. Each provider has its own isolated module, the only place that knows how that cloud behaves. Above it sits Flui’s cross-cutting core (the CLI, the dashboard, the orchestration engine, the application model, the operations layer), which is the same whatever provider is underneath. The core talks to “a provider”, never to a specific cloud, and the modules below absorb provider differences so they do not propagate upwards.

Capabilities are the contract

Nothing on either side of the abstraction speaks in provider products. A provider module declares what its cloud can do (buy machines by the hour, keep a DNS zone, drive a firewall at the edge), and everything above the layer asks for capabilities. Above the line, a requirement is stated and the platform chooses where it can be carried out. The provider is the execution target.

Where a capability is missing, Flui supplies what it can itself: a firewall with no provider edge is applied on the machines, and a cluster whose servers have no private network gets the Flui network. Anything Flui does not supply is stated, not hidden.

The rest of this chapter describes that contract, and the chapters after it apply it one capability at a time. Across a whole installation, it is what lets clusters on different providers join as one; see Multi-cluster topology and The network Flui builds.

Portability and lock-in

The abstraction takes an explicit position on vendor lock-in. The portable layer covers two things:

  • The flui.yaml manifest describes an application and its app-level resources: build, deploy, scaling profile, endpoints, domains. The same manifest, unchanged, describes the same app on any integrated provider.
  • The operating model: clusters, environments, deployments and observability, driven by the CLI, dashboard and API. The surfaces and commands are the same whatever provider is underneath.

The runtime adds a third layer of portability. Flui runs workloads on K3s, which is upstream Kubernetes and installs on practically any Linux machine: any cloud, bare metal or edge box. The applications you deploy through Flui are standard Kubernetes workloads at runtime, so in principle they can run wherever K3s can run.

Some things stay provider-specific: the underlying machines, the regions, the catalogue of instance types. A later section of this chapter shows where that line falls.

Moving from one provider to another means provisioning infrastructure again under a different credential, then redeploying the same applications from the same manifests.

Because the operating model and the manifest are the same across providers, an installation can also run workloads on different providers at the same time. Where an installation allows clusters on more than one provider, the same control plane drives them all; see Multi-cluster topology for when that is the case. Flui also encourages cross-provider backups: data lives on one provider and backups land on another, so an outage or account incident at one provider does not take everything down at once.

Modes of integration

Flui works with the underlying infrastructure in three modes, each with its own automation boundary:

  • Flui Full. Full integration with a cloud provider. Provisioning, firewall, DNS, private network and storage (block and object) are all exposed by the provider and automated end to end. You never have to open the provider’s console for routine operations.
  • Flui Partial. The provider exposes the baseline (Flui can provision servers, and the provider bills by the hour) but not every capability through its API. What it does not expose, Flui supplies or takes from elsewhere: the Flui firewall on the machines, DNS from a zone held on another provider. The platform on top is the same as in Full mode.
  • Flui BYOS (bring your own server). No cloud provider is involved. You point Flui at a Linux machine you already own, flui env create --host installs over SSH, and everything Flui ships on top (clusters, ingress, TLS, observability and the rest) is the same as in Full or Partial mode. More machines join the same way, one at a time, with flui node connect. There is no provisioning to automate, because you already provisioned the machine.

The mode follows from what the provider exposes; the user does not pick it. A provider that supports every capability Flui needs ends up in Full mode, and one that supports only some ends up in Partial mode.

BYOS goes through the same abstraction as any cloud. It is a provider with its own capability declaration, with almost every capability declared off: no API to create a server, no catalogue of machine shapes, no region list, no price list, no managed firewall at the edge.

The rest follows mechanically, with no special cases. flui env firewall apply takes the same rules and the same command, and because BYOS declares no managed firewall, the rules are applied on the machine itself instead of at a provider’s edge. A cluster that needs to grow raises an alarm naming the machine to attach, instead of buying one, because BYOS declares no way to buy one. Neither behaviour branches on the provider’s name. Both come from what the provider says it can do.

Behind the modes, Flui tracks a finer set of capability dimensions each provider can declare: server lifecycle, hourly billing, SSH key registry, firewall, DNS, private network, block storage, object storage and power management. Where the provider’s API offers a capability (managed firewalls, DNS zones, private networks, volumes), Flui drives it directly, so the provider’s strengths come through. Where it does not, Flui supplies the piece itself or takes it from another provider. Only where neither is possible does it become a manual step, and that fallback is documented, so an integrator does not have to guess what happens when their provider has no firewall. The platform on top looks the same either way.

The providers integrated today

Here is what the model above resolves to now. Every row is the provider module’s own capability declaration.

Buys machinesBillingPrivate networkDNS zonesFirewall
Hetzneryeshourlyzone-scopedyesprovider edge
Scalewayyeshourlyper regionyesprovider edge
OVHcloudyeshourlyper regionnoon the host
Your own serversnoyourswhatever you wirednoon the host

Hetzner, Scaleway and OVHcloud are trademarks of their respective owners. Flui is not affiliated with or endorsed by them.

Four more differences matter when you choose, because each is something you either get or arrange yourself:

  • Resizing and stopping a node. Hetzner and Scaleway can change a machine’s shape in place, and power one down without destroying it. On OVHcloud neither is exposed, so growing a node means replacing it.
  • Live stock. On Hetzner, Flui reads region by region whether a shape can be bought right now. On Scaleway and OVHcloud it does not, so a sold-out shape shows up only when an order is refused. What Flui does with the signal where it has it is described below.
  • Block volumes. All three clouds create, attach and grow the volume that carries the cluster’s shared storage. On your own servers that is the disk already in the machine.
  • Object storage for backups. Backups are Flui’s own, taken from inside the cluster, and land on any S3-compatible bucket you point them at, wherever it lives, including at another provider. On the supported clouds, setting one up takes one click: Flui creates the bucket and wires the credentials itself. What that click does differs by provider. Scaleway provisions the bucket with the credential Flui already holds for compute, OVHcloud mints an S3 key from its OpenStack one, and Hetzner asks for a second set of Object Storage credentials before doing the rest.

Two capabilities these clouds sell are left out of the table: server snapshots and provider load balancers. Flui drives neither on any provider, so listing them would describe the cloud’s catalogue rather than what Flui does with it. Ingress is Traefik running on your own nodes, and backups work as described above.

The table also cannot show the shapes you can pick and what they cost. These are read from the provider rather than from a list kept inside Flui, so they follow the provider’s catalogue as it changes. On OVHcloud the regions are read live as well, scoped to your credential, because the regions a project can use differ from one account to the next.

Read across a row rather than ranking the columns. Hetzner and Scaleway are Full-mode integrations: everything Flui needs is behind the provider’s API. OVHcloud is Partial: servers, the private network and volumes go through its API, while the firewall is Flui’s own, applied on the machines, and DNS comes from a zone held on another provider. Your own servers are BYOS: nothing to buy, and the same platform on top.

The difference that matters most is growth. A cluster can add a node by itself only where Flui can buy one. On your own servers it cannot, so a cluster that runs out of room raises an alarm naming the machine to attach. That behaviour comes from nodeProvisioning, never from the provider’s name.

Live availability

A machine shape can sell out in one region and still be available in the next. Where a provider reports its stock, Flui reads it at the moment you choose (flui server-types list marks a shape that cannot be bought in a region right now), so a purchase does not fail halfway through.

The check matters most when a cluster buys its own machines. A scaling group lists the shapes it may buy, in your order of preference. When the first is sold out where the cluster needs it, the group buys the next one it is allowed to. A sold-out shape moves to the back of the list but never leaves it, because stock comes back, and when it does, the cluster buys that shape.

If every shape on the list is sold out, the cluster raises an alarm that says so and keeps looking. If a machine sells out between the reading and the order, the group pauses briefly and checks availability again. Either way, as soon as the machine can be bought, the cluster buys it, within the spending ceiling you set and only if the group is allowed to act on its own.

Adding more providers

Hetzner, Scaleway and OVHcloud are where Flui starts, and it is not limited to them. Each sits behind the same provider layer, so adding another means writing its module and its capability declaration; the rest of Flui adapts to what that declaration says.

Before an integration makes sense, a provider needs two things:

  • A well-documented API for its servers. Flui has to create, read, delete and list servers and report their status, through an interface the provider documents and keeps stable. That is the minimum. A private network, a firewall, DNS and a catalogue of shapes with prices are capabilities declared on top of it, and none of them is required to get in.
  • Hourly billing. A cluster that buys machines and gives them back on its own only makes sense where a machine costs the hours it ran. With monthly billing, every short-lived node would cost a full month.

A provider with both gets the whole platform on top, with whatever it does not expose handled as Modes of integration describes. A provider with neither can still be used: to Flui, the servers you rent there are your own servers.

What the abstraction hides, and what it does not

The abstraction works in two directions. Most of the time you talk to Flui in Flui terms, and anything you normally have to think about is expressed that way.

Flui conceptWhat it represents
clusterA set of servers with a private network, a firewall, and cluster-scoped resources, all tagged as managed by Flui.
nodeA machine inside a cluster. Its row records where the machine came from (provider, region, shape) and what it costs per hour.
vnet + subnetA private network and one or more subnets the cluster’s nodes attach to.
firewallA set of inbound/outbound rules attached to one or more servers.
dns-zoneA managed DNS zone, when the provider exposes a DNS API.
endpointA FQDN with TLS, attached to a workload, backed by an A-record and a certificate.
manifest (flui.yaml)Independent of any provider; see the manifest chapter.
build / release / operationTracked centrally by Flui. Build execution is delegated to an external system.

A few things are not hidden. They stay provider-specific, because hiding them would mislead you:

  • Server-type identifiers. Each provider has its own catalogue of instance shapes. Flui keeps a cache with pricing and availability per region, but does not pretend two different providers’ types are interchangeable.

  • Region and zone codes. The user picks one; Flui validates it against the provider.

  • Prices. Every machine carries the price of the shape it actually is, read from that provider’s own catalogue. This lets Flui talk about money instead of machine counts: what a cluster already commits to for the month, and what one more machine would add. It is also why the limit on what a cluster may spend on itself is stated in money rather than in a number of machines, since the number of machines is not the bill. When Flui decides to add a machine, or declines to, the decision it records names the shape, the region and the hourly price it was weighing.

    Two readings are kept apart. A machine whose price Flui cannot see (your own hardware under BYOS, or a shape the provider does not publish a price for) is recorded as unknown, never as zero, because zero reads as free. A total built from those rows is therefore a floor, and the machines it could not price are counted next to it rather than folded in.

  • Provider-side IP ranges. When a provider documents constraints on CIDRs or routes, those constraints win.

  • External-side configuration. When something Flui needs touches a system outside the provider’s API, for example delegating a domain registered elsewhere by setting NS records at the registrar, you configure it manually on that external side. Flui manages what it can reach.

Why this design pays off

This design pays off in three ways:

  1. Adding a provider does not destabilise the rest. A new provider integration is built as a self-contained piece: it implements the abstraction and declares which capabilities the provider supports. The CLI, the dashboard and the orchestration engine stay untouched. The work is real, but it stops at the new integration’s boundary.
  2. Dropping a provider is also self-contained. Every operation that touches a provider goes through a single point inside Flui. Removing a provider means removing that one integration, without chasing changes across the rest of the platform.
  3. Capability-driven UX without conditionals. The dashboard and the CLI read the provider’s capability declaration instead of hardcoding behaviour, so a provider that gains DNS support gets DNS controls in the UI as soon as its capability flag flips, with no client release.

How this chapter is referenced elsewhere