gVisor 评测:runsc 应用内核如何隔离容器,以及它不适合谁
项目速览:容器应用程序内核。 runsc 运行时与 Docker 和 Kubernetes 集成,使运行沙盒容器变得简单。
秒懂
- 它是什么?
- gVisor 用 Go 写了一个用户态应用内核,通过 runsc 运行时接入 Docker 和 Kubernetes。它比 VM 轻、比普通容器隔离强,但性能和兼容性有代价。本文基于官方文档与仓库信息,说明它的机制、用法、局限和替代方案。
- 适合谁用?
- gVisor 适合需要把不可信代码放进容器、但又不想付出完整虚拟机开销的团队,尤其是多租户 SaaS 或 CI 执行环境。它不适合追求极致性能的批处理任务,也不适合依赖未实现 syscall 或特殊设备驱动的应用。
- 能商用吗?
- 可以。Apache-2.0 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
- 还在维护吗?
- 在维护。仓库在最近一天内有新的提交。
- 用什么语言写的?
- 主要是 Go(依据 GitHub 的语言统计)。
以上回答依据项目的 GitHub 数据(最近同步于 2026年9月15日)和我们的分析,不构成法律意见。
开源项目深度解析
容器不是沙箱,gVisor 想补这个洞
普通容器共享宿主内核,一个漏洞就可能造成容器逃逸。gVisor 的出发点很简单:容器不是沙箱。它不想做 seccomp-bpf 那样的系统调用过滤器,也不想做基于 Linux 隔离原语的包装器。gVisor 走第三条路,在用户态实现一个应用内核,用 Go 写,运行在用户空间。这个内核拦截应用的系统调用,自己处理,而不是直接传给宿主内核。这样一来,应用看到的 Linux 接口是 gVisor 模拟出来的,宿主内核的暴露面被大幅缩小。gVisor 面向的是需要运行不可信代码的场景,比如多租户服务或 CI 执行环境。它不解决外部攻击或数据泄露问题,文档明确提醒,要小心容器里放了什么数据。
runsc 不是虚拟机,也不是过滤器,它是应用内核
gVisor 的核心是 runsc,一个符合 OCI 规范的运行时。Docker 和 Kubernetes 都能通过它启动沙箱容器。runsc 不是虚拟机,它不模拟硬件,也不跑完整客户机操作系统。它也不是 syscall 过滤器,它不逐个放行或拦截系统调用,而是实现了一个完整的 Linux 内核接口。这个内核用 Go 编写,运行在用户态,通过宿主内核的普通进程机制运行。gVisor 文档说它“用 Linux 的方式实现 Linux”,意思是它借助宿主内核的线程、内存管理和文件系统功能,但应用的系统调用由 gVisor 自己处理。这种设计让 gVisor 保持用户态程序的启动速度和资源占用,同时提供接近虚拟机的隔离强度。但代价是,每个系统调用都要经过一层转换,性能不可能和原生容器一样。
从源码构建 runsc,命令和依赖
gVisor 官方推荐用 Bazel 构建,但为了简化,Makefile 把 Bazel 和依赖封装在一个构建容器里。你需要 Linux 5.6 以上内核和 Docker 17.09 以上版本。构建发布包的命令是 make release-tarball DESTINATION=bin/,然后解压到 /usr/local/bin。这个 tarball 包含 runsc、containerd-shim-runsc-v1 以及几个 runsc 依赖的侧车二进制,它们必须放在 runsc 旁边的 gvisor-bin/ 目录里。如果你想直接构建某个库,比如网络栈,可以指定目标 make build TARGETS="//pkg/tcpip:tcpip"。不用 Docker 直接跑 Bazel 也行,但官方不推荐,因为依赖列表很长,需要看 images/default/Dockerfile。测试命令是 make unit-tests 和 make tests,也可以指定单个测试。macOS 上只能跑部分包的测试,需要 bazel 8。注意,go get 方式只适用于导入 gVisor 子包,比如 Netstack,runsc 本身不支持从 go 分支构建。
性能损耗和兼容性,这是最大的坑
gVisor 的隔离强度来自系统调用拦截,这直接带来性能开销。文档没有给出具体基准数字,但任何了解系统调用路径的人都能推断,每个 syscall 都要经过用户态内核处理,比直接进入宿主内核慢。对于 I/O 密集型或系统调用频繁的应用,性能下降会非常明显。兼容性方面,gVisor 实现的是 Linux 接口,但不是完整实现。某些 syscall 可能不支持,某些行为可能和原生 Linux 不同。文档没有列出具体不支持的功能,但明确说它是“Linux-like interface”,不是完整 Linux。如果你的应用依赖特殊设备、内核模块或某些高级网络功能,很可能跑不起来。在部署前,你必须用你的实际工作负载做测试,而不是假设它能跑任何容器。
和 seccomp、Kata Containers 的路线差异
gVisor 的替代方案不是另一个运行时那么简单,而是隔离策略的根本不同。seccomp-bpf 是 syscall 过滤器,它允许或禁止特定系统调用,但应用仍然直接和宿主内核交互。AppArmor 和 firejail 是包装器,它们限制资源或路径,但不拦截系统调用本身。这些工具轻量,但隔离强度有限,一个漏洞可能绕过过滤。Kata Containers 是真正的轻量虚拟机,每个容器跑在独立的 VM 里,硬件虚拟化提供强隔离,但启动速度和内存占用比 gVisor 高。gVisor 的定位在中间,它不模拟硬件,也不做过滤器,而是自己实现内核。如果你需要强隔离且能接受性能损耗,Kata 是备选;如果你只想降低风险且性能敏感,seccomp 加 AppArmor 可能更合适。gVisor 适合那些既想要 VM 级隔离、又不想付 VM 开销的场景。
维护成本和许可证,升级是常态
gVisor 的发布节奏很快,最近一个版本是 20260817.0,发布时间是 2026 年 8 月 25 日。这意味着安全修复和功能更新持续不断,但你也得持续跟进。runsc 是二进制,升级时你需要重新构建或下载新版本,并确保 gvisor-bin/ 目录里的侧车二进制匹配。containerd-shim-runsc-v1 也需要同步更新。gVisor 使用 Apache-2.0 许可证,这对商业使用友好,但你自己构建时要注意 Bazel 依赖的许可。文档提到 go 分支是合成分支,只用于导入子包,runsc 构建不支持,这增加了维护复杂度:如果你用 go get 依赖 gVisor 的 Netstack,要注意 go 分支和 master 的同步可能滞后。社区治理有 GOVERNANCE.md,生产用户列在 ADOPTERS.md,但文档没有给出具体用户名单,所以不要依赖这些文件来评估稳定性。
谁该用,谁不该用,先验证什么
gVisor 适合运行不可信代码的容器环境,比如处理用户提交的代码、多租户后端或 CI 执行器。它不适合性能敏感的生产服务,也不适合依赖完整 Linux 特性的应用。在决定采用前,先用你的实际镜像跑一遍 runsc,检查所有功能是否正常。特别要测试网络和文件系统操作,因为这两块是系统调用最密集的地方。Kubernetes 用户可以通过 RuntimeClass 将 runsc 作为替代运行时,但你需要先验证 containerd-shim-runsc-v1 的集成。Docker 用户可以直接用 runsc 作为运行时,但要注意 Docker 版本要求。最后,检查 gvisor.dev 的快速入门指南,那里有最新的配置示例。gVisor 不是银弹,它是个有明确取舍的工具,用对场景是隔离利器,用错场景是性能灾难。
编辑结论
gVisor 适合需要把不可信代码放进容器、但又不想付出完整虚拟机开销的团队,尤其是多租户 SaaS 或 CI 执行环境。它不适合追求极致性能的批处理任务,也不适合依赖未实现 syscall 或特殊设备驱动的应用。对 Kubernetes 用户,先验证你的工作负载是否能在 runsc 下通过测试,再考虑用 RuntimeClass 逐步替换默认运行时。对 Docker 用户,先跑一遍官方 quick start,确认网络和挂载行为符合预期。gVisor 的维护成本不低:你需要跟踪 runsc 的版本更新,因为安全修复会持续发布,而且升级可能改变行为。如果你的应用对 syscall 兼容性要求苛刻,或者你无法接受性能损耗,那么 gVisor 不是正确工具,你应该继续使用普通容器并配合 seccomp 和 AppArmor,或者直接上 Kata Containers。
社区笔记