An immutable, container-native Linux distribution that boots into a Kubernetes node.
Corium is Fedora bootc with k0s in the read-only system, a Kubernetes version you can choose independently of the OS image, and a small declarative configuration layer on top of cloud-init.
Status: 0.x. The architecture is settled and the path works end to end — a node boots, joins, upgrades, drains itself before rebooting, rolls back when it comes up broken, and refuses an image that is not signed. Two things are not settled. The configuration surface can still change between minor releases, and the testing is narrower than it looks: everything has been verified on virtual machines, none of it on physical hardware. Pin a version, read the changelog, and do not put anything on it you would miss.
A complete single-node Kubernetes cluster:
#cloud-config
corium:
role: singleA worker joining an existing one:
#cloud-config
corium:
role: worker
join:
token: <k0s join token>That is the whole interface for the common case. Everything else has a default, and every default is overridable. See examples for the full surface, including the escape hatches.
Every node runs a small management API that answers for itself and nothing
else. It is on by default: a machine installed from the ISO with no configuration prints a
pairing code on its console and waits to be told what it is, rather than being unreachable. cctl is the client: it claims a node, reads what it is, restarts a
service, drains it, and rolls it on to a new image. cctl ui is the same thing with a page
in front of it.
It runs on your machine, not on the nodes. The server binds loopback, holds your client certificate, and talks to each node over the same mutual TLS every other command uses. No machine gains a port, a password or a session because somebody opened a browser — which is what keeps what it is not true. It reads, and it restarts a unit, cordons, uncordons and drains. It cannot reboot, reset, apply a configuration or upgrade anything: those are irreversible, or they are rollouts whose order across nodes matters, and a button is the wrong shape for both.
Three properties, chosen together because each one reinforces the others.
The operating system is a container image. Corium is built with a Containerfile, pushed
to a registry, and versioned by digest. You inspect it with podman, scan it with the
scanner you already run, promote it between environments by moving a tag, and roll it back
atomically. There is no separate image-building toolchain to learn, because the one you use
for your applications already works.
Kubernetes ships with the OS, and its version is still yours to choose. The k0s binary
lives in the read-only /usr, so a node always has a working Kubernetes and needs no network
to get one. What that binary is can be overlaid by a signed system extension, which makes
the Kubernetes version an axis of its own: a Fedora security fix no longer drags a Kubernetes
minor bump behind it, and moving between Kubernetes releases no longer means rebasing the OS.
Both axes stay immutable — nothing is ever written in place — and a node remains a disposable
artefact rebuilt from a digest rather than a machine that accumulates state.
Configuration is cloud-init, where cloud-init exists. Not a bespoke API, not a new config
language: the mechanism every hypervisor and cloud already speaks. Corium adds a corium:
block that collapses the tedious parts into a handful of keys, and gets out of the way the
moment you need something it did not anticipate.
Where cloud-init does not exist — bare metal without a seed device, PXE, an appliance shipped preconfigured — the same configuration is read from a file, the kernel command line, or a default baked into the image. One schema, four ways in.
Corium is not a fleet manager — it provisions nodes and stops there. It does not fork or patch k0s. It does not invent a configuration language. Those are deliberate omissions: the project is an opinionated integration, and its value is in what it declines to do.
Talos Linux is the dominant option in this space and is excellent; it is also an API-driven system with no shell and its own configuration model, which is a real commitment. Kairos covers similar ground — immutable OS, pluggable Kubernetes distribution, cloud-init configuration — but deliberately builds its own A/B partition scheme on top of an arbitrary base distribution rather than using the OSTree/bootc lineage.
Corium's bet is narrower and specific: that for teams already living in OCI registries and GitOps, an operating system that is an image — built, signed, scanned, and promoted like every other image they ship — is worth more than a bespoke mechanism, however good.
The comparison covers these and the rest properly, including the cases where you should pick something else.
Sources are tried in order, most specific first, and the first one that answers wins:
| Source | For |
|---|---|
/etc/corium/config.yaml |
An operator's answer for this machine |
| cloud-init | Every cloud and hypervisor: NoCloud, ConfigDrive, EC2, Azure, GCE, OpenStack, Hetzner, VMware |
corium.config= on the kernel command line |
PXE and netboot, where the command line is all you control |
/usr/share/corium/config.yaml |
A default baked into a derived image |
A source that fails for any reason other than being absent stops the search. An unreachable config URL means your intent is unknown, and falling through to a baked-in default is how a node silently joins the wrong cluster.
mise run artefacts produces, via
image-builder:
| Artefact | For | Built by |
|---|---|---|
qcow2 |
Proxmox, KVM, libvirt | image-builder build --bootc-ref |
raw |
Bare metal, and most clouds' import paths | image-builder build --bootc-ref |
anaconda-iso |
Interactive or kickstarted bare-metal installs | the bootc-image-builder entry point |
Both builders are pinned by digest and come from the same upstream release.
The disks are on the code path upstream develops; the ISO is on the
compatibility entry point bootc-image-builder left behind when it was
archived in June 2026, because that is the only one that still builds the
type — and that type is itself on its way out upstream.
ADR 9 is the plan for the rest.
You only need to build these if you have changed the image. Every release publishes the ISO and the qcow2 ready-made and signed: see Downloads for where they live, why nothing is attached to the release itself, and how to check what you got.
Start here
- Concepts — how it works and why it is shaped this way
- Quick start — from a published image to a working node in four steps
- Which install guide — pick the path that matches your target
- Troubleshooting — failures indexed by what you observe
Installing
- Downloads — where the ISO and the qcow2 are published, and how to verify them
- Proxmox — a node on a Proxmox host, start to finish
- OpenStack — a node on an OpenStack cloud, UEFI image included
- Rescue mode — a dedicated server, installed from a provider's rescue system
- HA cluster — building a three-controller control plane by hand
- Stretched cluster — one cluster across two locations
Operating
- Upgrades — moving a node to a new image, changing its Kubernetes version, rolling back
- cctl — every command of the management CLI, what each role reaches, and how to read a refusal
- Building your own image — deriving an image, signing it so nodes accept it
- Cilium — replacing kube-router, including the kube-proxy-free variant
- Software RAID — mdadm arrays on a node's spare disks, and where a RAID root stands
- WireGuard overlay — joining hosts across sites over an encrypted overlay
Reference
- Configuration reference — every field, and what Corium does with it
- Examples — annotated documents for each common node shape
- Feature support — what is modelled, what passes through to k0s, what is out of scope
- Comparison — Talos, Kairos, Flatcar, and when not to use Corium
- Changelog — what each release changed, and what is known to be broken
AGENTS.md— contributor and agent guidelines, architectural decisionsdocs/adr/— architecture decision records
MIT. See LICENSE.
