Skip to main content

CentOS Stream 10: Create Virtual Machine

Create and manage virtual machines using KubeVirt within a Kubernetes cluster on CentOS Stream 10.

May 24, 2026 8 min read
centoscentos-stream-10kubernetesk8scluster

Create a virtual machine with KubeVirt.

This example is based on the environment like follows.

+----------------------+   +----------------------+

|  [ ctrl.srv.world ]  |   |   [ dlp.srv.world ]  |

|     Manager Node     |   |     Control Plane    |

+-----------+----------+   +-----------+----------+

        eth0|10.0.0.25             eth0|10.0.0.30

            |                          |

------------+--------------------------+-----------

            |                          |

        eth0|10.0.0.51             eth0|10.0.0.52

+-----------+----------+   +-----------+----------+

| [ node01.srv.world ] |   | [ node02.srv.world ] |

|     Worker Node#1    |   |     Worker Node#2    |

+----------------------+   +----------------------+

Step 1

A Persistent storage is needed to store OS images.

On this example, install NFS Server on Control Plane Node and configure [/home/nfsshare] directory as NFS share

as external persistent storage, and also configure dynamic volume provisioning with NFS plugin

like the example of [1], [2], [3].

Step 2

Install Containerized Data Importer to store OS images.

[cent@ctrl ~]$ export TAG=$(curl -s -w %{redirect_url} https://github.com/kubevirt/containerized-data-importer/releases/latest)

[cent@ctrl ~]$ export VERSION=$(echo ${TAG##*/})

[cent@ctrl ~]$ wget https://github.com/kubevirt/containerized-data-importer/releases/download/${VERSION}/cdi-operator.yaml

[cent@ctrl ~]$ wget https://github.com/kubevirt/containerized-data-importer/releases/download/${VERSION}/cdi-cr.yaml

[cent@ctrl ~]$ vi cdi-cr.yaml

apiVersion: cdi.kubevirt.io/v1beta1

kind: CDI

metadata:

  name: cdi

spec:

  config:

    <span class="color2"># add resource section to expand memory limits</span>

    <span class="color1">podResourceRequirements:

      limits:

        cpu: '1'

        memory: 4Gi</span>

    featureGates:

    - HonorWaitForFirstConsumer

  imagePullPolicy: IfNotPresent

  infra:

    nodeSelector:

      kubernetes.io/os: linux

    tolerations:

    - key: CriticalAddonsOnly

      operator: Exists

  workload:

    nodeSelector:

      kubernetes.io/os: linux

[cent@ctrl ~]$ kubectl apply -f cdi-operator.yaml

namespace/cdi created

customresourcedefinition.apiextensions.k8s.io/cdis.cdi.kubevirt.io created

clusterrole.rbac.authorization.k8s.io/cdi-operator-cluster created

clusterrolebinding.rbac.authorization.k8s.io/cdi-operator created

serviceaccount/cdi-operator created

role.rbac.authorization.k8s.io/cdi-operator created

rolebinding.rbac.authorization.k8s.io/cdi-operator created

deployment.apps/cdi-operator created

[cent@ctrl ~]$ kubectl apply -f cdi-cr.yaml

cdi.cdi.kubevirt.io/cdi created

after a few minutes, the pods will start up as follows

[cent@ctrl ~]$ kubectl get pods -n cdi

NAME                              READY   STATUS    RESTARTS      AGE

cdi-apiserver-6c76687b66-fx6jq    1/1     Running   1 (25s ago)   55s

cdi-deployment-5f6ff949d7-pjx8c   1/1     Running   0             55s

cdi-operator-ccb895984-hnnls      1/1     Running   0             76s

cdi-uploadproxy-b499c7956-wcfrg   1/1     Running   0             55s

Step 3

Create a virtual machine. On this example, create it with Ubuntu 24.04.

[cent@ctrl ~]$ kubectl get sc

NAME         PROVISIONER                                                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE

nfs-client   cluster.local/nfs-client-nfs-subdir-external-provisioner   Delete          Immediate           true                   97m

create PVC definition

[cent@ctrl ~]$ vi ubuntu-pvc.yml

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: "ubuntu-pvc"

  labels:

    app: containerized-data-importer

  annotations:

    cdi.kubevirt.io/storage.import.endpoint: "http://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"

spec:

  accessModes:

  - ReadWriteOnce

  resources:

    requests:

      storage: 15Gi

  storageClassName: nfs-client

[cent@ctrl ~]$ kubectl apply -f ubuntu-pvc.yml

persistentvolumeclaim/ubuntu-pvc created

[cent@ctrl ~]$ kubectl get pvc

NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

ubuntu-pvc   Bound    pvc-91489452-5712-4a35-986a-7385e130a0dc   15Gi       RWO            nfs-client     <unset>                 5s

[cent@ctrl ~]$ kubectl get pods

NAME                  READY   STATUS    RESTARTS   AGE

importer-ubuntu-pvc   1/1     Running   0          3s

possible to see importing logs

[cent@ctrl ~]$ kubectl logs -f importer-ubuntu-pvc

.....

.....

I0520 05:27:44.437641       1 data-processor.go:341] Expanding image size to: 15220080640

E0520 05:27:44.445445       1 prlimit.go:156] failed to kill the process; os: process already finished

I0520 05:27:44.445500       1 data-processor.go:253] Validating image

E0520 05:27:44.449675       1 prlimit.go:156] failed to kill the process; os: process already finished

I0520 05:27:44.452912       1 data-processor.go:247] New phase: Complete

I0520 05:27:44.453080       1 importer.go:231] {"scratchSpaceRequired":false,"preallocationApplied":false,"message":"Import Complete"}

after finishing importing, importer pod will also finish

[cent@ctrl ~]$ kubectl get pods

No resources found in default namespace.

create VM definition

[cent@ctrl ~]$ vi ubuntu-vm.yml

apiVersion: kubevirt.io/v1

kind: VirtualMachine

metadata:

  name: ubuntu2404

  labels:

    kubevirt.io/os: linux

spec:

  runStrategy: Halted

  template:

    spec:

      domain:

        cpu:

          cores: 2

        devices:

          disks:

          - disk:

              bus: virtio

            name: disk0

          - cdrom:

              bus: sata

              readonly: true

            name: cloudinitdisk

          interfaces:

          - name: default

            masquerade: {}

        machine:

          type: q35

        resources:

          requests:

            memory: 4096M

      networks:

      - name: default

        pod: {}

      volumes:

      - name: disk0

        persistentVolumeClaim:

          claimName: ubuntu-pvc

      - cloudInitNoCloud:

          userData: |

            #cloud-config

            hostname: ubuntu2404

            ssh_pwauth: true

            disable_root: false

            chpasswd:

              list: |

                root:myrootpassword

                ubuntu:userpassword

              expire: False

        name: cloudinitdisk

[cent@ctrl ~]$ kubectl apply -f ubuntu-vm.yml

virtualmachine.kubevirt.io/ubuntu2404 created

[cent@ctrl ~]$ kubectl get vms

NAME         AGE   STATUS    READY

ubuntu2404   10s   Stopped   False

<span class="color1">virtctl start ubuntu2404 </span>

VM ubuntu2404 was scheduled to start

[cent@ctrl ~]$ kubectl get vmi

NAME         AGE   PHASE     IP               NODENAME           READY

ubuntu2404   18s   Running   192.168.40.215   node01.srv.world   True

<span class="color1">virtctl console ubuntu2404 </span>

Successfully connected to ubuntu2404 console. The escape sequence is ^]

ubuntu2404 login: <span class="color1">root</span>

Password:

Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)

 * Documentation:  https://help.ubuntu.com

 * Management:     https://landscape.canonical.com

 * Support:        https://ubuntu.com/pro

.....

.....

root@ubuntu2404:~#

<span class="color2"># to go back to the Host's console, push Ctrl + ] key

# * same operation as virsh command</span>

<span class="color2"># connect to VM via ssh</span>

<span class="color1">kubectl get pods </span>

NAME                             READY   STATUS    RESTARTS   AGE

virt-launcher-ubuntu2404-vssn2   2/2     Running   0          33s

<span class="color1">kubectl port-forward pod/virt-launcher-ubuntu2404-vssn2 2220:22 & </span>

<span class="color1">ssh ubuntu@127.0.0.1 -p 2220 </span>

Handling connection for 2220

The authenticity of host '[127.0.0.1]:222 ([127.0.0.1]:222)' can't be established.

ED25519 key fingerprint is SHA256:W/jCnIP+PoghhP3FOrVDa9HBGjOzip+QVBqGEep5roM.

This key is not known by any other names.

Are you sure you want to continue connecting (yes/no/[fingerprint])? <span class="color1">yes</span>

Warning: Permanently added '[127.0.0.1]:222' (ED25519) to the list of known hosts.

ubuntu@127.0.0.1's password:

Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)

 * Documentation:  https://help.ubuntu.com

 * Management:     https://landscape.canonical.com

 * Support:        https://ubuntu.com/pro

....

.....

ubuntu@ubuntu2404:~$