Creating Windows Images Based on ISO using KubeVirt

This document discusses a virtual machine solution based on the open-source component KubeVirt, using KubeVirt virtualization technology to create a Windows operating system image through an ISO image file.

TOC

Prerequisites

  • All components in the cluster are functioning correctly.

  • Please prepare the Windows image and the latest virtio-win-tools in advance.

  • Please prepare the repository for storing the image. This document takes the build-harbor.example.cn repository as an example, and please replace it according to your actual environment.

Constraints and Limitations

  • When starting KubeVirt, the size of the custom image's filesystem will affect the speed of writing the image to the disk in PVC. If the filesystem is too large, it may result in extended creation times.

  • It is recommended to keep the Linux root partition or Windows C drive below 100G to minimize the initial size. Subsequent expansion can be done through cloud-init (for Windows systems, it must be expanded manually after creation).

Procedure

Create Image

Create a Docker image from the prepared Windows and virtio-win ISO images, and push it to the repository. This document uses Windows Server 2019 as an example.

Create a Docker Image from the Windows ISO

  1. Navigate to the directory where the ISO image is stored, and execute the following command in the terminal to rename the ISO image to win.iso.

    mv <ISO image name> win.iso # Replace <ISO image name> with the actual image name, e.g., mv en_windows_server_2019_x64_dvd_4cb967d8.iso win.iso
  2. Execute the following command to create a Dockerfile.

    touch Dockerfile
  3. Edit the Dockerfile, add the following content, and save it.

    FROM scratch
    ADD --chown=107:107 win.iso /disk/
  4. Execute the following command to build the Docker image.

    docker build -t build-harbor.example.cn/3rdparty/vmdisks/winiso:2019 . # Replace the repository according to your actual environment
  5. Execute the following command to push the image to the repository.

    docker push  build-harbor.example.cn/3rdparty/vmdisks/winiso:2019 # Replace the repository according to your actual environment

Create a Docker Image from the virtio-win ISO

  1. Navigate to the directory where the ISO image is stored, and execute the following command in the terminal to create a Dockerfile.

    touch Dockerfile
  2. Edit the Dockerfile, add the following content, and save it.

    FROM scratch
    ADD --chown=107:107 virtio-win.iso  /disk/
  3. Execute the following command to build the Docker image.

    docker build -t build-harbor.example.cn/3rdparty/vmdisks/win-virtio:latest . # Replace the repository according to your actual environment
  4. Execute the following command to push the image to the repository.

    docker push  build-harbor.example.cn/3rdparty/vmdisks/win-virtio:latest # Replace the repository according to your actual environment

Create Virtual Machine

  1. Access the Container Platform.

  2. In the left navigation bar, click on Virtualization > Virtual Machines.

  3. Click on Create Virtual Machine.

  4. Fill in the necessary parameters such as Name, Image, etc., in the form page. For detailed parameters and configuration, please refer to Create Virtual Machine.

  5. Switch to YAML.

  6. Replace the configuration under the spec.template.spec.domain.devices.disks field with the following content.

      domain:
        devices:
          disks:
            - disk:
                bus: virtio
              name: cloudinitdisk
            - bootOrder: 1
              cdrom:
                bus: sata
              name: containerdisk
            - cdrom:
                bus: sata
              name: virtio
            - disk:
                bus: sata
              name: rootfs
              bootOrder: 10
  7. Add the following content under the spec.template.spec.volumes field.

            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/winiso:2019 # Replace the image according to your actual environment
              name: containerdisk
            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/win-virtio # Replace the image according to your actual environment
              name: virtio
  8. Check the YAML file. The complete YAML after finishing the configuration is as follows.

    apiVersion: kubevirt.io/v1alpha3
    kind: VirtualMachine
    metadata:
      annotations:
        cpaas.io/creator: test@example.io
        cpaas.io/display-name: ""
        cpaas.io/updated-at: 2024-09-01T14:57:55Z
        kubevirt.io/latest-observed-api-version: v1
        kubevirt.io/storage-observed-api-version: v1
      generation: 16
      labels:
        virtualization.cpaas.io/image-name: debian-2120-x86
        virtualization.cpaas.io/image-os-arch: amd64
        virtualization.cpaas.io/image-os-type: debian
        virtualization.cpaas.io/image-supply-by: public
        vm.cpaas.io/name: aa-test
      name: aa-test
      namespace: acp-service-self
    spec:
      dataVolumeTemplates:
        - metadata:
            creationTimestamp: null
            labels:
              vm.cpaas.io/reclaim-policy: Delete
              vm.cpaas.io/used-by: aa-test
            name: aa-test-rootfs
          spec:
            pvc:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 100Gi
              storageClassName: vm-cephrbd
              volumeMode: Block
            source:
              http:
                url: http://192.168.254.12/kube-debian-12.2.0-x86-out.qcow2
      running: true
      template:
        metadata:
          annotations:
            cpaas.io/creator: test@example.io
            cpaas.io/display-name: ""
            cpaas.io/updated-at: 2024-09-01T14:55:44Z
            kubevirt.io/latest-observed-api-version: v1
            kubevirt.io/storage-observed-api-version: v1
          creationTimestamp: null
          labels:
            virtualization.cpaas.io/image-name: debian-2120-x86
            virtualization.cpaas.io/image-os-arch: amd64
            virtualization.cpaas.io/image-os-type: debian
            virtualization.cpaas.io/image-supply-by: public
            vm.cpaas.io/name: aa-test
        spec:
          affinity:
            nodeAffinity: {}
          architecture: amd64
          domain:
            devices:
              disks:
                - disk:
                    bus: virtio
                  name: cloudinitdisk
                - bootOrder: 1
                  cdrom:
                    bus: sata
                  name: containerdisk
                - cdrom:
                    bus: sata
                  name: virtio
                - disk:
                    bus: sata
                  name: rootfs
                  bootOrder: 10
               interfaces:
                - bridge: {}
                  name: default
            machine:
              type: q35
            resources:
              limits:
                cpu: "4"
                memory: 8Gi
              requests:
                cpu: "4"
                memory: 8Gi
          networks:
            - name: default
              pod: {}
          nodeSelector:
            kubernetes.io/arch: amd64
            vm.cpaas.io/baremetal: "true"
          volumes:
            - cloudInitConfigDrive:
                userData: >-
                  #cloud-config
                  disable_root: false
                  ssh_pwauth: true
                  users:
                    - default
                    - name: root
                      lock_passwd: false
                      hashed_passwd: $6$0vlhl57e$0rawYwaeu9jL6hBf3XP9lk6XXaMUS9/W6LPbWRinUoXujo39lP3l98VOcOObtr.LDoAv/ylm85FLQmxwNlWFe/
              name: cloudinitdisk
            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/winiso:2019 # Replace the image according to your actual environment
              name: containerdisk
              - containerDisk
                 image: registry.example.cn:60070/3rdparty/vmdisks/win-virtio # Replace the image according to your actual environment
               name: virtio
             - dataVolume:
                name: aa-test-rootfs
              name: rootfs
  9. Click Create.

  10. Click Actions > VNC Login.

  11. When the prompt press any key boot from CD or DVD appears, press any key to enter the Windows installation program; if you do not see the prompt, click on Send Remote Command in the top left of the page, then select Ctrl-Alt-Delete from the dropdown menu to restart the server.

    Note: If a message appears at the top of the virtual machine details page stating The current virtual machine has configuration changes that require a restart to take effect, please restart, this message can be ignored; no restart is necessary.

Install Windows Operating System

  1. Follow the installation instructions to install the system after entering the installation page.

    Note: During the partition selection step, the bus must be sata for the disk to be correctly recognized. Therefore, you need to select each partition in turn and click Delete to remove all partitions, allowing the system to handle it automatically.

  2. After configuring the administrator account password, click Send Remote Command in the top left of the page, then select Ctrl-Alt-Delete from the dropdown menu.

  3. When prompted The Ctrl+Alt+Delete combination will restart the server, confirm to restart, click OK.

  4. Enter the password to access the Windows system desktop; at this point, the Windows operating system installation is complete.

Install virtio-win-tools

This tool primarily contains the necessary drivers.

  1. Open File Explorer.

  2. Double-click CD Drive(E:) virtio-win-<version>, run the virtio-win-guest-tools directory to enter the installation page, and follow the installation instructions. The <version> part should be based on the actual situation.

  3. After the installation is complete, power off the Windows system.

Export Custom Windows Image

Please refer to Export Virtual Machine Image for the specific operation.

Use Windows Image

  1. Access the Container Platform.

  2. In the left navigation bar, click on Virtualization > Virtual Machines.

  3. Click on Create Virtual Machine.

  4. Fill in the necessary parameters on the form page. For the image, select the exported Windows image. For detailed parameters and configuration, please refer to Create Virtual Machine.

  5. (Optional) If using a newer operating system, such as Windows 11, enable features like clock, UEFI, TPM, etc. Switch to YAML and replace the original YAML file with the following YAML file.

    apiVersion: kubevirt.io/v1
    kind: VirtualMachineInstance
    metadata:
      labels:
        special: vmi-windows
      name: vmi-windows
    spec:
      domain:
        clock:
          timer:
            hpet:
              present: false
            hyperv: {}
            pit:
              tickPolicy: delay
            rtc:
              tickPolicy: catchup
          utc: {}
        cpu:
          cores: 2
        devices:
          disks:
          - disk:
              bus: sata
            name: pvcdisk
          interfaces:
          - masquerade: {}
            model: e1000
            name: default
          tpm: {}
        features:
          acpi: {}
          apic: {}
          hyperv:
            relaxed: {}
            spinlocks:
              spinlocks: 8191
            vapic: {}
          smm: {}
        firmware:
          bootloader:
            efi:
              secureBoot: true
          uuid: 5d307ca9-b3ef-428c-8861-06e72d69f223
        resources:
          requests:
            memory: 4Gi
      networks:
      - name: default
        pod: {}
      terminationGracePeriodSeconds: 0
      volumes:
      - name: pvcdisk
        persistentVolumeClaim:
          claimName: disk-windows
      - name: winiso
        persistentVolumeClaim:
          claimName: win11cd-pvc
  6. Click Create.

Add Internal Route

By configuring a NodePort type internal route, expose the port for remote desktop connections.

  1. Access the Container Platform.

  2. In the left navigation bar, click on Virtualization > Virtual Machines.

  3. Click on the virtual machine name created with the Windows image in the list to enter the details page.

  4. Click on the Add icon next to Internal Route in the Login Information area.

  5. Configure parameters according to the following instructions.

    ParameterDescription
    TypeSelect NodePort.
    Port
    • Protocol: Select TCP.
    • Service Port: Use 3389.
    • Virtual Machine Port: Use 3389.
    • Service Port Name: Use rdp.
  6. Click OK to return to the details page.

  7. Click on the Internal Route link in the Login Information area.

  8. Save the Virtual IP information in the basic information area and the Host Port information in the port area.

Remote Access

This document discusses using the Windows operating system for remote connection as an example. Other operating systems can use software that supports the RDP protocol for connection.

  1. Open Remote Desktop Connection.

  2. Enter the saved Virtual IP and Host Port from the Add Internal Route step, formatted as Virtual IP:Host Port, for example: 192.1.1.1:3389 .

  3. Click Connect.