Ubuntu 26.04

Kubernetes : Create Virtual Machine2026/05/15

 

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    |
+----------------------+   +----------------------+

[1]

A Persistent storage is needed to store OS images.
On this example, install NFS Server on a Node in local network 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].

[2] Install Containerized Data Importer to store OS images.
ubuntu@ctrl:~$
export TAG=$(curl -s -w %{redirect_url} https://github.com/kubevirt/containerized-data-importer/releases/latest)

ubuntu@ctrl:~$
export VERSION=$(echo ${TAG##*/})

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

ubuntu@ctrl:~$
wget https://github.com/kubevirt/containerized-data-importer/releases/download/${VERSION}/cdi-cr.yaml
ubuntu@ctrl:~$
vi cdi-cr.yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: CDI
metadata:
  name: cdi
spec:
  config:
    # add resource section to expand memory limits
    podResourceRequirements:
      limits:
        cpu: '1'
        memory: 4Gi
    featureGates:
    - HonorWaitForFirstConsumer
  imagePullPolicy: IfNotPresent
  infra:
    nodeSelector:
      kubernetes.io/os: linux
    tolerations:
    - key: CriticalAddonsOnly
      operator: Exists
  workload:
    nodeSelector:
      kubernetes.io/os: linux

ubuntu@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

ubuntu@ctrl:~$
kubectl apply -f cdi-cr.yaml

cdi.cdi.kubevirt.io/cdi created
# after a few minutes, the pods will start up as follows

ubuntu@ctrl:~$
kubectl get pods -n cdi

NAME                               READY   STATUS    RESTARTS   AGE
cdi-apiserver-758bd98876-g4k7t     1/1     Running   0          2m11s
cdi-deployment-7cc48944c4-sdjpt    1/1     Running   0          2m11s
cdi-operator-6545899497-jfjmv      1/1     Running   0          2m33s
cdi-uploadproxy-77c9464b97-r7zl2   1/1     Running   0          2m11s
[3] Create a virtual machine. On this example, create it with ubuntu.
ubuntu@ctrl:~$
kubectl get sc

NAME         PROVISIONER                                                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   cluster.local/nfs-client-nfs-subdir-external-provisioner   Delete          Immediate           true                   45m

# create PVC definition

ubuntu@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/26.04/release/ubuntu-26.04-server-cloudimg-amd64.img"
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: nfs-client

ubuntu@ctrl:~$
kubectl apply -f ubuntu-pvc.yml

persistentvolumeclaim/ubuntu-pvc created
ubuntu@ctrl:~$
kubectl get pvc

NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
ubuntu-pvc   Bound    pvc-a5005fbf-4a6e-40c5-953e-64695055efc0   10Gi       RWO            nfs-client     <unset>                 4s

ubuntu@ctrl:~$
kubectl get pods

NAME                  READY   STATUS    RESTARTS   AGE
importer-ubuntu-pvc   1/1     Running   0          21s

# possible to see importing logs

ubuntu@ctrl:~$
kubectl logs -f importer-ubuntu-pvc

.....
.....
E0515 01:24:01.026378       1 prlimit.go:156] failed to kill the process; os: process already finished
I0515 01:24:01.026398       1 data-processor.go:260] New phase: Resize
E0515 01:24:01.030518       1 prlimit.go:156] failed to kill the process; os: process already finished
W0515 01:24:01.030560       1 data-processor.go:343] Available space less than requested size, resizing image to available space 10129244160.
I0515 01:24:01.030568       1 data-processor.go:354] Expanding image size to: 10129244160
E0515 01:24:01.037929       1 prlimit.go:156] failed to kill the process; os: process already finished
I0515 01:24:01.037948       1 data-processor.go:266] Validating image
E0515 01:24:01.042916       1 prlimit.go:156] failed to kill the process; os: process already finished
I0515 01:24:01.046421       1 data-processor.go:260] New phase: Complete
I0515 01:24:01.046671       1 importer.go:251] {"scratchSpaceRequired":false,"preallocationApplied":false,"message":"Import Complete"}

# after finishing importing, importer pod will also finish

ubuntu@ctrl:~$
kubectl get pods

No resources found in default namespace.
# create VM definition

ubuntu@ctrl:~$
vi ubuntu-vm.yml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: ubuntu2604
  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: ubuntu2604
            ssh_pwauth: true
            disable_root: false
            chpasswd:
              list: |
                root:myrootpassword
                ubuntu:userpassword
              expire: False
        name: cloudinitdisk

ubuntu@ctrl:~$
kubectl apply -f ubuntu-vm.yml

virtualmachine.kubevirt.io/ubuntu13 created
ubuntu@ctrl:~$
kubectl get vms

NAME         AGE   STATUS    READY
ubuntu2604   5s    Stopped   False

ubuntu@ctrl:~$ virtctl start ubuntu2604 
VM ubuntu2604 was scheduled to start

ubuntu@ctrl:~$
kubectl get vmi

NAME         AGE   PHASE     IP               NODENAME           READY
ubuntu2604   17s   Running   192.168.40.204   node01.srv.world   True

ubuntu@ctrl:~$ virtctl console ubuntu2604 
Successfully connected to ubuntu2604 console. Press Ctrl+] or Ctrl+5 to exit console.

ubuntu2604 login: root
Password:
Welcome to Ubuntu 26.04 LTS (GNU/Linux 7.0.0-14-generic x86_64)

 * Documentation:  https://docs.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Fri May 15 01:31:48 UTC 2026

  System load:  0.05              Processes:               147
  Usage of /:   23.7% of 8.00GB   Users logged in:         0
  Memory usage: 6%                IPv4 address for enp1s0: 10.0.2.2
  Swap usage:   0%


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@ubuntu2604:~#
# to go back to the Host's console, push Ctrl + ] key
# * same operation as virsh command


# connect to VM via ssh
ubuntu@ctrl:~$ kubectl get pods 
NAME                             READY   STATUS    RESTARTS   AGE
virt-launcher-ubuntu2604-6nmv7   2/2     Running   0          61s

ubuntu@ctrl:~$ kubectl port-forward pod/virt-launcher-ubuntu2604-6nmv7 2221:22 & 

ubuntu@ctrl:~$ ssh ubuntu@127.0.0.1 -p 2221 
Handling connection for 2221
The authenticity of host '[127.0.0.1]:2221 ([127.0.0.1]:2221)' can't be established.
ED25519 key fingerprint is: SHA256:M/gQskFSgKcbCAJixFzdx0QG6yOyVpjoqAg9SxUVoQk
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:2221' (ED25519) to the list of known hosts.
ubuntu@127.0.0.1's password:
Welcome to Ubuntu 26.04 LTS (GNU/Linux 7.0.0-14-generic x86_64)

 * Documentation:  https://docs.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

 System information as of Fri May 15 01:29:25 UTC 2026

  System load:  0.37              Processes:               150
  Usage of /:   23.5% of 8.00GB   Users logged in:         0
  Memory usage: 6%                IPv4 address for enp1s0: 10.0.2.2
  Swap usage:   0%

Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

ubuntu@ubuntu2604:~$
Matched Content