Guide: End-to-End Setup — Bootstrap to Running VMs¶
Every other guide in this section zooms into one step of the pipeline. This page is the map: it walks the whole chain, from "nothing exists yet" to a running VM (and, optionally, that VM joining a k0s cluster), and links out to the guide that covers each step in depth.
Steps 3 and 5 are drawn for both backends to show the target shape. Only the vSphere path is fully wired end-to-end today:
banlieue-provider-libvirthandles registration + image import (steps 2–3) but has noLibvirtMachinereconciler yet, so step 5 only clones/powers on a real VM on vSphere. See Project status.
Walkthrough¶
0. Bootstrap the management cluster¶
Starting from bare metal?
bootstrap-k0s-cluster.sh assumes its substrate already exists — a working
libvirtd with storage pools, or a reachable vCenter plus govc. If you
are starting from a machine with nothing on it, do
Host Bootstrap first.
Before any of banlieue's own CRDs exist, something has to run the cluster
banlieue's controllers will live on. scripts/bootstrap-k0s-cluster.sh
does this the old-fashioned way — no banlieue CRDs involved yet, because
banlieue doesn't exist in this cluster yet:
libvirtbackend — clones/installs Kairos VMs viavirt-installon a KVM host.vspherebackend — clones cluster-specific Kairos templates viagovc, spreading nodes evenly across compute clusters so each is its own etcd failure domain.- Either way, k0sctl installs k0s
onto the resulting VMs. An opt-in
fluxstep (FLUX_ENABLED=true) pulls a registry credential from HashiCorp Vault and pushesflux-operator/flux-coremanifests onto the first controller node.
No environment-specific identifier is ever committed — every value comes
from the GOVC_* environment, govc discovery, or an untracked operator
config (ADR-0017, ADR-0018).
vSphere¶
# Scaffold the untracked env file (BACKEND must be set explicitly — it
# defaults to libvirt otherwise, even for this template-only step)
BACKEND=vsphere ./scripts/bootstrap-k0s-cluster.sh --print-env-template \
> ~/.k0s/banlieue.env
# Fill in the node table (name/cluster/ip/role) and per-cluster placement
# maps (VSPHERE_RP / VSPHERE_DSC / VSPHERE_NET / VSPHERE_TPL), then:
BANLIEUE_ENV_FILE=~/.k0s/banlieue.env BACKEND=vsphere \
./scripts/bootstrap-k0s-cluster.sh all
Subcommands run individually: vms | config | apply | kubeconfig | label |
flux | destroy. GOVC_* (URL/creds/datacenter/CA) comes from the ambient
environment; nothing environment-specific is ever committed to the env file
(rules/no-real-infrastructure.md).
libvirt (default)¶
LIBVIRT_URI=qemu:///system \
VM_COUNT=4 VCPUS=2 MEM_MB=8192 DISK_GB=25 \
./scripts/bootstrap-k0s-cluster.sh all
Run on the KVM/libvirt host itself, or point LIBVIRT_URI at a remote one.
Kairos installs itself from IMAGE_URL's ISO onto an empty disk before
k0sctl takes over.
Output of this phase: a running k0s management cluster with nothing banlieue-specific on it yet.
1. Install banlieue¶
banlieue bootstrap operator (ADR-0013) — same binary, bootstrap
subcommand — applies, in order: namespace → CRDs (built at runtime from the
binary's own Rust types, so schema and binary can never disagree) →
banlieue-controller → banlieue-operator → one ProviderClass per
backend compiled into the binary. --dry-run prints the exact YAML instead
of applying it, for a GitOps repo.
Output: CRDs installed, two controllers running, zero backends registered yet. See Core Controller.
2. Register a backend¶
Apply a Provider (endpoint, credentials, declared storage/network
classes). banlieue-operator mints a dedicated Deployment + ServiceAccount
+ Role + RoleBinding for it (one per Provider, so a hung backend never
stalls another — ADR-0003), and that pod logs in, introspects the backend,
and publishes status.failureDomains[].
Output: one or more reachable failure domains, ready for scheduling.
See vSphere Provider /
libvirt Provider, and
Environment / Provider Isolation
before you reach for a second Provider for what's actually the same
backend.
3. Build or register an image¶
A VMImage with a Template/BackingFile source just needs the named
template/file to already exist on the backend — the provider verifies it.
A Url source (an OCI-referenced Kairos image) triggers the actual build
pipeline: banlieue-imagebuilder requests an OSArtifact from
kairos-operator, and once it's Ready, each matching
provider fans out one import Job per failure domain, turning the
built artifact into a template/volume in every zone.
Output: a template (or raw disk) available in every failure domain a
matching VMClass could schedule onto. See
Using banlieue-imagebuilder and
Setting up the Kairos Operator.
4. Define a VM shape¶
A VMClass names a hardware tier (CPU/memory/disks) plus the abstract
storage/network classes a Provider must satisfy — no backend-specific
field. It's shared by every VirtualMachine that wants this shape, and
(since ADR-0030)
portable across every cluster of a Provider, and across multiple
Providers, without being rewritten per zone.
5. Provision a VM¶
A VirtualMachine references a classRef/imageRef and (optionally)
placement constraints. banlieue-controller resolves the scheduling
decision and server-side-applies the backend-specific infra CR
(VSphereMachine today; a LibvirtMachine is the design target but not
implemented yet — see libvirt Provider) owned by the
VirtualMachine, and that provider clones a real VM from the template
resolved in step 3.
Output: a running VM, with VirtualMachine.status mirroring the infra
CR's own status. See vSphere Provider step 6.
6. Optional: use these VMs as a k0s workload cluster¶
Nothing above required Cluster API. If you do want CAPI-driven
replication — "N replicas spread across failure domains" — apply a CAPI
Cluster + VSphereCluster (an InfraCluster, aggregating the selected
Providers' failure domains) + VSphereMachineTemplate +
MachineDeployment, and a control-plane provider (k0smotron for k0s).
CAPI mints one Machine per replica; banlieue's VSphereMachine
reconciler realizes each exactly as it would for a hand-applied one.
banlieue ships no native replica/tier controller of its own — that's a
deliberate non-negotiable (ADR-0001): cluster-level replica management is
CAPI's job, not banlieue's, so the same provider can serve any CAPI
consumer (kubeadm, RKE2, k0smotron), not just banlieue's own
VirtualMachine.
See Infrastructure CRDs & CAPI.
Why phase 0 is not "banlieue all the way down"¶
It's a fair question: doesn't the management cluster itself need VMs, and
couldn't banlieue provision those? It could, in principle — but at that
point in time there is no Kubernetes cluster for banlieue's controllers to
run on yet, so there's no CRD API to apply a VirtualMachine against.
Phase 0 is deliberately the one piece that talks to govc/virt-install
directly, precisely so it has no circular dependency on the thing it's
building. Once the management cluster exists, everything from phase 1
onward — including, if you choose, a second, CAPI-provisioned k0s
cluster in phase 6 — goes through banlieue's own CRD-only contract.
Full detail, phase by phase¶
| Phase | Guide |
|---|---|
| 0 — Bootstrap | scripts/bootstrap-k0s-cluster.sh --help; ADR-0017, ADR-0018 |
| 1 — Install banlieue | Core Controller |
| 2 — Register a backend | vSphere Provider, libvirt Provider, Provider Lifecycle & Install, Environment / Provider Isolation |
| 3 — Build an image | Using banlieue-imagebuilder, Setting up the Kairos Operator, Building an Alpine VM Template, Building a Kairos Hadron VM Template |
| 4 / 5 — VMClass / VirtualMachine | vSphere Provider steps 4–7 |
| 6 — CAPI workload cluster | Infrastructure CRDs & CAPI |
Every field of every CRD used along the way: API Reference.