Platform stack

Kubernetes VM Stack v1.36.6-kubevirt1.9.1

Virtual machines on a three-node, highly available Kubernetes cluster, from images ReadyStack built with the network off, each pinned by digest and pulled only from your own registry.

Released 2026-10-29 · The bundle's release page · Docker Hub

What it is

The Kubernetes VM Stack runs virtual machines on a three-node Kubernetes cluster. Every part is a signed ReadyStack release, built with the network off from pinned upstream source and packages, and every image the cluster runs is pinned by digest in one install bundle.

  • Clusterkubeadm v1.36.6, highly available: all three nodes run the control plane, with etcd v3.7.3 stacked on them, behind a kube-vip virtual IP.
  • Add-onsflannel for the Pod network, Multus with a host bridge so VMs get an interface on your LAN, and KubeVirt v1.9.1, which runs VMs from static local disks.
  • ImagesEvery image is a ReadyStack release pinned by digest. The hosts pull only from a local registry on your own network.
  • RootEvery image runs as a non-root user by default. Where a component needs root, the bundle's Pod specs and kubeadm patches set it: root is set by the Pod, not by the image.
  • The bundleAn image FROM scratch that holds the install bundle, the pin manifest (kubevirt-stack.json) and the operator runbook, with a checker, stack-bundle, that verifies every file against the bundle's SHA256SUMS.
  • HostsThree Ubuntu 24.04 x86-64 hosts on one layer-2 network, with /dev/kvm on each (without it KubeVirt falls back to emulation, which is slow), a free address for the virtual IP, and a machine for the local registry. The stack was tested end to end on three Ubuntu 24.04 nodes.
  • Bundle imagereadystack/kubernetesvmstack:v1.36.6-kubevirt1.9.1-CE-scratch-r2
  • linux/amd64 digestsha256:0268790dadac6fbc392784cb7f77f996526f4d1b6394bb30228d19ddaae062e9
  • SignatureSigned (key 04daa92344a52dbc)
  • Offline rebuildRebuilt bit-for-bit on 2026-10-29 with the network off

Who installs it and why

Our pitch

Our pitch: who we built it for. It is not a list of customers.

  • Teams that run a fleet of virtual machines on their own hardware and want those VMs managed beside their containers: one Kubernetes API, one set of manifests, one registry.
  • Sites that cannot pull from the internet, such as air-gapped, regulated and sovereign environments. Every host pulls only from a local registry on your own network, and each image can be checked against its signature, SBOM and provenance before it goes in.
  • Teams that must show what they run. Every part is a signed ReadyStack release with an SPDX SBOM and SLSA v1 provenance, and the bundle's pin manifest names the upstream repository and commit of every component it pins.

What's in it

As JSON

Each part is its own ReadyStack release. The names, tags, digests and grades below are read from the catalogue (/api/products) and our scans (/api/scans) when the page is served; each name opens that part's page.

PartRelease taglinux/amd64 digestGrade: original → current
Host programs
Kubernetes Node v1.36.6kubelet, kubeadm, kubectl, containerd, runc, the CNI plugins and crictl. Its one layer is the node tarball the install bundle puts on each host. v1.36.6-CE-scratch-r1 sha256:0a264881a0b7357fb20767b0922661bf4ba4423b3e90e595195bf18748a8d79c AA
Control plane
kube-apiserver v1.36.6The Kubernetes API server, a static Pod on each node. Root is set by a kubeadm patch. v1.36.6-CE-ubuntu24.04-r1 sha256:49c4d7708668d7ab42ae0d1d3d584063f67ef87f2d746e21d6709288afdb997e AA
kube-controller-manager v1.36.6The controller manager, a static Pod on each node. Root is set by a kubeadm patch. v1.36.6-CE-ubuntu24.04-r1 sha256:f832d6d6174e904cb86f178379571f02421cd5e056f112da12062aec8d2f93a2 AA
kube-scheduler v1.36.6The scheduler, a static Pod on each node. Root is set by a kubeadm patch. v1.36.6-CE-ubuntu24.04-r1 sha256:db92258d58a8e98424edd20418624e6625c4360acedd4dd919443a3e538c9ef8 AA
kube-proxy v1.36.6Service routing on each node, deployed by the bundle's own DaemonSet, which sets root. v1.36.6-CE-ubuntu24.04-r1 sha256:690fd8d24cd4ffbf70dbe1ba26ac48ce80a972d7183cf691948ff5ff8ca8d56c AA
pause 3.10.2The Pod sandbox image containerd starts for every Pod. 3.10.2-CE-scratch-r1 sha256:6b74cfa71db2c51e1a21e3342402d3993573ea02a0c85063897eda87958dca26 AA
Cluster DNS
CoreDNS v1.14.2Cluster DNS, at exactly the version kubeadm names. v1.14.2-CE-ubuntu24.04-r1 sha256:faf5d9691f306d7f318377a2db731aa843ef8ed23866e7c410cdbc001dda2c4b AA
Networking
kube-vip v1.3.1Holds the control-plane virtual IP and moves it when a node is lost. Root is set in the bundle's YAML. v1.3.1-CE-ubuntu24.04-r1 sha256:74dd28c7b8af69cd7cf4684338b782d1fbf939a1dbfabeb1545d70b077cf934b AA
flannel v0.28.10The Pod network across the nodes. Root is set in the bundle's YAML. v0.28.10-CE-ubuntu24.04-r1 sha256:6d3fb1140502d71df92ae2b107532acaf809aa42a94e2e6b9eec291fab4b8856 AA
flannel CNI plugin v1.9.1-flannel3flannel's CNI plugin, put on each node by the flannel DaemonSet. v1.9.1-flannel3-CE-ubuntu24.04-r1 sha256:4511acd7413d1e6fd78d3d712921d794cb820a3b62973512532d7b64f2cc4e8a AA
Multus CNI v4.3.1Multus: gives Pods and VMs a second interface on the hosts' bridge. Root is set in the bundle's YAML. v4.3.1-CE-ubuntu24.04-r1 sha256:f90014221243e98cf21d56dc66e3f53bf386c1c1484a633e550dadf4e39f324e AA
KubeVirt
virt-operator v1.9.1Installs and manages the KubeVirt components. v1.9.1-CE-debian12-r1 sha256:78de21c348d6b5c03db14e9b14e4fe02f947114771f8897f53c2f52bf435a0a6 AA
virt-api v1.9.1KubeVirt's API server. v1.9.1-CE-debian12-r1 sha256:1b50959eea78ae4db3a6037b90943ada86b9cb5426bb4790525316087d0ff582 AA
virt-controller v1.9.1KubeVirt's cluster-wide controller. v1.9.1-CE-debian12-r1 sha256:4e9192b84b55aa401f992f0337ac4a76e79d25ff2519e803274a3c353b01ad12 AA
virt-exportproxy v1.9.1Serves exports of VM disks. v1.9.1-CE-debian12-r1 sha256:3bb06b5880899bf2955da20fb6c47810f0a863a9057c0c9ec13f61a3a624322b AA
readystack/virthandler Not listedvirt-handler: KubeVirt's agent on each node. Root is set by the KubeVirt CR's patch.Published and signed, but not listed: it scores below A on our scan. KubeVirt builds virt-handler on its own CentOS Stream 9 package set, which carries high vulnerabilities that CentOS Stream has not fixed yet. Its Docker Hub page gives the grade and every deduction. v1.9.1-CE-centos9-r1 Not in /api/products (unlisted); its Docker Hub page gives it FF
readystack/virtlauncher Not listedvirt-launcher: the Pod each VM runs in. It starts libvirt and QEMU as the unprivileged qemu user.Published and signed, but not listed: it scores below A on our scan. KubeVirt builds virt-launcher, QEMU and libvirt included, on its own CentOS Stream 9 package set, which carries high vulnerabilities that CentOS Stream has not fixed yet. Its Docker Hub page gives the grade and every deduction. v1.9.1-CE-centos9-r1 Not in /api/products (unlisted); its Docker Hub page gives it FF
VM client
virtctl v1.9.1The VM client for the admin machine (console, start, stop): the binary and its release tarball. v1.9.1-CE-scratch-r1 sha256:634431da66d601627ffc0cddd0e41d02678ff5c1a2f6407661ae9f8a85091501 AA
Reused from the catalogue
etcd v3.7.3The cluster's datastore, stacked on the three nodes: the catalogue's own etcd release, used as it is. Root is set by a kubeadm patch. v3.7.3-CE-ubuntu24.04-r1 sha256:b21b8089f1957b35bfaf54647f871c1e9e56d36d20af32a2fdb9b2b6483d62f6 AA
Distribution Registry v3.1.2The local registry every host pulls from, on your own network.Not pinned by the bundle: any release of it serves. v3.1.2-CE-ubuntu24.04-r5 sha256:9b7a9955779cf093257a24546a860c35f627315956b12a93b9a03f013dffc449 AA
The bundle
Kubernetes VM Stack v1.36.6-kubevirt1.9.1This stack's install bundle: the install files, the pin manifest and the operator runbook, with the stack-bundle checker. v1.36.6-kubevirt1.9.1-CE-scratch-r2 sha256:0268790dadac6fbc392784cb7f77f996526f4d1b6394bb30228d19ddaae062e9 AA

Grades are ReadyStack's own daily scan of each published image: a syft SBOM and grype vulnerability matches, scored with cerodeo-v1, the rubric ce.rodeo published until 2026-10-26. The original grade is the first recorded scan of the release, the current grade the latest. A part's own page explains its score. A part of the stack that does not score A on this scan is published and signed but not listed in the catalogue; it is shown here as not listed, with the reason.

How it was tested before release

Record of 2026-10-29

Acceptance run, 2026-10-29, 11:03–11:55 UTC: passed

Before release, the published images were installed on three test nodes (Ubuntu 24.04 virtual machines with KVM available inside them) and checked end to end. Every check of the run passed.

  • Every image was pulled from Docker Hub at its published digest into a local registry on the test network. The mirror copies an image only when its linux/amd64 digest is the one the bundle lists.
  • cosign verified 60 of 60 signatures against ReadyStack's release key: the 30 names mirrored into the local registry, each by tag and by digest. The host-side kubernetesnode and virtctl releases verified too.
  • Every mirrored image, and both host-side releases, carried an SPDX SBOM and SLSA v1 provenance.
  • The test nodes could not reach the internet: from each node, HTTPS to public IP addresses was refused, checked at the start and again after KubeVirt was installed.
  • On every node, every image ran at exactly its published digest, with none failing the check. No image defaulted to root: uid 0 came only where the bundle's files set it.
  • Pods reached each other across the nodes and through a Service, and the Multus bridge gave a Pod a second interface.
  • Failover: the control-plane node holding the virtual IP was switched off. The API answered on the virtual IP again after 17 s, from another node, and a write was accepted. Started again, the node was Ready after 68 s.
  • KubeVirt became Available from the published images. A CirrOS VM booted from a static local disk ran under KVM, gave a console login prompt through the published virtctl, and took an address on the hosts' LAN.
  • Two failures in the test's own scripts were fixed during the run. The record keeps both, and neither was a defect of a published image.

Also checked

  • The bundle image, checked the same way the same day: cosign verified it by index and by linux/amd64 digest, its SBOM and SLSA v1 provenance were attached, its own check verified 26 files, and its 23 install files were byte-identical to the files the acceptance run used. (release v1.36.6-kubevirt1.9.1-CE-scratch-r2)
  • etcd restore, 2026-10-29, 13:41–13:44 UTC: the runbook's restore of every etcd member from a kept backup was checked live on the same cluster, and 13 of 13 checks passed. Afterwards a marker written after the backup was gone, and the VM was still Running. The record of these checks ships in the bundle, as runbook/RUNBOOK_EVIDENCE.json.
  • The operator runbook was checked against the stack's test cluster: 69 of 69 of its checks passed, as the release notes record. (release v1.36.6-kubevirt1.9.1-CE-scratch-r2)

Source: ReadyStack's integration report for the stack, its acceptance run and the evidence file of every check.

How to get it

The image is free on Docker Hub

1. Pull the bundle and verify it. cosign checks the image against ReadyStack's release key; then the image's own check verifies every file of the bundle against its SHA256SUMS. The image has no shell, so the bundle is copied out of a container that is created but never started, and the copy is checked again on your machine.

KEY=https://readystack.dev/keys/cosign.pub
IMAGE=readystack/kubernetesvmstack:v1.36.6-kubevirt1.9.1-CE-scratch-r2@sha256:0268790dadac6fbc392784cb7f77f996526f4d1b6394bb30228d19ddaae062e9
cosign verify --key "$KEY" "$IMAGE"
docker run --rm "$IMAGE"                  # prints "Kubernetes VM Stack v1.36.6-kubevirt1.9.1: 26 files verified", or names each problem and exits 1
docker create --name kvs-bundle "$IMAGE"  # the image has no shell
docker cp kvs-bundle:/kubernetesvmstack .
docker rm kvs-bundle
(cd kubernetesvmstack && sha256sum --quiet -c SHA256SUMS)

2. Unpack it. kubernetesvmstack/install/ is the install bundle, with its README.md, the full order of operations; kubernetesvmstack/runbook/RUNBOOK.md is the operator runbook, with the checks to repeat on your own cluster; kubernetesvmstack/kubevirt-stack.json is the pin manifest.

3. Install, in this order (each step in full in install/README.md):

  1. The local registry. Run readystack/registry on a machine the hosts reach, with TLS from a CA the hosts trust.
  2. The registry config. Put the registry's address, CA and credential on every host, in a root-only file.
  3. The host bridge. On each host, move the uplink onto a bridge (br0) with the bundle's netplan example.
  4. Mirror the images. mirror-images.sh copies every image by digest into the local registry, signatures and attestations included; then check each with cosign.
  5. The hosts. install-node.sh installs the host programs from the Kubernetes Node bundle and points containerd at the local registry, with no public fallback.
  6. The first node. The kubeadm patches, kube-vip, then kubeadm init.
  7. The other two nodes. The same patches and kube-vip, then kubeadm join as control-plane nodes.
  8. Add-ons. kube-proxy, flannel and Multus, then spread CoreDNS over the nodes.
  9. KubeVirt. The operator, then the KubeVirt CR; wait until it is Available.
  10. VMs. A VM from an existing disk on a static local volume, with a NIC on the host bridge; then virtctl console.

Known limits

  • A VM on a local volume is pinned to its node: it cannot live-migrate, and it stops while that node is down.
  • Kubernetes 1.37 waits for a KubeVirt release that supports it. KubeVirt 1.9 supports Kubernetes 1.34 to 1.36, so we hold the stack on the 1.36 line.
  • containerd reads the registry credential from its deprecated registry.configs setting. The runbook says why, and the stack keeps containerd on a release that still reads it.
  • The OCI licences labels of the pause and kubernetesnode images understate their licences: they leave out glibc, which is linked into them statically and is LGPL-2.1-or-later. Their Docker Hub pages and SBOMs say so, and each image's next revision corrects the label.
  • virt-handler and virt-launcher are published and signed but not listed, because they score below A on our scan (see the table above).
  • readystack/registry's health check probes 127.0.0.1, so with the registry bound to another address and TLS on, Docker reports it unhealthy while it serves.
  • Built for x86-64 (linux/amd64) only.

Ask for another stack

Need a different platform built this way? Tell us the platform, its components and the machines; we check the licence and feasibility first. $250 when it ships. Your card is saved, not charged, and if we cannot take it on we remove it.