Docker内部深度探讨:当你运行 docker run 时到底发生了什么(2025 版)

发布: (2025年12月16日 GMT+8 11:10)
11 min read
原文: Dev.to

Source: Dev.to

(未提供需要翻译的正文内容。如需翻译,请提供完整的文本。)

现代容器平台概览

现代容器平台依赖于可预测、模块化的行为。Docker 的架构是围绕标准接口 — REST、gRPC、OCI Runtime 和 Linux‑kernel 原语构建的分层执行管道。了解此流程可消除在调试、扩展或与编排系统集成时的歧义。

1. 核心架构

CLI  →  dockerd (API + Orchestration)  →  containerd (Runtime mgmt)
      →  containerd‑shim (Process supervisor)  →  runc (OCI runtime)
      →  Linux Kernel (Namespaces, cgroups, fs, net)

Docker CLI

  • 面向用户的命令界面
  • 将标志转换为 JSON
  • 通过 /var/run/docker.sockdockerd 通信

dockerd

  • REST API 服务器
  • 容器生命周期编排
  • 网络和卷管理
  • 将镜像和运行时操作委派给 containerd

containerd

  • 高级运行时管理器
  • 管理快照、镜像和内容存储
  • 拉取/解压层并创建 OCI 运行时规范
  • 为每个容器启动一个 containerd‑shim

镜像存储细节

  • 每个层通过 SHA‑256 进行内容寻址
  • 相同的层会去重
  • OverlayFS 使用硬链接,层在容器之间共享

containerd‑shim

  • 容器工作负载的父进程
  • dockerd/containerd 重启时保持容器存活
  • 管理 I/O 流(日志、附加)
  • 将退出码返回给 containerd

runc

  • 实现 OCI 运行时规范
  • 创建命名空间、应用 cgroup 限制、挂载根文件系统并执行入口点
  • 在容器创建后立即退出(shim 仍保持存活)

Linux 内核

  • 强制进程隔离(命名空间)
  • 控制资源(cgroups)
  • 提供分层文件系统(OverlayFS)
  • 处理网络(veth 对、桥接、iptables/NAT)

✈️ 机场类比 – 思维模型

Docker ComponentAirport RoleReal‑World Impact
Docker CLI乘客航站楼你输入 docker run,检查状态
dockerd机场运营中心管理所有航班、登机口和时刻表
containerd地面指挥装载行李(镜像),分配跑道
containerd‑shim登机口代理即使运营中心重启,也确保飞机保持就绪
runc机师真正驾驶飞机(执行容器)
Kernel空中交通管制管理空域(资源),防止冲突
Container实际航班你的应用在隔离的空域中运行

使用此模型在故障排除时记住组件之间的关系。

2. 执行流程:docker run -d -p 8080:80 nginx

步骤描述
1. CLI → dockerdCLI 解析命令,构建 JSON 负载,并通过 Unix 套接字发送。
2. dockerd Validation验证配置,检查本地镜像,并协调容器创建。
3. Image Pull (if needed)containerd 处理注册表认证、清单解析、层下载与校验,并将层存储在内容存储中。
4. Filesystem Assemblycontainerd 准备快照,创建 OverlayFS 的上层/下层布局,并构建包含元数据和运行时配置的 OCI 包。
5. Networking Setupdockerd 配置网络命名空间:
• 创建 veth 对(主机端连接到 docker0
• 分配容器 IP(例如 172.17.0.2
• 为端口映射添加 iptables DNAT 规则
• 为出站流量添加 MASQUERADE 规则
6. containerd → containerd‑shimcontainerd 启动 shim,交付 OCI 规范,并委托生命周期监督。
7. shim → runcrunc 创建命名空间,挂载 rootfs,应用 cgroup 限制,执行容器入口点,然后退出(shim 保持运行)。
8. Container Running容器作为隔离的 Linux 进程运行:
• Shim 维护生命周期
dockerd 流式传输日志并报告状态
• 内核强制隔离

Docker workflow

3. 组件职责

组件角色委派给
CLI用户界面,请求创建dockerd
dockerdAPI、编排、网络containerd
containerd镜像管理、快照、生命周期runc
containerd‑shim监督容器进程内核(通过 runc 创建的命名空间)
runc创建容器环境内核
Kernel隔离 + 资源控制硬件

相关架构(Kubernetes)

dockerd → kubelet → CRI → containerd

下游的所有部分(containerd → shim → runc → kernel)保持不变。

4. 关键说明

  • 容器是 进程,而不是虚拟机。
  • runc 不会 常驻;shim 管理容器的生命周期。
  • Docker 的分层文件系统是 写时复制,实现高效存储。
  • Kubernetes 移除了 dockerd,直接与 containerd 通信,以实现更简洁的 CRI 流程。
  • 实时恢复能够工作是因为 shim 将容器与 dockerd 解耦。

Source:

5. 调试指南(运维版)

一套结构化、分层的序列,用于诊断容器故障。面向 SRE、DevOps 和运行时工程团队。

容器立即退出

方法: 从最高层(应用层)到最低层(内核层)逐层排查。

1. 应用层

严重程度:低 – 大多数故障源于此。

docker logs <container>

检查日志中是否有崩溃、缺失的二进制文件、入口点配置错误等信息。

2. Shim / Runtime 层

  • 验证 shim 是否存活:ps -ef | grep containerd-shim
  • 检查 runc 退出状态:docker inspect --format='{{.State.ExitCode}}' <container>

3. Containerd 层

  • 查看 containerd 日志:journalctl -u containerd,关注快照或 OCI 规范错误。

4. Dockerd 层

  • 检查 Docker 守护进程日志:journalctl -u docker,寻找 API 级别的拒绝或网络设置失败。

5. 内核层

  • 确认命名空间创建情况:lsnsip netns list
  • 检查 cgroup 限制:cat /sys/fs/cgroup/.../memory.max

使用此分层检查清单定位故障发生的具体阶段,然后采取相应的修复措施。


调试 Docker 运行时问题

关注点: 运行时异常、崩溃循环、缺失配置、入口点失败。

运行时层(containerd / OCI)

严重程度:中 – 问题影响容器创建,而非应用逻辑。

journalctl -u containerd

可检测到:

  • 无效的 OCI 规范
  • 快照 / 解压错误
  • 权限问题
  • 镜像元数据失败

内核层

严重程度:高 – 内核故障会影响节点上 所有 容器。

dmesg | tail -20

揭示:

  • 命名空间创建失败
  • cgroup 强制执行错误
  • LSM 阻断(AppArmor / SELinux)
  • OverlayFS 挂载问题

容器启动缓慢

定位延迟发生在注册表、存储还是运行时。

镜像拉取 / 解压延迟

journalctl -u containerd --since "2 minutes ago" | grep -Ei "pull|unpack"

发现远程拉取慢、层解压延迟、解压缩问题等。

主机存储瓶颈

iostat -dx 1 /var/lib/containerd

检测:

  • 高 I/O 等待
  • OverlayFS 底层存储饱和
  • 磁盘慢或卷负载过高

注册表 / 网络慢

time docker pull alpine:latest

测量:

  • 往返延迟
  • 下载吞吐量
  • 注册表认证或代理延迟

网络问题

追踪 主机 → 桥接 → 容器 的连通性。

验证 NAT / 端口转发规则

sudo iptables -t nat -L DOCKER -n -v

桥接与 veth 拓扑

ip addr show docker0
brctl show

容器命名空间网络

docker exec <container> ip addr show

常见错误模式

错误信息可能原因
no such file or directory缺失入口点或工作目录错误
permission denied用户命名空间限制、卷权限问题
address already in use主机端口冲突
exec format error架构不匹配(如 amd64 与 arm64)
layer does not exist镜像存储损坏、拉取不完整
failed to setup network namespace内核缺少所需能力

恢复操作

镜像拉取失败

  • 检查注册表身份验证令牌。
  • 验证代理 / SSL 配置。
  • 测试与注册表端点的连通性。

OCI 规范 / 运行时错误

  • 确保 Docker、containerd 和 runc 版本兼容。
  • 验证自定义 seccomp 或 AppArmor 配置文件。
  • 重新创建损坏的快照。

内核命名空间 / Cgroup 失败

  • 确认内核版本支持所需功能。
  • 验证 cgroup v1 与 v2 模式。
  • 检查影响命名空间的 sysctl 覆盖。

Debugging tree

6. 摘要

一次 docker run 调用会沿着一条有纪律、模块化的执行路径进行。每个组件只承担一小块、定义明确的职责,并干净利落地交给下一个组件,从而形成可预测的控制流:

  • Dockerd 解析意图并将其转换为运行时指令。
  • Containerd 通过稳定的 gRPC API 编排容器生命周期。
  • containerd‑shim 将容器的进程管理与守护进程的重启隔离开来。
  • runc 将 OCI Runtime Spec 实现为 Linux 原语。
  • 内核 通过命名空间、cgroup 和文件系统驱动提供最终的强制执行层。

这些边界由开放标准(REST → gRPC → OCI Spec → 系统调用)治理,确保兼容性、可靠性以及跨层的深度可观测性。隔离、资源治理和性能效率直接源自原生 Linux 构造——没有隐藏的 hypervisor,也没有额外的抽象层。

操作说明

由于进程所有权被委托给 containerd‑shimdockerdcontainerd 都可以在不影响正在运行的容器的情况下重启。该设计支持安全的守护进程升级、节点维护以及 不会中断工作负载 的高可用工作流。


快速参考

  • 核心架构 – 执行流 → 组件职责
  • 关键说明 – 调试指南(运维版)
  • 调试树 – 容器立即退出 → 启动缓慢 → 网络问题 → 常见错误模式 → 恢复操作
  • 摘要 – 模块化栈的高级回顾
Back to Blog

相关文章

阅读更多 »