news 2026/9/25 5:24:36

Kata Containers 限制与差异全景指南:VM 级容器运行时的已知限制、架构约束与规避方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kata Containers 限制与差异全景指南:VM 级容器运行时的已知限制、架构约束与规避方案
  • 云原生
  • 容器运行时

【免费下载链接】kata-containers

Kata Containers is an open source project and community working to build a standard implementation of lightweight Virtual Machines (VMs) that feel and perform like containers, but provide the workload isolation and security advantages of VMs. https://katacontainers.io/

项目地址:https://gitcode.com/gh_mirrors/ka/kata-containers
点击查看免费下载

Kata Containers 通过为每个容器负载启动独立、硬件隔离的虚拟机(VM)来换取更强的安全性与工作负载隔离,因此与默认的 Docker 运行时runc相比,在命令行行为、OCI 规范符合度、网络、存储与资源管理等方面存在一系列固有差异与限制。本指南基于 docs/Limitations.md 整理出完整限制清单,结合 src/runtime 与 src/agent 源码解释每项限制的成因、可复现的配置选项与当前规避方案,帮助你在使用 Kata Containers 之前评估功能兼容性、排查问题并为 Pod 清单提前规划安全边界。

为什么 VM 级容器会存在"限制"

一个 Kata Container 运行在由 hypervisor 启动的轻量级虚拟机内,每个 VM 拥有自己独立的内核,与宿主机之间通过精简的虚拟化设备(如 virtio)进行 I/O 交互。Kata Containers 运行时的架构可简要概括为:kata-runtime/containerd-shim-kata-v2位于宿主机侧负责解析 OCI 规范、配置并启动 VM,Kata Agent(src/agent)位于 guest 内部负责在虚拟机内创建真实容器。正因如此:

  • 容器内进程看到的是guest 内核而非宿主机内核;
  • 网络接口、块设备、文件系统共享等能力需要经过虚拟化层的中转;
  • 部分宿主机内核能力(如直接修改宿主网络配置)在 guest 内天然不可达。

更高的隔离度带来两类"限制":一类是可以修复的功能缺口(例如 CLI 命令未实现),另一类是由 VM 架构决定、本质上难以消除的差异(例如网络命名空间共享)。下文先明确"限制"的判定标准,再分别展开两类清单。

"限制"的定义:OCI 规范与runc双重标准

Open Container Initiative(OCI)Runtime Specification 定义了运行时与 Docker 等容器管理器互操作所需的最低规范。如果一个运行时不支持 OCI 规范的某些方面,按定义即构成一项"限制"。

但问题的复杂性在于参考实现runc自身也没有百分之百对齐 OCI 规范。Docker 默认使用runc,因此 Docker 事实上期望所有运行时"表现得像runc一样"。这等于存在两套标准:

  1. 官方的 OCI 规范;
  2. runc提供的非标准扩展行为。

这意味着一个要接入 Docker 生态的运行时必须同时兼容官方规范和runc的扩展行为,任何一处不一致都会在实际使用中表现为"限制"。理解这一点有助于区分:哪些限制是 Kata 自身缺陷,哪些是 VM 架构与runc行为模式的本质差异。

限制的跟踪方式

每一个已知限制都会被记录为一个单独的 GitHub issue,并打上limitation标签,本文档(docs/Limitations.md)是对这些 issue 的精选摘要。如果你准备在某个环境评估 Kata Containers 的适用性,应以带limitation标签的 issue 列表作为最新依据;仓库侧则以 docs/Limitations.md 为权威入口。新增限制可向 Kata 仓库提交 issue,修复限制则需遵循社区贡献指南。

可修复类限制(Pending items)

这类限制理论上存在修复路径,属于"当前未实现"而非"架构上不可能"。

OCI 命令行工具支持:Podman、Docker 与 containerd

  • Podman 暂不支持:Kata Containers 目前无法与 Podman 配合使用(对应 issue kata-containers#722)。
  • Docker 支持:Docker 自 22.06 起支持 Kata Containers,通过--runtime指定 shim v2 运行时即可:
sudo docker run --runtime io.containerd.kata.v2
  • 推荐路径是 containerd:Kata Containers 与 containerd 配合良好,官方建议使用 containerd 生态的 Docker 风格命令行工具nerdctl作为日常操作入口,例如:
sudo nerdctl run --runtime io.containerd.kata.v2 ...

也就是说,在 Kubernetes / containerd 场景下 Kata 功能完备,而在 Podman 场景下应避免选用。

runtime 子命令缺口

Kata 的运行时命令行(kata-runtime)目前存在三个子命令层面的缺口:

  • checkpoint与restore:运行时未提供这两个命令。社区在探讨借助 VM 的 save/restore 能力实现类似criu的功能(对应 issue runtime#184)。需要注意 OCI 规范本身并不规定checkpoint/restore命令,因此这是与runc对齐层面的差距。
  • events命令:未完整实现,其中OOM 通知与Intel RDT 统计两类事件不支持(对应 issue runtime#308、runtime#309)。同样,OCI 规范未规定events命令。
  • update命令:仅block I/O weight(块 I/O 权重)一项配置不支持,其余资源配置均已支持且工作正常。这意味着基于 cgroups v2 的内存、CPU 等动态更新能力是可用的。

网络相关限制

网络是 VM 架构下差异最集中的领域:

  • Host network 不支持:nerdctl/docker run --net=host以及 Kubernetes 的HostNetwork模式均不支持,原因是从 VM 内部无法直接访问宿主机网络配置。值得注意的是,--net=host仍可用于runc容器,并与 Kata 容器混合部署,从而在必要时保留 host 网络能力。但切勿将--net=host传给 Kata 容器——当前实现下这可能导致 Kata 容器的网络初始化流程去修改、重配宿主机网络,甚至破坏宿主机网络配置。
  • 不支持加入已有 VM 网络命名空间:Docker 的docker run --net=container:<id>允许容器共享另一容器的网络命名空间,Kata 不支持网络命名空间共享。若将 Kata 容器配置为共享某个runc容器的网络命名空间,运行时会把该命名空间中分配的所有网络接口"接管"并绑定到 VM,导致runc容器失去网络连接。
  • docker run --link不支持:该命令已被 Docker 弃用,Kata 无意支持;可用 Docker 新的网络命令实现等价功能。

资源管理:CPU 约束的挑战

由于 VM 在 CPU、内存分配与宿主机共享方式上与普通进程差异巨大,为 Kata 实现与runc等价的 CPU/内存约束命令存在较大难度(对应 issue clearcontainers/runtime#341)。CPU 约束的完整设计可参考 CPU constraints(runtime-go) 与 CPU constraints(runtime-rs) 两份设计文档,其中讨论了 vCPU 与容器 CPU 配额之间的映射关系,这也是下文"约束挑战"附录的重点。

架构性限制(Architectural limitations)

以下限制源于"软容器"(传统 Linux 容器)与基于 VM 的容器在架构上的根本差异,通常难以在不改变安全模型的前提下消除。

存储限制

Block 型 KubernetesemptyDir卷与sizeLimit

Kubernetes 的emptydir_mode中block-plain与block-encrypted两种变体,目前不会以 Kubernetes 的emptyDir.sizeLimit作为呈现给 guest 的块设备容量。原因是 CRI 挂载信息中并不包含sizeLimit,shim 只能将稀疏后备镜像(sparse backing image)大小设置为承载该emptyDir的宿主机文件系统的总容量。

由此产生一个隐蔽的问题:在宿主机文件系统很大的情况下,对逻辑上很大的镜像做 ext4 元数据初始化会占用大量物理宿主机存储。kubelet 会把这部分已分配块计入emptyDir用量,因此:

  • 即使工作负载几乎没写数据,元数据开销也可能超过较小的sizeLimit,导致 Pod 被驱逐;
  • 即便没有立即超过限额,这部分开销也压缩了应用实际可写的数据量,使 Pod 提前触发 kubelet 的驱逐判定。

按当前文档记录,block-plain模式下 ext4 文件系统元数据分配约占逻辑文件系统大小的0.08%(精确值取决于 ext4 格式化选项与e2fsprogs版本);block-encrypted还会有额外的加密与完整性元数据开销——在一次 2.9 TB 逻辑文件系统的测试中,额外开销约 50 MB,而总元数据分配约 2.5 GB。

当前规避手段(尚无配置项能直接封顶 block 型emptyDir镜像大小):

  1. 为sizeLimit预留足够的元数据余量(即令sizeLimit大于宿主文件系统大小的 0.08% 以上);
  2. 将 kubelet 的卷数据放在更小的专用文件系统上。

该问题的潜在修复方案跟踪于 issue kata-containers#2438。

源码佐证:emptydir_mode的定义位于 configuration-qemu.toml.in,注释明确给出三种取值:

  • shared-fs(默认):通过shared_fs指定的方法将 emptyDir 目录共享给 guest;
  • block-encrypted:在 guest 内插入一个加密块设备;
  • block-plain:在 guest 内直接挂载块设备。

对应常量定义于 kata_agent.go:EmptyDirModeSharedFs = "shared-fs"、EmptyDirModeVirtioBlkEncrypted = "block-encrypted"、EmptyDirModeVirtioBlkPlain = "block-plain";取值校验在 config.go 的emptyDirMode()中完成,非法值会报错。另外disable_guest_empty_dir(configuration-qemu.toml.in)可以在关闭 guest 文件系统 emptyDir 的同时改用 virtio-fs 从宿主机共享。实际挂载逻辑分支见 container.go。

KubernetesvolumeMounts.subPath

Kata Containers 目前不支持volumeMount.subPath(对应 issue runtime#2812;专门针对emptyDir的 subPath 场景见 issue kata-containers#1728)。在使用 Kata 运行工作负载时,应避免依赖 subPath 定向挂载卷的子目录。

KuberneteshostPath卷

在 Kata 中,hostPath卷可以通过文件系统共享把宿主机目录和普通文件挂载进 guest VM,前提是shared_fs配置项已启用(配置说明见 src/runtime/README.md#configuration)。默认行为分两种环境:

  • 非 TEE 环境:使用文件系统共享(如 virtio-fs)挂载宿主文件;
  • TEE 环境(如 TDX/SEV/SNP):文件系统共享被禁用,宿主文件在容器启动时被复制进 guest VM,此后宿主与 guest 之间的文件变更不再同步。

此外 hostPath 在 Kata 中还有两类与runc明显不同的特殊行为:

  • 挂载宿主块设备:当 hostPath 卷类型为BlockDevice时,Kata 会把宿主块设备**热插拔(hotplug)**进 guest,并直接暴露给容器。
  • 挂载 guest 设备:当 hostPath 的源路径位于/dev之下(或就是/dev),且该路径对应的是非普通文件(设备、目录或其他特殊文件),或该路径对 Kata shim 不可访问时,Kata Agent 会直接从guest 文件系统将该路径 bind mount 进容器。
procfs与sysfs挂载限制

出于安全考虑,以下挂载被明确禁止:

TypeSourceDestinationRationale
bind!= proc/procCVE-2019-16884
bind*/proc/*(下述例外除外)CVE-2019-16884
proc \|\| sysfs*非目录(如符号链接)CVE-2019-19921

/proc下的 bind 挂载仅允许以下 8 个目的路径:

  • /proc/cpuinfo
  • /proc/diskstats
  • /proc/meminfo
  • /proc/stat
  • /proc/swaps
  • /proc/uptime
  • /proc/loadavg
  • /proc/net/dev

源码佐证:这条白名单与 guest 侧实现一一对应。Kata Agent 的 rustjail 组件在 mount.rs 中实现check_proc_mount():白名单数组(/proc/cpuinfo、/proc/diskstats、/proc/meminfo、/proc/stat、/proc/swaps、/proc/uptime、/proc/loadavg、/proc/net/dev)与文档完全一致;挂载到/proc时必须校验源为proc超级块(PROC_SUPER_MAGIC),其余/proc/*目的地直接拒绝。同时 mount.rs 对proc/sysfs类型挂载检查目标必须是普通目录,防止经符号链接挂载(对应 CVE-2019-19921)。单元测试见 mount.rs。

特权容器(Privileged containers)

Kata 对特权容器的支持与runc本质不同:容器在 guest 内以提升的 capabilities 运行,Kubernetes 中securityContext.privileged=true同理。但Kata 不支持默认的"将宿主设备透传给特权容器"行为,使用特权容器前必须显式关闭该默认行为,具体配置步骤见 Privileged Kata Containers。这意味着原本依赖宿主设备透传的特权工作负载需要重新设计为显式设备挂载/热插拔方案。

Guest 内拉取镜像(guest-pull)与用户/组 ID

当使用nydus guest-pull这类在 guest 内部拉取镜像的功能时,必须在 Pod 清单中显式设置 user/group ID。若省略 ID 值:

  • 工作负载可能以意外的 user/group ID 执行——因为镜像层对 containerd 不可用,镜像配置(含 user/group 信息)不会被应用;
  • 若同时启用 policy 或 genpolicy,生成的策略可能检测到这些意外值,拒绝创建工作负载容器。

正确做法是显式设置securityContext:Pod 级使用spec.securityContext(Pod)或spec.template.spec.securityContext(Deployment 等控制器),容器级使用spec.containers[].securityContext,至少包含:

  • runAsUser— 主用户 ID
  • runAsGroup— 主组 ID
  • fsGroup— 卷组所有权(常体现为附加组)
  • supplementalGroups— 附加组 ID 列表(按需)

官方给出的示例:

# Explicit user/group/supplementary groups to support nydus guest-pull securityContext: runAsUser: 0 runAsGroup: 0 fsGroup: 0 supplementalGroups: [1, 2, 3, 4, 6, 10, 11, 20, 26, 27]

源码佐证:guest-pull 的落地依赖 agent 侧镜像拉取能力,相关挂载点处理与镜像层持久化逻辑可参见 agent/src/storage/mod.rs 与 agent/src/storage/multi_layer_erofs.rs,其中processed_mount_points机制负责跟踪 guest 内已处理的挂载点,印证镜像层由 guest 侧管理、宿主机 containerd 不可见的设计。

附录:约束挑战(The Constraints Challenge)

将 cgroup、CPU、内存、存储等资源约束应用到工作负载,在 VM 架构下并不总是直截了当的。Kata 容器运行于虚拟机内的隔离环境中,结合 Kata 的整体架构,约束可施加的"层级与上下文"比传统 Linux 容器多得多,有时需要把约束同时施加到多个层面,有时 VM 的硬件隔离本身就提供了等价于所请求约束的能力。可施加约束的层面包括:

  • VM 内部:约束 guest 内核。可通过 guest 内核启动命令行传入特定值,或在早期启动阶段应用 sysctl 值实现。
  • 容器内部:约束 VM 内创建的容器本身。
  • VM 外部:
    • 约束 hypervisor 进程——通过施加宿主级约束实现;
    • 约束 hypervisor 内运行的所有进程——通过指定特定的 hypervisor 配置选项实现。

需要注意的是,在某些场景下需要同时对上述多个层面施加约束,才能达到期望的隔离与资源控制水平。以 CPU 为例,vCPU 分配、guest 内核调度与容器 cgroup 三个层面共同决定最终效果,这也是为什么 CPU 约束需要参考 runtime-go 设计文档 与 runtime-rs 设计文档 来理解其完整语义。

小结:使用 Kata Containers 前的限制自查清单

基于上述限制清单,为生产环境评估 Kata Containers 时可快速自查以下几点:

  1. 运行时入口:使用 containerd / nerdctl / Docker 22.06+(--runtime io.containerd.kata.v2),避免 Podman。
  2. 网络:不使用--net=host、HostNetwork、--net=container共享、--link;网络命名空间共享类编排模式需改为 Kata 原生网络方案。
  3. 命令面:不依赖checkpoint/restore、events(OOM/RDT)与update的 block I/O weight 能力。
  4. 存储:规避volumeMount.subPath;block 型emptyDir需为sizeLimit预留 ≥0.08% 宿主文件系统大小的元数据余量或使用专用小文件系统;hostPath 需区分共享/复制两种模式并注意块设备热插拔行为;不要 bind 挂载/proc、/proc/*或把 proc/sysfs 挂到非目录目标。
  5. 安全模型:特权容器不自动透传宿主设备;TEE 环境下文件不同步;guest-pull 场景显式设置runAsUser/runAsGroup/fsGroup/supplementalGroups。
  6. 资源约束:理解 CPU/内存约束需在 guest 内核、容器与 hypervisor 进程多个层面联合设计,参考 vcpu-handling 设计文档确认映射关系。

以上每一项限制都对应明确的 issue 跟踪与源码实现位置,排查问题时可直接按本文给出的文件路径深入对应模块。

  • 云原生
  • 容器运行时

【免费下载链接】kata-containers

Kata Containers is an open source project and community working to build a standard implementation of lightweight Virtual Machines (VMs) that feel and perform like containers, but provide the workload isolation and security advantages of VMs. https://katacontainers.io/

项目地址:https://gitcode.com/gh_mirrors/ka/kata-containers
点击查看免费下载

相关推荐

上一篇:K8M自动伸缩:HPA与VPA实战指南
下一篇:异步HTTP客户端自定义SSL引擎:SslEngineFactory实现终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!