一文看透「容器运行时」与「容器构建」:大白话拆解 containerd、runc 与 BuildKit
前言
很多同学刚接触容器技术时,眼里只有 Docker。但随着技术的演进,尤其是 Kubernetes(K8s)统一江湖后,各种硬核名词扑面而来:containerd、dockerd、runc、runsc、nerdctl、BuildKit……
面试被问到一脸懵?看官方文档觉得像天书?
别慌!今天我们用**”费曼技巧”,把这些高深的概念全部放进”拍电影”和”开饭店”的生活场景里,保证你几分钟就能把现代容器生态里的容器运行时与容器构建**底层逻辑彻底扒干洗净!
一、 容器运行时到底是个啥?(剧组拍戏篇)
简单来说,容器运行时就是**”让容器真正跑起来的幕后包工头”**。
早年间 Docker 大包大揽,什么活都干。后来 K8s 嫌它太臃肿,于是业界定了一个标准(CRI),把”跑容器”这个最核心的苦力活拆分了出来,这就诞生了各种独立的”容器运行时”。
把运行一个容器,想象成**”剧组拍戏”**。容器运行时分为两类,它们分工明确:
1. 高级运行时(High-level Runtime):剧组统筹(制片主任)
- 代表人物:
containerd(目前最火,Docker 和 K8s 都在用)、CRI-O - 它的工作:负责整体调配后勤。它不管演员具体怎么演戏,只负责去网上把剧本下载下来(拉取镜像)、解压剧本、安排拍摄场地和盒饭(网络和存储管理)。
2. 低级运行时(Low-level Runtime):现场执行导演
- 它的工作:只干最核心的一件事——盯着演员演戏。统筹把场地准备好后,它负责在现场喊”Action!”,给演员划定好活动范围(系统隔离 Namespace)和预算(资源限制 Cgroups),让代码真正跑起来。
二、 乱花渐欲迷人眼:runc / runv / runsc / rund 有何不同?
既然低级运行时是”执行导演”,那根据拍摄环境的危险程度(对安全隔离的要求),业界诞生了四位风格迥异的导演。
想象你需要安排演员(代码)在剧组(服务器)里住宿,这四个运行时代表了四种安保方案:
- runc(标准大开间):行业默认标准(90%以上的容器都在用)。大家住在同一个大厂房里(共享宿主机内核),中间用薄木板隔开。优点是进出极快,成本极低;缺点是如果有人在房间放火(恶意攻击内核),整个厂房都会遭殃。
- runv(独立小别墅):Kata Containers 的前身。基于虚拟机技术,直接给每个演员建一栋带独立地基的小别墅(独立微型内核)。绝对安全,但启动慢、占资源。
- runsc(配私人管家的高级公寓):Google 开源的 gVisor。演员住公寓,但配了”私人管家”(用户态内核拦截)。演员不能直接碰大楼的电闸,必须让管家去操作。兼顾了安全和启动速度,是目前 Serverless(云函数)的最爱。
- rund(外星人培养皿):专为 WebAssembly(Wasm)设计的运行时。里面住的不是传统 Linux 程序,而是 Wasm 模块。极致轻量,毫秒级启动,未来边缘计算的明星。
三、 对讲机与大堂经理:docker、nerdctl 与 dockerd
很多同学在服务器上习惯了敲 docker run,但你是否知道这句命令背后经历了什么?这里我们要引入”开饭店”的比喻。
1. dockerd(饭店大堂经理)
- 角色定位:传统 Docker 架构的核心后台。它负责接待客人、设计菜单(打包镜像)、安排结账。
- 特点:功能大而全,但体量太重。
2. containerd(后厨厨师长)
- 角色定位:dockerd 的下属。他不关心客人是谁,只听指令去冷库拿食材(拉取镜像),然后开火炒菜(调用更底层的
runc启动容器)。 - 为什么 K8s 抛弃 Docker? K8s 觉得自己已经有大堂经理了,不需要
dockerd这个中间商赚差价,于是直接绕过它,通过 CRI 接口给后厨的containerd下单。这就有了著名的”K8s 弃用 Docker”事件。
3. docker 与 nerdctl(你手里的对讲机)
- docker CLI:老牌全能对讲机,专门呼叫
dockerd大堂经理。 - nerdctl:新式直连对讲机。为了适应没有
dockerd的纯containerd环境诞生。它完美兼容 docker 命令,但直接指挥containerd干活,更加轻量,还支持 P2P 镜像分发等黑科技。
四、 容器构建到底靠谁?dockerd vs BuildKit
既然纯 containerd 环境下没有了 dockerd(大堂经理),那镜像(菜谱)谁来构建?记住:containerd 只负责跑容器,绝对不会进行容器构建!
为了解决这个问题,社区把”容器构建”剥离出来,做成了一个独立的神器:BuildKit(专业菜谱研发员)。
传统 dockerd 构建 vs 现代 BuildKit 构建
把写 Dockerfile 打包镜像,想象成”盖一栋别墅”:
- dockerd(老式施工队):单线程干活。必须先盖一楼,再盖二楼,最后去院子种花。哪怕种花和盖楼不冲突,工人也得干等着。而且它会把你目录下所有无关的废文件都搬到工地(全量发送 Context),速度极慢。
- BuildKit(智能超级工厂):极度聪明。它会分析依赖树,发现”前端编译”和”后端编译”互不干扰,直接派两拨人并发干活;并且按需拿料,绝不多传废文件。配合多阶段构建,打包速度能起飞。
💡 避坑指南:
你以为你还在用落后的 dockerd 打包?其实从 Docker 23.0 开始,你敲下docker build时,后台默认早就在用 BuildKit 疯狂飙车了!而在纯 containerd 环境下,你只需要组合使用nerdctl build+buildkitd就能完美实现同样的极速容器构建。
五、 极客实操:如何切换底层运行导演?
懂了理论,我们来点硬核实操。假设你想在服务器上用更安全的 runsc(gVisor)或者跑 Wasm 的 rund,怎么把默认的 runc 换掉?
就像网约车平台呼叫”特种车辆”,只需要简单三步(以 containerd 为例):
Step 1:下载并安装”新导演”
将对应的二进制文件(如 containerd-wasm-shim 或 runsc)放入系统的 /usr/local/bin 目录。
Step 2:在总部登记(修改配置)
打开 containerd 的配置文件 /etc/containerd/config.toml,给新导演”上户口”:
1 | |
(修改后记得 systemctl restart containerd)
Step 3:点名上场(带参数运行)
使用对讲机发起呼叫时,带上 --runtime 参数:
1 | |
(注:如果你用的是 Docker Desktop,直接在设置中勾选 “Enable Wasm”,就可以用 docker run --runtime=io.containerd.wasmedge.v1 体验了!)
六、 总结与最佳实践
把这套解耦的积木拼在一起,现代容器生态的终极轻量化与高效架构其实是这样的:
- 发号施令:用
nerdctl(或 docker CLI)。 - 容器构建:呼叫
BuildKit,享受并发编译与高效缓存的快感。 - 统筹调度:交给
containerd(高级运行时)专心做大管家。 - 底层执行:根据场景选择低级运行时,普通业务用
runc,高安全需求切runsc,边缘计算玩rund。
技术的演进永远是朝着解耦、专业、轻量的方向发展。搞懂了容器运行时和容器构建的底层逻辑,以后无论 Kubernetes 怎么升级,还是各种新出的云原生工具,你都能一眼看透它们的本质。
📚 推荐进一步深入的参考资源
如果你想进一步修炼内功,千万不要错过以下高质量官方文档和权威资料:
- 容器运行时的基础心法:
- K8s 官方文档 - Container Runtimes
- 极客时间 - 张磊老师的《深入剖析 Kubernetes》专栏(透彻讲解 Namespace 与 Cgroups 的神作)
- 架构演进与大局观:
- K8s 官方博客 - Don’t Panic: Kubernetes and Docker (解释弃用 dockerd 的经典文章)
- containerd 官方网站架构图 - containerd.io
- 安全沙箱与底层隔离:
- Google gVisor 开源项目 - Architecture Guide(强烈建议看里面的隔离对比图)
- 轻量化容器构建与运行实战:
- GitHub 项目 - containerd/nerdctl
- Docker 官方文档 - BuildKit & Buildx (掌握多阶段构建与并发缓存机制必读)
- WasmEdge 官方文档 - Integration with Docker/containerd