在容器与虚拟化融合的云原生架构中,KubeVirt凭借“统一K8s技术栈管理容器与虚机”的核心优势,成为企业迁移传统虚拟化 workload 的优选方案。本文基于生产级环境配置,从前期准备、核心组件部署到最终虚拟机创建与验证,提供全流程可复现的实操步骤,帮助读者快速上手KubeVirt虚拟机创建。
一、前置准备:环境校验与基础配置
创建KubeVirt虚拟机的前提是搭建符合要求的K8s集群环境,并完成虚拟化支持、节点隔离等基础配置,这是保障虚机稳定运行的基础。
1.1 硬件与系统环境校验
KubeVirt依赖KVM虚拟化技术,需先在所有计算节点完成硬件虚拟化支持校验:
# 1. 校验CPU是否支持虚拟化(Intel CPU查vmx,AMD CPU查svm)
cat /proc/cpuinfo | grep -E "(vmx|svm)"
# 若有输出则支持虚拟化,无输出则不支持(需开启BIOS/UEFI虚拟化开关)
# 2. 校验KVM模块是否加载
lsmod | grep kvm
# 若未输出,手动加载模块(Intel CPU)
modprobe kvm
modprobe kvm_intel
# AMD CPU执行:modprobe kvm_amd
# 3. 设置KVM模块开机自启
echo "kvm" >> /etc/modules-load.d/kvm.conf
echo "kvm_intel" >> /etc/modules-load.d/kvm.conf # AMD替换为kvm_amd
1.2 节点标签与污点配置(负载隔离)
为避免虚机与容器负载争抢资源,需将特定节点划分为“虚机专属节点”,通过标签标识、污点排斥普通容器:
# 1. 为虚机节点打标签(假设18台节点命名为node-vm-01至node-vm-18)
kubectl label node node-vm-{01..18} node-role.kubernetes.io/virtualization=true
kubectl label node node-vm-{01..18} kubevirt.io/schedulable=true
# 2. 为虚机节点添加污点,阻止普通Pod调度
kubectl taint node node-vm-{01..18} virtualization=true:NoSchedule
1.3 依赖组件版本选型(生产级)
需提前规划好各组件版本,避免兼容性问题,推荐生产环境版本组合如下:
| 组件 | 版本 | 说明 |
|---|---|---|
| 操作系统 | Rocky Linux 8.9 | 稳定且兼容K8s与KubeVirt |
| Kubernetes | 1.28.4 | 通过kubeadm部署,稳定性佳 |
| KubeVirt | 1.1.1 | 功能完善,支持生产级特性 |
| CDI | 1.58.1 | 负责虚机镜像导入与管理 |
| 存储 | Rook-Ceph 1.12.9 | 高性能分布式存储,适配大规模虚机 |
| 网络 | Multus v4.0.2 + OVN-Kubernetes | 支持多网络与VLAN隔离,兼容传统网络架构 |
| # 二、核心组件部署:KubeVirt+存储+网络+CDI |
完成前置准备后,依次部署KubeVirt核心组件、存储(Rook-Ceph)、镜像管理(CDI)与网络(Multus+OVN),构建完整的虚机运行环境。
2.1 部署KubeVirt核心组件
KubeVirt通过Operator模式部署,简化组件管理与版本升级,步骤如下:
# 1. 设置KubeVirt版本
export KUBEVIRT_VERSION=v1.1.1
# 2. 部署KubeVirt Operator
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml
# 3. 等待Operator就绪(超时300秒)
kubectl wait --for=condition=available --timeout=300s deployment/virt-operator -n kubevirt
# 4. 部署KubeVirt核心组件(通过CR触发)
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml
# 5. 验证组件运行状态(需所有Pod处于Running状态)
kubectl get pods -n kubevirt
期望输出(核心组件示例):
NAME READY STATUS RESTARTS AGE
virt-api-7d5c9b8c8b-4x7k9 1/1 Running 0 5m
virt-api-7d5c9b8c8b-8j2m3 1/1 Running 0 5m
virt-controller-6c7d8f9b7-2k4n5 1/1 Running 0 5m
virt-controller-6c7d8f9b7-9x8m2 1/1 Running 0 5m
virt-handler-4k2j8 1/1 Running 0 4m # 每个节点1个
2.2 KubeVirt生产级配置优化
默认配置不适用于大规模虚机场景,需通过修改KubeVirt CR优化迁移、网络、资源等配置:
apiVersion: kubevirt.io/v1
kind: KubeVirt
metadata:
name: kubevirt
namespace: kubevirt
spec:
certificateRotateStrategy: {}
configuration:
developerConfiguration:
featureGates:
- LiveMigration # 支持热迁移
- HotplugVolumes # 支持卷热插拔
- HotplugNICs # 支持网卡热插拔
- Snapshot # 支持虚机快照
- VMExport # 支持虚机导出
- ExpandDisks # 支持磁盘扩容
- GPU # 支持GPU透传
migrations:
parallelMigrationsPerCluster: 10 # 集群级并行迁移数
parallelOutboundMigrationsPerNode: 4 # 单节点出站并行迁移数
bandwidthPerMigration: 1Gi # 每迁移带宽限制
completionTimeoutPerGiB: 800 # 每GiB数据迁移超时
allowAutoConverge: true # 自动收敛迁移
allowPostCopy: true # 支持PostCopy迁移(加速)
network:
defaultNetworkInterface: bridge # 默认网络接口类型
permitBridgeInterfaceOnPodNetwork: true
supportedGuestAgentVersions: # 支持的Guest Agent版本
- "4.*"
- "5.*"
customizeComponents:
patches:
# 增加virt-controller副本数(高可用)
- resourceType: Deployment
resourceName: virt-controller
patch: '{"spec":{"replicas":3}}'
type: strategic
# 增加virt-api副本数(高可用)
- resourceType: Deployment
resourceName: virt-api
patch: '{"spec":{"replicas":3}}'
type: strategic
imagePullPolicy: IfNotPresent
workloadUpdateStrategy:
workloadUpdateMethods:
- LiveMigrate # 组件更新时通过热迁移保障虚机可用性
应用优化配置:
kubectl apply -f kubevirt-optimize.yaml
2.3 部署存储:Rook-Ceph(高性能分布式存储)
存储是虚机运行的核心依赖,推荐使用Rook-Ceph提供分布式块存储,步骤如下:
2.3.1 部署Rook-Ceph Operator
# 1. 克隆Rook仓库(指定版本分支)
git clone --single-branch --branch v1.12.9 https://github.com/rook/rook.git
cd rook/deploy/examples
# 2. 部署CRDs、基础配置与Operator
kubectl create -f crds.yaml -f common.yaml -f operator.yaml
# 3. 等待Operator就绪(超时600秒)
kubectl -n rook-ceph wait --for=condition=available --timeout=600s deployment/rook-ceph-operator
2.3.2 部署Ceph集群
创建Ceph集群配置文件cluster.yaml(适配3个存储节点,使用NVMe磁盘):
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
dataDirHostPath: /var/lib/rook # 主机数据存储路径
cephVersion:
image: quay.io/ceph/ceph:v18.2.1 # Ceph版本
allowUnsupported: false
mon:
count: 3 # 3个mon节点(高可用)
allowMultiplePerNode: false
volumeClaimTemplate:
spec:
storageClassName: local-storage
resources:
requests:
storage: 50Gi
mgr:
count: 2 # 2个mgr节点(高可用)
modules:
- name: pg_autoscaler # 自动扩缩容PG
enabled: true
- name: prometheus # 监控集成
enabled: true
dashboard:
enabled: true # 启用Ceph Dashboard
ssl: true
storage:
useAllNodes: false
useAllDevices: false
config:
osdsPerDevice: "1"
encryptedDevice: "false"
nodes: # 存储节点配置(3个节点,每个节点4块NVMe磁盘)
- name: "storage-node-01"
devices:
- name: "nvme0n1"
- name: "nvme1n1"
- name: "nvme2n1"
- name: "nvme3n1"
- name: "storage-node-02"
devices:
- name: "nvme0n1"
- name: "nvme1n1"
- name: "nvme2n1"
- name: "nvme3n1"
- name: "storage-node-03"
devices:
- name: "nvme0n1"
- name: "nvme1n1"
- name: "nvme2n1"
- name: "nvme3n1"
resources: # 资源限制(根据实际环境调整)
mgr:
limits:
cpu: "2"
memory: "2Gi"
requests:
cpu: "1"
memory: "1Gi"
mon:
limits:
cpu: "2"
memory: "2Gi"
requests:
cpu: "1"
memory: "1Gi"
osd:
limits:
cpu: "4"
memory: "8Gi"
requests:
cpu: "2"
memory: "4Gi"
priorityClassNames: # 优先级配置(保障核心组件运行)
mon: system-node-critical
osd: system-node-critical
mgr: system-cluster-critical
部署Ceph集群并验证:
# 1. 部署Ceph集群
kubectl apply -f cluster.yaml
# 2. 等待Ceph集群就绪(需耐心等待,约10-20分钟)
kubectl -n rook-ceph wait --for=condition=Ready --timeout=1200s cephcluster/rook-ceph
# 3. 验证Ceph集群状态(health为HEALTH_OK即正常)
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph status
2.3.3 创建虚机专用StorageClass
创建Ceph块池与StorageClass,供虚机磁盘动态挂载:
---
# 创建Ceph块池(3副本,高可用)
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool-vm
namespace: rook-ceph
spec:
failureDomain: host
replicated:
size: 3
requireSafeReplicaSize: true
parameters:
compression_mode: aggressive # 启用激进压缩(节省空间)
---
# 创建StorageClass(虚机专用)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-ceph-block-vm
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
clusterID: rook-ceph
pool: replicapool-vm
imageFormat: "2"
imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock # 优化性能
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete # 删除虚机时自动删除磁盘
allowVolumeExpansion: true # 支持磁盘扩容
volumeBindingMode: Immediate
应用配置并验证:
kubectl apply -f ceph-storageclass-vm.yaml
# 验证StorageClass(provisioner正确,且为默认可选项)
kubectl get sc
2.4 部署CDI:虚机镜像导入与管理
CDI(Containerized Data Importer)负责将ISO、qcow2等格式的虚机镜像导入K8s存储,为虚机提供镜像源,部署步骤如下:
# 1. 设置CDI版本
export CDI_VERSION=v1.58.1
# 2. 部署CDI Operator与CR
kubectl apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/${CDI_VERSION}/cdi-operator.yaml
kubectl apply -f https://github.com/kubevirt/containerized-data-importer/releases/download/${CDI_VERSION}/cdi-cr.yaml
# 3. 等待CDI就绪(超时300秒)
kubectl wait --for=condition=available --timeout=300s deployment/cdi-deployment -n cdi
# 4. 验证CDI组件
kubectl get pods -n cdi
2.5 部署网络:Multus+OVN-Kubernetes(支持VLAN隔离)
KubeVirt虚机需接入传统VLAN网络时,需通过Multus实现多网络接入,OVN-Kubernetes实现二层网络转发,步骤如下:
2.5.1 部署Multus CNI
# 部署Multus(支持多网络接口)
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/v4.0.2/deployments/multus-daemonset-thick.yml
# 验证Multus运行状态
kubectl get pods -n kube-system -l app=multus
2.5.2 配置OVN-Kubernetes与VLAN网络
创建NetworkAttachmentDefinition(NAD),定义VLAN网络(以VLAN 100生产网、VLAN 200数据库网为例):
---
# VLAN 100 生产网络
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vlan100-production
namespace: vm-production # 虚机所属命名空间
spec:
config: |
{
"cniVersion": "0.3.1",
"name": "vlan100-production",
"type": "ovn-k8s-cni-overlay",
"topology": "localnet",
"netAttachDefName": "vm-production/vlan100-production",
"vlanID": 100, # 对应物理网络VLAN ID
"mtu": 9000, # 巨帧配置(提升性能)
"subnets": "10.100.0.0/16" # 网络网段
}
---
# VLAN 200 数据库网络
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vlan200-database
namespace: vm-production
spec:
config: |
{
"cniVersion": "0.3.1",
"name": "vlan200-database",
"type": "ovn-k8s-cni-overlay",
"topology": "localnet",
"netAttachDefName": "vm-production/vlan200-database",
"vlanID": 200,
"mtu": 9000,
"subnets": "10.200.0.0/16"
}
在每个节点配置OVS桥接映射(关联物理网卡与VLAN桥):
# 1. 设置OVN桥接映射(所有节点执行)
ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings="physnet-vlan100:br-vlan100,physnet-vlan200:br-vlan200"
# 2. 创建VLAN桥
ovs-vsctl add-br br-vlan100
ovs-vsctl add-br br-vlan200
# 3. 绑定物理网卡子接口到桥(ens2f0为物理网卡,根据实际调整)
ovs-vsctl add-port br-vlan100 ens2f0.100 tag=100
ovs-vsctl add-port br-vlan200 ens2f0.200 tag=200
应用网络配置并验证:
# 创建虚机命名空间
kubectl create ns vm-production
# 应用NAD配置
kubectl apply -f ovn-vlan-nad.yaml
# 验证NetworkAttachmentDefinition
kubectl get nad -n vm-production
三、创建虚拟机:从镜像导入到虚机启动
完成所有基础组件部署后,即可通过CDI导入虚机镜像,再创建VirtualMachine(VM)资源,最终启动虚拟机。本节以导入CentOS 7 qcow2镜像、创建1台生产环境虚机为例。
3.1 导入虚机镜像(通过CDI)
使用CDI的DataVolume资源导入镜像,支持从HTTP/HTTPS地址、本地文件等方式导入,此处以HTTP导入为例:
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
name: centos7-base-image
namespace: vm-production
spec:
storage:
resources:
requests:
storage: 50Gi # 镜像存储大小
storageClassName: rook-ceph-block-vm # 关联虚机专用存储类
accessModes:
- ReadWriteOnce
source:
http:
url: "https://mirrors.aliyun.com/centos-cloud/centos/7/images/CentOS-7-x86_64-GenericCloud-2009.qcow2" # 阿里云CentOS 7镜像地址
应用配置并监控镜像导入状态:
kubectl apply -f centos7-datavolume.yaml
# 查看DataVolume状态(Phase变为Succeeded即导入完成)
kubectl get dv -n vm-production -w
# 导入完成后,查看对应的PVC(DataVolume会自动创建PVC)
kubectl get pvc -n vm-production
3.2 创建虚拟机配置文件
创建VirtualMachine资源配置文件centos7-vm.yaml,指定镜像、网络、资源、节点调度等信息:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: centos7-production-01
namespace: vm-production
spec:
running: true # 创建后自动启动
template:
metadata:
labels:
kubevirt.io/vm: centos7-production-01
spec:
nodeSelector:
# 调度到虚机专属节点
node-role.kubernetes.io/virtualization: "true"
volumes:
# 系统盘(关联导入的CentOS 7镜像)
- name: centos7-root
dataVolume:
name: centos7-base-image
# 临时存储(emptyDir)
- name: cloud-init
cloudInitNoCloud:
userData: |
#cloud-config
users:
- name: admin
ssh-authorized-keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... # 替换为自己的SSH公钥
sudo: ['ALL=(ALL) NOPASSWD:ALL']
hostname: centos7-prod-01
manage_etc_hosts: true
domain:
cpu:
cores: 4 # CPU核心数
sockets: 1
threads: 1
resources:
requests:
cpu: 4
memory: 8Gi
limits:
cpu: 4
memory: 8Gi
devices:
disks:
- name: centos7-root
disk:
bus: virtio # 磁盘总线类型(virtio性能最优)
- name: cloud-init
disk:
bus: virtio
interfaces:
# 接入VLAN 100生产网络
- name: vlan100-production
bridge: {} # 使用桥接模式
networkInterfaceMultiqueue: true # 启用多队列(提升网络性能)
networks:
- name: vlan100-production
multus:
networkName: vm-production/vlan100-production # 关联NAD配置
关键配置说明:
nodeSelector:确保虚机调度到专属虚机节点,避免资源争抢;
volumes:通过dataVolume关联导入的镜像,cloudInit配置SSH密钥与主机名,实现免密码登录;
domain:定义CPU、内存资源,根据业务需求调整;
networks:通过multus关联VLAN 100网络,实现与传统生产网络互通。
3.3 启动虚拟机并验证
# 1. 应用虚机配置,创建并启动虚机
kubectl apply -f centos7-vm.yaml
# 2. 查看虚机状态(Phase为Running即启动成功)
kubectl get vm -n vm-production
kubectl get vmi -n vm-production # VMI是虚机实例,实际运行的资源
# 3. 查看虚机对应的Pod(每个虚机对应1个virt-launcher Pod)
kubectl get pods -n vm-production -l kubevirt.io/vm=centos7-production-01
# 4. 查看虚机IP(通过virtctl工具,需提前安装)
# 安装virtctl(与KubeVirt版本一致)
export KUBEVIRT_VERSION=v1.1.1
curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/virtctl-${KUBEVIRT_VERSION}-linux-amd64
chmod +x virtctl
mv virtctl /usr/local/bin/
# 获取虚机IP
virtctl expose vm centos7-production-01 -n vm-production --port=22 --target-port=22 --name=vm-ssh
kubectl get svc -n vm-production # 查看暴露的SSH服务IP
3.4 登录虚拟机验证功能
# 通过SSH登录虚机(替换为实际IP)
ssh admin@10.100.0.10
# 验证网络连通性
ping 网关IP
ping 外网IP(如223.5.5.5)
# 验证磁盘挂载
df -h
# 验证资源使用
top
四、常见问题排查
4.1 虚机启动失败(virt-launcher Pod异常)
查看Pod日志定位问题:
kubectl logs -n vm-production 虚机Pod名称 -c virt-launcher
常见原因:
节点未开启虚拟化:重新检查CPU虚拟化配置与KVM模块;
存储类不存在或不可用:验证rook-ceph-block-vm是否正常;
网络配置错误:检查NAD配置与OVS桥接映射。
4.2 虚机无法获取IP
排查步骤:
验证Multus与OVN组件是否正常运行;
检查NAD配置中的VLAN ID与物理网络是否一致;
查看虚机内部网络配置:virtctl console 虚机名称 -n 命名空间。
4.3 镜像导入缓慢或失败
排查步骤:
检查CDI组件状态:kubectl get pods -n cdi;
查看DataVolume导入日志:kubectl describe dv 镜像名称 -n 命名空间;
更换镜像源(如使用国内阿里云、华为云镜像源)。
五、总结
基于KubeVirt创建虚拟机的核心流程可概括为“环境准备→组件部署→镜像导入→虚机创建”,其中环境校验(虚拟化支持、节点隔离)与核心组件(存储、网络)的稳定性是关键。本文基于生产级配置,提供了全流程实操步骤,读者可根据实际环境调整资源规格、网络配置等参数。通过KubeVirt,企业可实现容器与虚机的统一管理,降低运维复杂度,为传统虚拟化 workload 的云原生迁移提供可行路径。
(注:文档部分内容可能由 AI 生成)