在容器与虚拟化融合的云原生架构中,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 生成)