文章目录
- [1. Docker 整体架构详解:C/S 模式的核心组件与交互机制](#1. Docker 整体架构详解:C/S 模式的核心组件与交互机制)
-
- [1.1 核心组件职责划分](#1.1 核心组件职责划分)
-
- [1.1.1 Docker 客户端 (Client)](#1.1.1 Docker 客户端 (Client))
- [1.1.2 Docker 守护进程 (Docker Daemon / dockerd)](#1.1.2 Docker 守护进程 (Docker Daemon / dockerd))
- [1.1.3 镜像 (Image)](#1.1.3 镜像 (Image))
- [1.1.4 容器 (Container)](#1.1.4 容器 (Container))
- [1.1.5 镜像仓库 (Registry)](#1.1.5 镜像仓库 (Registry))
- [1.2 组件交互流程](#1.2 组件交互流程)
- [2. 核心技术原理:Linux 内核隔离机制深度解析](#2. 核心技术原理:Linux 内核隔离机制深度解析)
-
- [2.1 命名空间 (Namespaces):资源隔离的基石](#2.1 命名空间 (Namespaces):资源隔离的基石)
-
- [2.1.1 六大命名空间类型](#2.1.1 六大命名空间类型)
- [2.1.2 隔离实现原理](#2.1.2 隔离实现原理)
- [2.2 控制组 (cgroups):精准资源控制](#2.2 控制组 (cgroups):精准资源控制)
-
- [2.2.1 核心子系统功能](#2.2.1 核心子系统功能)
- [2.2.2 资源控制实现](#2.2.2 资源控制实现)
- [2.3 联合文件系统 (UnionFS):分层镜像存储引擎](#2.3 联合文件系统 (UnionFS):分层镜像存储引擎)
-
- [2.3.1 分层架构原理](#2.3.1 分层架构原理)
- [2.3.2 主要存储驱动实现](#2.3.2 主要存储驱动实现)
- [3. 容器运行时深度剖析:containerd 与 runc 的协作机制](#3. 容器运行时深度剖析:containerd 与 runc 的协作机制)
-
- [3.1 containerd:容器生命周期管理器](#3.1 containerd:容器生命周期管理器)
-
- [3.1.1 核心职责](#3.1.1 核心职责)
- [3.1.2 交互方式](#3.1.2 交互方式)
- [3.2 runc:OCI 运行时规范实现者](#3.2 runc:OCI 运行时规范实现者)
-
- [3.2.1 核心职责](#3.2.1 核心职责)
- [3.2.2 生命周期特性](#3.2.2 生命周期特性)
- [3.3 containerd-shim:进程监控与隔离层](#3.3 containerd-shim:进程监控与隔离层)
- [3.4 完整工作流程解析](#3.4 完整工作流程解析)
1. Docker 整体架构详解:C/S 模式的核心组件与交互机制
Docker 采用经典的客户端-服务器(C/S)架构模式,通过松耦合的组件设计实现高可扩展性与模块化。整个架构可视为一个分层协作的系统,各组件通过标准化接口进行通信。
1.1 核心组件职责划分
1.1.1 Docker 客户端 (Client)
- 职责:用户交互入口,提供命令行工具(docker CLI)和 REST API 接口。负责将用户指令(如 docker run、docker build)封装为 API 请求。
- 交互方式:通过 UNIX 套接字(默认 /var/run/docker.sock)或 TCP 连接与 Docker 守护进程通信,支持本地与远程调用。
- 关键特性:无状态设计,可轻松实现多客户端并发操作。
1.1.2 Docker 守护进程 (Docker Daemon / dockerd)
- 核心定位:架构的"大脑",常驻后台的单一二进制文件,负责管理所有 Docker 对象的生命周期。
- 职责范围 :
- 容器管理:创建、启动、监控、停止、删除容器,维护容器状态机。
- 镜像管理:处理镜像构建、拉取、推送、存储、分发的完整流程,与 Registry 进行交互。
- 网络管理:管理容器网络命名空间、veth 设备、网桥及端口映射。
- 存储管理:管理镜像分层、容器可写层及数据卷挂载。
- 集群管理:在 Swarm 模式下承担编排调度职责。
- 交互方式:监听 Docker API 请求,作为中央协调器调度 containerd、网络插件和存储驱动。
1.1.3 镜像 (Image)
- 本质:只读模板,采用分层文件系统结构(Layered Architecture),每层对应 Dockerfile 中的一条指令。
- 核心作用:通过不可变层实现高效存储与快速分发,支持跨环境一致性交付。
- 管理机制:由守护进程管理,通过内容寻址存储(Content-Addressable Storage)确保唯一性与完整性。
1.1.4 容器 (Container)
- 本质:镜像的可运行实例,在镜像只读层之上添加可写层(Container Layer)。
- 隔离机制:通过 Linux 命名空间实现进程、网络、文件系统等资源隔离。
- 生命周期:由守护进程全程管控,状态包括 created、running、paused、exited 等。
1.1.5 镜像仓库 (Registry)
- 职责:镜像的集中存储与分发中心,支持公有(Docker Hub)与私有部署。
- 交互流程:守护进程通过 HTTP/HTTPS 协议与 Registry 通信,实现镜像的推送(push)与拉取(pull),支持认证与版本控制。
1.2 组件交互流程
当用户执行 docker run nginx 时,完整的交互链如下:
- CLI 解析:客户端解析命令,通过 API 发送创建容器请求至守护进程。
- 守护进程调度:dockerd 验证镜像是否存在本地,若不存在则向 Registry 发起拉取请求。
- 镜像拉取:守护进程分层下载镜像,校验每层内容哈希,存储于本地驱动。
- 运行时调用:守护进程通过 gRPC 调用 containerd 创建容器。
- 容器初始化:containerd 调用 runc 创建进程,配置命名空间与 cgroups。
- 网络配置:守护进程创建 veth 对,一端接入容器命名空间,另一端接入网桥。
- 启动监控:containerd-shim 作为父进程监控容器生命周期,守护进程持续监控状态。
2. 核心技术原理:Linux 内核隔离机制深度解析
Docker 并非传统虚拟化,而是通过 Linux 内核提供的三大核心技术------命名空间(Namespaces)、控制组(cgroups)和联合文件系统(UnionFS)------实现轻量级隔离与资源管理。
2.1 命名空间 (Namespaces):资源隔离的基石
命名空间是 Linux 内核实现资源虚拟化的根本机制,它为进程创建一个"隔离视图",使每个容器只能看到属于自己的资源。
2.1.1 六大命名空间类型
- PID Namespace:隔离进程 ID 空间,容器内的 PID 1 是应用进程,而非宿主机的 init 系统。容器无法看到宿主机或其他容器的进程树。
- Mount Namespace:隔离文件系统挂载点,每个容器拥有独立的根文件系统(/),实现文件系统视图的隔离。
- Network Namespace:隔离网络栈,包括网络接口、IP 地址、路由表、端口空间等。每个容器拥有独立的 eth0 和回环接口。
- UTS Namespace:隔离主机名与域名,允许容器拥有独立的主机名。
- IPC Namespace:隔离进程间通信资源(如消息队列、信号量、共享内存),防止容器间 IPC 干扰。
- User Namespace:隔离用户与组 ID,实现用户权限映射,是 Rootless 模式的核心技术。
2.1.2 隔离实现原理
内核通过 clone() 系统调用创建新进程时传入 CLONE_NEW* 标志位来创建新的命名空间。子进程进入全新命名空间后,其对资源的操作(如挂载文件系统、绑定端口)仅影响本命名空间,不影响全局系统。
2.2 控制组 (cgroups):精准资源控制
cgroups 是 Linux 内核的资源管理器,将进程分组并分配到不同层级(hierarchy),对每个层级的资源使用进行限制、统计与隔离。
2.2.1 核心子系统功能
- cpu 子系统:限制 CPU 使用时间配额(cpu.cfs_quota_us)与周期(cpu.cfs_period_us),实现 CPU 带宽控制。
- memory 子系统:限制内存使用量(memory.limit_in_bytes),支持 OOM Killer 行为配置,防止内存耗尽影响宿主机。
- blkio 子系统:限制块设备 I/O 速率,控制容器磁盘读写带宽。
- pids 子系统:限制容器内可创建的最大进程数,防止 fork 炸弹攻击。
- devices 子系统:控制容器对设备文件的访问权限,实现设备白名单机制。
2.2.2 资源控制实现
Docker 守护进程在创建容器时,为每个容器创建独立的 cgroup 目录(如 /sys/fs/cgroup/memory/docker/< container-id>),将容器进程 PID 写入 cgroup.procs 文件,内核自动对进程组应用资源限制。这种机制确保即使有容器失控,也无法耗尽系统资源。
2.3 联合文件系统 (UnionFS):分层镜像存储引擎
UnionFS 是实现 Docker 镜像分层与写时复制(Copy-on-Write, CoW)的关键技术,它将多个目录(分支)挂载为单一文件系统,提供统一视图。
2.3.1 分层架构原理
- 镜像层(Image Layers) :每个层是只读的,对应 Dockerfile 指令结果,通过哈希值标识。
- 可写层(Writable Layer) :容器启动时在镜像顶层添加可写层,所有修改操作仅写入该层。
- 写时复制机制:当容器尝试修改只读层文件时,系统将该文件复制到可写层再修改,原始镜像层保持不变。这种机制实现快速启动与空间高效利用。
2.3.2 主要存储驱动实现
- OverlayFS/Overlay2:当前主流驱动,基于文件级 CoW,性能优异,支持页缓存共享。
- Aufs:早期默认驱动,基于 UnionFS,兼容性较好但性能略逊于 Overlay2。
- Devicemapper:基于块设备,适合 I/O 密集型场景,但配置复杂。
- Btrfs:提供快照与数据完整性校验,适合高级存储管理需求。
3. 容器运行时深度剖析:containerd 与 runc 的协作机制
现代 Docker 架构将容器运行时解耦,形成分层调用链:dockerd → containerd → containerd-shim → runc,每层专注特定职责。
3.1 containerd:容器生命周期管理器
containerd 是 CNCF 毕业项目,作为 Docker 引擎与底层运行时之间的桥梁,提供高级容器管理功能。
3.1.1 核心职责
- 生命周期管理:全面管理容器从创建到删除的完整生命周期,包括状态机维护与事件通知。
- 镜像管理:处理镜像的拉取、存储、解压与元数据管理,支持 OCI 镜像规范。
- 存储与网络管理:管理容器根文件系统、快照及网络命名空间准备。
- 插件架构:支持可插拔的 runtime、snapshotter 与 content store。
3.1.2 交互方式
- 与 Docker 引擎通信:通过 gRPC API 接收来自 dockerd 的指令,实现低延迟、高并发的远程过程调用。
- 与 runc 协作:containerd 不直接创建容器进程,而是调用 runc 执行具体操作,自身保持独立与稳定。
3.2 runc:OCI 运行时规范实现者
runc 是轻量级 CLI 工具,直接基于 OCI(Open Container Initiative)运行时规范创建和运行容器,是容器进程的"启动器"。
3.2.1 核心职责
- 容器创建:读取 OCI 配置文件 config.json,设置命名空间、cgroups、seccomp、AppArmor 等安全机制。
- 进程启动:调用 execve 执行容器内初始进程(通常是 ENTRYPOINT),成为容器 PID 1。
- 规范遵循:严格遵守 OCI 标准,确保跨平台与跨运行时兼容性。
3.2.2 生命周期特性
runc 是典型的"一次性"工具:创建并启动容器进程后,runc 自身退出,容器进程作为子进程继续运行。这种设计避免运行时长期占用资源。
3.3 containerd-shim:进程监控与隔离层
职责:作为 containerd 与 runc 之间的中间件,containerd-shim 在 runc 退出后继续监控容器进程。
- 状态监控:捕获容器退出状态码,向 containerd 报告生命周期事件。
- 信号转发:将 SIGTERM、SIGKILL 等信号转发至容器进程。
- 守护进程规避:避免 containerd 成为所有容器的父进程,降低 containerd 崩溃对运行中容器的影响。
3.4 完整工作流程解析
以 docker run 为例的调用链:
- CLI 请求:用户执行 docker run -d nginx。
- dockerd 处理:守护进程解析请求,向 containerd 发送 CreateContainer gRPC 请求。
- containerd 调度:containerd 创建容器元数据,分配唯一 ID,调用 io.containerd.runc.v2 runtime。
- runc 执行:runc 设置命名空间与 cgroups,执行 nginx 二进制文件,此时 nginx 成为容器 PID 1,runc 退出。
- shim 监控:containerd-shim 监控 nginx 进程,若进程退出,shim 收集状态并通知 containerd。
- 状态同步:containerd 更新容器状态为 Exited,dockerd 通过事件流获知状态变更。