KubeVirt 镜像制作
一、概述
KubeVirt 中的虚拟机镜像主要有以下几种形式:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| Container Disk | 将磁盘镜像打包为 OCI 容器镜像 | 只读系统盘、快速部署 |
| PVC 镜像 | 直接写入 PersistentVolumeClaim | 需要持久化写入 |
| DataVolume | CDI 管理的增强型 PVC | 自动导入、克隆、上传 |
二、Container Disk 镜像制作
2.1 什么是 Container Disk
Container Disk 是 KubeVirt 特有的镜像格式,将虚拟机磁盘镜像(qcow2/raw)打包为标准 OCI 容器镜像,存储在任何容器镜像仓库中。
优势:
- 复用现有容器镜像基础设施(Docker Hub、Harbor 等)
- 无需额外存储管理
- 支持镜像分层和缓存
- 启动速度快(无需数据拷贝)
2.2 从现有镜像制作 Container Disk
方法一:使用 Dockerfile(推荐)
# Dockerfile
FROM scratch
# 添加虚拟机磁盘镜像
# 磁盘文件必须放在容器的根目录 / 下
ADD disk.img /disk.img
# 准备磁盘镜像
# 如果是 qcow2 格式,建议先转换为 raw
qemu-img convert -f qcow2 -O raw ubuntu-22.04.qcow2 disk.img
# 构建容器镜像
docker build -t my-registry/ubuntu-vm:1.0 .
# 推送到镜像仓库
docker push my-registry/ubuntu-vm:1.0
方法二:使用 virtctl 上传
# 直接从本地文件上传为 Container Disk
virtctl image-upload \
--image-path=./ubuntu-22.04.qcow2 \
--size=10Gi \
--storage-class=standard \
--uploadproxy-url=https://<cdi-upload-proxy> \
pvc ubuntu-disk
2.3 从零制作 Linux 镜像
步骤 1:创建空白磁盘
# 创建 20GB 的 qcow2 磁盘
qemu-img create -f qcow2 linux-base.img 20G
# 或创建 raw 格式
qemu-img create -f raw linux-base.raw 20G
步骤 2:使用 virt-install 安装系统
# 下载 ISO 安装镜像
wget https://releases.ubuntu.com/22.04/ubuntu-22.04-live-server-amd64.iso
# 使用 virt-install 安装
virt-install \
--name kubevirt-ubuntu \
--memory 2048 \
--vcpus 2 \
--disk path=./linux-base.img,format=qcow2 \
--cdrom ./ubuntu-22.04-live-server-amd64.iso \
--os-variant ubuntu22.04 \
--network network=default \
--graphics vnc,listen=0.0.0.0 \
--noautoconsole
步骤 3:配置 cloud-init
安装完成后,在虚拟机内配置 cloud-init 支持:
# 在虚拟机内部执行
sudo apt-get update
sudo apt-get install -y cloud-init cloud-utils
# 配置 cloud-init
sudo tee /etc/cloud/cloud.cfg << 'EOF'
# The top level settings are always merged module data
# and then the module's data.
users:
- default
disable_root: false
preserve_hostname: false
cloud_init_modules:
- migrator
- seed_random
- bootcmd
- write-files
- growpart
- resizefs
- disk_setup
- mounts
- set_hostname
- update_hostname
- update_etc_hosts
- rsyslog
- users-groups
- ssh
cloud_config_modules:
- emit_upstart
- snap
- ssh-import-id
- locale
- set-passwords
- grub-dpkg
- apt-pipelining
- apt-configure
- ntp
- timezone
- disable-ec2-metadata
- runcmd
- byobu-by-default
cloud_final_modules:
- package-update-upgrade-install
- fan
- puppet
- chef
- mcollective
- salt-minion
- rightscale_userdata
- scripts-vendor
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- ssh-authkey-fingerprints
- keys-to-console
- final-message
system_info:
default_user:
name: ubuntu
lock_passwd: True
gecos: Ubuntu
groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
distro: ubuntu
paths:
cloud_dir: /var/lib/cloud/
templates_dir: /etc/cloud/templates/
ssh_svcname: ssh
EOF
步骤 4:清理和转换
# 在虚拟机关机后执行
# 清理虚拟机内的临时文件(在虚拟机内)
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
sudo rm -rf /tmp/*
sudo cloud-init clean --logs
# 转换为 raw 格式(Container Disk 推荐 raw)
qemu-img convert -f qcow2 -O raw linux-base.qcow2 disk.img
# 验证镜像
qemu-img info disk.img
步骤 5:打包为 Container Disk
# Dockerfile
FROM scratch
ADD disk.img /disk.img
# 构建
docker build -t my-registry/ubuntu-base:22.04 .
# 推送
docker push my-registry/ubuntu-base:22.04
2.4 从零制作 Windows 镜像
步骤 1:准备 VirtIO 驱动
# 下载 VirtIO Windows 驱动
wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
步骤 2:创建磁盘并安装
# 创建磁盘
qemu-img create -f qcow2 windows-base.qcow2 50G
# 安装 Windows
virt-install \
--name kubevirt-windows \
--memory 4096 \
--vcpus 2 \
--disk path=./windows-base.qcow2,format=qcow2 \
--cdrom ./Windows_Server_2022.iso \
--disk path=./virtio-win.iso,device=cdrom \
--os-variant win2k22 \
--network network=default,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--noautoconsole
步骤 3:安装 VirtIO 驱动
在 Windows 虚拟机内部:
- 打开设备管理器
- 挂载 VirtIO ISO
- 安装所有驱动(网络、存储、内存气球等)
- 安装 QEMU Guest Agent
# 在 Windows 内安装 QEMU Guest Agent
# 从 VirtIO ISO 中运行
msiexec /i guest-agent\qemu-ga-x86_64.msi /quiet
步骤 4:打包
# 转换为 raw
qemu-img convert -f qcow2 -O raw windows-base.qcow2 disk.img
# 构建 Container Disk
docker build -t my-registry/windows-base:2022 .
docker push my-registry/windows-base:2022
三、使用 CDI 导入镜像
3.1 CDI 概述
Container Storage Interface(CDI)是 KubeVirt 的存储管理组件,支持:
- 从 HTTP/S3/Registry 导入镜像
- 克隆现有 PVC
- 上传本地镜像
- 自动格式转换
3.2 从 HTTP 导入
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: ubuntu-import
spec:
source:
http:
url: "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
# 可选:添加认证头
# secretRef: "http-auth-secret"
pvc:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
3.3 从容器镜像仓库导入
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: ubuntu-from-registry
spec:
source:
registry:
url: "docker://my-registry/ubuntu-base:22.04"
# 可选:拉取密钥
# secretRef: "registry-secret"
pvc:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
3.4 克隆 PVC
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: ubuntu-clone
spec:
source:
pvc:
name: ubuntu-import # 源 PVC 名称
namespace: default # 源 PVC 命名空间
pvc:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
3.5 上传本地镜像
# 使用 virtctl 上传
virtctl image-upload dv ubuntu-upload \
--size=10Gi \
--image-path=./local-image.qcow2 \
--storage-class=standard
# 或使用 kubectl virt plugin
kubectl virt image-upload dv ubuntu-upload \
--size=10Gi \
--image-path=./local-image.qcow2
四、镜像优化
4.1 镜像瘦身
# 1. 清理系统缓存(在虚拟机内)
sudo apt-get clean
sudo rm -rf /var/log/*
sudo rm -rf /tmp/*
sudo rm -rf /var/tmp/*
sudo history -c
# 2. 零填充空闲空间(减小 raw 镜像体积)
dd if=/dev/zero of=/EMPTY bs=1M || true
rm -f /EMPTY
sync
# 3. 转换为 qcow2(压缩)
qemu-img convert -f raw -O qcow2 -c disk.raw disk.qcow2
# 4. 缩小镜像
qemu-img resize disk.qcow2 --shrink 20G
4.2 镜像预配置
# 使用 virt-customize 预配置镜像(需要 libguestfs-tools)
sudo apt-get install -y libguestfs-tools
# 设置 root 密码
virt-customize -a disk.qcow2 --root-password password:mysecret
# 安装软件包
virt-customize -a disk.qcow2 --install nginx,curl,wget
# 运行自定义脚本
virt-customize -a disk.qcow2 --run-command "systemctl enable nginx"
# 设置 hostname
virt-customize -a disk.qcow2 --hostname my-vm
4.3 镜像格式对比
| 特性 | raw | qcow2 |
|---|---|---|
| 性能 | 最佳 | 略低 |
| 大小 | 固定大小 | 支持精简配置 |
| 压缩 | 不支持 | 支持 |
| 快照 | 不支持 | 支持 |
| 加密 | 不支持 | 支持 |
| 推荐场景 | Container Disk | PVC/DataVolume |
五、在 KubeVirt 中使用镜像
5.1 使用 Container Disk
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: ubuntu-vm
spec:
running: true
template:
spec:
domain:
cpu:
cores: 2
memory:
guest: 2Gi
devices:
disks:
- name: rootdisk
disk:
bus: virtio
- name: cloudinitdisk
disk:
bus: virtio
volumes:
- name: rootdisk
containerDisk:
image: my-registry/ubuntu-base:22.04
- name: cloudinitdisk
cloudInitNoCloud:
userData: |-
#cloud-config
password: ubuntu
chpasswd: {
expire: False }
5.2 使用 DataVolume
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: ubuntu-dv-vm
spec:
running: true
template:
spec:
domain:
cpu:
cores: 2
memory:
guest: 2Gi
devices:
disks:
- name: rootdisk
disk:
bus: virtio
volumes:
- name: rootdisk
dataVolume:
name: ubuntu-dv
dataVolumeTemplates:
- metadata:
name: ubuntu-dv
spec:
source:
registry:
url: "docker://my-registry/ubuntu-base:22.04"
pvc:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
六、镜像仓库管理
6.1 使用 Harbor 私有仓库
# 登录 Harbor
docker login harbor.example.com
# 推送镜像
docker tag my-registry/ubuntu-base:22.04 harbor.example.com/kubevirt/ubuntu-base:22.04
docker push harbor.example.com/kubevirt/ubuntu-base:22.04
# 创建镜像拉取密钥
apiVersion: v1
kind: Secret
metadata:
name: harbor-registry-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>
# 在 CDI 中使用
spec:
source:
registry:
url: "docker://harbor.example.com/kubevirt/ubuntu-base:22.04"
secretRef: harbor-registry-secret
6.2 镜像版本管理
# 使用语义化版本
docker build -t my-registry/ubuntu-base:22.04.1 .
docker build -t my-registry/ubuntu-base:22.04.2 .
docker build -t my-registry/ubuntu-base:latest .
# 推送所有版本
docker push my-registry/ubuntu-base:22.04.1
docker push my-registry/ubuntu-base:22.04.2
docker push my-registry/ubuntu-base:latest
七、常见问题
7.1 Container Disk 启动失败
# 检查镜像是否正确
docker run --rm my-registry/ubuntu-base:22.04 ls -la /disk.img
# 确保磁盘文件在根目录
# 错误:/disk/disk.img
# 正确:/disk.img
7.2 DataVolume 导入失败
# 检查 CDI Pod 日志
kubectl logs -n cdi deployment/cdi-importer
# 检查 DataVolume 状态
kubectl describe dv ubuntu-dv
# 检查 PVC 状态
kubectl get pvc
7.3 镜像格式不兼容
# 检查镜像格式
qemu-img info disk.img
# 转换为兼容格式
qemu-img convert -f vmdk -O qcow2 disk.vmdk disk.qcow2
qemu-img convert -f vdi -O raw disk.vdi disk.raw
7.4 镜像过大
# 查看实际占用空间
qemu-img measure disk.qcow2
# 压缩 qcow2 镜像
qemu-img convert -O qcow2 -c input.qcow2 output-compressed.qcow2
# 使用 sparsify 精简镜像
virt-sparsify input.qcow2 output-sparse.qcow2