Skip to main content
☘️ Septvean's Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

runc

这是一个容器领域里“最底层、最核心、但又最容易被忽略”的组件

内容:定位 -> 架构 -> 生命周期 -> 内核机制 -> 与 Docker / containerd 的关系 -> 为什么必须理解 runc。

一句话定位(先记住)

runc 是一个“把 Linux 内核能力真正用起来”的程序:

它负责把 namespaces、cgroups、capabilities、seccomp 等配置,转化为一个真正运行中的 Linux 进程。

  • 📌 runc 本身不是守护进程
  • 📌 runc 启动完容器就退出
  • 📌 容器 = 被 runc 创建并配置的普通 Linux 进程

一、runc 在容器体系中的位置

容器完整技术栈(自上而下)

┌───────────────────────────┐
│ Kubernetes / Docker CLI   │
├───────────────────────────┤
│ containerd / cri-o        │
├───────────────────────────┤
│ runc                      │ <-【核心】
├───────────────────────────┤
│ Linux Kernel              │
│ namespaces / cgroups / fs │
└───────────────────────────┘

👉 所有 OCI 标准容器,最终都由 runc 创建

二、runc 是什么?

不是虚拟机!

runc 的本质

  • 一个 CLI 程序
  • 用 Go 编写
  • 实现 OCI Runtime Specification

功能只有一个:创建 + 启动 一个进程,并套上隔离与限制

三、OCI Runtime Spec 简介(runc 的合同)

OCI 定义了三样东西:

  1. filesystem layout
  2. config.json
  3. runtime behavior

config.json(核心)

{
  "process": {
    "args": ["mysql"],
    "env": ["PATH=/usr/bin"],
    "cwd": "/"
  },
  "root": {
    "path": "rootfs",
    "readonly": false
  },
  "linux": {
    "namespaces": [
      { "type": "pid" },
      { "type": "net" },
      { "type": "mnt" }
    ],
    "resources": {
      "cpu": {},
      "memory": {}
    }
  }
}

📌 runc 就是 config.json 的“执行器”

四、runc 创建容器的完整生命周期(重点)

1️⃣ runc create

runc create mycontainer

runc 做了什么:

  1. clone() 创建进程
  2. 设置 namespaces
  3. 设置 cgroups
  4. mount rootfs
  5. 设置 capabilities
  6. 准备但不执行 ENTRYPOINT

📌 容器进程:Paused 状态

2️⃣ runc start

runc start mycontainer
  • 执行 config.json 中的进程
  • PID 诞生
  • 容器“活了”

3️⃣ runc kill / delete

  • 发送信号
  • 清理 cgroups
  • 清理 namespace 句柄

五、runc 如何使用 Linux 内核能力?

1️⃣ Namespaces(隔离)

Namespace 隔离什么
pid 进程
net 网络
mnt 文件系统
uts hostname
ipc 共享内存
user UID/GID

📌 runc 调用 clone(CLONE_NEW)

2️⃣ cgroups(资源限制)

资源 控制
CPU quota / shares
Memory limit / swap
IO blkio
PIDs 最大进程数

📌 直接写 /sys/fs/cgroup

3️⃣ Capabilities(权限收缩)

CAP_SYS_ADMIN ❌
CAP_NET_ADMIN ❌
CAP_CHOWN ✅

👉 容器 root ≠ 宿主机 root

4️⃣ Seccomp(系统调用过滤)

"seccomp": {
  "defaultAction": "SCMP_ACT_ERRNO",
  "syscalls": [
    { "names": ["read", "write"], "action": "SCMP_ACT_ALLOW" }
  ]
}

📌 减少攻击面

六、runc 与 containerd / Docker 的关系

Docker 实际调用链

docker run
 -> dockerd
   -> containerd
     -> containerd-shim
       -> runc

为什么要有 containerd-shim?

  • runc 退出后容器仍需存在
  • shim 持有 stdio
  • shim 处理信号 & exit code

📌 runc 不常驻

七、runc 与虚拟机的根本区别

对比项 runc / container 虚拟机
内核 宿主机 独立
启动 ms 级 秒级
隔离 进程级 硬件级
安全 依赖内核
资源开销 极低

八、为什么“容器逃逸”几乎都是 runc 相关?

因为:

  • runc 运行在 宿主机 root
  • 操作 namespaces / mount
  • 任何漏洞 = root 权限

📌 历史漏洞:

  • CVE-2019-5736(容器覆盖 runc 二进制)

九、为什么必须理解 runc?

理解 runc 等于:

  • 理解 容器的真实边界
  • 理解 容器 ≠ VM
  • 理解 数据库为什么绕不过 overlay2
  • 理解 cgroups/NUMA/IO 调优的生效点

📌 容器不是魔法,只是进程

十、总结

runc = 把 “普通 Linux 进程” 包装成 “看起来像独立系统” 的工具。