Virtual machines
A complete virtual computer running its own guest operating system and kernel.
- KubeVirt
- KVM
Compute platforms · OpenShift · Netherlands
Applications are delivered in different shapes, and each shape expects a different execution model. GRN.CLOUD runs virtual machines, containers and serverless functions on one OpenShift platform, so the choice is made per workload rather than per provider.
This page explains how each compute model works — what it isolates, how it starts, where it stores state, and which workloads it suits. Sizing, resource configuration and pricing are handled on the Shared Public Cloud page.
Virtual machines · OS images · containers · serverless — one platform, EU-hosted.
One platform — four building blocksOpenShift
KubeVirt
Golden images
Kubernetes
Knative
One control plane, one identity model, one network and storage layer.
Why a cloud platform runs more than one compute model.
A cloud platform is not a single runtime. Some applications are shipped as a full operating system with an installer and expect a machine to own. Some are packaged as a container image holding one process and its dependencies. Some are a single handler that only needs to execute when an event arrives, and needs no capacity in between.
These shapes have genuinely different requirements — isolation boundary, startup latency, state handling, patching model, lifecycle — and no single execution model satisfies all of them. A platform that offers only virtual machines makes cloud-native applications expensive to run. A platform that offers only containers cannot run a Windows-only ERP system or an appliance that ships as a disk image.
A complete virtual computer running its own guest operating system and kernel.
The versioned, bootable disk artifacts that virtual machines are created from.
Isolated processes sharing the host kernel, packaged as OCI images and scheduled as Pods.
Request- and event-driven services that scale to zero when they are idle.
Figure 1 — how the four building blocks relate
Figure 1. The building blocks are layered, not alternative. Images are the packaging; virtual machines, containers and serverless revisions are the three things that run.
An operating system image is the packaging format for a virtual machine — you do not choose between them, you build the image and instantiate VMs from it. A container is packaged as an OCI image, which is the same kind of artifact — versioned, immutable, content-addressed — applied to a process instead of a machine. And a serverless function is a container: the difference is who controls the replica count. With a Deployment you declare it; with Knative the platform derives it from traffic and is allowed to take it to zero.
A typical estate uses all four at once: a licensed database in a virtual machine, the application tier in containers, document conversion and webhook handling on serverless, and every one of them built from a versioned image in the same registry.
Deployment unit, not deployment destination. On OpenShift all four are
Kubernetes objects. A VirtualMachine, a Deployment and a Knative
Service are scheduled by the same control plane, authorised by the same RBAC
rules, observed by the same monitoring stack, and attached to the same networks and storage
classes. Moving a workload between models changes how it is packaged, not which platform it
runs on.
A complete computer implemented in software, running its own operating system.
A virtual machine is presented with virtual CPUs, a virtual memory map, virtual disks and virtual network interfaces, and it boots an unmodified operating system on top of them. That guest operating system has its own kernel, its own init system, its own drivers and its own patch cycle, and it does not know that its hardware is synthetic.
The hypervisor presents virtual hardware to guests and arbitrates access to the physical hardware beneath them. A type-1 (bare-metal) hypervisor runs directly on the hardware; a type-2 (hosted) hypervisor runs as a process on a host operating system.
GRN.CLOUD uses KVM, the virtualisation subsystem built into the Linux kernel, with QEMU providing device emulation and libvirt managing the domain lifecycle. Because KVM turns the Linux kernel itself into the hypervisor, the distinction between the two types largely dissolves: the host kernel schedules virtual CPUs as ordinary threads.
Hardware virtualisation extensions (Intel VT-x, AMD-V) let guest instructions execute directly
on the physical CPU. Only privileged operations — page-table changes, I/O port access, interrupts
— trap into the hypervisor, which is why guest code runs at close to native speed rather than
being interpreted. Paravirtualised drivers (virtio-blk, virtio-net)
remove most of the remaining emulation cost on the disk and network paths.
On this platform, KubeVirt runs each VM inside a Pod (virt-launcher). That is the
mechanism that makes a VM a first-class Kubernetes object: it is scheduled, quota-accounted,
network-attached and RBAC-controlled by exactly the same machinery as any other Pod.
Figure 2 — hypervisor architecture
VM 1 — Linux
VM 2 — Windows
VM 3 — Linux
virt-launcher Pod, so KubeVirt schedules it like any other workloadFigure 2. Every guest carries its own kernel. That extra layer is what costs boot time and memory — and what buys the isolation.
Each VM boots a complete stack: firmware, bootloader, kernel, init, system services, then the application. The guest can therefore be a different operating system from the host — Windows Server on a Linux hypervisor — and can load kernel modules, custom drivers and software that expects to own a machine.
vCPU, memory and disk are allocated per VM. The memory boundary is enforced by the CPU's second-level address translation and CPU and I/O shares by cgroups on the launcher Pod. Because the guest runs its own kernel, the boundary between two VMs is the hypervisor's small interface rather than the host kernel's full system-call surface.
Virtual disks are backed by PersistentVolumeClaim objects, so data survives
restart, rescheduling and node failure. Disks can be snapshotted and cloned, and a snapshot
can be promoted into a new golden image. Storage class selection is the same decision made
for any other workload.
Each VM receives virtual NICs on the cluster's software-defined network, with its own IP
address and participation in NetworkPolicy rules. Containers and VMs sit on the
same fabric, so a containerised front end can address a VM-hosted database by service name
with no gateway between them.
A running VM moves to another node without shutting down: memory pages are copied while the guest executes, changed pages are re-copied, and the guest is paused only briefly to move the last delta and device state. It needs read-write-many storage and compatible CPU features, and it is what makes node maintenance non-disruptive.
When a node fails, its VMs are rescheduled onto surviving nodes and started there. This is a restart, not a continuation — the guest boots again and anything held only in memory is lost. Surviving a node failure without losing in-flight state still requires clustering or replication inside the guest.
Typical workloads
The versioned artifact a virtual machine is created from.
An operating system image is a bootable disk artifact: a partition table, a bootloader, a
kernel and a root filesystem, captured as a single file. Common formats are qcow2
(sparse, compressible, snapshot-capable) and raw. On this platform images are
delivered either as OCI artifacts (containerDisk) pulled from a registry, or
imported into a DataVolume that becomes the VM's root disk.
The image is the unit of provisioning. Creating a VM is not installing an operating system; it is copying or referencing an image and booting it.
Figure 3 — golden image workflow
Upstream cloud image or boot source
Patches, CIS baseline, agents, trust store
Boot check, compliance scan, smoke tests
Immutable tag + digest, never overwritten
Every machine of the type starts identical
Figure 3. A CVE returns to step 2 and produces the next version. Running machines are replaced, not patched.
A golden image is a base image built once, deliberately, and then used as the source for every machine of that type. It typically contains the operating system at a known patch level, hardening applied to a security baseline (CIS, STIG or an internal standard), the monitoring and backup agents, the certificate trust store, and the accounts and SSH configuration the organisation expects.
The point is that this work happens once in a pipeline rather than repeatedly by hand. Every VM built from the image starts identical and starts compliant.
A template pairs an image with the rest of the machine definition: default vCPU and memory
shape, disk size, network attachment, and first-boot configuration (cloud-init on Linux,
sysprep or unattend on Windows). In OpenShift Virtualization these are Template
objects together with VirtualMachineClusterInstancetype for the resource shape
and VirtualMachineClusterPreference for guest-OS-specific settings such as
firmware, bus types and clock.
A template turns "provision a RHEL 9 application server" into a single selection with a known result, instead of a checklist.
Immutable infrastructure means never modifying a running instance. When something has to change — a package update, a CVE fix, a configuration change — a new image version is built and instances are replaced with it, rather than being patched in place.
Two properties follow. Configuration drift disappears, because no instance is ever altered after boot, so the image is an accurate description of every machine running from it. And every change becomes reviewable, because it happens in a build pipeline under version control rather than on a console.
OpenShift Virtualization maintains a set of boot sources — automatically imported and updated cloud images for common distributions — so a current base image is available without operating an import pipeline first.
Custom golden images are added alongside them in the same catalogue and are selected the same way, so an organisation can move from "the platform's Ubuntu" to "our Ubuntu" without changing how machines are provisioned.
| Image family | Typical use |
|---|---|
| Ubuntu Server LTS | General-purpose Linux workloads, broad package availability |
| Red Hat Enterprise Linux | Enterprise Linux with a support subscription and a long lifecycle |
| Debian | Stable, minimal base for infrastructure services |
| Fedora | Current kernel and toolchain, shorter lifecycle |
| Rocky Linux / AlmaLinux | RHEL-compatible rebuilds without a subscription |
| Windows Server | Active Directory, IIS, SQL Server, Windows-only applications |
Published images are versioned and immutable. A build produces a new tag — for example
rhel9-app-base:2026.08.1 — and a published tag is never overwritten; a rebuild
produces the next tag. Four consequences follow in practice:
If a new base image regresses, redeploy the previous tag. There is no repair procedure to write.
Each tag maps to a pipeline run, a package manifest and a base digest — which is what an auditor asks for.
Tags are labels; content is addressed by digest, so a deployment can pin an exact artifact.
Old versions cost storage. Define how many to keep and for how long — enough to cover the rollback window and the audit period.
An ordinary process, isolated by the kernel rather than by a hypervisor.
Three kernel mechanisms do the work. Namespaces control what the process can see — its own PID tree, network stack, mount table, hostname, IPC and user mapping. cgroups control what it can use — CPU shares, memory limits, I/O and PID counts. Capabilities, seccomp and SELinux control what it can do — which privileged operations and system calls are permitted.
There is no guest operating system and no virtual hardware. The container image supplies the userland — libraries, binaries, configuration — while the kernel is the host's.
Figure 4 — virtual machine stack and container stack, side by side
Virtual machines
Two applications · two kernels · two full operating systems to patch
Containers
Three applications · one kernel · one operating system to patch
Figure 4. The guest-kernel row is the whole difference. Most of the comparison table further down follows from its presence or absence.
Every container on a node uses the same kernel. This single fact explains most of the rest: it is why container images are megabytes rather than gigabytes, why startup is fast, why density is high, and why the isolation boundary is the kernel's system-call surface rather than a hypervisor's much narrower interface.
It also sets the hard limits. Containers cannot run a different operating system from the host — a Windows container needs a Windows node — and cannot load kernel modules or run a different kernel version from their neighbours.
A container image is a stack of read-only filesystem layers plus a JSON configuration object describing the entrypoint, environment, working directory and user. Layers are content-addressed by digest, so identical layers are stored and transferred once no matter how many images reference them, and a pulled layer is reused from the node's cache.
"Docker image" and "OCI image" refer to the same artifact in practice. Docker's original image
format was standardised by the Open Container Initiative as the OCI Image
Specification, and OCI images are what Kubernetes runtimes consume. A
Dockerfile produces an OCI image; the build tool — docker build,
podman build, buildah — is a detail.
Figure 5 — an OCI image, and the Pod that runs it
OCI image
sha256:9f2c…sha256:41ab…sha256:c7e0… · sharedsha256:18d4… · sharedRead-only, content-addressed. Shared layers are pulled and stored once per node.
Kubernetes Pod
localhostThe Pod, not the container, is the smallest deployable unit.
Figure 5. The image is the artifact; the Pod is the running
unit. Controllers — Deployment, StatefulSet, Job —
manage Pods, not containers.
Deployment
Holds no data that must survive the instance. Any replica can serve any request, replicas are interchangeable, and scaling is a matter of changing a number. Web front ends, APIs and workers reading from a queue are stateless.
StatefulSet + PVC
Owns data, so it needs stable network identity, storage that follows the replica, and
ordered start-up and shutdown. Databases can and do run in containers, but they should run
under an operator that encodes the backup, failover and version-upgrade procedure. Running a
database in a bare Deployment is where container data loss usually comes from.
A virtual machine boot executes a full machine start-up: firmware initialisation, bootloader, kernel decompression and boot, device probing, init and system services, and only then the application. That sequence takes tens of seconds at best.
Starting a container skips all of it. The kernel is already running. The runtime creates namespaces and cgroups, mounts the image's layers as an overlay filesystem, and executes the entrypoint process. This is a matter of milliseconds; in practice the dominant cost is pulling the image, which disappears once the layers are cached on the node.
The difference is structural, not an optimisation. A virtual machine boots an operating system. A container starts a process. No amount of tuning closes that gap, and no amount of tuning gives a container a hypervisor boundary.
Typical workloads
Code that runs when something happens, and holds no capacity in between.
In a serverless model, code is not kept resident waiting for work. It executes in response to a trigger — an HTTP request, a message on a broker, an object written to storage, a timer — and the platform is responsible for having an instance available when the trigger arrives and for removing it afterwards. The unit of capacity is the invocation, not the instance.
FaaS is the packaging convention of the model: the developer supplies a handler function and its dependencies, and the platform builds it into a container image, deploys it, routes traffic to it and scales it. There is no server, replica count, load balancer or operating system to configure. What is given up is control over the runtime environment and the request lifecycle.
Service · Revision · Route
Manages request-driven workloads. A Knative Service produces immutable
Revisions; each revision has its own autoscaler, and traffic can be split
across revisions by percentage — which is how canary and blue/green releases are expressed,
with no extra tooling.
Source · Broker · Trigger
Connects sources to workloads over CloudEvents. Source objects
emit events, a Broker receives them, and Trigger objects route them
to consumers by attribute filter — so producers and consumers stay decoupled and can be
deployed independently.
Because a Knative Service is a Kubernetes object, the same RBAC, quotas, network policy, storage classes and monitoring apply as to any other workload.
Figure 6 — request flow and the scale-to-zero cycle
HTTP, broker message, object write, timer
Receives CloudEvents from every source
Routes by event attribute filter
Buffers the request while a replica starts — the cold start
Serves the request, then scales back to zero
Figure 6. The route stays in place while the revision holds no replicas. The first request after an idle period pays the cold start; the ones behind it do not. Shape is illustrative — no timings are implied.
When a revision receives no traffic for the configured idle window, its replicas are removed and it holds no capacity. The route stays in place. The next request arrives at the activator, which buffers it, signals the autoscaler to create a replica, and forwards the request as soon as the replica is ready.
The Knative Pod Autoscaler scales on concurrency — requests in flight per replica — rather than on CPU. That tracks queueing directly, so it reacts to a burst before CPU utilisation has risen. Target concurrency, minimum and maximum scale and the scale-down delay are set per revision.
Capacity is consumed while a revision serves requests and released when it does not. For workloads busy in bursts and idle in between the difference against a permanently sized deployment is the whole point. For workloads under constant load it is not: a service that never scales to zero costs what its replicas cost.
Cold start, stated plainly. Its length is dominated by image pull — avoided when the image is cached on the node — and by the application's own initialisation. A small static binary is ready in well under a second; a JVM service loading a large dependency graph takes considerably longer. Where cold starts are unacceptable, a minimum scale of one keeps a replica resident, at the cost of the property that made the model attractive.
Typical workloads
The three execution models on the properties that usually decide the choice.
Operating system images are omitted from the comparison because they are the packaging format for virtual machines rather than a separate runtime.
| Feature | Virtual machine | Container | Serverless |
|---|---|---|---|
| Startup time | Tens of seconds to minutes — a full OS boot | Seconds; milliseconds when the image is cached | Milliseconds when warm; cold start on the first request after idle |
| Operating system | Own guest OS and kernel; can differ from the host, including Windows | Shares the host kernel; the image supplies the userland only | Shares the host kernel; the runtime is chosen by the platform |
| Isolation | Hypervisor boundary — the strongest available on shared infrastructure | Kernel namespaces, cgroups, seccomp and SELinux | As containers, plus a per-revision instance boundary |
| Resource usage | A whole OS per instance — gigabytes of memory and disk | Process-level; megabytes of image, no OS overhead | Zero while idle; container-level while serving |
| Performance | Near-native with hardware extensions and paravirtualised drivers | Native — a normal process on the host kernel | Native while warm; cold start dominates short, infrequent requests |
| Scalability | Coarse and slow — whole machines, minutes to add | Fine-grained; the HPA adjusts replicas in seconds | Automatic 0→N on concurrency, in seconds |
| Management | Guest OS lifecycle: patching, monitoring and backup per machine | Cluster and manifest lifecycle: images, controllers, rollouts | Least — the platform owns scaling, routing and instance lifecycle |
| Persistent storage | Virtual disks on persistent volumes; snapshot and clone | PVCs, with StatefulSet for per-replica identity |
Not local — external object storage or a database |
| Networking | Own virtual NIC and IP on the cluster network; NetworkPolicy applies |
Pod IP, Service and Gateway API; NetworkPolicy applies |
Platform-managed routing; traffic split across revisions |
| Typical workloads | Windows, ERP, SQL Server, legacy and appliance software | APIs, web apps, microservices, CI/CD, operator-managed databases | Event handlers, automation, batch jobs, bursty APIs, inference endpoints |
| Best for | Software that expects to own a machine | Applications that are actively developed and deployed often | Work that is intermittent, event-driven and stateless |
Figure 7 — the same comparison at a glance
Startup time — longer bar means slower to be ready
Runtime performance — longer bar is better
Isolation strength — longer bar is a stronger boundary
Scaling speed and granularity — longer bar is faster and finer
Resource consumption while idle — longer bar means more capacity held
Management effort — longer bar means more to operate
Figure 7. Bar lengths are qualitative and are there to show direction and relative order. They are not measurements — no benchmark is implied.
When to use each technology.
KubeVirt
Kubernetes
Knative
And when the answer is more than one. Most estates run all three, and modernisation moves between them one application at a time: existing servers are migrated into virtual machines first, the components that benefit most from orchestration are re-platformed into containers, and the intermittent parts — webhooks, scheduled jobs, batch handlers — move to serverless last.
Because all three run on the same cluster with the same network, storage and identity model, that sequence needs no migration deadline and no second platform running in parallel.
All of these compute models, on one OpenShift platform.
There is one control plane, one RBAC model, one network fabric and one storage layer beneath all of them. Everything the platform creates is a standard Kubernetes object that can be inspected, edited, exported and version-controlled.
VMs as VirtualMachine objects, with live migration and restart on node
failure.
Maintained boot sources and templates, with custom golden images alongside them.
Standard registries and standard image formats. The image is the deployment unit.
Deployments, StatefulSets, Jobs and Operators, with autoscaling, load balancing and ingress as platform features.
Revisions, percentage traffic splitting, scale to zero and CloudEvents routing.
GPU-enabled nodes for AI and ML — training and inference, attached to containers and to virtual machines.
Browsers, APIs, devices and internal systems
Ingress, TLS termination, hostname routing, traffic policy
Scheduling, RBAC, autoscaling, observability — one declarative API
KubeVirt
Kubernetes
Knative
Persistent volumes, block and object storage
Cluster network, NetworkPolicy, MetalLB
Regional sites of independent availability zones, powered by renewable energy, operated under Dutch jurisdiction
Figure 8. Only the workload layer differs between compute models. Everything above and below it is shared.
Sizing, resource configuration and pricing are documented on the Shared Public Cloud page. Related platform documentation: storage, networking, managed Kubernetes and application development.
Run virtual machines, containers and serverless functions on one OpenShift platform in the Netherlands — and move workloads between them without changing platform.