【K8s笔记】kubernetes的容器

containerd & runc

containerd 和 runc 的关系在容器运行时体系中非常重要,经常被问到。可以用一句话概括:

containerd 是一个高级的容器管理器,runc 是底层的容器运行工具,containerd 调用 runc 来创建和管理容器进程。

下面详细解释:


1. 各自是什么?

  • containerd
    一个容器运行时守护进程,负责容器的整个生命周期管理,包括镜像管理、容器创建、启动、停止、快照、网络、日志等。
    它有 gRPC API,可以被 Kubernetes、Docker 等上层调用。

  • runc
    一个容器运行时工具,是 OCI Runtime 规范 的参考实现,
    负责按照 OCI 标准把一个 rootfs(文件系统)和配置变成一个真正的 Linux 容器进程(用 Linux namespace、cgroups 等技术)。


2. 它们的关系

  • containerd 负责“管理”,runc 负责“启动”。
  • 当你用 Kubernetes 或 Docker 创建容器时,containerd 会处理大部分管理流程。
  • 真正到“启动容器进程”这一步时,containerd 会调用 runc(通过 containerd-shim-runc-v2 这个 shim 进程),让 runc 去创建容器进程。
  • runc 启动容器后就退出,由 shim 进程继续托管容器进程。

图示关系

1
2
3
4
5
[Kubernetes/Docker]

(API)

[containerd] ---(调用)---> [containerd-shim-runc-v2] ---(调用)---> [runc] ---> [容器进程]
  • containerd 负责生命周期和管理
  • runc 只负责一次性的“启动”容器进程

3. 为什么要这样分层?

  • 解耦:containerd 可以支持不同的 runtime(不仅仅是 runc,比如 crun、Kata 等)
  • 安全与隔离:shim 进程隔离 containerd 和容器进程,提升稳定性
  • 符合标准:runc 遵循 OCI 规范,生态兼容性好

4. 一句话总结

containerd 是容器管理器,runc 是容器启动器,containerd 通过 shim 调用 runc 创建容器,runc 启动后退出,shim 继续托管容器进程。

docker & containred & runc

这个问题非常经典,也是容器生态里容易混淆的地方。Docker 和 runc 的关系可以这样理解:


1. 各自是什么?

  • Docker
    是一个完整的容器引擎/平台,提供了镜像管理、容器管理、网络、存储等全套功能。用户常用的 docker 命令其实是 Docker 的客户端,底层有 Docker Daemon(服务端)。

  • runc
    是一个容器运行时工具,实现了 OCI Runtime 规范,专门负责把容器文件系统和配置变成实际的 Linux 容器进程(用 namespace、cgroup 等技术)。


2. 谁调用谁?

  • Docker 不是直接“运行”容器的。
  • Docker 的后台服务(dockerd)会调用 containerd(作为容器管理组件)。
  • containerd 再调用 runc(通过 shim),让 runc 去启动容器进程。

所以:

Docker → containerd → runc → 容器进程


图示关系

1
2
3
4
5
6
7
8
9
10
11
[docker 命令]

[dockerd(Docker Daemon)]

[containerd]

[containerd-shim-runc-v2]

[runc]

[容器进程]

3. 关系本质

  • Docker 是“上层管理者”,runc 是“底层启动器”
  • Docker 负责用户体验、API、镜像、网络等全套生态
  • runc 只负责把容器真正跑起来(一次性启动进程),遵循 OCI 标准

4. 为什么要这样设计?

  • 分层解耦,方便替换和扩展(比如可以用 crun、kata 替换 runc)
  • 标准化,runc 遵循 OCI 规范,兼容性好
  • 安全稳定,shim 进程隔离,防止 dockerd 崩溃影响容器

5. 一句话总结

Docker 通过 containerd 间接调用 runc,runc 负责把容器进程真正运行起来。Docker 是“总管”,runc 是“工人”。

ctr & crictl

ctrcrictl 都是和容器运行时(比如 containerd)打交道的命令行工具,但它们的定位、用途和接口层级是不同的。


1. ctrcrictl 的关系与区别

工具名 直接操作对象 主要用途 典型场景 适用人群
ctr containerd 内部API 底层容器调试和管理 containerd开发/调试 运维/开发/底层专家
crictl CRI(K8s标准接口) Kubernetes容器调试 K8s集群运维/排障 K8s运维/开发

2. 具体解释

ctr

  • 作用:直接通过 containerd 的本地 API 操作容器、镜像、命名空间等。
  • 接口:调用的是 containerd 的原生 API(比 CRI 更底层)。
  • 特点:功能强大但复杂,操作不受 K8s 约束,能做很多底层操作(甚至是 K8s 不允许的)。
  • 典型命令ctr images listctr containers listctr tasks start ...

crictl

  • 作用:通过 CRI(Container Runtime Interface,K8s 的容器运行时接口)与 containerd 等运行时交互。
  • 接口:调用的是 CRI gRPC 接口(K8s 标准接口),K8s 直接用的就是这个接口。
  • 特点:只支持 K8s 规范允许的操作,适合排查 Pod、容器、镜像等 K8s 相关问题。
  • 典型命令crictl pscrictl imagescrictl logs ...

3. 关系总结

  • ctr 是 containerd 的“原生”命令行工具,直接操作 containerd,功能最全最底层。
  • crictl 是对接 Kubernetes(通过 CRI)的通用命令行工具,只做 K8s 允许的操作。
  • crictl 的底层实现最终可能还是调用 containerd,但它中间隔了一层 CRI 适配,安全且受控。

4. 简单类比

  • ctr:直接操作 containerd 的“原生”接口,相当于直接和发动机对话,能做一切底层操作。
  • crictl:通过 Kubernetes 的 CRI(容器运行时接口)和 containerd 交互,相当于通过一层“标准协议”来控制发动机,只能做 K8s 允许的事情。

5. 关系图

1
2
3
4
5
6
7
Kubernetes

CRI(标准接口)

ctr(直接操作底层)

containerd(容器运行时)
  • crictl 是通过 CRI 这层接口来管理 containerd
  • ctr 是直接管理 containerd

6. 举例

  • K8s 集群中排查 Pod 问题:用 crictl
  • containerd 本身出问题、需要做底层调试:用 ctr
  • 日常开发:通常用 docker(如果是 Docker 引擎)
  • ctr 能做的事更多,比如直接操作命名空间、快照、底层镜像管理等,K8s 不一定允许你这么做。
  • crictl 只能做 K8s 允许的操作,比如查看 Pod 容器、日志、拉取镜像等。

总结一句话

ctr 是 containerd 的底层命令行工具,crictl 是 Kubernetes 标准接口(CRI)的命令行工具,两者都能管理容器,但服务的对象和场景不同。

kubelet & container

kubelet 直接操作 Docker、containerd 这些容器运行时(container runtime),来实现容器的创建、启动、停止等功能。


具体来说:

1. kubelet 通过 CRI 跟容器运行时通信

  • 早期(K8s 1.6 之前):kubelet 直接调用 Docker 的 API。
  • 后来:Kubernetes 推出了 CRI(Container Runtime Interface),让 kubelet 能通过统一接口对接不同的容器运行时。
    • 这样 kubelet 就不仅能用 Docker,还能用 containerd、CRI-O 等。

2. 工作流程

  1. kubelet 从 kube-apiserver 获取本节点需要运行的 Pod 信息。
  2. kubelet 根据 PodSpec,调用容器运行时(比如 containerd、Docker)启动或停止容器。
  3. kubelet 监控这些容器的运行状态,并上报给 apiserver。

图示关系

1
2
3
4
5
6
7
8
kubelet

│ 通过 CRI(gRPC 接口)

containerd / Docker / CRI-O 等


实际的容器进程

注意

  • Docker 不是唯一的容器运行时,containerd 现在用得更多(因为 Docker 其实底层也是用 containerd)。
  • K8s 1.24 以后官方已移除对 Docker 的直接支持(即 dockershim 被移除了),推荐直接用 containerd、CRI-O 等。

总结一句话

kubelet 就是通过 CRI 这个标准接口,直接“指挥” Docker、containerd 这些容器运行时,让它们去启动、停止和管理容器。

runc & lxc

你这个问题非常好,runc 和 lxc 确实可以类比,它们都属于“容器运行时”,本质上都是利用 Linux 的 namespace 和 cgroup 技术来实现进程隔离。但它们之间还是有一些区别的。


一、相同点

  • 都是容器运行时(Container Runtime):都能直接在 Linux 主机上创建和管理隔离的容器进程。
  • 都用 Linux 内核的 namespace、cgroup 技术来实现资源和环境隔离。
  • 都不做硬件虚拟化,不启动新内核,而是让容器共享宿主机的内核。

二、主要区别

对比点 runc lxc
标准 OCI(Open Container Initiative) LXC 自有规范
生态 Docker、containerd、Kubernetes 等 LXD、Proxmox、独立用法等
设计理念 “只做一件事”:只负责容器启动/停止 更像“轻量级虚拟机”,功能更全
配置方式 通过 OCI runtime spec(json 文件) 通过 lxc 配置文件
管理能力 只做容器生命周期(不监控/管理) 提供丰富的管理命令和工具
复杂度 轻量、专注于 runtime 功能丰富,支持更多高级特性

更直观地说:

  • runc 是 Docker、containerd 这类现代容器平台的底层“发动机”,只关注启动/停止一个容器进程
  • lxc 更像是一个“传统的容器管理套件”,既能启动容器,也能管理、监控、配置网络、挂载等,功能更丰富。

三、关系和发展

  • lxc 是最早的 Linux 容器实现之一,docker 早期其实就是基于 lxc 的。
  • 后来社区推动标准化,出现了 OCI 规范,runc 就是 OCI 标准的实现,成为现代容器生态(Docker、K8s)的基石。

四、总结一句话

runc 和 lxc 都是容器运行时,原理类似,但 runc 更加专注、轻量,符合 OCI 标准,主要为现代云原生和容器平台服务;lxc 更像传统容器的“全功能套件”,适合需要复杂管理的场景。


【K8s笔记】kubernetes的容器
https://学习.fun/k8s-note/k8s-container/
Author
Stephen Zeng
Posted on
April 29, 2025
Licensed under