KubeVirt 做的事说起来一句话就能讲完:往 Kubernetes 里加一组 CRD(VirtualMachine、VirtualMachineInstance)和一个由 virt-controller、virt-handler、virt-launcher 组成的控制面,让你用 kubectl apply 创建一台跑 qemu-kvm 的虚拟机。创建出来的虚拟机在集群里表现为一个 Pod,Pod 里的 qemu 进程直接操作 /dev/kvm,业务方看到的是"容器和虚拟机共用一个资源池、同一个调度器、同一套监控和告警"。
统一是有代价的。KubeVirt 并没有把虚拟化层变没了,它只是把虚拟化层的管理入口从 vCenter 或者 virsh 换成了 etcd 和 CRD。qemu 还在,libvirtd 还在,虚拟机的内存开销还在,热迁移对共享存储的要求还在。所以真正要想清楚的不是"要不要上 KubeVirt",而是"这台物理机买回来,能跑多少台虚拟机,剩下的还有多少能给容器"。本文就按这个口径写:先把每一层开销拆开算清楚,再反过来定机器的内存和核数,最后说清楚哪些团队压根不该碰这套东西。
说明一下边界:下面出现的容量比例、内存开销比例、连接数上限,全部是工程经验值,不同 KubeVirt 版本、不同 qemu 版本、不同内核和不同镜像会有明显差异,落地前必须在你自己的机器上压测复核,不能直接照抄当成实测数据用。所有涉及费用的地方一律写需询价,公开渠道差异较大,以实时报价为准。
在 KubeVirt 里一台虚拟机对应一个 virt-launcher Pod,这个 Pod 里跑的不是一个进程而是一组:virt-launcher 自身的 Go 进程负责生命周期与状态上报,libvirtd 负责跟 qemu 通信,qemu-system-x86_64 才是真正执行 guest 指令的那个进程。这三个进程各自的常驻内存都要落在宿主机上,而它们都属于虚拟机声明内存之外的固定开销。
工程经验值(需压测验证,随版本、vCPU 数与挂载设备数浮动):每台虚拟机的额外开销可以粗分成四块。第一块是 qemu 进程自身的代码段、堆以及每个 vCPU 线程的栈,vCPU 越多、挂的设备越多这部分越大;第二块是 virt-launcher 与 libvirtd 的常驻内存,规模相对固定,不随虚拟机规格线性变化;第三块是 guest 内存对应的页表、virtio 环、设备 DMA 缓冲区等结构,大致和 guest 内存成正比;第四块是 qemu 为气球驱动、迁移脏页跟踪这类机制预留的结构。
四块叠起来,一台声明 8 GB 内存的虚拟机,在宿主机上实际吃掉的会明显超过 8 GB。常见的工程做法是按声明内存的 5% 到 15% 预留额外开销,小规格虚拟机的比例更接近上限(固定开销摊薄得少),大规格虚拟机更接近下限,再额外加一个几百 MB 量级的固定值。这个数字不要照抄,用你自己的镜像开机之后,对比 Pod 的 working_set 和宿主机上 qemu 进程的 RSS 差值来定。
还有一个容易踩的点:KubeVirt 会给 virt-launcher Pod 设 memory limits,这个 limit 必须覆盖"guest 内存加开销",否则 guest 还没跑满,Pod 先被 cgroup 干掉了。而 Kubernetes 里 requests 决定调度、limits 决定 OOM 边界,如果 requests 只填了 guest 内存、limits 填了 guest 加开销,调度器会以为这台机器还塞得下更多虚拟机,结果开机开到一半触发节点级 OOM。requests 和 limits 在虚拟机这件事上必须一起加开销,只改一个是典型的事故来源。
另外宿主机本身也要留一份:kubelet、容器运行时、CNI 插件、CSI 节点插件、日志采集、监控 agent、virt-handler 这一整套,加上内核给自己留的余量。这部分在内存规划里通常按固定值先扣掉,剩下的才是可以分给虚拟机和容器的部分。很多人算容量的时候直接从物理内存往下减虚拟机内存,忘掉这一层,最后发现机器根本跑不到理论台数。
KubeVirt 的虚拟机磁盘走的是 PVC,但 PVC 里不能是空的,得先把镜像灌进去。这一步由 CDI(Containerized Data Importer)负责,它提供三种主流入口:从 HTTP 或对象存储的 URL 拉取 qcow2 或 raw 文件,从容器镜像 registry 里拉取打包好的 containerDisk,以及从已有的 PVC 做克隆。三种方式对存储的压力曲线完全不一样,选错了就会在批量交付那天翻车。
从 URL 导入是最常见的。CDI 会起一个 importer Pod,下载文件,如果需要就把 qcow2 转成 raw(取决于目标 PVC 的 volumeMode 和文件系统开销配置),写进目标 PVC。这里有两个隐藏开销:一是 qcow2 是稀疏格式,标称大小可能是 40 GB,实际占用只有 3 GB,但转成 raw 之后会按标称大小铺开,写入量直接放大一个数量级;二是转换过程中 CDI 可能需要一块临时空间(取决于配置是否开启 filesystem overhead 与预分配),这块空间在导入完成后才释放。
从 PVC 克隆是第二个大坑。克隆一个 100 GB 的系统盘,在没有存储层快照或写时复制支持的情况下,就是一次 100 GB 的全量拷贝。如果一次性批量开 50 台虚拟机,那就是 5 TB 的写入在几分钟内压到共享存储上。存储后端如果是三副本的 Ceph 或者类似的分布式存储,实际落盘的写入量还要再乘副本数。这就是为什么很多团队第一次批量开机时把存储打满:不是容量规划没做,而是没把"克隆的瞬时写入"当成一种负载类型单独算。
规避思路有三条,按效果排序。第一条是用支持快照或克隆的存储后端,让 CDI 走 CSI 的 volume clone 或 volume snapshot 接口,把全量拷贝变成存储层内部的元数据操作,多数分布式存储和部分企业级 SAN 支持这个能力,落地前要向存储侧确认 CSI 驱动是否实现了对应接口。第二条是把基础镜像做成 containerDisk 或者预置的 golden PVC,并在业务低峰提前预热,不要在交付当天现场转换 qcow2。第三条是给导入和克隆动作单独设限流与并发上限,CDI 的配置项里可以限制并发导入数量,把突发写入摊平到更长的时间窗口里。
还有个长期问题叫镜像 sprawl:每个业务线自己传一份 40 GB 的镜像,一年下来就是几十份重复数据。工程上建议把基础镜像收敛成少数几个版本,业务差异用 cloud-init 或者配置管理在开机后注入,而不是为每种差异烤一个新镜像。这既是容量问题,也是 patch 管理问题——镜像越多,漏打补丁的概率越高。
KubeVirt 的在线迁移要求源节点和目标节点都能同时访问同一块虚拟机磁盘,也就是说后端 PVC 的访问模式必须是 ReadWriteMany(RWX)。如果 PVC 是 ReadWriteOnce(RWO),在线迁移根本不会成功,KubeVirt 会拒绝这个迁移请求。这一点直接决定了你的宿主机维护窗口怎么排。
用 RWO 意味着什么?意味着每次内核升级、固件升级、硬件更换、virt-handler 版本升级,都要先把这台机器上的虚拟机停掉、在别处重新调度起来。停机时间等于虚拟机的启动时间加上应用自身拉起的时间,对数据库类负载来说是分钟级;对有状态服务来说还要考虑数据一致性检查。RWO 加上本地盘(比如直接用宿主机 NVMe 做 PVC)的组合性能最好、成本最低,但代价就是你没有在线维护这条路。
用 RWX 意味着什么?意味着宿主机可以逐台 drain,业务无感。但 RWX 通常来自分布式存储或者 NFS,虚拟机的磁盘 IO 要过网络协议栈,延迟和吞吐都和本地盘不在一个量级。工程经验值(需压测验证):同一块 NVMe 走本地盘和走网络文件系统的顺序写带宽差距可能是数倍,4K 随机写 IOPS 的差距更大,延迟从微秒级跳到毫秒级。所以用 RWX 之前,要确认你的业务能不能接受这种 IO 特征。
另外即使有了 RWX,迁移也不是免费的。KubeVirt 迁移时会跟踪脏页,如果虚拟机内存写速率高于迁移带宽,脏页永远追不完,迁移就会卡住或者超时失败。所以内存大、写密集的虚拟机迁移窗口要挑业务低峰,或者提前把虚拟机的脏页速率降到可接受范围。KubeVirt 提供了迁移策略相关的配置项(比如带宽限制、自动收敛开关、完成超时),这些参数要按你的实际网络和存储带宽调,用默认值在写密集场景下容易迁不动。
判断方法很直接:打开你的虚拟机定义,看 dataVolume 或 PVC 的 accessModes 字段。写的是 ReadWriteOnce,那么这台机器就没有在线维护窗口,排期按停机算;写的是 ReadWriteMany,那么可以先确认一次真实迁移耗时(在测试环境跑一遍,记录从发起迁移到完成的时间和业务侧抖动),再决定维护窗口的长度。这个字段是运维排期的输入,不是存储团队的内部实现细节。
KubeVirt 的虚拟机网络大致有三档,复杂度和性能是正相关的。第一档是 Pod 网络,虚拟机拿到的 IP 就是 Pod 的 IP,通过 CNI 的桥接直接出现在集群网络里,外部路由可达,调试最直观。第二档是 masquerade,虚拟机的 IP 是私有的,出网时经过一层 NAT 换成 Pod IP,入站流量需要显式配置端口转发。第三档是直通,通过 Multus 挂额外的网卡,配合 SR-IOV 或者设备直通把物理网卡的虚拟功能直接交给虚拟机。
Pod 网络的好处是零额外配置、服务发现和 NetworkPolicy 都能直接用,坏处是要求 CNI 支持桥接模式并能把虚拟机 MAC 暴露出来,部分 CNI 组合下需要额外开启混杂模式或者特定特性开关,落地前要在目标 CNI 上验证,别在测试环境用一种 CNI、生产换另一种。
masquerade 模式是默认也最常见的,但它有两个具体代价。第一个是入站:虚拟机在 Pod 内部,外部访问它必须逐条配端口转发,端口一多管理就乱,也不适合端口范围动态的服务。第二个是出网:所有连接要过一遍 NAT,这层 NAT 由节点内核的 conntrack 维护,虚拟机的每条并发连接都占一条 conntrack 表项。这个问题下一节单独说。
直通(Multus 加 SR-IOV)能拿到接近物理网卡的吞吐和延迟,代价是三件事:一是要有支持 SR-IOV 的网卡和对应的设备插件,二是直通之后虚拟机就不再受 CNI 和 NetworkPolicy 管,安全策略得靠外部手段补,三是热迁移能力受影响,直通设备的虚拟机通常没法做在线迁移,这又回到上一节那个运维窗口的问题上去了。所以直通适合"网络性能是瓶颈、且这台虚拟机不需要频繁迁移"的少数负载,不是默认选项。
选型的判断顺序:先看业务要不要被集群内的服务发现和 NetworkPolicy 管——要,就排除直通;再看入站端口是不是固定少量——是固定少量,masquerade 就够;最后看 pps 和延迟指标,只有真的打满了才上直通。很多团队一上来就上 SR-IOV,最后发现瓶颈在磁盘,白折腾一遍网络。
masquerade 模式下虚拟机的出网连接会经过宿主机内核的 NAT,每一条并发连接对应一条 conntrack 表项。这里的关键认知是:conntrack 表是节点级的共享资源,不是 Pod 级的。一台宿主机上跑的所有容器、所有虚拟机、以及节点自身的所有连接,共用同一张表。
Kubernetes 安装文档里通常会要求把节点 conntrack 上限调到一个比较大的值,这个值是按"节点上会跑很多 Pod"来估的。虚拟机加入之后情况变了:一台虚拟机里跑的应用可能自己就维护几千条长连接,一个跑数据库或者消息队列的虚拟机轻松就能占掉上万条。十台这样的虚拟机叠在一台宿主机上,conntrack 表就可能被打满。
表满之后的症状很有迷惑性:不是报错,而是新建连接随机失败、丢包、延迟飙升,而且只在连接数高的时段出现。排查的时候如果只看虚拟机的监控,看到的是"虚拟机内部一切正常,就是连不上",很容易误判成网络设备的故障。真正的指标在宿主机上:看 conntrack 当前条目数和上限的比值,以及内核日志里有没有表满的告警。
工程经验值(需压测验证,不同内核版本默认上限不同):conntrack 默认上限是按宿主机内存大小自动推算的,但推算出来的值在混部场景下往往偏小。建议的做法是把它显式设为一个固定值,并且把"当前使用量除以上限"做成节点级告警,阈值设在七成左右,留出排查时间。同时要统计每台虚拟机的平均并发连接数,这个数字直接决定一台宿主机能放多少台虚拟机——它和内存、CPU 一样,是一种需要被计入容量模型的资源。
如果连接数实在压不下来,有两条路:一是改用 Pod 网络或者直通,绕开这层 NAT;二是在虚拟机内部做连接池收敛,把长连接数降下来。前者是基础设施的改动,后者是应用的改动,哪个成本低就先做哪个,但别指望靠调大 conntrack 上限无限解决——表项本身也吃内存,调得过大一样会有问题。
虚拟机要跑出接近物理机的内存性能,绕不开巨页。原因是虚拟机的内存访问要经过两级地址翻译:guest 虚拟地址到 guest 物理地址,guest 物理地址再到宿主机物理地址。第二级靠硬件的 EPT/NPT 支持,但每次翻译都要查多级页表,TLB 装不下的时候就要走内存里的页表遍历,一次访问多出几次访存。用 2M 或者 1G 的巨页能显著减少页表层级和 TLB miss,对内存带宽敏感、随机访存多的负载效果最明显。
巨页的麻烦在于它是静态资源。2M 或 1G 的巨页必须在系统启动阶段或者启动后早期预留,预留出去之后这部分内存就从普通内存池里消失了,普通容器拿不到。透明大页(THP)虽然能在运行时动态合并,但它带来的规整等待和 khugepaged 后台扫描会造成延迟抖动,对延迟敏感的负载常常是要关掉的。所以在混部机器上的现实是:要用巨页,就得先划一块出来,剩下的才归容器。
这就产生了一个具体的规划顺序问题:先确定有多少台虚拟机需要巨页、每台要多少,把这部分从物理内存里预扣掉;剩下的内存再按"虚拟机开销加容器用量"来分配。如果反过来先按虚拟机台数算内存、最后才想起来要开巨页,就会发现普通内存不够用,要么减虚拟机台数,要么加内存。
2M 和 1G 怎么选?1G 巨页的 TLB 覆盖能力更强,但需要硬件支持、需要在启动参数里显式预留、而且分配粒度太粗,一台只要 4 GB 的虚拟机按 1G 巨页分配就是 4 页,还算合理,但更大的浪费风险在于碎片和预留粒度。2M 巨页更灵活,兼容性更好,多数场景够用。工程上的判断方法(需压测验证):先用 2M 跑一轮基准测试,看 TLB miss 相关的硬件计数器(perf 里可以取)和目标业务的延迟分布,如果 2M 下已经压不出差距,就没必要上 1G。
还有一点:巨页是按 NUMA 节点分配的。在双路机器上,如果 virt-launcher Pod 没有做 NUMA 亲和,qemu 进程可能跨节点访问内存,巨页带来的性能提升会被跨片访问吃掉一半。所以开了巨页还要配 CPU Manager 和拓扑管理器,让虚拟机的 vCPU 和内存落在同一个 NUMA 节点上,这一步很多人会漏。
KubeVirt 的 vCPU 本质上就是 qemu 进程里的线程,由宿主机内核调度到物理核上。如果 kubelet 的 CPU Manager 工作在默认的 none 策略,这些线程跟节点上其他所有进程的线程一起竞争 CPU 时间,受 CFS 配额和调度延迟支配。结果就是虚拟机的性能抖:同一条指令,空载时快,邻居一忙就慢。
要让虚拟机的 vCPU 独占物理核,需要三件事一起做。第一件是把 kubelet 的 CPU Manager 策略设为 static,并且给容器预留一定数量的核(reservedSystemCPUs),被预留的核留给宿主机系统进程和其他 Pod,剩下的才参与独占分配。第二件是给 virt-launcher Pod 申请整数个 CPU,并让 Pod 的 QoS 等级是 Guaranteed——也就是 CPU 的 requests 等于 limits,且是整数。第三件是把 kubelet 的拓扑管理器策略设为 single-numa-node 或者 best-effort,让 CPU 和设备、巨页对齐到同一个 NUMA 节点。
这三件事缺一件,独占就只有一半效果。只开 CPU Manager 不做 NUMA 对齐,vCPU 可能在 A 片的核上跑,内存却在 B 片;只做 NUMA 对齐不开 CPU Manager,vCPU 还是会被 CFS 调度到别的核上。判断有没有生效的方法:进到 virt-launcher Pod 里看 qemu 线程的 CPU 亲和掩码,独占成功的话每个 vCPU 线程应该绑定在一个固定的物理核上,且掩码不重叠。
独占的代价是这些核不能给别的负载用。一台 32 核的机器,如果给虚拟机独占 16 核,剩下的 16 核要同时承载宿主机系统、容器业务和其他虚拟机。所以"要不要独占"是一个按负载分档的决策:延迟敏感的虚拟机(数据库、实时计算、交易链路)值得独占;批处理、内部工具、CI 这类虚拟机不值得,走共享池更划算。混部机器上通常两种档位并存,用节点标签或者资源类把它们分开调度。
还有个超线程的问题。独占核数怎么算,取决于你算的是物理核还是逻辑核。如果两个 vCPU 落在同一个物理核的两个超线程上,它们共享执行单元和缓存,性能远不如两个独立物理核。对延迟敏感的虚拟机,工程上通常按物理核分配并避开同核超线程,或者在 BIOS 层直接关掉超线程——后者更简单粗暴,但会让整机的通用算力下降,得算清楚账。
KubeVirt 不是虚拟化的通用替代品,它是一个"已经有 Kubernetes、且必须同时跑容器和虚拟机"的场景下的收敛方案。有几种情况上了只会更累。
第一种:只有虚拟机,没有容器。这种情况下你引入 Kubernetes 只是为了跑 KubeVirt,等于维护一整套 etcd、控制面、CNI、CSI、证书轮换、版本升级,只为了得到一个比成熟虚拟化平台更难用的管理界面。如果你的团队过去五年没有容器化负载,也没有容器化的计划,那么直接用成熟的虚拟化平台(比如 OpenStack、Proxmox VE 或者商业方案)成本更低。OpenNebula 也好、OpenStack 也好,它们的存储和网络模型就是为虚拟机设计的,不需要你先理解 Pod 网络再理解桥接。
第二种:已经有成熟稳定的虚拟化平台,且没有统一调度的需求。很多企业的虚拟化跑得好好的,存储是 SAN、网络是传统 VLAN、运维有完整的流程和工具链。这时候迁到 KubeVirt,收益是"和容器共用一个资源池",但代价是重建整套运维流程、重新培训团队、重新验证所有高可用方案。如果容器负载和虚拟机负载本来就不共享机器(大多数企业是这样,因为合规隔离或者资源特征差异太大),那么这个收益根本不存在。
第三种:团队不熟 Kubernetes。KubeVirt 的故障排查链路比传统虚拟化长:虚拟机的现象要一路查到 qemu、libvirtd、virt-launcher Pod、kubelet、CNI、CSI、etcd。如果团队对 Kubernetes 的调度、网络、存储没有扎实的理解,出问题的时候只会两边都查不动。传统虚拟化出问题是 virsh 加日志,KubeVirt 出问题是 kubectl describe 加 Pod 事件加节点状态加存储事件,认知负担高一个量级。
第四种:对显卡直通、特殊硬件、或者老旧操作系统有强依赖的场景。这些场景在传统虚拟化里有成熟的方案(vGPU、设备直通、老驱动兼容),在 KubeVirt 里要么需要额外的设备插件和内核配置,要么受限于 Kubernetes 的设备模型,能跑但折腾。特别是老操作系统(比如还在跑 Windows Server 老版本或者特定内核的 Linux),驱动和 virtio 设备的兼容性要在你的目标版本上逐个验证,不要假设 qemu 支持就等于能用。
判断的口径其实很简单:先问"我们有没有已经在生产的 Kubernetes 集群",再问"容器和虚拟机是不是真的要抢同一批物理机",最后问"团队里有没有人能在凌晨三点排查 CNI 问题"。三个问题有一个答案是不,就先别上。
单台虚拟机开机和测试环境里连开五十台,是两个完全不同的问题。批量开机的瞬间,集群同时承受三股压力,任何一股没提前准备都会让交付现场卡住。
第一股是调度压力。五十个 virt-launcher Pod 同时进入 Pending,调度器要在同一时间为它们做过滤和打分。如果虚拟机开了巨页或者要求 CPU 独占,调度器还要参与 NUMA 拓扑匹配,单个 Pod 的决策耗时比普通容器长得多。节点数量少、资源碎片多的时候,很容易出现部分 Pod 长时间 Pending,或者被调度到不合适的节点上。工程上的缓解办法是提前给节点打标签、用污点和亲和性把虚拟机池和容器池分开,减少调度器的搜索空间;并且在批量交付前做一次预演,观察调度队列的堆积情况。
第二股是镜像预热压力。如果用的是 containerDisk 或者需要拉取容器镜像,五十个节点同时从同一个 registry 拉镜像,registry 和镜像仓库的出向带宽会瞬间打满,镜像分发服务本身也会成为瓶颈。规模大的时候要考虑在节点侧做镜像预拉取,或者在集群内部署镜像缓存与分发组件,把集中式的拉取变成分布式的分发。
第三股是存储压力,也就是前面 CDI 那节说的克隆全量写入。这三股压力叠在一起的时候,现象往往是"虚拟机卡在 Starting 状态不动",但从单一视角看每个组件都还在正常工作。所以批量交付前必须做一次全链路演练,把调度耗时、镜像拉取耗时、存储写入峰值和端到端开机时间分别记下来,形成基线,后面每次扩容都拿这个基线对比。
把前面几节的开销项合起来,可以给出一个按场景分档的容量口径。下表是工程经验值,用于做第一轮预算,落地前必须在你自己的机器、镜像和负载上压测复核。所有费用相关项一律需询价,公开渠道差异较大,以实时报价为准。
| 场景档位 | 虚拟机规格与台数 | 需要预扣的部分 | 建议物理内存(含余量) | 存储与网络要留的余量 |
|---|---|---|---|---|
| 入门验证档 | 4 到 6 台,每台 4 vCPU 加 8 GB | 虚拟机开销约 15%,不开巨页,宿主机固定扣 4 GB | 64 GB(预估) | 系统盘 500 GB 级 SSD,克隆并发限 2 到 4 |
| 常规混部档 | 10 到 14 台,每台 8 vCPU 加 16 GB | 虚拟机开销约 10%,2M 巨页预留 32 GB,宿主机固定扣 8 GB | 256 GB(预估) | RWX 共享存储,预留 30% 突发写入余量 |
| 数据库独享档 | 4 到 6 台,每台 16 vCPU 加 64 GB | 虚拟机开销约 8%,1G 巨页按台预留,CPU 独占加 NUMA 对齐 | 512 GB(预估) | 本地 NVMe 或高性能集中存储,禁用克隆突发 |
| 容器为主档 | 2 到 4 台过渡期虚拟机,每台 4 vCPU 加 8 GB | 主要容量留给容器,虚拟机开销按 15% 保守估 | 128 GB(预估) | conntrack 上限显式设置,连接数纳入容量模型 |
表里最容易被忽略的是"需要预扣的部分"这一列。裸算虚拟机内存总和是 6 乘 8 等于 48 GB,看起来 64 GB 的机器绰绰有余,但加上 15% 开销、宿主机固定扣除、以及给未来的余量,实际能放的台数会明显少于理论值。这就是为什么容量规划必须倒着算:从物理内存里一层一层扣,扣到最后剩下的才是能分给虚拟机的。
把本文所有开销项整理成一个可执行的计算顺序,就是这套口径。按从上到下的顺序扣,不要跳步。
第一步,扣宿主机固定开销。包括操作系统、kubelet、容器运行时、CNI 与 CSI 节点插件、virt-handler、日志与监控 agent,以及内核自身的余量。这部分按实际测量取值,不要拍脑袋,实测方法是在没有虚拟机、只有系统组件的节点上看可用内存。
第二步,扣巨页预留池。统计需要巨页的虚拟机台数和每台的量,向上取整到巨页粒度的整数倍,一次性划出去。划出去之后这部分内存对普通容器完全不可用,所以要单独算,不要混在虚拟机内存里。双路机器还要注意巨页是按 NUMA 节点分的,两个节点各预留一半,避免单边耗尽。
第三步,加上虚拟机额外开销。每台虚拟机的实际占用等于声明内存乘上一个大于 1 的系数,再加一个固定值。系数取 1.05 到 1.15,小规格取高值、大规格取低值,固定值在几百 MB 量级。这个值要用你自己的镜像开机后实测校准,方法是对比 virt-launcher Pod 的 working_set 与 guest 声明内存的差值。
第四步,给存储突发留余量。这里不是内存,但是必须同步算:批量克隆和 qcow2 转 raw 的瞬时写入量等于镜像标称大小乘台数乘副本数,要确认存储池在承担这部分写入的同时还能支撑正常运行时的 IO。空间余量建议留出三成左右,并且用 CDI 的并发限制把写入摊平。
第五步,给网络会话留余量。统计每台虚拟机的平均并发连接数,累加后和节点的 conntrack 上限比较,使用率控制在七成以内。超限就调大上限、做连接池收敛或者改用非 NAT 的网络模式。
第六步,剩下的内存和核数才是容器的。到这一步才谈容器的 requests 和 limits,不要一开始就按容器需求定机器,然后在剩下的空间里硬塞虚拟机。
再强调一遍取舍:这套口径里的所有比例数字都是工程经验值,会随 KubeVirt 版本、qemu 版本、内核版本、镜像内容和工作负载特征变化。它们的作用是把"要预留"这件事变成一个可计算的框架,而不是提供一个可以直接抄的答案。真正落地的数字只能来自你自己机器上的压测。
本文的机制描述基于公开的 KubeVirt 架构与文档口径:虚拟机以 virt-launcher Pod 形式运行,Pod 内包含 qemu 与 libvirtd 进程;磁盘通过 PVC 与 DataVolume 提供,镜像导入与克隆由 CDI 组件负责;在线迁移要求后端存储支持多节点同时访问;网络可选 Pod 网络、masquerade 或通过 Multus 挂载额外网卡;vCPU 独占依赖 kubelet 的 CPU Manager 与拓扑管理器;巨页需要在节点上预先预留,属于静态资源。
需要你在自己环境里核的项目,逐条列出:virt-launcher Pod 的 requests 与 limits 是否覆盖了"guest 内存加开销";PVC 的 accessModes 字段是 ReadWriteOnce 还是 ReadWriteMany;CDI 导入走的是 URL、registry 还是 PVC 克隆,以及并发上限设了多少;节点 conntrack 当前条目数、上限以及使用率告警阈值;巨页预留量、粒度(2M 还是 1G)以及跨 NUMA 的分配是否均衡;CPU Manager 策略、拓扑管理器策略以及预留核数;qemu 线程的实际 CPU 亲和掩码是否真的做到了独占。
核对方法:用 kubectl 读取 VirtualMachine 与 virt-launcher Pod 的定义与状态,对比声明值和实际分配值;在节点上用内核接口和 perf 读取巨页使用量、NUMA 分布和 TLB 相关计数器;用一次真实的在线迁移测试来测量迁移耗时与业务侧抖动,而不是只看文档说支持;用批量开机演练来测量存储的瞬时写入峰值和恢复时间,不要在交付当天才第一次跑这个流程。
本文不涉及任何价格数字。服务器租用、带宽、IP、存储扩容等费用项一律需询价,公开渠道差异较大,以实时报价为准。文中所有比例、台数与规格数字为工程经验值(预估),用于建立容量计算框架,落地前需在目标硬件与负载上压测验证,不作为实测数据引用。
一万网络深耕 19 年(成立于 2007 年),可提供上述混部形态的服务器租用以及带宽、IP、共享存储与本地盘方案;具体机型、计费周期与支持边界需询价,公开渠道差异较大,以实时报价为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品