style: apply global formatting fixes (struct, spacing, zhlint)

This commit is contained in:
Baohua Yang
2026-02-21 11:08:52 -08:00
parent ad68b2d973
commit 79ac9c639a
159 changed files with 1708 additions and 882 deletions

View File

@@ -27,31 +27,31 @@ graph LR
Docker 的内部架构如同洋葱一样分层每一层专注解决特定问题
#### 1. Docker CLI客户端
#### 1Docker CLI (客户端)
用户与 Docker 交互的主要方式它将用户命令 `docker run`转换为 API 请求发送给 dockerd
用户与 Docker 交互的主要方式它将用户命令 ( `docker run`) 转换为 API 请求发送给 dockerd
#### 2. Dockerd守护进程
#### 2Dockerd (守护进程)
Docker 的大脑
- 监听 API 请求
- 管理 Docker 对象镜像容器网络
- 管理 Docker 对象 (镜像容器网络)
- 编排下层组件完成工作
#### 3. Containerd高级运行时
#### 3Containerd (高级运行时)
行业标准的容器运行时CNCF 毕业项目
- 管理容器的完整生命周期启动停止
行业标准的容器运行时 (CNCF 毕业项目)
- 管理容器的完整生命周期 (启动停止)
- 镜像拉取与存储
- **不包含** 复杂的与容器无关的功能如构建API
- Kubernetes 也可以直接使用 containerd跳过 Docker
- **不包含**复杂的与容器无关的功能 (如构建API)
- Kubernetes 也可以直接使用 containerd (跳过 Docker)
#### 4. Runc低级运行时
#### 4Runc (低级运行时)
用于创建和运行容器的 CLI 工具
- 直接与内核交互Namespaces, Cgroups
- 直接与内核交互 (NamespacesCgroups)
- 遵循 OCI (Open Container Initiative) 规范
- **主要职责**根据配置启动一个容器然后退出将控制权交给容器进程
- **主要职责**根据配置启动一个容器然后退出 (将控制权交给容器进程)
#### 5. Shim
@@ -95,9 +95,9 @@ flowchart TD
Shim -.-> |8. Monitor IO/Exit| Container
```
1. **CLI**发送请求给**Dockerd**2.**Dockerd**解析请求调用**Containerd**3.**Containerd** 准备镜像转换为 OCI Bundle
4. **Containerd**创建**Shim** 进程
5. **Shim**调用**Runc**6.**Runc** 与系统内核交互创建 Namespaces Cgroups
1. **CLI** 发送请求给 **Dockerd**2**Dockerd** 解析请求调用 **Containerd**3**Containerd** 准备镜像转换为 OCI Bundle
4. **Containerd** 创建 **Shim** 进程
5. **Shim** 调用 **Runc**6**Runc** 与系统内核交互创建 Namespaces Cgroups
7. **Runc** 启动 nginx 进程后退出
8. **Shim** 接管容器 IO 和生命周期监控
@@ -108,7 +108,7 @@ flowchart TD
Docker Engine v29 (2025/2026) 开始架构进一步简化和标准化
- **Containerd 镜像存储 (Image Store)**默认启用Docker 直接使用 Containerd 的镜像管理能力不再维护自己的一套 graphdriver
- **优势**多平台镜像支持更好镜像拉取更快lazy pulling K8s 共享镜像
- **优势**多平台镜像支持更好镜像拉取更快 (lazy pulling) K8s 共享镜像
---
@@ -127,8 +127,8 @@ flowchart TD
end
```
- 使用轻量级虚拟机Apple Virtualization / WSL 2运行 Linux 内核
- 文件挂载Bind Mount需要跨越 VM 边界这也是文件 I/O 慢的原因
- 使用轻量级虚拟机 (Apple Virtualization / WSL 2) 运行 Linux 内核
- 文件挂载 (Bind Mount) 需要跨越 VM 边界 (这也是文件 I/O 慢的原因)
- 网络端口需要从宿主机转发到 VM
---

View File

@@ -1,8 +1,8 @@
命名空间Namespace Linux 内核的一个强大特性为容器提供了隔离的运行环境
命名空间 (Namespace) Linux 内核的一个强大特性为容器提供了隔离的运行环境
### 什么是 Namespace
## 什么是 Namespace
> **Namespace Linux 内核提供的资源隔离机制它让容器内的进程仿佛运行在独立的操作系统中**Namespace 是容器技术的核心基础之一它回答了一个关键问题**如何让一个进程"以为"自己独占整个系统**
> **Namespace Linux 内核提供的资源隔离机制它让容器内的进程仿佛运行在独立的操作系统中**Namespace 是容器技术的核心基础之一它回答了一个关键问题**如何让一个进程 以为 自己独占整个系统**
```mermaid
flowchart LR
@@ -71,7 +71,7 @@ PID USER COMMAND
- 容器内的 PID 1 进程特殊重要它是容器的主进程退出则容器停止
- 容器内无法看到宿主机或其他容器的进程
- 宿主机可以看到所有容器内的进程 PID 不同
- 宿主机可以看到所有容器内的进程 ( PID 不同)
---
@@ -85,6 +85,8 @@ NET Namespace 负责网络栈的隔离,包括网卡、路由表和 iptables
#### NET 隔离效果
如下代码块所示展示了相关示例
```mermaid
flowchart LR
subgraph Host ["宿主机"]
@@ -105,7 +107,7 @@ flowchart LR
#### NET 关键点
- 每个容器有独立的网卡IP路由表iptables 规则
- 多个容器可以监听相同端口如都监听 80
- 多个容器可以监听相同端口 (如都监听 80)
- Docker 使用 veth pair 连接容器网络和宿主机网桥
---
@@ -120,6 +122,8 @@ MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的
#### MNT 隔离效果
如下代码块所示展示了相关示例
```
宿主机文件系统: 容器内看到的:
/ / ← 容器的根目录
@@ -167,7 +171,7 @@ $ docker run --hostname mycontainer ubuntu hostname
mycontainer
```
UTS = "UNIX Time-sharing System"是历史遗留的名称
UTS = UNIX Time-sharing System是历史遗留的名称
---
@@ -181,14 +185,14 @@ IPC Namespace 用于隔离进程间通信资源,如 System V IPC 和 POSIX 消
#### 隔离的资源
- 信号量semaphores
- 消息队列message queues
- 共享内存shared memory
- 信号量 (semaphores)
- 消息队列 (message queues)
- 共享内存 (shared memory)
#### IPC 关键点
- 同一容器内的进程可以通过 IPC 通信
- 不同容器的进程无法通过 IPC 通信除非显式共享
- 不同容器的进程无法通过 IPC 通信 (除非显式共享)
---
@@ -202,6 +206,8 @@ USER Namespace 允许将容器内的用户 ID 映射到宿主机的不同用户
#### USER 隔离效果
如下代码块所示展示了相关示例
```mermaid
flowchart LR
subgraph Container ["容器内"]

View File

@@ -1,10 +1,10 @@
## 14.3 控制组
控制组Cgroups Linux 内核提供的另一种关键机制主要用于资源的限制和审计
控制组 (Cgroups) Linux 内核提供的另一种关键机制主要用于资源的限制和审计
### 什么是控制组
控制组Control Groups简称 cgroups Linux 内核的一个特性用于**限制记录和隔离**进程组的资源使用CPU内存磁盘 I/O网络等
控制组 (Control Groups简称 cgroups) Linux 内核的一个特性用于**限制记录和隔离**进程组的资源使用 (CPU内存磁盘 I/O网络等)
> **核心作用**让多个容器公平共享宿主机资源防止单个容器耗尽系统资源
@@ -163,6 +163,8 @@ $ docker inspect mycontainer --format '{{json .HostConfig}}' | jq
### 资源限制的效果
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 内存超限
运行以下命令
@@ -213,6 +215,10 @@ $ docker run --rm --cpus=1 stress --cpu 4
| PSI压力监控 | | |
| rootless 容器 | 部分支持 | 完整支持 |
#### 概述
总体概述了以下内容
#### 检查系统使用的版本
运行以下命令
@@ -235,7 +241,7 @@ nodev cgroup2
### Compose 中设置限制
Compose 中设置限制 配置如下
Compose 中设置限制配置如下
```yaml
services:
@@ -257,7 +263,7 @@ services:
在使用 Cgroups 限制资源时遵循一些最佳实践可以避免潜在的问题
#### 1. 始终设置内存限制
#### 1始终设置内存限制
运行以下命令
@@ -267,7 +273,7 @@ services:
$ docker run -m 1g myapp
```
#### 2. 为关键应用设置 CPU 保证
#### 2为关键应用设置 CPU 保证
运行以下命令
@@ -275,7 +281,7 @@ $ docker run -m 1g myapp
$ docker run --cpus=2 --cpu-shares=2048 critical-app
```
#### 3. 监控资源使用
#### 3监控资源使用
运行以下命令

View File

@@ -1,10 +1,10 @@
## 14.4 联合文件系统
联合文件系统UnionFS Docker 镜像分层存储的基础它允许将多个目录挂载为同一个虚拟文件系统
联合文件系统 (UnionFS) Docker 镜像分层存储的基础它允许将多个目录挂载为同一个虚拟文件系统
### 什么是联合文件系统
联合文件系统UnionFS是一种**分层轻量级**的文件系统它将多个目录"联合"挂载到同一个虚拟目录形成一个统一的文件系统视图
联合文件系统 (UnionFS) 是一种**分层轻量级**的文件系统它将多个目录 联合 挂载到同一个虚拟目录形成一个统一的文件系统视图
> **核心思想**将多个只读层叠加最上层可写形成完整的文件系统
@@ -28,7 +28,9 @@ flowchart TD
Docker 选择联合文件系统作为其存储驱动主要基于以下几个核心优势
#### 1. 镜像分层复用
#### 1镜像分层复用
如下代码块所示展示了相关示例
```mermaid
flowchart TD
@@ -38,7 +40,7 @@ flowchart TD
多个镜像共享相同的底层节省磁盘空间
#### 2. 快速构建
#### 2快速构建
每个 Dockerfile 指令创建一层只有变化的层需要重建
@@ -49,9 +51,9 @@ RUN npm install # 层3安装依赖
COPY . . # 层4应用代码
```
代码变化时只需重建层4层1-3 使用缓存
代码变化时只需重建层 4 1-3 使用缓存
#### 3. 容器启动快
#### 3容器启动快
容器启动时不需要复制镜像只需
1. 在镜像层上创建一个薄的可写层
@@ -59,7 +61,7 @@ COPY . . # 层4应用代码
---
### Copy-on-Write写时复制
### Copy-on-Write (写时复制)
当容器修改只读层中的文件时
@@ -141,11 +143,15 @@ flowchart TD
OverlayFS --> Lower1
```
- **lowerdir**只读的镜像层可以有多个
- **lowerdir**只读的镜像层 (可以有多个)
- **upperdir**可写的容器层
- **workdir**OverlayFS 的工作目录
- **merged**联合挂载后的视图
#### 概述
总体概述了以下内容
#### 文件操作行为
| 操作 | 行为 |
@@ -190,7 +196,9 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
为了构建高效轻量的镜像我们在使用联合文件系统时应注意以下几点
#### 1. 减少镜像层数
#### 1减少镜像层数
如下代码块所示展示了相关示例
```docker
## ❌ 每条命令创建一层
@@ -206,13 +214,13 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/*
```
#### 2. 避免在容器中写入大量数据
#### 2避免在容器中写入大量数据
容器层的写入性能低于直接写入大量数据应使用
- 数据卷Volume
- 绑定挂载Bind Mount
- 数据卷 (Volume)
- 绑定挂载 (Bind Mount)
#### 3. 使用 .dockerignore
#### 3使用dockerignore
排除不需要的文件可以
- 减小构建上下文

View File

@@ -1,15 +1,15 @@
## 14.6 Docker 网络实现
Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备特别是 veth pair建议先熟悉了解这两部分的基本概念再阅读本章
Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备 (特别是 veth pair)建议先熟悉了解这两部分的基本概念再阅读本章
### 基本原理
首先要实现网络通信机器需要至少一个网络接口物理接口或虚拟接口来收发数据包此外如果不同子网之间要进行通信需要路由机制
首先要实现网络通信机器需要至少一个网络接口 (物理接口或虚拟接口) 来收发数据包此外如果不同子网之间要进行通信需要路由机制
Docker 中的网络接口默认都是虚拟的接口虚拟接口的优势之一是转发效率较高
Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中对于本地系统和容器内系统看来就像是一个正常的以太网卡只是它不需要真正同外部网络设备通信速度要快很多
Docker 容器网络就利用了这项技术它在本地主机和容器内分别创建一个虚拟接口并让它们彼此连通这样的一对接口叫做 `veth pair`
Docker 容器网络就利用了这项技术它在本地主机和容器内分别创建一个虚拟接口并让它们彼此连通 (这样的一对接口叫做 `veth pair`)
### 创建网络参数
@@ -21,7 +21,7 @@ Docker 创建一个容器的时候,会执行如下操作:
完成这些之后容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络
可以在 `docker run` 的时候通过 `--net` 参数来指定容器的网络配置4个可选值
可以在 `docker run` 的时候通过 `--net` 参数来指定容器的网络配置 4 个可选值
* `--net=bridge` 这个是默认值连接到默认的网桥
* `--net=host` 告诉 Docker 不要将容器网络放到隔离的命名空间中即不要容器化容器内的网络此时容器使用本地主机的网络它拥有完全的本地主机接口访问权限容器进程可以跟主机其它 root 进程一样可以打开低范围的端口可以访问本地网络服务比如 D-bus还可以让容器做一些影响整个主机系统的事情比如重启主机因此使用这个选项的时候要非常小心如果进一步的使用 `--privileged=true`容器会被允许直接配置主机的网络堆栈
* `--net=container:NAME_or_ID` Docker 将新建容器的进程放到一个已存在容器的网络栈中新容器进程有自己的文件系统进程列表和资源限制但会和已存在的容器共享 IP 地址和端口等网络资源两者进程可以直接通过 `lo` 环回接口通信
@@ -57,7 +57,7 @@ $ sudo ip link add A type veth peer name B
$ sudo brctl addif docker0 A
$ sudo ip link set A up
```
B放到容器的网络命名空间命名为 eth0启动它并配置一个可用 IP桥接网段和默认网关
B 放到容器的网络命名空间命名为 eth0启动它并配置一个可用 IP (桥接网段) 和默认网关
```bash
$ sudo ip link set B netns $pid
$ sudo ip netns exec $pid ip link set dev B name eth0

View File

@@ -1,16 +1,16 @@
# 第十四章 底层实现
# 第十四章底层实现
Docker 底层的核心技术包括 Linux 上的命名空间Namespaces控制组Control groupsUnion 文件系统Union file systems和容器格式Container format
Docker 底层的核心技术包括 Linux 上的命名空间 (Namespaces)控制组 (Control groups)Union 文件系统 (Union file systems) 和容器格式 (Container format)
我们知道传统的虚拟机通过在宿主主机中运行 hypervisor 来模拟一整套完整的硬件环境提供给虚拟机的操作系统虚拟机系统看到的环境是可限制的也是彼此隔离的
这种直接的做法实现了对资源最完整的封装但很多时候往往意味着系统资源的浪费
例如以宿主机和虚拟机系统都为 Linux 系统为例虚拟机中运行的应用其实可以利用宿主机系统中的运行环境
我们知道在操作系统中包括内核文件系统网络PIDUIDIPC内存硬盘CPU 等等所有的资源都是应用进程直接共享的
要想实现虚拟化除了要实现对内存CPU网络IO硬盘IO存储空间等的限制外还要实现文件系统网络PIDUIDIPC等等的相互隔离
要想实现虚拟化除了要实现对内存CPU网络 IO硬盘 IO存储空间等的限制外还要实现文件系统网络PIDUIDIPC 等等的相互隔离
前者相对容易实现一些后者则需要宿主机系统的深入支持
随着 Linux 系统对于命名空间功能的完善实现程序员已经可以实现上面的所有需求让某些进程在彼此隔离的命名空间中运行大家虽然都共用一个内核和某些运行时环境例如一些系统命令和系统库但是彼此却看不到都以为系统中只有自己的存在这种机制就是容器Container利用命名空间来做权限的隔离控制利用 cgroups 来做资源分配
随着 Linux 系统对于命名空间功能的完善实现程序员已经可以实现上面的所有需求让某些进程在彼此隔离的命名空间中运行大家虽然都共用一个内核和某些运行时环境 (例如一些系统命令和系统库)但是彼此却看不到都以为系统中只有自己的存在这种机制就是容器 (Container)利用命名空间来做权限的隔离控制利用 cgroups 来做资源分配
* [基本架构](14.1_arch.md)
* [命名空间](14.2_namespace.md)

View File

@@ -11,7 +11,7 @@
### 延伸阅读
- [控制组Cgroups](14.3_cgroups.md)资源限制机制
- [控制组 (Cgroups)](14.3_cgroups.md)资源限制机制
- [联合文件系统](14.4_ufs.md)分层存储的实现
- [安全](../11_ops/security/README.md)容器安全实践
- [Linux Namespace 官方文档](https://man7.org/linux/man-pages/man7/namespaces.7.html)