1.2 Docker 架构与安装:一条命令的旅程


1.2 Docker 架构与安装:一条命令的旅程

摘要:Docker 是客户端—守护进程架构。本节跟踪一条 docker run 命令从 CLI 到容器进程诞生的完整调用链,讲清 dockerd、containerd、runc 各自的分工与历史原因,并完成安装、镜像加速配置与守护进程体检。

学习目标

  1. 画出 CLI → dockerd → containerd → runc 的调用链并说明各环节职责
  2. 在主流系统上安装 Docker Engine 并验证服务状态
  3. 配置镜像加速器与国内可达的 registry mirror
  4. 通过 daemon 配置文件调整守护进程行为

先想一个问题:为什么 Docker 要拆成好几块

你敲的 docker 命令本身几乎不干活。它是个客户端,把命令翻译成 REST 请求发给守护进程 dockerd。早期的 Docker 把所有活都揽在 dockerd 一个进程里:管镜像、管容器、管网络、管存储卷。后果是这个进程越来越臃肿,而且它一旦重启,所有容器都要跟着遭殃——因为容器的主进程是 dockerd 的子进程。

2016 年 Docker 把容器生命周期管理拆给了 containerd,又把"按规范创建容器"这一步交给了 runc。拆完之后链路变成这样:

有一处细节值得注意:runc 创建完容器进程后会退出,容器进程随即被"移交"给 containerd 收养。正因为如此,后来 dockerd 或 containerd 升级重启时,容器可以不中断地存活——运行中的容器不再依附于启动它的进程树。这是当年拆分带来的最重要的工程收益。

runc 遵循的是 OCI(Open Container Initiative)运行时规范,它只做一件事:读取一份配置(rootfs 路径、要设置的 namespace 列表、cgroup 参数、进程入口),然后调用系统调用把容器进程拉起来,拉完就退。任何符合 OCI 规范的镜像可以被任何符合规范的运行时运行——这就是为什么后来容器生态能长出 Podman、Kata、gVisor 这些替代品而互不排斥。

安装:以 Ubuntu 与 CentOS 为例

Ubuntu 上的官方推荐安装方式:

# 移除可能存在的旧版本 sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖并添加官方仓库 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings # 安装引擎 sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io

CentOS 上则是添加 docker-ce 仓库后 yum install -y docker-ce docker-ce-cli containerd.io,两边的核心包名一致:引擎、客户端、containerd 三件套。

装完先启动并设置开机自启:

sudo systemctl enable --now docker docker version

docker version 会输出两段内容,Client 一段和 Server 一段。如果 Server 段是空的,说明守护进程没起来,用 systemctl status docker 查原因。再来一条体检命令:

docker info

输出里有几个字段值得养成习惯去瞄一眼:Storage Driver(应为 overlay2,第 5 章的主角)、Cgroup Driver(systemd 或 cgroupfs)、Registry Mirrors(加速器是否生效)。一份健康的输出类似:

Server: Storage Driver: overlay2 Backing Filesystem: extfs Cgroup Driver: systemd Registry Mirrors: https://mirror.example.com

免 sudo 与镜像加速

默认只有 root 和 docker 组用户能访问守护进程的套接字。把自己加进 docker 组即可免 sudo:

sudo usermod -aG docker $USER # 重新登录后生效 docker ps

⚠️ 这里有一个安全含义要知道:能访问 docker 套接字约等于拿到 root 权限,因为可以挂载宿主机任意目录进容器。多用户的生产机上,docker 组成员应当被视为管理员。第 7 章会展开这个话题。

镜像加速通过守护进程配置完成。编辑 /etc/docker/daemon.json

{ "registry-mirrors": ["https://mirror.example.com"], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

然后重载:

sudo systemctl daemon-reload sudo systemctl restart docker

顺手把日志上限配上是个好习惯——json-file 日志驱动默认不限大小,长期运行的服务会把磁盘写爆,这是生产环境最常见的事故之一,第 7 章还会再遇到它。

验证:跑通第一个容器

docker run hello-world

正常输出从 "Hello from Docker!" 开始,这段文案其实是一次完整的链条演练:客户端发请求、守护进程发现本地没有镜像、从仓库拉取、创建容器、运行、退出。你在屏幕上看到的每一行提示,都能对应到前面时序图里的某一步。

再做个小实验,验证 containerd 的存在:

ps -ef | grep containerd

你会看到一个独立的 containerd 进程常驻后台——这就是那条调用链里承上启下的中间层,它不随 dockerd 的重启而消失。

Windows 与 macOS 的特殊之处

Docker Desktop 在这两个系统上跑的是一台轻量虚拟机(WSL2 或 HyperKit / Apple 虚拟化框架),Linux 内核藏在这台虚拟机里。你所有看似跑在"本机"的容器,实际都落在这台虚拟机内部——这解释了两个常见困惑:容器里访问的 localhost 为什么有时不通(网络层第 4 章细讲);绑定挂载的性能为什么明显低于 Linux 原生(跨了虚拟机文件系统边界)。理解这层包裹,桌面版的所有"怪异行为"都能推演出来。

本节要点回顾

  • docker 命令是客户端,真正干活的是 dockerd,容器生命周期归 containerd,创建进程的脏活归 runc
  • runc 创建完即退出,容器进程由 containerd 收养,这是容器能脱离守护进程存活的原因
  • OCI 规范让镜像与运行时解耦,是容器生态可替换性的来源
  • docker info 是体检入口:存储驱动、cgroup 驱动、镜像加速器一眼可见
  • 日志上限要早配:json-file 默认不封顶,生产磁盘杀手之一
  • 桌面版多一层虚拟机,性能与网络差异都能从这层推演

架构看清了。下一章开始解剖最底下那层——镜像分层与联合文件系统。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U