Show examples as

Cluster & node upgrades

kcore nodes run NixOS. Host upgrades move the system forward using an immutable flake revision (flakeRef + flakeRev) while the controller orchestrates prepare/activate work on each node. Workloads (VMs/containers) use the normal lifecycle APIs; they are not upgraded by this flow.

These pages match one kcore release. The GitHub Release for that version includes cluster-update-X.Y.Z.yaml. Community Edition nodes fetch that git commit and compile it. A later private channel will serve prebuilt closures of newer versions, the provisioner, and the backup service.

Cluster rollout vs single node

Both use the same kind: ClusterUpdate manifest. The selector decides scope:

There is no separate command for “upgrade this machine only”; narrow the selector instead.

CLI (kctl update cluster)

Alias: kctl update os. Requires a working controller context (same TLS setup as other kctl commands).

# Dry-run: resolve targets, viability, reboot hints
kctl update cluster plan -f rollout.yaml

# Submit or update the ClusterUpdate resource
kctl update cluster apply -f rollout.yaml

# Observe cluster + per-node phases
kctl update cluster get release-0-4-2
kctl update cluster list

# If approvalPolicy is manual
kctl update cluster approve release-0-4-2

kctl update cluster cancel release-0-4-2
kctl update cluster rollback release-0-4-2

# Boot a generation staged because the kernel or guest units changed
kctl update cluster reboot release-0-4-2 --node <node-id>

Switch to CLI in the strip above for command blocks.

YAML manifest outline

The release asset is camelCase. kctl also accepts the snake_case names. See YAML manifest reference (ClusterUpdate). Copy cluster-update-X.Y.Z.yaml from the GitHub Release for that version. It already contains the commit and the tested pins.

kind: ClusterUpdate
metadata:
  name: release-0-4-2
spec:
  target:
    version: "0.4.2"
    flakeRef: github:kcorehypervisor/kcore
    flakeRev: "<full-git-sha>"
  selector:
    allNodes: true
  strategy:
    strategyType: one-at-a-time
    maxUnavailable: 1
    batchSize: 1
  drainVms: false
  activation:
    mode: auto
  approvalPolicy: manual
  updateKind: kcore

Showing Terraform examples. Provider source is kcorehypervisor/kcore, version 0.5.0.

Reboot stays kctl update cluster reboot. Destroy cancels the rollout.

resource "kcore_cluster_update" "os" {
  name                    = "release-0-5-0"
  version                 = "0.5.0"
  flake_ref               = "github:kcorehypervisor/kcore"
  flake_rev               = "<full-git-sha>"
  nixpkgs_rev             = "<nixpkgs-rev>"
  all_nodes               = true
  strategy                = "one-at-a-time"
  max_unavailable         = 1
  batch_size              = 1
  drain_vms               = false
  activation              = "auto"
  update_kind             = "kcore"
  schema_version          = 59
  previous_schema_version = 56
  min_compatible_reader   = 56
  approval                = "manual"
  approve                 = false

  tested_os_pins {
    nixpkgs_rev        = "<nixpkgs-rev>"
    ceph_rev           = "<ceph-rev>"
    ceph_sha256        = "<ceph-sha256>"
    kubernetes_version = "1.37.0"
  }
}

With approvalPolicy: manual, the controller waits for kctl update cluster approve <name> before rolling. Automatic policies advance without that step. strategyType for this release is one-at-a-time. A nixpkgs move is a second manifest with updateKind: nixpkgs whose nixpkgsRev is one of testedOsPins.

Phases

The cluster resource exposes a phase (pending, rolling_out, succeeded, failed, …). Each node row tracks prepare/activate progress and errors. Use kctl update cluster get for detail.

canary, batch, and per-dc are refused. The rollout advances one node at a time.

Host rollback

Controller rollback expresses rollout intent. For a broken activation you can still recover with normal NixOS generation commands on the machine (e.g. previous bootloader generation); keep that in your physical/datacenter runbook.

Further reading