从 docker 到 runC
从 Docker 到 runC揭开容器运行时神秘面纱大家好我是你们的资深技术博主。今天我们来聊一个有趣又硬核的话题——从 Docker 到 runC。很多同学可能用过 Docker知道它能“打包应用、随处运行”。但你有没有想过Docker 是怎么在底层实现容器隔离的它背后到底调用了什么今天我们就从 Docker 这个“指挥官”出发深入到它手下的“执行者”——runC。## 什么是 Docker——一个漂亮的“管家”我们先简单回顾一下 Docker。Docker 是一个容器化平台它提供了从镜像构建、存储、拉取到运行的一整套工具链。简单说Docker 像一个“管家”你告诉它“我要跑一个 Nginx”它就会帮你拉镜像、创建容器、跑起来。但 Docker 本身并不直接创建容器。它依赖一个更底层的工具——runC。## 什么是 runC——真正的“执行者”runC 是一个轻量级的命令行工具它按照 OCIOpen Container Initiative标准来创建和运行容器。OCI 是一套容器格式和运行时的行业标准而 runC 是其参考实现。换句话说Docker 是一个高层工具它负责用户交互、镜像管理、网络等复杂功能而 runC 是底层工具它只做一件事让容器跑起来。我们可以把 Docker 想象成一个高级饭店的经理runC 则是后厨里专门负责炒菜的厨师。经理接单、协调、上菜但真正把食材变成菜的是厨师。## Docker 和 runC 的关系Docker 从 1.11 版本开始就采用了 runC 作为其默认的容器运行时。具体流程如下1. 用户输入docker run命令2. Docker 守护进程dockerd接收命令3. dockerd 调用 containerd容器管理守护进程4. containerd 启动 runC 实例5. runC 根据 OCI 规范创建并运行容器所以最终容器进程是由 runC 创建的Docker 只是“指挥官”。## 动手实践安装并运行 runC理论说太多不如动手跑一下。下面我们来看看如何安装 runC 并直接用它运行一个容器。### 安装 runC在 Ubuntu/Debian 上可以直接用包管理器安装bashsudo apt-get updatesudo apt-get install runc或者从 GitHub 下载预编译的二进制文件bashwget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64chmod x runc.amd64sudo mv runc.amd64 /usr/local/bin/runc验证安装bashrunc --version### 用 runC 运行一个容器安装好后我们准备一个 OCI 标准的容器配置。OCI 标准规定容器的配置以 JSON 格式存放在config.json文件中根文件系统放在rootfs目录下。首先创建一个工作目录bashmkdir my-runc-containercd my-runc-container接下来我们需要一个根文件系统。最简单的办法是从 Docker 镜像导出bash# 拉取一个最小的 Alpine 镜像docker pull alpine:latest# 导出为 tar 包docker export $(docker create alpine:latest) -o alpine-rootfs.tar# 解压到 rootfs 目录mkdir rootfstar -xf alpine-rootfs.tar -C rootfs然后使用 runC 自带的工具生成配置bashrunc spec这会生成一个config.json文件里面包含了容器的默认配置。现在我们把它修改一下让容器启动后打印一句话。打开config.json找到process部分修改args为json{ process: { args: [/bin/sh, -c, echo Hello from runC! sleep 10], ... }}现在我们运行容器bashrunc run my-first-container你会看到输出Hello from runC!容器运行 10 秒后自动退出。恭喜你你已经直接使用 runC 运行了一个容器### 代码示例用 Go 调用 runC如果你是一个 Go 语言开发者还可以直接通过编程方式调用 runC。下面是一个简单的示例gopackage mainimport ( fmt os/exec log)func main() { // 准备 runC 命令指定容器 ID 和操作 cmd : exec.Command(runc, run, my-container) // 设置工作目录该目录下必须包含 config.json 和 rootfs cmd.Dir /path/to/container/config // 执行命令 err : cmd.Start() if err ! nil { log.Fatalf(启动容器失败: %v, err) } fmt.Println(容器 my-container 已启动) // 等待容器退出 err cmd.Wait() if err ! nil { log.Fatalf(容器运行出错: %v, err) } fmt.Println(容器已退出)}这个示例展示了如何用 Go 代码调用 runC。在实际的 containerd 源码中就是通过类似的机制来启动容器的。## runC 的底层原理Linux 内核特性runC 之所以能“隔离”进程是因为它利用了 Linux 内核的几大特性-命名空间Namespaces让容器有独立的进程、网络、挂载等视图。-控制组Cgroups限制容器的 CPU、内存等资源使用。-联合文件系统UnionFS实现分层镜像runC 本身不处理镜像但依赖挂载点。-Seccomp、Capabilities增强安全性。当我们运行runc run时它会1. 解析config.json2. 设置命名空间3. 配置 cgroups4. 挂载 rootfs5. 使用clone()系统调用创建新进程6. 最后通过exec()执行用户指定的命令## Docker 如何调用 runC为了让大家更清楚我们写一个简单的 Python 脚本模拟 Docker 调用 runC 的过程pythonimport subprocessimport osimport json# 模拟 Docker 创建容器配置def create_config(): config { ociVersion: 1.0.2-dev, process: { args: [/bin/sh, -c, echo Hello from simulated Docker!], env: [PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin], cwd: / }, root: { path: rootfs # 根文件系统路径 }, linux: { namespaces: [ {type: pid}, {type: network}, {type: ipc}, {type: uts}, {type: mount} ] } } with open(config.json, w) as f: json.dump(config, f, indent2)# 模拟 Docker 调用 runCdef run_container(): container_id simulated-container # 设置工作目录 work_dir /tmp/my-container os.makedirs(work_dir, exist_okTrue) os.chdir(work_dir) # 创建配置 create_config() # 假设 rootfs 已经存在 if not os.path.exists(rootfs): print(错误: rootfs 目录不存在) return # 调用 runC print(f模拟 Docker 调用 runC 运行容器: {container_id}) result subprocess.run( [runc, run, container_id], capture_outputTrue, textTrue ) print(标准输出:, result.stdout) print(标准错误:, result.stderr) if result.returncode 0: print(容器运行成功) else: print(f容器运行失败返回码: {result.returncode})if __name__ __main__: run_container()这个脚本展示了 Docker 底层的工作流程生成 OCI 配置然后调用 runC 执行。当然Docker 的实际实现要复杂得多但核心思想是一样的。## 总结今天我们走了一遍从 Docker 到 runC 的探索之旅。总结一下1.Docker 是高层工具提供了完整的容器生态链包括镜像管理、网络、存储等。2.runC 是底层工具专注于按照 OCI 标准创建和运行容器是容器真正的执行者。3.Docker 调用 containerdcontainerd 再调用 runC形成“Docker → containerd → runC”的三层架构。4. runC 利用 Linux 内核的命名空间、cgroups等特性实现隔离。5. 通过直接使用 runC我们可以更深入地理解容器本质容器本质上就是加了隔离和限制的普通进程。理解了 runC你就能明白 Docker 并不是什么黑魔法。它只是一个漂亮的壳里面包裹着 Linux 内核提供的能力。下次你用docker run时可以想想背后那个默默工作的 runC——它才是那个真正让容器“跑起来”的英雄。希望这篇文章对你有帮助如果你有任何问题欢迎在评论区留言。我们下期再见

相关新闻

Spring Cloud:分布式系统的“粘合剂”(四)

Spring Cloud:分布式系统的“粘合剂”(四)

专栏:Spring Cloud 个人主页:手握风云 目录 一、负载均衡 1.1. 问题 1.2. 定义 1.3. 分类 二、Spring Cloud LoadBalancer 2.1. 快速上手 2.2. 负载均衡策略 2.3. 底层原理 三、多机部署 3.1. 前置准备 3.2. Maven 项目打包 3.3. 服务器 Jar…

2026/10/17 18:22:40 阅读更多 →
Unity责任链模式实战:游戏事件处理与代码解耦

Unity责任链模式实战:游戏事件处理与代码解耦

1. 项目概述:为什么Unity开发者需要掌握责任链模式?如果你在Unity里写过稍微复杂一点的逻辑,比如处理一个UI按钮点击后要经过登录验证、资源检查、冷却判断、最终执行一连串操作,或者处理一个游戏事件需要被多个系统(音…

2026/10/18 17:20:23 阅读更多 →
Claude Opus在ARC-AGI-3基准测试创SOTA:AGI评估标准变革与开发实践

Claude Opus在ARC-AGI-3基准测试创SOTA:AGI评估标准变革与开发实践

最近在 AI 圈子里,一个消息引起了不小的震动:Claude Opus 在 ARC-AGI-3 基准测试中创下了新的 SOTA(State-of-the-Art)成绩。但如果你以为这只是又一个“模型刷榜”的新闻,那就错过了真正重要的信息。这个成绩背后真正…

2026/10/17 16:12:48 阅读更多 →

最新新闻

从日榜看技术趋势:Rust崛起与AI应用层霸榜的深度拆解

从日榜看技术趋势:Rust崛起与AI应用层霸榜的深度拆解

1. 日榜项目的整体观察与拆解思路每天早上刷一遍热榜,已经成了我这些年做技术选型和趋势判断的固定动作。2026年10月8日这一期的日榜,整体看下来有一个很明显的特征:工具类项目占比超过六成,AI 应用层项目继续霸榜,但底…

2026/10/20 13:40:50 阅读更多 →
日榜速报:从开源趋势到技术选型的评估方法论

日榜速报:从开源趋势到技术选型的评估方法论

1. 日榜速报到底在解决什么信息焦虑每天早上打开代码托管平台,首页那个趋势榜单就像一份技术圈的晨报。但问题在于,榜单只给你一个仓库名和一句话简介,至于它为什么突然冲上来、背后用了什么技术栈、值不值得你花半小时去克隆下来跑一遍&…

2026/10/20 13:40:50 阅读更多 →
C++中变量进行初始化的3种方法

C++中变量进行初始化的3种方法

前言 「变量初始化有哪几种写法」这个问题,答案取决于你按什么维度分类。按语法形式分,最常说的是三种:复制初始化(copy-initialization,int a 1;)、直接初始化(direct-initialization&#xf…

2026/10/20 13:40:50 阅读更多 →
Serverpod客户端鸿蒙适配:端云屏障与序列化同步实战指南

Serverpod客户端鸿蒙适配:端云屏障与序列化同步实战指南

1. 为什么专门聊“Serverpod客户端的鸿蒙适配”1.1 Serverpod到底解决了什么问题这几年用 Flutter 做跨端业务,最舒服的一点就是 UI 层可以一套代码铺到手机、平板、桌面,甚至嵌入式设备。但等到真要对接后端的时候,很多人会突然发现一个问题…

2026/10/20 13:40:50 阅读更多 →
机器视觉框架实战:AOI检测与机械手定位引导全解析

机器视觉框架实战:AOI检测与机械手定位引导全解析

搞机器视觉的兄弟应该都有过这种经历:项目接下来,相机、镜头、光源选型好解决,真正的坑全在工程层。视觉检测模板要调,AOI缺陷检测要同时顶住误检和漏检两头压力,机械手定位要做手眼标定,一套流程捋下来&am…

2026/10/20 13:40:50 阅读更多 →
Kafka消息顺序性真相:从分区内有序到生产消费端全链路保序实践

Kafka消息顺序性真相:从分区内有序到生产消费端全链路保序实践

搞过分布式消息的同学应该都遇到过这类问题:明明往Kafka里发消息的时候还想着要顺序,等消费端一跑起来,订单状态直接被回滚回退,或者用户余额扣减顺序反了,一时半会又查不出问题在哪。我之前接手过一个订单系统&#x…

2026/10/20 13:39:46 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →