使用 KubeVirt 基于 ISO 创建 Linux 镜像

本文档介绍了基于开源组件 KubeVirt 实现的虚拟机方案,利用 KubeVirt 虚拟化技术从 ISO 镜像文件创建 Linux 操作系统镜像。

前提条件

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

  • 需提前准备好 Linux 镜像,本文以 Ubuntu 操作系统 为例。

  • 需提前准备好用于存储镜像的仓库,本文以 build-harbor.example.cn 仓库为例,请根据实际环境替换。

约束与限制

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

  • 建议保持 Linux 根分区大小低于 100G,以减少初始大小。配置 cloud-init 后,创建虚拟机时为根分区分配更大存储,系统会自动扩展。

操作步骤

将 Linux ISO 镜像转换为 Docker 镜像

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

    mv <ISO image name> ubuntu.iso # 将 <ISO image name> 替换为实际镜像名称,例如 mv ubuntu-24.04-live-server-amd64.iso ubuntu.iso
  2. 执行以下命令创建 Dockerfile。

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

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

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

    docker push build-harbor.example.cn/3rdparty/vmdisks/ubuntu-iso:24.04 # 请根据实际环境替换仓库地址

创建虚拟机

  1. 进入 容器平台

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

  3. 点击 创建虚拟机

  4. 在表单页面填写参数,具体参数及配置请参考 创建虚拟机

    参数说明
    选择镜像选择虚拟机的模板镜像。
    IP 地址保持默认,通过 DHCP 获取。
    网络模式使用 NAT 模式,此处不要使用 桥接 模式。
  5. 切换至 YAML。

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

          domain:
            devices:
              disks:
                - bootOrder: 1
                  cdrom:
                    bus: sata
                  name: containerdisk
                - disk:
                    bus: virtio
                  name: cloudinitdisk
                - disk:
                    bus: virtio
                  name: rootfs
                  bootOrder: 10
  7. 在 spec.template.spec.volumes 字段下添加以下内容。

            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/ubuntu-iso:24.04 # 请根据实际环境替换镜像地址
              name: containerdisk
  8. 检查 YAML 文件,完成后的完整 YAML 配置如下。

    apiVersion: kubevirt.io/v1alpha3
    kind: VirtualMachine
    metadata:
      annotations:
        kubevirt.io/latest-observed-api-version: v1
        kubevirt.io/storage-observed-api-version: v1
      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
      name: aa
    spec:
      dataVolumeTemplates:
        - metadata:
            creationTimestamp: null
            labels:
              vm.cpaas.io/reclaim-policy: Delete
              vm.cpaas.io/used-by: aa
            name: aa-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-09T03:49:08Z
            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
        spec:
          accessCredentials:
            - sshPublicKey:
                propagationMethod:
                  qemuGuestAgent:
                    users:
                      - root
                source:
                  secret:
                    secretName: test-xeon
          affinity:
            nodeAffinity: {}
          architecture: amd64
          domain:
            devices:
              disks:
                - bootOrder: 1
                  cdrom:
                    bus: sata
                  name: containerdisk
                - disk:
                    bus: virtio
                  name: cloudinitdisk
                - disk:
                    bus: virtio
                  name: rootfs
                  bootOrder: 10
               interfaces:
                - bridge: {}
                  name: default
            machine:
              type: q35
            resources:
              limits:
                cpu: "1"
                memory: 2Gi
              requests:
                cpu: "1"
                memory: 2Gi
          networks:
            - name: default
              pod: {}
          nodeSelector:
            kubernetes.io/arch: amd64
            vm.cpaas.io/baremetal: "true"
          volumes:
            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/ubuntu-iso:24.04 # 请根据实际环境替换镜像地址
              name: containerdisk
            - cloudInitConfigDrive:
                userData: |-
                  #cloud-config
                  disable_root: false
                  ssh_pwauth: false
                  users:
                    - default
                    - name: root
                      lock_passwd: false
                      hashed_passwd: ""
              name: cloudinitdisk
            - dataVolume:
                name: aa-rootfs
              name: rootfs
  9. 点击 创建

  10. 点击 操作 > VNC 登录

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

    注意:如果虚拟机详情页顶部出现提示 当前虚拟机有配置变更需重启生效,请重启,可忽略该提示,无需重启。

安装 Linux 操作系统

  1. 进入安装页面后,按照安装向导进行操作。本文以安装 Ubuntu 操作系统为例,不同操作系统安装过程中的配置项大致相同,故不再赘述。部分配置项说明如下。

    配置项说明
    安装类型建议选择最小安装,以减少镜像体积。
    存储配置选择自定义存储。将磁盘格式化为 ext4 或 xfs 格式,并挂载为根分区(/)。
    注意:不要使用 LVM 分区(创建卷组 (LVM))。
    SSH 配置选择安装 OpenSSH 工具以支持 SSH 访问。
  2. 等待安装完成。

修改 YAML 文件

  1. 进入 容器平台

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

  3. 点击列表中的 虚拟机名称 进入详情页。

  4. 点击 停止

  5. 点击右上角 操作 > 更新

  6. 切换至 YAML。

  7. 确认 spec.template.spec.domain.devices.disks 下名为 rootfs 的磁盘的 bootOrder 为 1,若不是,修改为 1。

  8. 删除 spec.template.spec.domain.devices.disks 下名为 containerdisk 的相关内容,具体删除内容如下。

                - bootOrder: 1
                  cdrom:
                    bus: sata
                  name: containerdisk
  9. 删除 spec.template.spec.volumes 下名为 containerdisk 的相关内容,具体删除内容如下。

            - containerDisk:
                image: registry.example.cn:60070/3rdparty/vmdisks/ubuntu-iso:24.04
              name: containerdisk
  10. 点击 更新

  11. 点击 启动

安装所需软件并修改配置

注意:以下命令及配置文件在不同操作系统间可能略有差异,请根据实际环境调整。

  1. 输入用户名和密码登录操作系统。

  2. 切换到 root 用户权限。

  3. 安装软件包。

    • CentOS 系列执行命令:

      yum install cloud-utils cloud-init qemu-guest-agent vim
    • Debian 系列执行命令:

      apt install cloud-init cloud-guest-utils qemu-guest-agent vim
  4. 编辑 SSHD 配置文件。

    1. 执行以下命令编辑 sshd_config 文件。

      vim /etc/ssh/sshd_config
    2. 添加以下配置。

      PermitRootLogin yes  # 允许 root 用户密码登录
      PubkeyAuthentication yes  # 允许密钥登录
    3. 保存修改后的配置。

  5. 执行以下命令删除 root 用户默认密码。

    passwd -d root
  6. 修改源地址文件。

    1. 执行以下命令修改系统源地址文件,替换为合适的镜像站地址。

      vim /etc/apt/sources.list.d/ubuntu.sources
    2. 修改完成后保存配置。

  7. 修改 cloud-init 配置,实现根目录自动扩容。

    1. 执行以下命令编辑 cloud.cfg 配置文件。

      vim /etc/cloud/cloud.cfg
    2. 添加以下配置内容。

      runcmd:
        - [growpart, /dev/vda, 1]  # growpart 命令用于扩展磁盘上的分区,这里扩展 /dev/vda1 分区。
        - [xfs_growfs, /dev/vda1]  # xfs_growfs 命令用于扩展 XFS 文件系统以占满分区空间。/dev/vda1 是待扩展文件系统所在分区。扩展分区后,使用 xfs_growfs 确保文件系统也扩展到新分区大小。
    3. 修改完成后保存配置。

  8. 配置完成后,关闭操作系统。

导出并使用自定义 Linux 镜像

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