Loading

Docker 容器引擎概述与体系结构


一、Docker 是什么?为什么要用 Docker?

之前我们用 C 语言编写了一个能够创建容器名称空间的小程序,本质就是调用了 clone 系统调用,并传入一系列系统调用参数,在 clone 创建的第一个进程外围初始化好容器的名称空间,做到了多种资源的隔离,并为该名称空间挂载了一个单独的 rootfs(来自容器镜像)。那个程序其实就是一个容器引擎,但它只是为了演示底层原理,并不完善——比如容器的网络、安全等都没有实现。

Docker 就是别人为我们开发好的一个完善的容器引擎。 但要知道,Docker 最底层也一定是通过调用 clone 系统调用、传入系统调用参数来创建容器的。之所以先用 C 语言带大家实现过一遍,就是为了让大家理解本质原理,再学 Docker 时就不会觉得陌生。


二、Docker 的三大组成部分

Docker 本身是一个 C/S 架构(客户端/服务端架构),不像我们之前用 C 语言写的那个程序全都在一个文件里。Docker 的客户端是专门的客户端,服务端是专门的服务端。整套体系分为三大部分

组成部分 职责
客户端(Client) 发起请求,如 docker builddocker pulldocker run 等命令
Docker 守护进程(Docker Daemon) 接收客户端请求,负责具体干活:创建容器、拉取镜像、为容器挂载文件系统等
镜像仓库(Registry) 存放各种镜像(CentOS、Ubuntu 等各种 Linux 发行版的镜像),需要时去仓库里找

三大部分分工明确:客户端负责发指令,守护进程负责执行,镜像仓库负责提供镜像资源。


三、以 docker run 为例串联整体流程

当你在命令行执行 docker run 命令后,整个流程如下:

docker run(客户端命令)
    │
    ▼
Docker Daemon(守护进程收到命令)
    │
    ├── 1. 调用 clone 系统调用,创建一个进程
    │
    ├── 2. 根据传入的系统调用参数,在进程外围初始化名称空间
    │      把该隔离的资源都隔离好
    │
    ├── 3. 为名称空间关联文件系统(操作系统)
    │      操作系统从哪来?→ docker run 时指定的镜像
    │
    ├── 4. 去镜像仓库找到对应镜像,下载到本地
    │
    ├── 5. 将镜像作为 lowerdir(只读),搭配一个 upperdir(可写)
    │      通过 Overlay 联合文件系统做联合挂载
    │
    └── 6. 挂载到容器的名称空间里 → 容器启动完成

这就是 Docker 三大组成部分协同工作的完整流程。


四、Docker Daemon ≠ 完整的容器引擎

在上面的介绍中,我们把 Docker Daemon 当作了"干活的核心"。但需要澄清的是:dockerd 守护进程并不等于容器引擎,它只是容器引擎的一部分。

一个完整的容器引擎实际上分为四层结构

┌─────────────────────────────────┐
│  dockerd(Docker Daemon)        │  ← 最上层,接收客户端命令
├─────────────────────────────────┤
│  containerd                      │  ← 负责容器生命周期管理
├─────────────────────────────────┤
│  containerd-shim                 │  ← 中间垫片进程
├─────────────────────────────────┤
│  runc(容器运行时)               │  ← 最底层,真正创建并运行容器
└─────────────────────────────────┘

具体调用链路是:dockerd 收到客户端发来的 run/build/pull 等命令后 → 调用 containerdcontainerd 启动一个 containerd-shim 进程 → containerd-shim 调用 runc(容器运行时) → runc 具体把容器运行起来。

当前阶段只需要有个基本印象即可,后面会详细介绍这四层结构。为了快速理解 Docker 管理体系,暂时可以简单地把 Docker Daemon 理解为容器引擎的代表。


五、关于客户端的种类

Docker 体系中的客户端不止一种:

客户端 说明
docker 命令 单机版客户端指令,管理本机容器
docker-compose 基于 YAML 文件编排容器的起停销毁
Kubernetes(K8s) 平台级客户端,本质也是客户端的一种,后面重点学习

学了 K8s 之后,docker-compose 基本就不用了。但 docker 单机客户端命令仍然常用——你可能需要登录到某台机器上用客户端命令查看和管理容器。


六、关于 K8s 与 Docker 的关系说明

有些了解多一点的同学会知道:K8s 从 1.20 版本之后,不再跟 dockerd 打交道,而是直接绕过 dockerd,调用 containerd 来创建容器。

K8s 1.20 之前:  K8s → dockerd → containerd → containerd-shim → runc
K8s 1.20 之后:  K8s → containerd → containerd-shim → runc(跳过 dockerd)

由此会产生一个疑问:既然 K8s 不再需要 dockerd 了,还有必要学 Docker 客户端命令吗?

答案是必须要学,原因有两点:

  1. 学习路径:还没学到 K8s 之前,得先用 Docker 把容器的基本操作学会——启动容器、管理容器等。而且即便以后用上了 K8s,单机上的一些管理操作仍然需要用 Docker 客户端命令
  2. 版本兼容:1.20 之前的 K8s 仍然需要通过 dockerd 来工作,学习 Docker 管理体系仍然有必要

至于 K8s 为什么从 1.20 版本之后抛弃 dockerd,原因其实可以猜到:直接跟 containerd 打交道可以省去调用链路,效率更高、管理成本更低,而且 K8s 代码不需要维护与 dockerd 交互的那层逻辑,更新迭代也更方便。具体细节后面再详细介绍。


七、本节总结与下一步

要点 说明
Docker 的本质 一个完善的容器引擎,底层同样是通过 clone 系统调用创建容器
C/S 架构 客户端发请求 + Docker Daemon 执行 + 镜像仓库提供镜像
docker run 流程 客户端 → Daemon → clone 创建进程 → 初始化名称空间 → 从仓库拉镜像 → Overlay 联合挂载 → 容器启动
容器引擎四层结构 dockerdcontainerdcontainerd-shimruncdockerd 只是最上层
K8s 1.20 变化 跳过 dockerd 直接调 containerd,但学习 Docker 客户端命令仍然必要

接下来的任务:安装 Docker 引擎,然后学习一系列客户端命令,向 Docker 守护进程发请求来管理容器。至于守护进程下层的组件结构,等基本使用全部学完后再深入介绍。

posted @ 2026-06-19 09:57  知杏  阅读(8)  评论(0)    收藏  举报