基于 ISO 制作 Windows 镜像的 KubeVirt 操作

本文档讨论了一种基于开源组件 KubeVirt 的虚拟机解决方案,通过 KubeVirt 虚拟化技术使用 ISO 镜像文件创建 Windows 操作系统镜像。

前提条件

  • 集群中的所有组件均正常运行。

  • 请提前准备 Windows 镜像以及 最新的 virtio-win-tools

  • 请准备用于存储镜像的仓库。本文档以 build-harbor.example.cn 仓库作为示例,请根据实际环境进行替换。

约束与限制

  • 启动 KubeVirt 时,自定义镜像的文件系统大小将影响将镜像写入 PVC 中磁盘的速度。如果文件系统过大,可能导致创建时间延长。

  • 建议将 Linux 根分区或 Windows C 盘的大小控制在 100G 以内,以减少初始大小。后续可通过 cloud-init 进行扩展(对于 Windows 系统,必须在创建后手动扩展)。

操作步骤

创建镜像

创建由准备好的 Windows 和 virtio-win ISO 镜像构成的 Docker 镜像,并将其推送至仓库中,本文档以 Windows Server 2019 为例。

从 Windows ISO 创建 Docker 镜像

  1. 进入 ISO 镜像存放目录,在终端中执行以下命令将 ISO 镜像重命名为 win.iso。

    mv <ISO 镜像名> win.iso # 用实际镜像名称替换 <ISO 镜像名称>,例如:mv en_windows_server_2019_x64_dvd_4cb967d8.iso win.iso
    
  2. 执行以下命令创建 Dockerfile。

    touch Dockerfile
    
  3. 编辑 Dockerfile,添加以下内容并保存。

    FROM scratch
    ADD --chown=107:107 win.iso /disk/
    
  4. 执行以下命令构建 Docker 镜像。

    docker build -t build-harbor.example.cn/3rdparty/vmdisks/winiso:2019 . # 根据实际环境替换仓库
    
  5. 执行以下命令推送镜像到仓库。

    docker push build-harbor.example.cn/3rdparty/vmdisks/winiso:2019 # 根据实际环境替换仓库
    

从 virtio-win ISO 创建 Docker 镜像

  1. 进入 ISO 镜像存放目录,在终端中执行以下命令创建 Dockerfile。

    touch Dockerfile
    
  2. 编辑 Dockerfile,添加以下内容并保存。

    FROM scratch
    ADD --chown=107:107 virtio-win.iso /disk/
    
  3. 执行以下命令构建 Docker 镜像。

    docker build -t build-harbor.example.cn/3rdparty/vmdisks/win-virtio:latest . # 根据实际环境替换仓库
    
  4. 执行以下命令推送镜像到仓库。

    docker push build-harbor.example.cn/3rdparty/vmdisks/win-virtio:latest # 根据实际环境替换仓库
    

创建虚拟机

  1. 访问 Container Platform

  2. 在左侧导航栏中,点击 虚拟化 > 虚拟机

  3. 点击 创建虚拟机

  4. 在表单页面中填写必要的参数,如 名称镜像等,具体参数和配置请参考 创建虚拟机

  5. 切换到 YAML 格式。

  6. 将 spec.template.spec.domain.devices.disks 字段下的配置替换为以下内容。

      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. 在 spec.template.spec.volumes 字段下添加以下内容。

            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/winiso:2019 # 根据实际环境替换镜像
              name: containerdisk
            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/win-virtio # 根据实际环境替换镜像
              name: virtio
    
  8. 检查 YAML 文件。完成配置后的完整 YAML 如下。

    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 # 根据实际环境替换镜像
              name: containerdisk
              - containerDisk:
                  image: registry.example.cn:60070/3rdparty/vmdisks/win-virtio # 根据实际环境替换镜像
                name: virtio 
              - dataVolume:
                  name: aa-test-rootfs
                name: rootfs
    
  9. 点击 创建

  10. 点击 操作 > VNC 登录

  11. 当出现提示 press any key boot from CD or DVD 时,按下任意键以进入 Windows 安装程序;如果没有看到提示,请在页面左上角点击 发送远程命令,然后从下拉菜单中选择 Ctrl-Alt-Delete 以重启服务器。

    注意:如果在虚拟机详情页面顶部出现 当前虚拟机有配置变更,需执行重启以使配置生效,请重启 提示信息,可以忽略此信息,无需重启。

安装 Windows 操作系统

  1. 进入安装页面后,根据安装指引进行操作。

    注意:在选择分区的步骤中,磁盘必须设置为 sata 才能正确识别,因此需要逐个选择每个分区并点击 Delete 删除所有分区,让系统自动处理。

  2. 完成管理员账号密码配置后,点击页面左上角的 发送远程命令,在下拉菜单中选择 Ctrl-Alt-Delete

  3. 当提示 Ctrl+Alt+Delete 组合键将重启服务器,确定重启 时,点击 确定

  4. 输入密码以访问 Windows 系统桌面,此时 Windows 操作系统安装已完成。

安装 virtio-win-tools

此工具主要包含所需的驱动程序。

  1. 打开文件资源管理器。

  2. 双击 CD Drive(E:) virtio-win-<version>,运行目录下的 virtio-win-guest-tools 进入安装页面,并根据安装指引进行安装。<version> 部分需根据实际情况确认。

  3. 安装完成后,关闭 Windows 系统。

导出自定义 Windows 镜像

具体操作请参考 导出虚拟机镜像

使用 Windows 镜像

  1. 访问 Container Platform

  2. 在左侧导航栏中,点击 虚拟化 > 虚拟机

  3. 点击 创建虚拟机

  4. 在表单页面中填写必要参数。对于镜像,选择已导出的 Windows 镜像。具体详细参数和配置请参考 创建虚拟机

  5. (可选)如果使用较新的操作系统,例如 Windows 11,则可能需要启用 clock、UEFI、TPM 等功能。切换至 YAML 格式并用以下 YAML 文件替换原有文件。

    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. 点击 创建

添加内部路由

通过配置 NodePort 类型的内部路由,将远程桌面连接的端口进行暴露。

  1. 访问 Container Platform

  2. 在左侧导航栏中,点击 虚拟化 > 虚拟机

  3. 单击列表中用于创建 Windows 镜像的虚拟机名称,进入详情页面。

  4. 单击 登录信息 区域中 内部路由 右侧的 添加 图标。

  5. 根据以下说明配置参数。

    参数说明
    类型选择 NodePort
    端口
    • 协议:选择 TCP。
    • 服务端口:使用 3389。
    • 虚拟机端口:使用 3389。
    • 服务端口名称:使用 rdp。
  6. 点击 确定 返回详情页面。

  7. 登录信息 区域中点击 内部路由 链接。

  8. 保存基本信息区域中的 虚拟 IP 以及端口区域的 主机端口

远程访问

本文档以使用 Windows 操作系统进行远程连接为例进行说明。其他操作系统可以使用支持 RDP 协议的软件进行连接。

  1. 打开 远程桌面连接

  2. 输入 添加内部路由 步骤中保存的虚拟 IP 和主机端口,格式为 虚拟 IP:主机端口,例如:192.1.1.1:3389。

  3. 点击 连接