It is possible to use crun-vm as a Kubernetes runtime, allowing you to run VMs as regular pods.
To enable crun-vm on a Kubernetes cluster, follow these steps:
-
Ensure that the cluster is using the CRI-O container runtime. Refer to the Kubernetes docs on container runtimes.
-
Install crun-vm on all cluster nodes where pods may be scheduled. Refer to the installation instructions.
-
Append the following to
/etc/crio/crio.conf
(adjust theruntime_path
if necessary):[crio.runtime.runtimes.crun-vm] runtime_path = "/usr/local/bin/crun-vm"
-
Create a
RuntimeClass
that references crun-vm:apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: crun-vm handler: crun-vm
Under examples/minikube you can find a script that sets up a local minikube Kubernetes cluster with crun-vm available as a runtime. You can use it to easily try out the examples below.
From then on, you can run VM images packaged in container images by creating
pods that use this RuntimeClass
:
apiVersion: v1
kind: Pod
metadata:
name: my-vm
spec:
containers:
- name: my-vm
image: quay.io/crun-vm/example-http-server:latest
args:
- "" # unused, but must specify command because container image does not
ports:
- containerPort: 80
runtimeClassName: crun-vm
The VM's console output is logged:
$ kubectl logs my-vm
Assuming the VM supports cloud-init or Ignition, you can also SSH into it using
kubectl exec
, with the caveat that the user to SSH as is passed in place of
the command (this is the same behavior as with podman exec
or docker exec
;
see SSH'ing into the VM):
$ kubectl exec my-vm -- fedora whoami
fedora
$ kubectl exec -it my-vm -- fedora
[fedora@my-vm ~]$
The pod/VM defined above actually exposes an HTTP server on port 80. To talk to it, we must first forward a local port to the pod/VM:
$ kubectl port-forward my-vm 8000:80
Forwarding from 127.0.0.1:8000 -> 80
Forwarding from [::1]:8000 -> 80
With this command running, navigate to localhost:8000
on your browser, or
run the following on a second terminal:
$ curl localhost:8000
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Directory listing for /</title>
</head>
<body>
[...]
When using crun-vm as a Kubernetes runtime, paths given to --cloud-init
and
--ignition
are interpreted in the context of the container/VM, instead of the
host. This means that config files can be retrieved from mounted volumes. For
instance, you could store your cloud-init config in a ConfigMap
:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-cloud-init-config
data:
meta-data: ""
user-data: |
#cloud-config
runcmd:
- echo 'Hello, world!' > /home/fedora/hello-world
And pass it to your VMs like so:
apiVersion: v1
kind: Pod
metadata:
name: my-other-vm
spec:
containers:
- name: my-other-vm
image: quay.io/containerdisks/fedora:39
args:
- --cloud-init=/etc/cloud-init
volumeMounts:
- name: cloud-init-vol
mountPath: /etc/cloud-init
volumes:
- name: cloud-init-vol
configMap:
name: my-cloud-init-config
runtimeClassName: crun-vm