diff --git a/01_introduction/quickstart.md b/01_introduction/1.1_quickstart.md
similarity index 85%
rename from 01_introduction/quickstart.md
rename to 01_introduction/1.1_quickstart.md
index b404f08..15801e4 100644
--- a/01_introduction/quickstart.md
+++ b/01_introduction/1.1_quickstart.md
@@ -1,8 +1,8 @@
-# 快速上手 (5分钟)
+## 快速上手 (5分钟)
本节将通过一个简单的 Web 应用例子,带你快速体验 Docker 的核心流程:构建镜像、运行容器。
-## 1. 准备代码
+### 1. 准备代码
创建一个名为 `hello-docker` 的文件夹,并在其中创建一个 `index.html` 文件:
@@ -10,7 +10,7 @@
Hello, Docker!
```
-## 2. 编写 Dockerfile
+### 2. 编写 Dockerfile
在同级目录下创建一个名为 `Dockerfile` (无后缀) 的文件:
@@ -19,7 +19,7 @@ FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
```
-## 3. 构建镜像
+### 3. 构建镜像
打开终端,进入该目录,执行构建命令:
@@ -31,7 +31,7 @@ $ docker build -t my-hello-world .
* `-t my-hello-world`: 给镜像起个名字(标签)
* `.`: 指定上下文路径为当前目录
-## 4. 运行容器
+### 4. 运行容器
使用刚才构建的镜像启动一个容器:
@@ -43,22 +43,22 @@ $ docker run -d -p 8080:80 my-hello-world
* `-d`: 后台运行
* `-p 8080:80`: 将宿主机的 8080 端口映射到容器的 80 端口
-## 5. 访问测试
+### 5. 访问测试
打开浏览器访问 [http://localhost:8080](http://localhost:8080),你应该能看到 "Hello, Docker!"。
-## 6. 清理
+### 6. 清理
停止并删除容器:
```bash
-# 查看正在运行的容器 ID
+## 查看正在运行的容器 ID
$ docker ps
-# 停止容器
+## 停止容器
$ docker stop
-# 删除容器
+## 删除容器
$ docker rm
```
diff --git a/01_introduction/what.md b/01_introduction/1.2_what.md
similarity index 94%
rename from 01_introduction/what.md
rename to 01_introduction/1.2_what.md
index 52a5b7d..908b60b 100644
--- a/01_introduction/what.md
+++ b/01_introduction/1.2_what.md
@@ -1,6 +1,6 @@
-# 什么是 Docker
+## 什么是 Docker
-## 一句话理解 Docker
+### 一句话理解 Docker
> **Docker 是一种轻量级的虚拟化技术,它让应用程序及其依赖环境可以被打包成一个标准化的单元,在任何地方都能一致地运行。**
@@ -10,7 +10,7 @@
Docker 做的事情类似:无论你的应用是用 Python、Java、Node.js 还是其他语言写的,无论它需要什么样的依赖库和环境,一旦被打包成 Docker 镜像,就可以用同样的方式在任何支持 Docker 的机器上运行。
-## Docker 的核心价值
+### Docker 的核心价值
笔者认为,Docker 解决的是软件开发中最古老的问题之一:**"在我机器上明明能跑啊!"**
@@ -37,25 +37,25 @@ Docker 做的事情类似:无论你的应用是用 Python、Java、Node.js 还
运行正常 运行正常!
```
-## Docker vs 虚拟机
+### Docker vs 虚拟机
很多人第一次接触 Docker 时会问:**"这不就是虚拟机吗?"**
答案是:**不是,而且差别很大。**
-### 传统虚拟机
+#### 传统虚拟机
传统虚拟机技术是虚拟出一套完整的硬件,在其上运行一个完整的操作系统,再在该系统上运行应用:

-### Docker 容器
+#### Docker 容器
而 Docker 容器内的应用直接运行于宿主的内核,容器内没有自己的内核,也没有进行硬件虚拟:

-### 关键区别
+#### 关键区别
| 特性 | Docker 容器 | 传统虚拟机 |
|------|-------------|------------|
@@ -67,7 +67,7 @@ Docker 做的事情类似:无论你的应用是用 Python、Java、Node.js 还
> 笔者经常用这个类比来解释:虚拟机像是每个应用都住在一栋独立的房子里(有自己的地基、水电系统),而容器像是大家住在同一栋公寓楼里的不同房间(共享地基和水电系统,但各自独立)。
-## Docker 的技术基础
+### Docker 的技术基础
Docker 使用 [Go 语言](https://golang.google.cn/) 开发,基于 Linux 内核的以下技术:
@@ -77,7 +77,7 @@ Docker 使用 [Go 语言](https://golang.google.cn/) 开发,基于 Linux 内
> 如果你对这些底层技术感兴趣,可以阅读本书的[底层实现](../13_implementation/README.md)章节。
-### Docker 架构演进
+#### Docker 架构演进
Docker 的底层实现经历了多次演进:
@@ -101,7 +101,7 @@ LXC ──→ libcontainer ──→ runC ──→ containerd + runC
> `containerd` 是一个守护程序,它管理容器生命周期,提供了在一个节点上执行容器和管理镜像的最小功能集。
-## Docker 的历史与生态
+### Docker 的历史与生态
**Docker** 最初是 `dotCloud` 公司创始人 [Solomon Hykes](https://github.com/shykes) 在法国期间发起的一个公司内部项目,于 [2013 年 3 月以 Apache 2.0 授权协议开源](https://en.wikipedia.org/wiki/Docker_(software))。
@@ -114,11 +114,11 @@ Docker 的发展历程:
Docker 的成功推动了整个容器生态的发展,催生了 Kubernetes、Podman 等众多相关项目。笔者认为,Docker 最大的贡献不仅是技术本身,更是它**让容器技术从系统管理员的工具变成了每个开发者都能使用的标准工具**。
-## 本章小结
+### 本章小结
- Docker 是一种轻量级虚拟化技术,核心价值是**环境一致性**
- 与虚拟机相比,Docker 更轻量、更快速、资源利用率更高
- Docker 基于 Linux 内核的 Namespace、Cgroups 和 Union FS 技术
- Docker 推动了容器技术的标准化(OCI)和生态发展
-接下来,让我们了解[为什么要使用 Docker](why.md)。
+接下来,让我们了解[为什么要使用 Docker](1.3_why.md)。
diff --git a/01_introduction/why.md b/01_introduction/1.3_why.md
similarity index 91%
rename from 01_introduction/why.md
rename to 01_introduction/1.3_why.md
index 74f2abe..33a25e0 100644
--- a/01_introduction/why.md
+++ b/01_introduction/1.3_why.md
@@ -1,10 +1,10 @@
-# 为什么要使用 Docker?
+## 为什么要使用 Docker?
在回答"为什么用 Docker"之前,笔者想先问一个问题:**你有没有经历过这些场景?**
-## 没有 Docker 的世界
+### 没有 Docker 的世界
-### 场景一:"在我电脑上明明能跑"
+#### 场景一:"在我电脑上明明能跑"
```
周五下午 5:00
@@ -21,7 +21,7 @@
- 某些环境变量没有设置
- "哦,忘了说我本地装了个 XXX"
-### 场景二:环境配置的噩梦
+#### 场景二:环境配置的噩梦
```
新同事入职
@@ -32,7 +32,7 @@
└── Day 5:终于能跑起来了!但不知道为什么……
```
-### 场景三:服务器迁移的恐惧
+#### 场景三:服务器迁移的恐惧
```
运维:"我们需要把服务迁移到新服务器"
@@ -41,9 +41,9 @@
所有人:😱
```
-## Docker 如何解决这些问题
+### Docker 如何解决这些问题
-### 核心理念:一次构建,到处运行
+#### 核心理念:一次构建,到处运行
```
开发环境 测试环境 生产环境
@@ -57,9 +57,9 @@
完全一致 完全一致 完全一致
```
-## Docker 的核心优势
+### Docker 的核心优势
-### 1. 环境一致性
+#### 1. 环境一致性
Docker 镜像包含了应用运行所需的**一切**:代码、运行时、系统工具、库、配置。这意味着:
@@ -68,13 +68,13 @@ Docker 镜像包含了应用运行所需的**一切**:代码、运行时、系
- ✅ 新人入职,一条命令就能启动开发环境
```bash
-# 新同事入职第一天
+## 新同事入职第一天
$ git clone https://github.com/company/project.git
$ docker compose up
-# 完整的开发环境就准备好了
+## 完整的开发环境就准备好了
```
-### 2. 秒级启动
+#### 2. 秒级启动
传统虚拟机启动需要几分钟(引导操作系统),而 Docker 容器启动通常只需要**几秒甚至几百毫秒**。
@@ -91,7 +91,7 @@ $ docker compose up
- **弹性扩容**:流量高峰时能快速启动更多实例
- **开发体验**:快速重启服务进行调试
-### 3. 资源效率
+#### 3. 资源效率
Docker 容器共享宿主机内核,无需为每个应用运行完整的操作系统。
@@ -119,7 +119,7 @@ Docker 方案:
实际可用于应用:约 60GB ✅
```
-### 4. 持续交付和部署
+#### 4. 持续交付和部署
Docker 完美契合 DevOps 的工作流程:
@@ -131,12 +131,12 @@ Docker 完美契合 DevOps 的工作流程:
push build 运行测试 更新
```
-使用 [Dockerfile](../04_image/build.md) 定义镜像构建过程,使得:
+使用 [Dockerfile](../04_image/4.5_build.md) 定义镜像构建过程,使得:
- 构建过程**可重复、可追溯**
- 任何人都能从代码重建完全相同的镜像
- 配合 [GitHub Actions](../14_cases/ci/actions/README.md) 等 CI 系统实现自动化
-### 5. 轻松迁移
+#### 5. 轻松迁移
Docker 可以在几乎任何平台上运行:
- ✅ 本地开发机(macOS、Windows、Linux)
@@ -146,7 +146,7 @@ Docker 可以在几乎任何平台上运行:
**同一个镜像,在任何地方运行结果都一致。** 这让应用迁移变得前所未有的简单。
-### 6. 微服务架构的基石
+#### 6. 微服务架构的基石
现代微服务架构几乎都依赖容器技术。Docker 让你可以:
@@ -168,27 +168,27 @@ Docker 可以在几乎任何平台上运行:
└───────────────────────────────────────────────────┘
```
-## Docker 不适合的场景
+### Docker 不适合的场景
笔者认为,技术选型要客观。Docker 并非银弹,以下场景可能不太适合:
-### 1. 需要完全隔离的场景
+#### 1. 需要完全隔离的场景
容器共享宿主机内核,隔离性不如虚拟机。如果你需要运行不受信任的代码,虚拟机可能更安全。
-### 2. 需要特殊内核的场景
+#### 2. 需要特殊内核的场景
容器使用宿主机内核。如果应用需要特定版本的内核或内核模块,可能需要虚拟机。
-### 3. Windows 原生应用
+#### 3. Windows 原生应用
虽然 Docker 支持 Windows 容器,但生态不如 Linux 容器成熟。传统 Windows 应用的容器化仍有挑战。
-### 4. 桌面应用
+#### 4. 桌面应用
Docker 主要面向服务端应用。桌面 GUI 应用的容器化虽然可行,但通常得不偿失。
-## 与传统虚拟机的对比总结
+### 与传统虚拟机的对比总结
| 特性 | Docker 容器 | 传统虚拟机 |
|:------|:-----------|:-----------|
@@ -199,7 +199,7 @@ Docker 主要面向服务端应用。桌面 GUI 应用的容器化虽然可行
| 隔离性 | 进程级别 | 完全隔离 |
| 最佳场景 | 微服务、CI/CD、开发环境 | 多租户、高安全需求 |
-## 本章小结
+### 本章小结
Docker 的核心价值可以用一句话概括:**让应用的开发、测试、部署保持一致,同时极大提高资源利用效率。**
diff --git a/01_introduction/README.md b/01_introduction/README.md
index 45a0f90..a415be5 100644
--- a/01_introduction/README.md
+++ b/01_introduction/README.md
@@ -1,14 +1,14 @@
-# 简介
+# 第一章 Docker 简介
本章将带领你进入 **Docker** 的世界。
## 本章内容
-* [什么是 Docker](what.md)
+* [什么是 Docker](1.2_what.md)
* 介绍 Docker 的起源、发展历程以及其背后的核心技术(Cgroups, Namespaces, UnionFS)。
* 了解 Docker 是如何改变软件交付方式的。
-* [为什么要用 Docker](why.md)
+* [为什么要用 Docker](1.3_why.md)
* 对比传统虚拟机技术,阐述 Docker 在启动速度、资源利用率、交付效率等方面的巨大优势。
* 探讨 Docker 在 DevOps、微服务架构中的关键作用。
diff --git a/02_basic_concept/image.md b/02_basic_concept/2.1_image.md
similarity index 87%
rename from 02_basic_concept/image.md
rename to 02_basic_concept/2.1_image.md
index edee300..32a90d4 100644
--- a/02_basic_concept/image.md
+++ b/02_basic_concept/2.1_image.md
@@ -1,12 +1,12 @@
-# Docker 镜像
+## Docker 镜像
-## 一句话理解镜像
+### 一句话理解镜像
> **Docker 镜像是一个只读的模板,包含了运行应用所需的一切:代码、运行时、库、环境变量和配置文件。**
如果用一个类比:**镜像就像是一张光盘或 ISO 文件**。你可以用同一张光盘在不同电脑上安装系统,而光盘本身不会被修改。同样,一个镜像可以创建多个容器,而镜像本身保持不变。
-## 镜像与操作系统的关系
+### 镜像与操作系统的关系
我们都知道,操作系统分为**内核**和**用户空间**:
@@ -27,7 +27,7 @@
例如,官方镜像 `ubuntu:24.04` 包含了一套完整的 Ubuntu 24.04 最小系统的 root 文件系统——但**不包含 Linux 内核**(因为容器共享宿主机的内核)。
-## 镜像包含什么?
+### 镜像包含什么?
Docker 镜像是一个特殊的文件系统,包含:
@@ -44,9 +44,9 @@ Docker 镜像是一个特殊的文件系统,包含:
- ✅ 镜像**不包含**动态数据
- ✅ 镜像构建后**内容不会改变**
-## 分层存储:镜像的核心设计
+### 分层存储:镜像的核心设计
-### 为什么需要分层?
+#### 为什么需要分层?
笔者认为,分层存储是 Docker 最巧妙的设计之一。
@@ -76,7 +76,7 @@ Docker 分层方式:
总计:620MB ✅
```
-### 分层是如何工作的?
+#### 分层是如何工作的?
笔者用一个实际的 Dockerfile 来解释分层:
@@ -106,24 +106,24 @@ COPY app.conf /etc/nginx/ # 第 4 层:复制配置文件
- **可共享**:多个镜像可以共享相同的层
- **有缓存**:未变化的层不会重新构建
-### 分层存储的"陷阱"
+#### 分层存储的"陷阱"
> ⚠️ **笔者特别提醒**:理解这一点可以帮你避免构建出臃肿的镜像。
**关键原理**:每一层的文件变化会被记录,但**删除操作只是标记,不会真正减小镜像体积**。
```docker
-# 错误示范 ❌
+## 错误示范 ❌
FROM ubuntu:24.04
RUN apt-get update
RUN apt-get install -y build-essential # 安装编译工具(约 200MB)
RUN make && make install # 编译应用
RUN apt-get remove build-essential # 试图删除编译工具
-# 结果:镜像仍然包含 200MB 的编译工具!
+## 结果:镜像仍然包含 200MB 的编译工具!
```
```docker
-# 正确做法 ✅
+## 正确做法 ✅
FROM ubuntu:24.04
RUN apt-get update && \
apt-get install -y build-essential && \
@@ -131,13 +131,13 @@ RUN apt-get update && \
apt-get remove -y build-essential && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*
-# 在同一层完成安装、使用、清理
+## 在同一层完成安装、使用、清理
```
-### 查看镜像的分层
+#### 查看镜像的分层
```bash
-# 查看镜像的历史(每层的构建记录)
+## 查看镜像的历史(每层的构建记录)
$ docker history nginx:latest
IMAGE CREATED CREATED BY SIZE
@@ -149,27 +149,27 @@ a6bd71f48f68 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
...
```
-## 镜像的标识
+### 镜像的标识
Docker 镜像有多种标识方式:
-### 1. 镜像名称和标签
+#### 1. 镜像名称和标签
格式:`[仓库地址/]仓库名[:标签]`
```bash
-# 完整格式
+## 完整格式
registry.example.com/myproject/myapp:v1.2.3
-# 简写(使用 Docker Hub)
+## 简写(使用 Docker Hub)
nginx:1.25
ubuntu:24.04
-# 省略标签(默认使用 latest)
+## 省略标签(默认使用 latest)
nginx # 等同于 nginx:latest
```
-### 2. 镜像 ID(Content-Addressable)
+#### 2. 镜像 ID(Content-Addressable)
每个镜像有一个基于内容计算的唯一 ID:
@@ -180,7 +180,7 @@ nginx latest a6bd71f48f68 2 weeks ago 187MB
ubuntu 24.04 ca2b0f26964c 3 weeks ago 78.1MB
```
-### 3. 镜像摘要(Digest)
+#### 3. 镜像摘要(Digest)
更精确的标识,基于镜像内容的 SHA256 哈希:
@@ -192,7 +192,7 @@ nginx latest sha256:6db391d1c0cfb30588ba0bf72ea999404f2764184d8b8d10d89e8
> 💡 笔者建议:在生产环境使用镜像摘要而非标签,因为标签可以被覆盖,但摘要是不可变的。
-## 镜像的来源
+### 镜像的来源
Docker 镜像可以通过以下方式获取:
@@ -203,7 +203,7 @@ Docker 镜像可以通过以下方式获取:
| **从容器提交** | 保存容器状态(不推荐) | `docker commit` |
| **从文件导入** | 离线传输 | `docker load < image.tar` |
-## 本章小结
+### 本章小结
| 概念 | 要点 |
|------|------|
@@ -212,11 +212,11 @@ Docker 镜像可以通过以下方式获取:
| **只读特性** | 构建后不可修改,保证一致性 |
| **层的陷阱** | 删除操作只是标记,不减小体积 |
-理解了镜像,接下来让我们学习[容器](container.md)——镜像的运行实例。
+理解了镜像,接下来让我们学习[容器](2.2_container.md)——镜像的运行实例。
-## 延伸阅读
+### 延伸阅读
-- [获取镜像](../04_image/pull.md):从 Registry 下载镜像
-- [使用 Dockerfile 定制镜像](../04_image/build.md):创建自己的镜像
-- [Dockerfile 最佳实践](../15_appendix/best_practices.md):构建高质量镜像的技巧
-- [底层实现 - 联合文件系统](../13_implementation/ufs.md):深入理解分层存储的技术原理
+- [获取镜像](../04_image/4.1_pull.md):从 Registry 下载镜像
+- [使用 Dockerfile 定制镜像](../04_image/4.5_build.md):创建自己的镜像
+- [Dockerfile 最佳实践](../15_appendix/15.1_best_practices.md):构建高质量镜像的技巧
+- [底层实现 - 联合文件系统](../13_implementation/13.4_ufs.md):深入理解分层存储的技术原理
diff --git a/02_basic_concept/container.md b/02_basic_concept/2.2_container.md
similarity index 88%
rename from 02_basic_concept/container.md
rename to 02_basic_concept/2.2_container.md
index a931eb3..5604560 100644
--- a/02_basic_concept/container.md
+++ b/02_basic_concept/2.2_container.md
@@ -1,6 +1,6 @@
-# Docker 容器
+## Docker 容器
-## 一句话理解容器
+### 一句话理解容器
> **容器是镜像的运行实例。如果把镜像比作程序,那么容器就是进程。**
@@ -10,7 +10,7 @@
- 每个容器相互独立,互不影响
- 容器可以被创建、启动、停止、删除、暂停
-## 容器的本质
+### 容器的本质
> 💡 **笔者认为,理解这一点是理解 Docker 的关键**
@@ -38,7 +38,7 @@
这种隔离是通过 Linux 内核的 **Namespace** 技术实现的。
-## 容器 vs 虚拟机:核心区别
+### 容器 vs 虚拟机:核心区别
很多初学者会混淆容器和虚拟机。笔者用一张图来说明:
@@ -67,9 +67,9 @@
| **性能损耗** | 几乎为零 | 5-20% |
| **内核** | 共享宿主机内核 | 各自独立内核 |
-## 容器的存储层
+### 容器的存储层
-### 镜像层 + 容器层
+#### 镜像层 + 容器层
当容器运行时,Docker 会在镜像的只读层之上创建一个**可写层**(容器存储层):
@@ -88,7 +88,7 @@
└─────────────────────────────────────────────┘
```
-### Copy-on-Write(写时复制)
+#### Copy-on-Write(写时复制)
当容器需要修改镜像层中的文件时:
@@ -101,25 +101,25 @@
修改文件:复制到容器层,然后修改(只有这个容器能看到修改)
```
-### ⚠️ 容器存储层的生命周期
+#### ⚠️ 容器存储层的生命周期
> **笔者特别强调**:这是新手最容易踩的坑!
**容器存储层与容器生命周期绑定。容器删除,数据就没了!**
```bash
-# 创建容器,写入数据
+## 创建容器,写入数据
$ docker run -it ubuntu bash
root@abc123:/# echo "important data" > /data.txt
root@abc123:/# exit
-# 删除容器
+## 删除容器
$ docker rm abc123
-# 数据丢了!没有任何办法恢复!
+## 数据丢了!没有任何办法恢复!
```
-### 正确的数据持久化方式
+#### 正确的数据持久化方式
按照 Docker 最佳实践,容器存储层应该保持**无状态**。需要持久化的数据应该使用:
@@ -129,16 +129,16 @@ $ docker rm abc123
| **[绑定挂载(Bind Mount)](../07_data_network/data/bind-mounts.md)** | 挂载宿主机目录 | 开发时共享代码 |
```bash
-# 使用数据卷(推荐)
+## 使用数据卷(推荐)
$ docker run -v mydata:/var/lib/mysql mysql
-# 使用绑定挂载
+## 使用绑定挂载
$ docker run -v /host/path:/container/path nginx
```
这些位置的读写**会跳过容器存储层**,直接写入宿主机,性能更好,也不会随容器删除而丢失。
-## 容器的生命周期
+### 容器的生命周期
```
┌──────────────────────────────────────────────────┐
@@ -167,51 +167,51 @@ $ docker run -v /host/path:/container/path nginx
└──────────┘
```
-### 常用生命周期命令
+#### 常用生命周期命令
```bash
-# 创建并启动容器(最常用)
+## 创建并启动容器(最常用)
$ docker run nginx
-# 分步操作
+## 分步操作
$ docker create nginx # 创建容器(不启动)
$ docker start abc123 # 启动容器
-# 停止容器
+## 停止容器
$ docker stop abc123 # 优雅停止(发送 SIGTERM,等待后发送 SIGKILL)
$ docker kill abc123 # 强制停止(直接发送 SIGKILL)
-# 暂停/恢复(不常用,但有时有用)
+## 暂停/恢复(不常用,但有时有用)
$ docker pause abc123 # 暂停容器内所有进程
$ docker unpause abc123 # 恢复
-# 删除容器
+## 删除容器
$ docker rm abc123 # 删除已停止的容器
$ docker rm -f abc123 # 强制删除运行中的容器
```
-## 容器与进程的关系
+### 容器与进程的关系
> **核心概念**:容器的生命周期 = 主进程(PID 1)的生命周期
```bash
-# 主进程运行,容器运行
-# 主进程退出,容器停止
+## 主进程运行,容器运行
+## 主进程退出,容器停止
```
这就是为什么:
```bash
-# 这个容器会立即退出(bash 没有输入就退出了)
+## 这个容器会立即退出(bash 没有输入就退出了)
$ docker run ubuntu
-# 这个容器会持续运行(nginx 作为守护进程持续运行)
+## 这个容器会持续运行(nginx 作为守护进程持续运行)
$ docker run nginx
```
-详细解释请参考[后台运行](../05_container/daemon.md)章节。
+详细解释请参考[后台运行](../05_container/5.2_daemon.md)章节。
-## 容器的隔离性
+### 容器的隔离性
Docker 容器通过以下 Namespace 实现隔离:
@@ -224,9 +224,9 @@ Docker 容器通过以下 Namespace 实现隔离:
| **IPC** | 进程间通信 | 独立的信号量、消息队列 |
| **USER** | 用户 | 独立的用户和组 ID |
-> 想深入了解?请阅读[底层实现 - 命名空间](../13_implementation/namespace.md)。
+> 想深入了解?请阅读[底层实现 - 命名空间](../13_implementation/13.2_namespace.md)。
-## 本章小结
+### 本章小结
| 概念 | 要点 |
|------|------|
@@ -236,11 +236,11 @@ Docker 容器通过以下 Namespace 实现隔离:
| **数据持久化** | 使用 Volume 或 Bind Mount |
| **生命周期** | 与主进程(PID 1)绑定 |
-理解了镜像和容器,接下来让我们学习[仓库](repository.md)——存储和分发镜像的服务。
+理解了镜像和容器,接下来让我们学习[仓库](2.3_repository.md)——存储和分发镜像的服务。
-## 延伸阅读
+### 延伸阅读
-- [启动容器](../05_container/run.md):详细的容器启动选项
-- [后台运行](../05_container/daemon.md):理解容器为什么会"立即退出"
-- [进入容器](../05_container/attach_exec.md):如何操作运行中的容器
+- [启动容器](../05_container/5.1_run.md):详细的容器启动选项
+- [后台运行](../05_container/5.2_daemon.md):理解容器为什么会"立即退出"
+- [进入容器](../05_container/5.4_attach_exec.md):如何操作运行中的容器
- [数据管理](../07_data_network/README.md):Volume 和数据持久化详解
diff --git a/02_basic_concept/repository.md b/02_basic_concept/2.3_repository.md
similarity index 82%
rename from 02_basic_concept/repository.md
rename to 02_basic_concept/2.3_repository.md
index 7e748e4..263c980 100644
--- a/02_basic_concept/repository.md
+++ b/02_basic_concept/2.3_repository.md
@@ -1,14 +1,14 @@
-# Docker Registry
+## Docker Registry
-## 一句话理解 Registry
+### 一句话理解 Registry
> **Docker Registry 是存储和分发 Docker 镜像的服务,类似于代码的 GitHub 或包管理的 npm。**
镜像构建完成后,可以在当前机器上运行。但如果需要在其他服务器上使用这个镜像,就需要一个集中的存储和分发服务——这就是 Docker Registry。
-## 核心概念
+### 核心概念
-### Registry、仓库、标签的关系
+#### Registry、仓库、标签的关系
```
┌─────────────────────────────────────────────────────────────────────┐
@@ -37,7 +37,7 @@
| **Repository(仓库)** | 同一软件的镜像集合 | `nginx`、`mysql`、`mycompany/myapp` |
| **Tag(标签)** | 仓库内的版本标识 | `latest`、`1.25`、`alpine` |
-### 镜像的完整名称
+#### 镜像的完整名称
```
[registry地址/][用户名/]仓库名[:标签]
@@ -46,7 +46,7 @@
示例:
```bash
-# 完整格式
+## 完整格式
registry.example.com/mycompany/myapp:v1.2.3
│ │ │ │
│ │ │ └── 标签
@@ -54,23 +54,23 @@ registry.example.com/mycompany/myapp:v1.2.3
│ └── 用户名/组织名
└── Registry 地址
-# Docker Hub 官方镜像(省略 registry 和用户名)
+## Docker Hub 官方镜像(省略 registry 和用户名)
nginx:1.25
ubuntu:24.04
-# Docker Hub 用户镜像
+## Docker Hub 用户镜像
jwilder/nginx-proxy:latest
-# 其他 Registry
+## 其他 Registry
ghcr.io/username/myapp:v1.0
gcr.io/google-containers/pause:3.6
```
> 💡 **笔者提示**:如果不指定 Registry 地址,默认使用 Docker Hub。如果不指定标签,默认使用 `latest`。
-## 公共 Registry 服务
+### 公共 Registry 服务
-### Docker Hub(默认)
+#### Docker Hub(默认)
[Docker Hub](https://hub.docker.com/) 是最大的公共 Registry,也是 Docker 的默认 Registry。
@@ -80,16 +80,16 @@ gcr.io/google-containers/pause:3.6
- 付费账户支持私有仓库
```bash
-# 从 Docker Hub 拉取镜像
+## 从 Docker Hub 拉取镜像
$ docker pull nginx # 官方镜像
$ docker pull bitnami/redis # 第三方镜像
-# 推送镜像到 Docker Hub
+## 推送镜像到 Docker Hub
$ docker login
$ docker push username/myapp:v1.0
```
-### 其他公共 Registry
+#### 其他公共 Registry
| Registry | 地址 | 说明 |
|----------|------|------|
@@ -99,7 +99,7 @@ $ docker push username/myapp:v1.0
| **阿里云容器镜像服务** | registry.cn-*.aliyuncs.com | 国内访问快 |
| **腾讯云容器镜像服务** | ccr.ccs.tencentyun.com | 国内访问快 |
-## 镜像加速器
+### 镜像加速器
由于网络原因,在国内直接访问 Docker Hub 可能会很慢。可以配置**镜像加速器**(Registry Mirror)来加速下载。
@@ -112,38 +112,38 @@ $ docker push username/myapp:v1.0
}
```
-详细配置方法请参考[镜像加速器](../install/mirror.md)章节。
+详细配置方法请参考[镜像加速器](../install/3.9_mirror.md)章节。
> ⚠️ **笔者提醒**:镜像加速器的可用性经常变化,使用前建议先测试是否可用。
-## 私有 Registry
+### 私有 Registry
对于企业用户,通常需要搭建私有 Registry 来存储内部镜像。
-### 官方 Registry 镜像
+#### 官方 Registry 镜像
Docker 官方提供了 [registry](https://hub.docker.com/_/registry/) 镜像,可以快速搭建私有 Registry:
```bash
-# 启动一个本地 Registry
+## 启动一个本地 Registry
$ docker run -d -p 5000:5000 --name registry registry:2
-# 推送镜像到本地 Registry
+## 推送镜像到本地 Registry
$ docker tag myapp:v1.0 localhost:5000/myapp:v1.0
$ docker push localhost:5000/myapp:v1.0
-# 从本地 Registry 拉取
+## 从本地 Registry 拉取
$ docker pull localhost:5000/myapp:v1.0
```
-### 企业级解决方案
+#### 企业级解决方案
官方 Registry 功能较为基础,企业环境常用以下方案:
| 方案 | 特点 |
|------|------|
| **[Harbor](https://goharbor.io/)** | CNCF 项目,功能全面(用户管理、漏洞扫描、镜像签名) |
-| **[Nexus Repository](../repository/nexus3_registry.md)** | 支持多种制品类型(Docker、Maven、npm 等) |
+| **[Nexus Repository](../repository/6.4_nexus3_registry.md)** | 支持多种制品类型(Docker、Maven、npm 等) |
| **云厂商服务** | 阿里云 ACR、腾讯云 TCR、AWS ECR 等 |
笔者建议:
@@ -151,9 +151,9 @@ $ docker pull localhost:5000/myapp:v1.0
- 中大型团队:推荐 Harbor,功能完善且开源免费
- 已使用云服务:直接用云厂商的 Registry 服务更省心
-## 镜像的推送和拉取
+### 镜像的推送和拉取
-### 完整工作流程
+#### 完整工作流程
```
开发者机器 Registry 生产服务器
@@ -171,66 +171,66 @@ $ docker pull localhost:5000/myapp:v1.0
│ │ 运行容器 │
```
-### 常用命令
+#### 常用命令
```bash
-# 登录 Registry
+## 登录 Registry
$ docker login # 登录 Docker Hub
$ docker login registry.example.com # 登录其他 Registry
-# 拉取镜像
+## 拉取镜像
$ docker pull nginx:1.25
-# 标记镜像(准备推送)
+## 标记镜像(准备推送)
$ docker tag myapp:latest registry.example.com/myteam/myapp:v1.0
-# 推送镜像
+## 推送镜像
$ docker push registry.example.com/myteam/myapp:v1.0
-# 登出
+## 登出
$ docker logout
```
-## 镜像的安全性
+### 镜像的安全性
-### 使用官方镜像
+#### 使用官方镜像
Docker Hub 的[官方镜像](https://hub.docker.com/search?q=&type=image&image_filter=official)(标有 "Official Image" 标识)经过 Docker 团队审核,相对更安全。
```bash
-# 官方镜像示例
+## 官方镜像示例
nginx # ✅ 官方
mysql # ✅ 官方
redis # ✅ 官方
-# 第三方镜像(需要自行评估可信度)
+## 第三方镜像(需要自行评估可信度)
bitnami/redis # ⚠️ 需要评估
someuser/myapp # ⚠️ 需要评估
```
-### 镜像签名
+#### 镜像签名
使用 Docker Content Trust (DCT) 验证镜像来源:
```bash
-# 启用镜像签名验证
+## 启用镜像签名验证
$ export DOCKER_CONTENT_TRUST=1
-# 此后的 pull/push 会验证签名
+## 此后的 pull/push 会验证签名
$ docker pull nginx:latest
```
-### 漏洞扫描
+#### 漏洞扫描
```bash
-# 使用 Docker Scout 扫描镜像漏洞
+## 使用 Docker Scout 扫描镜像漏洞
$ docker scout cves nginx:latest
-# 使用 Trivy(开源工具)
+## 使用 Trivy(开源工具)
$ trivy image nginx:latest
```
-## 本章小结
+### 本章小结
| 概念 | 要点 |
|------|------|
@@ -240,11 +240,11 @@ $ trivy image nginx:latest
| **Docker Hub** | 默认的公共 Registry |
| **私有 Registry** | 企业内部使用,推荐 Harbor |
-现在你已经了解了 Docker 的三个核心概念:[镜像](image.md)、[容器](container.md)和仓库。接下来,让我们开始[安装 Docker](../install/README.md),动手实践!
+现在你已经了解了 Docker 的三个核心概念:[镜像](2.1_image.md)、[容器](2.2_container.md)和仓库。接下来,让我们开始[安装 Docker](../install/README.md),动手实践!
-## 延伸阅读
+### 延伸阅读
-- [Docker Hub](../repository/dockerhub.md):Docker Hub 的详细使用
-- [私有仓库](../repository/registry.md):搭建私有 Registry
-- [私有仓库高级配置](../repository/registry_auth.md):认证、TLS 配置
-- [镜像加速器](../install/mirror.md):配置镜像加速
+- [Docker Hub](../repository/6.1_dockerhub.md):Docker Hub 的详细使用
+- [私有仓库](../repository/6.2_registry.md):搭建私有 Registry
+- [私有仓库高级配置](../repository/6.3_registry_auth.md):认证、TLS 配置
+- [镜像加速器](../install/3.9_mirror.md):配置镜像加速
diff --git a/02_basic_concept/README.md b/02_basic_concept/README.md
index 38f8884..20bbf46 100644
--- a/02_basic_concept/README.md
+++ b/02_basic_concept/README.md
@@ -1,4 +1,4 @@
-# 基本概念
+# 第二章 基本概念
**Docker** 包括三个基本概念:
diff --git a/03_install/experimental.md b/03_install/3.10_experimental.md
similarity index 79%
rename from 03_install/experimental.md
rename to 03_install/3.10_experimental.md
index d32844e..4253e48 100644
--- a/03_install/experimental.md
+++ b/03_install/3.10_experimental.md
@@ -1,12 +1,12 @@
-# 开启实验特性
+## 开启实验特性
一些 docker 命令或功能仅当 **实验特性** 开启时才能使用,请按照以下方法进行设置。
-## Docker CLI 的实验特性
+### Docker CLI 的实验特性
从 `v20.10` 版本开始,Docker CLI 所有实验特性的命令均默认开启,无需再进行配置或设置系统环境变量。
-## 开启 dockerd 的实验特性
+### 开启 dockerd 的实验特性
编辑 `/etc/docker/daemon.json`,新增如下条目
diff --git a/03_install/ubuntu.md b/03_install/3.1_ubuntu.md
similarity index 85%
rename from 03_install/ubuntu.md
rename to 03_install/3.1_ubuntu.md
index baf3c07..e2c1ea6 100644
--- a/03_install/ubuntu.md
+++ b/03_install/3.1_ubuntu.md
@@ -1,10 +1,10 @@
-# Ubuntu 安装 Docker
+## Ubuntu 安装 Docker
>警告:切勿在没有配置 Docker APT 源的情况下直接使用 apt 命令安装 Docker.
-## 准备工作
+### 准备工作
-### 系统要求
+#### 系统要求
Docker 支持诸多版本的 [Ubuntu](https://ubuntu.com/server) 操作系统。但是较旧的版本上将不会有 Docker 新版本的持续更新,以截至 2026 年初的几个 Ubuntu LTS(Long Term Support,长期支持)版本为例:
@@ -16,7 +16,7 @@ Docker 支持诸多版本的 [Ubuntu](https://ubuntu.com/server) 操作系统。
在 Ubuntu LTS 版本上,目前 Docker 支持 amd64、arm64、armhf、ppc64el、s390x 等 5 个平台;而非 LTS 版本支持的平台通常较少。同时,LTS 版本会获得 5 年的升级维护支持,这样的系统会获得更长期的安全保障,因此在生产环境中推荐使用 LTS 版本。
-### 卸载旧版本
+#### 卸载旧版本
旧版本的 Docker 称为 `docker` 或者 `docker-engine`,使用以下命令卸载旧版本:
@@ -33,7 +33,7 @@ do
done
```
-## 使用 APT 安装
+### 使用 APT 安装
由于 `apt` 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
@@ -56,8 +56,8 @@ $ sudo apt install \
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
-# 官方源
-# $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
+## 官方源
+## $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```
然后,我们需要向 `sources.list` 中添加 Docker 软件源
@@ -68,15 +68,15 @@ $ echo \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
-# 官方源
-# $ echo \
-# "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
-# $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+## 官方源
+## $ echo \
+## "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
+## $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
>以上命令会添加稳定版本的 Docker APT 镜像源,如果需要测试版本的 Docker 请将 stable 改为 test。
-### 安装 Docker
+#### 安装 Docker
更新 apt 软件包缓存,并安装 `docker-ce`:
@@ -86,29 +86,29 @@ $ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io
```
-## 使用脚本自动安装
+### 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
> 若你想安装测试版的 Docker, 请从 test.docker.com 获取脚本
```bash
-# $ curl -fsSL test.docker.com -o get-docker.sh
+## $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
-# $ sudo sh get-docker.sh --mirror AzureChinaCloud
+## $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。
-## 启动 Docker
+### 启动 Docker
```bash
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-## 建立 docker 用户组
+### 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好地做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -126,7 +126,7 @@ $ sudo usermod -aG docker $USER
退出当前终端并重新登录,进行如下测试。
-## 测试 Docker 是否安装正确
+### 测试 Docker 是否安装正确
```bash
$ docker run --rm hello-world
@@ -161,10 +161,10 @@ For more examples and ideas, visit:
若能正常输出以上信息,则说明安装成功。
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
-## 参考文档
+### 参考文档
* [Docker 官方 Ubuntu 安装文档](https://docs.docker.com/install/linux/docker-ce/ubuntu/)
diff --git a/03_install/debian.md b/03_install/3.2_debian.md
similarity index 85%
rename from 03_install/debian.md
rename to 03_install/3.2_debian.md
index 87c97d4..97c88de 100644
--- a/03_install/debian.md
+++ b/03_install/3.2_debian.md
@@ -1,10 +1,10 @@
-# Debian 安装 Docker
+## Debian 安装 Docker
>警告:切勿在没有配置 Docker APT 源的情况下直接使用 apt 命令安装 Docker.
-## 准备工作
+### 准备工作
-### 系统要求
+#### 系统要求
Docker 支持以下版本的 [Debian](https://www.debian.org/intro/about) 操作系统:
@@ -12,7 +12,7 @@ Docker 支持以下版本的 [Debian](https://www.debian.org/intro/about) 操作
* Debian Bookworm 12 (oldstable)
* Debian Bullseye 11 (LTS)
-### 卸载旧版本
+#### 卸载旧版本
旧版本的 Docker 称为 `docker` 或者 `docker-engine`,使用以下命令卸载旧版本:
@@ -22,7 +22,7 @@ $ sudo apt-get remove docker \
docker.io
```
-## 使用 APT 安装
+### 使用 APT 安装
由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
@@ -45,8 +45,8 @@ $ sudo apt-get install \
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
-# 官方源
-# $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
+## 官方源
+## $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```
然后,我们需要向 `sources.list` 中添加 Docker 软件源:
@@ -59,16 +59,16 @@ $ echo \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
-# 官方源
-# $ echo \
-# "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
-# $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+## 官方源
+## $ echo \
+## "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
+## $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
>以上命令会添加稳定版本的 Docker APT 源,如果需要测试版本的 Docker 请将 stable 改为 test。 Debian11可能不使用`/etc/apt/keyrings/`, 如gpg错误可以考虑更换为`/etc/apt/trusted.gpg.d`, 见[issue 15727](https://github.com/docker/docs/issues/15727)。
-### 安装 Docker
+#### 安装 Docker
更新 apt 软件包缓存,并安装 `docker-ce`。
@@ -78,29 +78,29 @@ $ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
```
-## 使用脚本自动安装
+### 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Debian 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
> 若你想安装测试版的 Docker, 请从 test.docker.com 获取脚本
```bash
-# $ curl -fsSL test.docker.com -o get-docker.sh
+## $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
-# $ sudo sh get-docker.sh --mirror AzureChinaCloud
+## $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。
-## 启动 Docker
+### 启动 Docker
```bash
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-## 建立 docker 用户组
+### 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好地做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -118,7 +118,7 @@ $ sudo usermod -aG docker $USER
退出当前终端并重新登录,进行如下测试。
-## 测试 Docker 是否安装正确
+### 测试 Docker 是否安装正确
```bash
$ docker run --rm hello-world
@@ -153,10 +153,10 @@ For more examples and ideas, visit:
若能正常输出以上信息,则说明安装成功。
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
-## 参考文档
+### 参考文档
* [Docker 官方 Debian 安装文档](https://docs.docker.com/install/linux/docker-ce/debian/)
diff --git a/03_install/fedora.md b/03_install/3.3_fedora.md
similarity index 88%
rename from 03_install/fedora.md
rename to 03_install/3.3_fedora.md
index 8e2db8f..fd80d6b 100644
--- a/03_install/fedora.md
+++ b/03_install/3.3_fedora.md
@@ -1,10 +1,10 @@
-# Fedora 安装 Docker
+## Fedora 安装 Docker
>警告:切勿在没有配置 Docker dnf 源的情况下直接使用 dnf 命令安装 Docker.
-## 准备工作
+### 准备工作
-### 系统要求
+#### 系统要求
Docker 支持以下版本的 [Fedora](https://getfedora.org/) 操作系统:
@@ -12,7 +12,7 @@ Docker 支持以下版本的 [Fedora](https://getfedora.org/) 操作系统:
* 42
* 43
-### 卸载旧版本
+#### 卸载旧版本
旧版本的 Docker 称为 `docker` 或者 `docker-engine`,使用以下命令卸载旧版本:
@@ -29,7 +29,7 @@ $ sudo dnf remove docker \
docker-engine
```
-## 使用 dnf 安装
+### 使用 dnf 安装
执行以下命令安装依赖包:
@@ -48,10 +48,10 @@ $ sudo dnf config-manager \
$ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
-# 官方源
-# $ sudo dnf config-manager \
-# --add-repo \
-# https://download.docker.com/linux/fedora/docker-ce.repo
+## 官方源
+## $ sudo dnf config-manager \
+## --add-repo \
+## https://download.docker.com/linux/fedora/docker-ce.repo
```
如果需要测试版本的 Docker 请使用以下命令:
@@ -66,7 +66,7 @@ $ sudo dnf config-manager --set-enabled docker-ce-test
$ sudo dnf config-manager --set-disabled docker-ce-test
```
-### 安装 Docker
+#### 安装 Docker
更新 `dnf` 软件源缓存,并安装 `docker-ce`。
@@ -85,29 +85,29 @@ docker-ce.x86_64 18.06.1.ce-3.fc28 docker-ce-stable
$ sudo dnf -y install docker-ce-18.06.1.ce
```
-## 使用脚本自动安装
+### 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Debian 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
> 若你想安装测试版的 Docker, 请从 test.docker.com 获取脚本
```bash
-# $ curl -fsSL test.docker.com -o get-docker.sh
+## $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
-# $ sudo sh get-docker.sh --mirror AzureChinaCloud
+## $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 最新稳定(stable)版本安装在系统中。
-## 启动 Docker
+### 启动 Docker
```bash
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-## 建立 docker 用户组
+### 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好地做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -125,7 +125,7 @@ $ sudo usermod -aG docker $USER
退出当前终端并重新登录,进行如下测试。
-## 测试 Docker 是否安装正确
+### 测试 Docker 是否安装正确
```bash
$ docker run --rm hello-world
@@ -160,10 +160,10 @@ For more examples and ideas, visit:
若能正常输出以上信息,则说明安装成功。
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
-## 参考文档
+### 参考文档
* [Docker 官方 Fedora 安装文档](https://docs.docker.com/install/linux/docker-ce/fedora)。
diff --git a/03_install/centos.md b/03_install/3.4_centos.md
similarity index 89%
rename from 03_install/centos.md
rename to 03_install/3.4_centos.md
index 9ea854d..786e01a 100644
--- a/03_install/centos.md
+++ b/03_install/3.4_centos.md
@@ -1,10 +1,10 @@
-# CentOS 安装 Docker
+## CentOS 安装 Docker
>警告:切勿在没有配置 Docker YUM 源的情况下直接使用 yum 命令安装 Docker.
-## 准备工作
+### 准备工作
-### 系统要求
+#### 系统要求
> ⚠️ **重要提示**:CentOS 8 已于 2021 年 12 月 31 日停止维护,CentOS 7 已于 2024 年 6 月 30 日结束支持。建议新项目使用 **Rocky Linux** 或 **AlmaLinux** 作为替代。
@@ -12,7 +12,7 @@ Docker 支持 64 位版本 CentOS Stream 9、Rocky Linux 8/9、AlmaLinux 8/9,
对于 Rocky Linux、AlmaLinux 或 CentOS Stream,推荐使用 `dnf` 包管理器。
-### 卸载旧版本
+#### 卸载旧版本
旧版本的 Docker 称为 `docker` 或者 `docker-engine`,使用以下命令卸载旧版本:
@@ -31,7 +31,7 @@ $ sudo yum remove docker \
containerd.io
```
-## 使用 yum 安装
+### 使用 yum 安装
执行以下命令安装依赖包:
@@ -50,10 +50,10 @@ $ sudo dnf config-manager \
$ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/dnf.repos.d/docker-ce.repo
-# 官方源
-# $ sudo dnf config-manager \
-# --add-repo \
-# https://download.docker.com/linux/centos/docker-ce.repo
+## 官方源
+## $ sudo dnf config-manager \
+## --add-repo \
+## https://download.docker.com/linux/centos/docker-ce.repo
```
如果需要测试版本的 Docker 请执行以下命令:
@@ -62,7 +62,7 @@ $ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/dnf.r
$ sudo dnf config-manager --enable docker-ce-test
```
-### 安装 Docker
+#### 安装 Docker
更新 `dnf` 软件源缓存,并安装 `docker-ce`。
@@ -70,14 +70,14 @@ $ sudo dnf config-manager --enable docker-ce-test
$ sudo dnf install docker-ce docker-ce-cli containerd.io
```
-## CentOS8 额外设置
+### CentOS8 额外设置
由于 CentOS8 防火墙使用了 `nftables`,但 Docker 尚未支持 `nftables`, 我们可以使用如下设置使用 `iptables`:
更改 `/etc/firewalld/firewalld.conf`
```bash
-# FirewallBackend=nftables
+## FirewallBackend=nftables
FirewallBackend=iptables
```
@@ -89,29 +89,29 @@ $ firewall-cmd --permanent --zone=trusted --add-interface=docker0
$ firewall-cmd --reload
```
-## 使用脚本自动安装
+### 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
> 若你想安装测试版的 Docker, 请从 test.docker.com 获取脚本
```bash
-# $ curl -fsSL test.docker.com -o get-docker.sh
+## $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
-# $ sudo sh get-docker.sh --mirror AzureChinaCloud
+## $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。
-## 启动 Docker
+### 启动 Docker
```bash
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-## 建立 docker 用户组
+### 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好地做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -129,7 +129,7 @@ $ sudo usermod -aG docker $USER
退出当前终端并重新登录,进行如下测试。
-## 测试 Docker 是否安装正确
+### 测试 Docker 是否安装正确
```bash
$ docker run --rm hello-world
@@ -164,11 +164,11 @@ For more examples and ideas, visit:
若能正常输出以上信息,则说明安装成功。
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
-## 添加内核参数
+### 添加内核参数
如果在 CentOS 使用 Docker 看到下面的这些警告信息:
@@ -192,7 +192,7 @@ EOF
$ sudo sysctl -p
```
-## 参考文档
+### 参考文档
* [Docker 官方 CentOS 安装文档](https://docs.docker.com/install/linux/docker-ce/centos/)。
* https://firewalld.org/2018/07/nftables-backend
diff --git a/03_install/raspberry-pi.md b/03_install/3.5_raspberry-pi.md
similarity index 87%
rename from 03_install/raspberry-pi.md
rename to 03_install/3.5_raspberry-pi.md
index 122b995..f7422b0 100644
--- a/03_install/raspberry-pi.md
+++ b/03_install/3.5_raspberry-pi.md
@@ -1,8 +1,8 @@
-# 树莓派卡片电脑安装 Docker
+## 树莓派卡片电脑安装 Docker
>警告:切勿在没有配置 Docker APT 源的情况下直接使用 apt 命令安装 Docker.
-## 系统要求
+### 系统要求
Docker 不仅支持 `x86_64` 架构的计算机,同时也支持 `ARM` 架构的计算机,本小节内容以树莓派单片电脑为例讲解 `ARM` 架构安装 Docker。
@@ -14,7 +14,7 @@ Docker 支持以下版本的 [Raspberry Pi OS](https://www.raspberrypi.org/softw
*注:* `Raspberry Pi OS` 由树莓派的开发与维护机构 [树莓派基金会](https://www.raspberrypi.org/) 官方支持,并推荐用作树莓派的首选系统,其基于 `Debian`。
-## 使用 APT 安装
+### 使用 APT 安装
由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
@@ -38,8 +38,8 @@ $ sudo apt-get install \
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/raspbian/gpg | sudo apt-key add -
-# 官方源
-# $ curl -fsSL https://download.docker.com/linux/raspbian/gpg | sudo apt-key add -
+## 官方源
+## $ curl -fsSL https://download.docker.com/linux/raspbian/gpg | sudo apt-key add -
```
然后,我们需要向 `sources.list` 中添加 Docker 软件源:
@@ -51,16 +51,16 @@ $ sudo add-apt-repository \
stable"
-# 官方源
-# $ sudo add-apt-repository \
-# "deb [arch=armhf] https://download.docker.com/linux/raspbian \
-# $(lsb_release -cs) \
-# stable"
+## 官方源
+## $ sudo add-apt-repository \
+## "deb [arch=armhf] https://download.docker.com/linux/raspbian \
+## $(lsb_release -cs) \
+## stable"
```
>以上命令会添加稳定版本的 Docker APT 源,如果需要测试版本的 Docker 请将 stable 改为 test。
-#### 报错解决办法
+##### 报错解决办法
在 `Raspberry Pi OS Bullseye/Bookworm` 中,添加 Docker 软件源的步骤可能会出现如下报错:
@@ -83,11 +83,11 @@ aptsources.distro.NoDistroTemplateException: Error: could not find a distributio
$ sudo echo "deb [arch=armhf] https://mirrors.aliyun.com/docker-ce/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list
-# 官方源
-# $ sudo echo "deb [arch=armhf] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list
+## 官方源
+## $ sudo echo "deb [arch=armhf] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list
```
-### 安装 Docker
+#### 安装 Docker
更新 apt 软件包缓存,并安装 `docker-ce`。
@@ -97,29 +97,29 @@ $ sudo apt-get update
$ sudo apt-get install docker-ce
```
-## 使用脚本自动安装
+### 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Raspberry Pi OS 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
> 若你想安装测试版的 Docker, 请从 test.docker.com 获取脚本
```bash
-# $ curl -fsSL test.docker.com -o get-docker.sh
+## $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
-# $ sudo sh get-docker.sh --mirror AzureChinaCloud
+## $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定(stable)版本安装在系统中。
-## 启动 Docker
+### 启动 Docker
```bash
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-## 建立 docker 用户组
+### 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好地做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -137,7 +137,7 @@ $ sudo usermod -aG docker $USER
退出当前终端并重新登录,进行如下测试。
-## 测试 Docker 是否安装正确
+### 测试 Docker 是否安装正确
```bash
$ docker run --rm hello-world
@@ -174,6 +174,6 @@ For more examples and ideas, visit:
*注意:* ARM 平台不能使用 `x86` 镜像,查看 Raspberry Pi OS 可使用镜像请访问 [arm32v7](https://hub.docker.com/u/arm32v7/) 或者 [arm64v8](https://hub.docker.com/u/arm64v8/)。
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
diff --git a/03_install/offline.md b/03_install/3.6_offline.md
similarity index 87%
rename from 03_install/offline.md
rename to 03_install/3.6_offline.md
index f47aa0a..b060004 100644
--- a/03_install/offline.md
+++ b/03_install/3.6_offline.md
@@ -1,4 +1,4 @@
-# Linux 离线安装
+## Linux 离线安装
\[TOC]
@@ -8,15 +8,15 @@

-## CentOS/Rocky/AlmaLinux 离线安装Docker
+### CentOS/Rocky/AlmaLinux 离线安装Docker
> 注意:以下命令以 CentOS 7 为例。对于 CentOS Stream 9、Rocky Linux 9 或 AlmaLinux 9,请将 `yum` 替换为 `dnf`,并将软件包后缀 `el7` 替换为 `el9`。
-### YUM本地文件安装(推荐)
+#### YUM本地文件安装(推荐)
推荐这种方式,是因为在生产环境种一般会选定某个指定的文档软件版本使用。
-#### 查询可用的软件版本(A)
+##### 查询可用的软件版本(A)
```bash
#下载清华的镜像源文件
@@ -43,7 +43,7 @@ docker-ce.x86_64 3:19.03.1-3.el7 docker-ce-stable
....
```
-#### 下载到指定文件夹(A)
+##### 下载到指定文件夹(A)
```bash
sudo yum install --downloadonly --downloaddir=/tmp/docker24_offline_install/ docker-ce-24.0.4-1.el7 docker-ce-cli-24.0.4-1.el7
@@ -78,7 +78,7 @@ Total
exiting because "Download Only" specified
```
-#### 复制到目标服务器之后进入文件夹安装(C-N)
+##### 复制到目标服务器之后进入文件夹安装(C-N)
* 离线安装时,必须使用rpm命令不检查依赖的方式安装
@@ -86,7 +86,7 @@ exiting because "Download Only" specified
rpm -Uvh *.rpm --nodeps --force
```
-#### 锁定软件版本(C-N)
+##### 锁定软件版本(C-N)
**下载锁定版本软件**
@@ -143,19 +143,19 @@ versionlock deleted: 1
sudo yum versionlock delete all
```
-### YUM 本地源服务器搭建安装Docker
+#### YUM 本地源服务器搭建安装Docker
-#### 挂载 ISO 镜像搭建本地 File 源(AB)
+##### 挂载 ISO 镜像搭建本地 File 源(AB)
```bash
-# 删除其他网络源
+## 删除其他网络源
rm -f /etc/yum.repo.d/*
-# 挂载光盘或者iso镜像
+## 挂载光盘或者iso镜像
mount /dev/cdrom /mnt
```
```bash
-# 添加本地源
+## 添加本地源
cat >/etc/yum.repos.d/local_files.repo<< EOF
[Local_Files]
name=Local_Files
@@ -167,69 +167,69 @@ EOF
```
```bash
-# 测试刚才的本地源,安装createrepo软件
+## 测试刚才的本地源,安装createrepo软件
yum clean all
yum install createrepo -y
```
-#### 根据本地文件搭建BASE网络源(B)
+##### 根据本地文件搭建BASE网络源(B)
```bash
-# 安装apache 服务器
+## 安装apache 服务器
yum install httpd -y
-# 挂载光盘
+## 挂载光盘
mount /dev/cdrom /mnt
-# 新建centos目录
+## 新建centos目录
mkdir /var/www/html/base
-# 复制光盘内的文件到刚才新建的目录
+## 复制光盘内的文件到刚才新建的目录
cp -R /mnt/Packages/* /var/www/html/base/
createrepo /var/www/html/centos/
systemctl enable httpd
systemctl start httpd
```
-#### 下载Docker-CE 镜像仓库(A)
+##### 下载Docker-CE 镜像仓库(A)
在有网络的服务器上下载Docker-ce镜像
```bash
-# 下载清华的镜像源文件
+## 下载清华的镜像源文件
wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
```
```bash
-# 新建 docker-ce目录
+## 新建 docker-ce目录
mkdir /tmp/docker-ce/
-# 把镜像源同步到镜像文件中
+## 把镜像源同步到镜像文件中
reposync -r docker-ce-stable -p /tmp/docker-ce/
```
-#### 创建仓库索引(B)
+##### 创建仓库索引(B)
把下载的 docker-ce 文件夹复制到离线的服务器
```bash
-# 把docker-ce 文件夹复制到/var/www/html/docker-ce
-# 重建索引
+## 把docker-ce 文件夹复制到/var/www/html/docker-ce
+## 重建索引
createrepo /var/www/html/docker-ce/
```
-#### YUM 客户端设置(C...N)
+##### YUM 客户端设置(C...N)
```bash
rm -f /etc/yum.repo.d/*
cat >/etc/yum.repos.d/local_files.repo<< EOF
[local_base]
name=local_base
-# 改成B服务器地址
+## 改成B服务器地址
baseurl=http://x.x.x.x/base
enable=1
gpgcheck=0
proxy=_none_
[docker_ce]
name=docker_ce
-# 改成B服务器地址
+## 改成B服务器地址
baseurl=http://x.x.x.x/base
enable=1
gpgcheck=0
@@ -238,7 +238,7 @@ EOF
```
-#### Docker 安装(C...N)
+##### Docker 安装(C...N)
```bash
sudo yum makecache fast
diff --git a/03_install/mac.md b/03_install/3.7_mac.md
similarity index 92%
rename from 03_install/mac.md
rename to 03_install/3.7_mac.md
index e30ff38..8c09ded 100644
--- a/03_install/mac.md
+++ b/03_install/3.7_mac.md
@@ -1,12 +1,12 @@
-# macOS
+## macOS
-## 系统要求
+### 系统要求
[Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/) 要求系统最低为 macOS Sonora 14.0 或更高版本,建议升级到最新版本的 macOS。
-## 安装
+### 安装
-### 使用 Homebrew 安装
+#### 使用 Homebrew 安装
[Homebrew](https://brew.sh/) 的 [Cask](https://github.com/Homebrew/homebrew-cask) 已经支持 Docker Desktop for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装:
@@ -14,7 +14,7 @@
$ brew install --cask docker
```
-### 手动下载安装
+#### 手动下载安装
如果需要手动下载,请点击以下 [链接](https://desktop.docker.com/mac/main/amd64/Docker.dmg) 下载 Docker Desktop for Mac。
@@ -24,7 +24,7 @@ $ brew install --cask docker

-## 运行
+### 运行
从应用中找到 Docker 图标并点击运行。
@@ -62,10 +62,10 @@ $ docker stop webserver
$ docker rm webserver
```
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
-## 参考链接
+### 参考链接
* [官方文档](https://docs.docker.com/docker-for-mac/install/)
diff --git a/03_install/windows.md b/03_install/3.8_windows.md
similarity index 89%
rename from 03_install/windows.md
rename to 03_install/3.8_windows.md
index bf8f567..4baf68d 100644
--- a/03_install/windows.md
+++ b/03_install/3.8_windows.md
@@ -1,10 +1,10 @@
-# Windows 10/11
+## Windows 10/11
-## 系统要求
+### 系统要求
[Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/install/) 支持 64 位版本的 Windows 11 或 Windows 10(需开启 Hyper-V),推荐使用 Windows 11。
-## 安装
+### 安装
**手动下载安装**
@@ -18,11 +18,11 @@
$ winget install Docker.DockerDesktop
```
-## 在 WSL2 运行 Docker
+### 在 WSL2 运行 Docker
若你的 Windows 版本为 Windows 10 专业版或家庭版 v1903 及以上版本可以使用 WSL2 运行 Docker,具体请查看 [Docker Desktop WSL 2 backend](https://docs.docker.com/docker-for-windows/wsl/)。
-## 运行
+### 运行
在 Windows 搜索栏输入 **Docker** 点击 **Docker Desktop** 开始运行。
@@ -36,11 +36,11 @@ Docker 启动之后会在 Windows 任务栏出现鲸鱼图标。
> 推荐使用 [Windows Terminal](https://docs.microsoft.com/zh-cn/windows/terminal/get-started) 在终端使用 Docker。
-## 镜像加速
+### 镜像加速
-如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。
+如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
-## 参考链接
+### 参考链接
* [官方文档](https://docs.docker.com/docker-for-windows/install/)
* [WSL 2 Support is coming to Windows 10 Versions 1903 and 1909](https://devblogs.microsoft.com/commandline/wsl-2-support-is-coming-to-windows-10-versions-1903-and-1909/)
diff --git a/03_install/mirror.md b/03_install/3.9_mirror.md
similarity index 94%
rename from 03_install/mirror.md
rename to 03_install/3.9_mirror.md
index 03f967e..be30fad 100644
--- a/03_install/mirror.md
+++ b/03_install/3.9_mirror.md
@@ -1,10 +1,10 @@
-# 镜像加速器
+## 镜像加速器
国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。
> ⚠️ **注意**:镜像加速器的可用性经常变化。配置前请先访问 [docker-practice/docker-registry-cn-mirror-test](https://github.com/docker-practice/docker-registry-cn-mirror-test/actions) 查看各镜像站的实时状态。
-## 推荐配置方案
+### 推荐配置方案
1. **云服务器用户**:优先使用所在云平台提供的内部加速器(见本页末尾)
2. **本地开发用户**:使用阿里云个人加速器或其他可用的公共加速器
@@ -16,7 +16,7 @@
> `hub.atomgit.com` 仅包含部分官方镜像,可以满足初学者的使用。
-## Ubuntu 16.04+、Debian 8+、CentOS 7+
+### Ubuntu 16.04+、Debian 8+、CentOS 7+
目前主流 Linux 发行版均已使用 [systemd](https://systemd.io/) 进行服务管理,这里介绍如何在使用 systemd 的 Linux 发行版中配置镜像加速器。
@@ -47,7 +47,7 @@ $ sudo systemctl daemon-reload
$ sudo systemctl restart docker
```
-## Windows 10
+### Windows 10
对于使用 `Windows 10` 的用户,在任务栏托盘 Docker 图标内右键菜单选择 `Change settings`,打开配置窗口后在左侧导航菜单选择 `Docker Engine`,在右侧像下边一样编辑 json 文件,之后点击 `Apply & Restart` 保存后 Docker 就会重启并应用配置的镜像地址了。
@@ -59,7 +59,7 @@ $ sudo systemctl restart docker
}
```
-## macOS
+### macOS
对于使用 macOS 的用户,在任务栏点击 Docker Desktop 应用图标 -> `Settings...`,在左侧导航菜单选择 `Docker Engine`,在右侧像下边一样编辑 json 文件。修改完成之后,点击 `Apply & restart` 按钮,Docker 就会重启并应用配置的镜像地址了。
@@ -71,7 +71,7 @@ $ sudo systemctl restart docker
}
```
-## 检查加速器是否生效
+### 检查加速器是否生效
执行 `$ docker info`,如果从结果中看到了如下内容,说明配置成功。
@@ -80,7 +80,7 @@ Registry Mirrors:
https://hub.atomgit.com/
```
-## `k8s.gcr.io` 镜像
+### `k8s.gcr.io` 镜像
可以登录 [阿里云 容器镜像服务](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu&type=copy) **镜像中心** -> **镜像搜索** 查找。
@@ -89,12 +89,12 @@ Registry Mirrors:
一般情况下有如下对应关系:
```bash
-# $ docker pull k8s.gcr.io/xxx
+## $ docker pull k8s.gcr.io/xxx
$ docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/xxx
```
-## 不再提供服务的镜像
+### 不再提供服务的镜像
某些镜像不再提供服务,添加无用的镜像加速器,会拖慢镜像拉取速度,你可以从镜像配置列表中删除它们。
@@ -106,7 +106,7 @@ $ docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/xxx
建议 **watch(页面右上角)** [镜像测试](https://github.com/docker-practice/docker-registry-cn-mirror-test) 这个 GitHub 仓库,我们会在此更新各个镜像地址的状态。
-## 云服务商
+### 云服务商
某些云服务商提供了 **仅供内部** 访问的镜像服务,当您的 Docker 运行在云平台时可以选择它们。
diff --git a/03_install/README.md b/03_install/README.md
index cfa04d0..7f51f98 100644
--- a/03_install/README.md
+++ b/03_install/README.md
@@ -1,4 +1,4 @@
-# 安装 Docker
+# 第三章 安装 Docker
Docker 分为 `stable` `test` 和 `nightly` 三个更新频道。
diff --git a/04_image/pull.md b/04_image/4.1_pull.md
similarity index 84%
rename from 04_image/pull.md
rename to 04_image/4.1_pull.md
index 3acf58b..edaab42 100644
--- a/04_image/pull.md
+++ b/04_image/4.1_pull.md
@@ -1,6 +1,6 @@
-# 获取镜像
+## 获取镜像
-## docker pull 命令
+### docker pull 命令
从镜像仓库获取镜像的命令是 `docker pull`:
@@ -8,7 +8,7 @@
docker pull [选项] [Registry地址/]仓库名[:标签]
```
-### 镜像名称格式
+#### 镜像名称格式
```
docker.io / library / ubuntu : 24.04
@@ -25,31 +25,31 @@ Registry地址 用户名 仓库名 标签
| 仓库名 | 镜像名称 | 必须指定 |
| 标签 | 版本标识 | `latest` |
-### 示例
+#### 示例
```bash
-# 完整格式
+## 完整格式
$ docker pull docker.io/library/ubuntu:24.04
-# 省略 Registry(默认 Docker Hub)
+## 省略 Registry(默认 Docker Hub)
$ docker pull library/ubuntu:24.04
-# 省略 library(官方镜像)
+## 省略 library(官方镜像)
$ docker pull ubuntu:24.04
-# 省略标签(默认 latest)
+## 省略标签(默认 latest)
$ docker pull ubuntu
-# 拉取第三方镜像
+## 拉取第三方镜像
$ docker pull bitnami/redis:latest
-# 从其他 Registry 拉取
+## 从其他 Registry 拉取
$ docker pull ghcr.io/username/myapp:v1.0
```
---
-## 下载过程解析
+### 下载过程解析
```bash
$ docker pull ubuntu:24.04
@@ -62,7 +62,7 @@ Status: Downloaded newer image for ubuntu:24.04
docker.io/library/ubuntu:24.04
```
-### 输出解读
+#### 输出解读
| 输出内容 | 说明 |
|---------|------|
@@ -71,7 +71,7 @@ docker.io/library/ubuntu:24.04
| `Digest: sha256:...` | 镜像内容的唯一摘要 |
| `docker.io/library/ubuntu:24.04` | 镜像的完整名称 |
-### 分层下载
+#### 分层下载
从输出可以看到,镜像是**分层下载**的:
@@ -91,7 +91,7 @@ docker.io/library/ubuntu:24.04
---
-## 常用选项
+### 常用选项
| 选项 | 说明 | 示例 |
|------|------|------|
@@ -99,7 +99,7 @@ docker.io/library/ubuntu:24.04
| `--platform` | 指定平台架构 | `docker pull --platform linux/arm64 nginx` |
| `--quiet, -q` | 静默模式 | `docker pull -q nginx` |
-### 指定平台
+#### 指定平台
在 Apple Silicon Mac 上拉取 x86 镜像:
@@ -109,15 +109,15 @@ $ docker pull --platform linux/amd64 nginx
---
-## 拉取后运行
+### 拉取后运行
拉取镜像后,可以基于它启动容器:
```bash
-# 拉取镜像
+## 拉取镜像
$ docker pull ubuntu:24.04
-# 运行容器
+## 运行容器
$ docker run -it --rm ubuntu:24.04 bash
root@e7009c6ce357:/# cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04 LTS"
@@ -137,7 +137,7 @@ root@e7009c6ce357:/# exit
---
-## 镜像加速
+### 镜像加速
从 Docker Hub 下载可能较慢。可以配置镜像加速器:
@@ -155,16 +155,16 @@ root@e7009c6ce357:/# exit
```bash
$ sudo systemctl restart docker # Linux
-# 或在 Docker Desktop 中重启
+## 或在 Docker Desktop 中重启
```
-详见 [镜像加速器](../install/mirror.md) 章节。
+详见 [镜像加速器](../install/3.9_mirror.md) 章节。
---
-## 验证镜像完整性
+### 验证镜像完整性
-### 查看镜像摘要
+#### 查看镜像摘要
```bash
$ docker images --digests ubuntu
@@ -172,7 +172,7 @@ REPOSITORY TAG DIGEST
ubuntu 24.04 sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26 ca2b0f26964c
```
-### 使用摘要拉取
+#### 使用摘要拉取
用摘要拉取可确保获取完全相同的镜像:
@@ -184,15 +184,15 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
---
-## 常见问题
+### 常见问题
-### Q: 下载速度很慢
+#### Q: 下载速度很慢
1. 配置镜像加速器
2. 检查网络连接
3. 尝试拉取更小的镜像版本(如 `alpine` 变体)
-### Q: 提示镜像不存在
+#### Q: 提示镜像不存在
```bash
Error: pull access denied, repository does not exist
@@ -203,19 +203,19 @@ Error: pull access denied, repository does not exist
- 私有镜像未登录(需要 `docker login`)
- 镜像确实不存在
-### Q: 磁盘空间不足
+#### Q: 磁盘空间不足
```bash
-# 清理未使用的镜像
+## 清理未使用的镜像
$ docker image prune
-# 清理所有未使用资源
+## 清理所有未使用资源
$ docker system prune
```
---
-## 本章小结
+### 本章小结
| 操作 | 命令 |
|------|------|
@@ -224,9 +224,9 @@ $ docker system prune
| 指定平台 | `docker pull --platform linux/amd64 镜像名` |
| 用摘要拉取 | `docker pull 镜像名@sha256:...` |
-## 延伸阅读
+### 延伸阅读
-- [列出镜像](list.md):查看本地镜像
-- [删除镜像](rm.md):清理本地镜像
-- [镜像加速器](../install/mirror.md):加速镜像下载
-- [Docker Hub](../repository/dockerhub.md):官方镜像仓库
+- [列出镜像](4.2_list.md):查看本地镜像
+- [删除镜像](4.3_rm.md):清理本地镜像
+- [镜像加速器](../install/3.9_mirror.md):加速镜像下载
+- [Docker Hub](../repository/6.1_dockerhub.md):官方镜像仓库
diff --git a/04_image/list.md b/04_image/4.2_list.md
similarity index 79%
rename from 04_image/list.md
rename to 04_image/4.2_list.md
index 1565d34..07c0be0 100644
--- a/04_image/list.md
+++ b/04_image/4.2_list.md
@@ -1,6 +1,6 @@
-# 列出镜像
+## 列出镜像
-## 基本用法
+### 基本用法
查看本地已下载的镜像:
@@ -17,7 +17,7 @@ ubuntu noble 329ed837d508 3 days ago 78MB
---
-## 输出字段说明
+### 输出字段说明
| 字段 | 说明 |
|------|------|
@@ -27,22 +27,22 @@ ubuntu noble 329ed837d508 3 days ago 78MB
| **CREATED** | 创建时间 |
| **SIZE** | 本地占用空间 |
-### 同一镜像多个标签
+#### 同一镜像多个标签
注意上面的 `ubuntu:24.04` 和 `ubuntu:noble` 拥有相同的 IMAGE ID——它们是同一个镜像的不同标签,只占用一份存储空间。
---
-## 理解镜像大小
+### 理解镜像大小
-### 本地大小 vs Hub 显示大小
+#### 本地大小 vs Hub 显示大小
| 位置 | 显示大小 | 说明 |
|------|---------|------|
| Docker Hub | 29MB | 压缩后的网络传输大小 |
| docker image ls | 78MB | 本地解压后的实际大小 |
-### 实际磁盘占用
+#### 实际磁盘占用
由于镜像是分层存储,不同镜像可能共享相同的层:
@@ -56,7 +56,7 @@ ubuntu:24.04 nginx:latest redis:latest
因此,`docker image ls` 中各镜像大小之和 > 实际磁盘占用。
-### 查看实际空间占用
+#### 查看实际空间占用
```bash
$ docker system df
@@ -69,12 +69,12 @@ Build Cache 0 0 0B 0B
---
-## 过滤镜像
+### 过滤镜像
-### 按仓库名过滤
+#### 按仓库名过滤
```bash
-# 列出所有 ubuntu 镜像
+## 列出所有 ubuntu 镜像
$ docker images ubuntu
REPOSITORY TAG IMAGE ID SIZE
ubuntu 24.04 329ed837d508 78MB
@@ -82,7 +82,7 @@ ubuntu noble 329ed837d508 78MB
ubuntu 22.04 a1b2c3d4e5f6 72MB
```
-### 按仓库名和标签过滤
+#### 按仓库名和标签过滤
```bash
$ docker images ubuntu:24.04
@@ -90,7 +90,7 @@ REPOSITORY TAG IMAGE ID SIZE
ubuntu 24.04 329ed837d508 78MB
```
-### 使用过滤器 --filter
+#### 使用过滤器 --filter
| 过滤条件 | 说明 | 示例 |
|---------|------|------|
@@ -101,21 +101,21 @@ ubuntu 24.04 329ed837d508 78MB
| `reference=pattern` | 按名称模式 | `-f reference='*:latest'` |
```bash
-# 列出 nginx 之后创建的镜像
+## 列出 nginx 之后创建的镜像
$ docker images -f since=nginx:latest
-# 列出所有带 latest 标签的镜像
+## 列出所有带 latest 标签的镜像
$ docker images -f reference='*:latest'
-# 列出带特定 LABEL 的镜像
+## 列出带特定 LABEL 的镜像
$ docker images -f label=maintainer=example@email.com
```
---
-## 虚悬镜像(Dangling Images)
+### 虚悬镜像(Dangling Images)
-### 什么是虚悬镜像
+#### 什么是虚悬镜像
仓库名和标签都显示为 `` 的镜像:
@@ -125,26 +125,26 @@ REPOSITORY TAG IMAGE ID SIZE
00285df0df87 342MB
```
-### 产生原因
+#### 产生原因
1. **镜像重新构建**:新镜像使用了旧镜像的标签,旧镜像标签被移除
2. **docker pull 更新**:拉取更新版本时,旧版本失去标签
-### 处理虚悬镜像
+#### 处理虚悬镜像
```bash
-# 列出虚悬镜像
+## 列出虚悬镜像
$ docker images -f dangling=true
-# 删除虚悬镜像
+## 删除虚悬镜像
$ docker image prune
```
---
-## 中间层镜像
+### 中间层镜像
-### 查看所有镜像(包含中间层)
+#### 查看所有镜像(包含中间层)
```bash
$ docker images -a
@@ -156,9 +156,9 @@ $ docker images -a
---
-## 格式化输出
+### 格式化输出
-### 只输出 ID
+#### 只输出 ID
```bash
$ docker images -q
@@ -170,20 +170,20 @@ $ docker images -q
常用于配合其他命令:
```bash
-# 删除所有镜像
+## 删除所有镜像
$ docker rmi $(docker images -q)
-# 删除所有 redis 镜像
+## 删除所有 redis 镜像
$ docker rmi $(docker images -q redis)
```
-### 显示完整 ID
+#### 显示完整 ID
```bash
$ docker images --no-trunc
```
-### 显示摘要
+#### 显示摘要
```bash
$ docker images --digests
@@ -191,18 +191,18 @@ REPOSITORY TAG DIGEST IMAGE ID
nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
```
-### 自定义格式
+#### 自定义格式
使用 Go 模板语法自定义输出:
```bash
-# 只显示 ID 和仓库名
+## 只显示 ID 和仓库名
$ docker images --format "{{.ID}}: {{.Repository}}"
5f515359c7f8: redis
05a60462f8ba: nginx
329ed837d508: ubuntu
-# 表格形式(带标题)
+## 表格形式(带标题)
$ docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
REPOSITORY TAG SIZE
redis latest 183MB
@@ -210,7 +210,7 @@ nginx latest 181MB
ubuntu 24.04 78MB
```
-### 可用模板字段
+#### 可用模板字段
| 字段 | 说明 |
|------|------|
@@ -224,22 +224,22 @@ ubuntu 24.04 78MB
---
-## 常用命令组合
+### 常用命令组合
```bash
-# 列出所有镜像及其大小,按大小排序(需要系统 sort 命令)
+## 列出所有镜像及其大小,按大小排序(需要系统 sort 命令)
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -h
-# 查找大于 500MB 的镜像
+## 查找大于 500MB 的镜像
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | grep -E "^[0-9]+GB|^[5-9][0-9]{2}MB"
-# 导出镜像列表
+## 导出镜像列表
$ docker images --format "{{.Repository}}:{{.Tag}}" > images.txt
```
---
-## 本章小结
+### 本章小结
| 操作 | 命令 |
|------|------|
@@ -251,8 +251,8 @@ $ docker images --format "{{.Repository}}:{{.Tag}}" > images.txt
| 自定义格式 | `docker images --format "..."` |
| 查看空间占用 | `docker system df` |
-## 延伸阅读
+### 延伸阅读
-- [获取镜像](pull.md):从 Registry 拉取镜像
-- [删除镜像](rm.md):清理本地镜像
-- [镜像](../02_basic_concept/image.md):理解镜像概念
+- [获取镜像](4.1_pull.md):从 Registry 拉取镜像
+- [删除镜像](4.3_rm.md):清理本地镜像
+- [镜像](../02_basic_concept/2.1_image.md):理解镜像概念
diff --git a/04_image/rm.md b/04_image/4.3_rm.md
similarity index 80%
rename from 04_image/rm.md
rename to 04_image/4.3_rm.md
index 158a140..2647f19 100644
--- a/04_image/rm.md
+++ b/04_image/4.3_rm.md
@@ -1,6 +1,6 @@
-# 删除本地镜像
+## 删除本地镜像
-## 基本用法
+### 基本用法
使用 `docker image rm` 删除本地镜像:
@@ -12,7 +12,7 @@ $ docker image rm [选项] <镜像1> [<镜像2> ...]
---
-## 镜像标识方式
+### 镜像标识方式
删除镜像时,可以使用多种方式指定镜像:
@@ -23,7 +23,7 @@ $ docker image rm [选项] <镜像1> [<镜像2> ...]
| **镜像名:标签** | 仓库名和标签 | `docker rmi redis:alpine` |
| **镜像摘要** | 精确的内容摘要 | `docker rmi nginx@sha256:...` |
-### 使用短 ID 删除
+#### 使用短 ID 删除
```bash
$ docker image ls
@@ -31,13 +31,13 @@ REPOSITORY TAG IMAGE ID SIZE
redis alpine 501ad78535f0 30MB
nginx latest e43d811ce2f4 142MB
-# 只需输入足够区分的前几位
+## 只需输入足够区分的前几位
$ docker rmi 501
Untagged: redis:alpine
Deleted: sha256:501ad78535f0...
```
-### 使用镜像名删除
+#### 使用镜像名删除
```bash
$ docker rmi redis:alpine
@@ -45,23 +45,23 @@ Untagged: redis:alpine
Deleted: sha256:501ad78535f0...
```
-### 使用摘要删除
+#### 使用摘要删除
摘要删除最精确,适用于 CI/CD 场景:
```bash
-# 查看镜像摘要
+## 查看镜像摘要
$ docker images --digests
REPOSITORY TAG DIGEST IMAGE ID
nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
-# 使用摘要删除
+## 使用摘要删除
$ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
```
---
-## 理解输出信息
+### 理解输出信息
删除镜像时会看到两类信息:**Untagged** 和 **Deleted**
@@ -74,14 +74,14 @@ Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
```
-### Untagged vs Deleted
+#### Untagged vs Deleted
| 操作 | 含义 |
|------|------|
| **Untagged** | 移除镜像的标签 |
| **Deleted** | 删除镜像的存储层 |
-### 删除流程
+#### 删除流程
```
docker rmi redis:alpine
@@ -106,51 +106,51 @@ docker rmi redis:alpine
---
-## 批量删除
+### 批量删除
-### 删除所有虚悬镜像
+#### 删除所有虚悬镜像
虚悬镜像(dangling):没有标签的镜像,通常是旧版本被新版本覆盖后产生的
```bash
-# 查看虚悬镜像
+## 查看虚悬镜像
$ docker images -f dangling=true
-# 删除虚悬镜像
+## 删除虚悬镜像
$ docker image prune
-# 不提示确认
+## 不提示确认
$ docker image prune -f
```
-### 删除所有未使用的镜像
+#### 删除所有未使用的镜像
```bash
-# 删除所有没有被容器使用的镜像
+## 删除所有没有被容器使用的镜像
$ docker image prune -a
-# 保留最近 24 小时的
+## 保留最近 24 小时的
$ docker image prune -a --filter "until=24h"
```
-### 按条件删除
+#### 按条件删除
```bash
-# 删除所有 redis 镜像
+## 删除所有 redis 镜像
$ docker rmi $(docker images -q redis)
-# 删除 mongo:8.0 之前的所有镜像
+## 删除 mongo:8.0 之前的所有镜像
$ docker rmi $(docker images -q -f before=mongo:8.0)
-# 删除某个时间之前的镜像
+## 删除某个时间之前的镜像
$ docker image prune -a --filter "until=168h" # 7天前
```
---
-## 删除失败的常见原因
+### 删除失败的常见原因
-### 原因一:有容器依赖
+#### 原因一:有容器依赖
```bash
$ docker rmi nginx
@@ -161,15 +161,15 @@ Error: conflict: unable to remove repository reference "nginx"
**解决方案**:
```bash
-# 方案1:先删除依赖的容器
+## 方案1:先删除依赖的容器
$ docker rm abc123
$ docker rmi nginx
-# 方案2:强制删除镜像(容器仍可运行,但无法再创建新容器)
+## 方案2:强制删除镜像(容器仍可运行,但无法再创建新容器)
$ docker rmi -f nginx
```
-### 原因二:多个标签指向同一镜像
+#### 原因二:多个标签指向同一镜像
```bash
$ docker images
@@ -179,10 +179,10 @@ ubuntu latest ca2b0f26964c # 同一个镜像
$ docker rmi ubuntu:24.04
Untagged: ubuntu:24.04
-# 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
+## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
```
-### 原因三:被其他镜像依赖(中间层)
+#### 原因三:被其他镜像依赖(中间层)
```bash
$ docker rmi some_base_image
@@ -193,7 +193,7 @@ Error: image has dependent child images
---
-## 常用过滤条件
+### 常用过滤条件
| 过滤条件 | 说明 | 示例 |
|---------|------|------|
@@ -205,26 +205,26 @@ Error: image has dependent child images
---
-## 清理策略
+### 清理策略
-### 开发环境
+#### 开发环境
```bash
-# 定期清理虚悬镜像
+## 定期清理虚悬镜像
$ docker image prune -f
-# 一键清理所有未使用资源
+## 一键清理所有未使用资源
$ docker system prune -a
```
-### CI/CD 环境
+#### CI/CD 环境
```bash
-# 只保留最近使用的镜像
+## 只保留最近使用的镜像
$ docker image prune -a --filter "until=72h" -f
```
-### 查看空间占用
+#### 查看空间占用
```bash
$ docker system df
@@ -237,7 +237,7 @@ Build Cache 0 0 0B 0B
---
-## 本章小结
+### 本章小结
| 操作 | 命令 |
|------|------|
@@ -248,8 +248,8 @@ Build Cache 0 0 0B 0B
| 批量删除 | `docker rmi $(docker images -q -f ...)` |
| 查看空间占用 | `docker system df` |
-## 延伸阅读
+### 延伸阅读
-- [列出镜像](list.md):查看和过滤镜像
-- [删除容器](../05_container/rm.md):清理容器
+- [列出镜像](4.2_list.md):查看和过滤镜像
+- [删除容器](../05_container/4.3_rm.md):清理容器
- [数据卷](../07_data_network/data/volume.md):清理数据卷
diff --git a/04_image/commit.md b/04_image/4.4_commit.md
similarity index 99%
rename from 04_image/commit.md
rename to 04_image/4.4_commit.md
index 7556f3c..2f2b42c 100644
--- a/04_image/commit.md
+++ b/04_image/4.4_commit.md
@@ -1,4 +1,4 @@
-# 利用 commit 理解镜像构成
+## 利用 commit 理解镜像构成
> 注意:如果您是初学者,您可以暂时跳过后面的内容,直接学习 [容器](../05_container/) 一节。
@@ -120,7 +120,7 @@ docker run --name web2 -d -p 81:80 nginx:v2
至此,我们第一次完成了定制镜像,使用的是 `docker commit` 命令,手动操作给旧的镜像添加了新的一层,形成新的镜像,对镜像多层存储应该有了更直观的感觉。
-## 慎用 `docker commit`
+### 慎用 `docker commit`
使用 `docker commit` 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。
diff --git a/04_image/build.md b/04_image/4.5_build.md
similarity index 96%
rename from 04_image/build.md
rename to 04_image/4.5_build.md
index 0c3d27e..513ddba 100644
--- a/04_image/build.md
+++ b/04_image/4.5_build.md
@@ -1,10 +1,10 @@
-# 使用 Dockerfile 定制镜像
+## 使用 Dockerfile 定制镜像
从刚才的 `docker commit` 的学习中,我们可以了解到,镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的 **指令(Instruction)**,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
-## 使用 docker init 快速创建(推荐)
+### 使用 docker init 快速创建(推荐)
Docker 提供了 `docker init` 命令,可以根据项目类型自动生成 Dockerfile、.dockerignore 和 compose.yaml 文件:
@@ -14,7 +14,7 @@ $ docker init
该命令会交互式地询问项目类型(如 Go、Node.js、Python、Rust 等),并生成符合最佳实践的配置文件。对于新项目,这是推荐的起步方式。
-## 手动创建 Dockerfile
+### 手动创建 Dockerfile
还以之前定制 `nginx` 镜像为例,这次我们使用 Dockerfile 来定制。
@@ -35,7 +35,7 @@ RUN echo 'Hello, Docker!
' > /usr/share/nginx/html/index.html
这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,`FROM` 和 `RUN`。
-## FROM 指定基础镜像
+### FROM 指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 `nginx` 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 `FROM` 就是指定 **基础镜像**,因此一个 `Dockerfile` 中 `FROM` 是必备的指令,并且必须是第一条指令。
@@ -54,7 +54,7 @@ FROM scratch
不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 `FROM scratch` 会让镜像体积更加小巧。使用 [Go 语言](https://golang.google.cn/) 开发的应用很多会使用这种方式来制作镜像,这也是有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
-## RUN 执行命令
+### RUN 执行命令
`RUN` 指令是用来执行命令行命令的。由于命令行的强大能力,`RUN` 指令在定制镜像时是最常用的指令之一。其格式有两种:
@@ -114,7 +114,7 @@ RUN set -x; buildDeps='gcc libc6-dev make wget' \
很多人初学 Docker 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。
-## 构建镜像
+### 构建镜像
好了,让我们再回到之前定制的 nginx 镜像的 Dockerfile 来。现在我们明白了这个 Dockerfile 的内容,那么让我们来构建这个镜像吧。
@@ -142,7 +142,7 @@ docker build [选项] <上下文路径/URL/->
在这里我们指定了最终镜像的名称 `-t nginx:v3`,构建成功后,我们可以像之前运行 `nginx:v2` 那样来运行这个镜像,其结果会和 `nginx:v2` 一样。
-## 镜像构建上下文(Context)
+### 镜像构建上下文(Context)
如果注意,会看到 `docker build` 命令最后有一个 `.`。`.` 表示当前目录,而 `Dockerfile` 就在当前目录,因此不少初学者以为这个路径是在指定 `Dockerfile` 所在路径,这么理解其实是不准确的。如果对应上面的命令格式,你可能会发现,这是在指定 **上下文路径**。那么什么是上下文呢?
@@ -182,15 +182,15 @@ Sending build context to Docker daemon 2.048 kB
当然,一般大家习惯性的会使用默认的文件名 `Dockerfile`,以及会将其置于镜像构建上下文目录中。
-## 其它 `docker build` 的用法
+### 其它 `docker build` 的用法
-### 直接用 Git repo 进行构建
+#### 直接用 Git repo 进行构建
或许你已经注意到了,`docker build` 还支持从 URL 构建,比如可以直接从 Git repo 中构建:
```bash
-# $env:DOCKER_BUILDKIT=0
-# export DOCKER_BUILDKIT=0
+## $env:DOCKER_BUILDKIT=0
+## export DOCKER_BUILDKIT=0
$ docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
@@ -207,7 +207,7 @@ Successfully built 038ad4142d2b
这行命令指定了构建所需的 Git repo,并且指定分支为 `master`,构建目录为 `/amd64/hello-world/`,然后 Docker 就会自己去 `git clone` 这个项目、切换到指定分支、并进入到指定目录后开始构建。
-### 用给定的 tar 压缩包构建
+#### 用给定的 tar 压缩包构建
```bash
$ docker build http://server/context.tar.gz
@@ -215,7 +215,7 @@ $ docker build http://server/context.tar.gz
如果所给出的 URL 不是个 Git repo,而是个 `tar` 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
-### 从标准输入中读取 Dockerfile 进行构建
+#### 从标准输入中读取 Dockerfile 进行构建
```bash
docker build - < Dockerfile
@@ -229,7 +229,7 @@ cat Dockerfile | docker build -
如果标准输入传入的是文本文件,则将其视为 `Dockerfile`,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 `COPY` 进镜像之类的事情。
-### 从标准输入中读取上下文压缩包进行构建
+#### 从标准输入中读取上下文压缩包进行构建
```bash
$ docker build - < context.tar.gz
diff --git a/04_image/other.md b/04_image/4.6_other.md
similarity index 95%
rename from 04_image/other.md
rename to 04_image/4.6_other.md
index f139f5d..e304188 100644
--- a/04_image/other.md
+++ b/04_image/4.6_other.md
@@ -1,8 +1,8 @@
-# 其它制作镜像的方式
+## 其它制作镜像的方式
除了标准的使用 `Dockerfile` 生成镜像的方法外,由于各种特殊需求和历史原因,还提供了一些其它方法用以生成镜像。
-## 从 rootfs 压缩包导入
+### 从 rootfs 压缩包导入
格式:`docker import [选项] <文件>||- [<仓库名>[:<标签>]]`
@@ -37,11 +37,11 @@ IMAGE CREATED CREATED BY SIZE
f477a6e18e98 About a minute ago 214.9 MB Imported from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz
```
-## Docker 镜像的导入和导出 `docker save` 和 `docker load`
+### Docker 镜像的导入和导出 `docker save` 和 `docker load`
Docker 还提供了 `docker save` 和 `docker load` 命令,用以将镜像保存为一个文件,然后传输到另一个位置上,再加载进来。这是在没有 Docker Registry 时的做法,现在已经不推荐,镜像迁移应该直接使用 Docker Registry,无论是直接使用 Docker Hub 还是使用内网私有 Registry 都可以。
-### 保存镜像
+#### 保存镜像
使用 `docker save` 命令可以将镜像保存为归档文件。
diff --git a/04_image/internal.md b/04_image/4.7_internal.md
similarity index 96%
rename from 04_image/internal.md
rename to 04_image/4.7_internal.md
index d36b209..4420d7f 100644
--- a/04_image/internal.md
+++ b/04_image/4.7_internal.md
@@ -1,4 +1,4 @@
-# 镜像的实现原理
+## 镜像的实现原理
Docker 镜像是怎么实现增量的修改和维护的?
diff --git a/04_image/README.md b/04_image/README.md
index ddc4c52..9aeaed7 100644
--- a/04_image/README.md
+++ b/04_image/README.md
@@ -1,4 +1,4 @@
-# 使用 Docker 镜像
+# 第四章 使用镜像
在之前的介绍中,我们知道镜像是 Docker 的三大组件之一。
diff --git a/04_image/dockerfile/README.md b/04_image/dockerfile/README.md
index 15f5d4f..fa4d01f 100644
--- a/04_image/dockerfile/README.md
+++ b/04_image/dockerfile/README.md
@@ -1,3 +1,3 @@
-# Dockerfile 指令详解
+## Dockerfile 指令详解
我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。
diff --git a/04_image/dockerfile/add.md b/04_image/dockerfile/add.md
index facd258..1c4d66b 100644
--- a/04_image/dockerfile/add.md
+++ b/04_image/dockerfile/add.md
@@ -1,6 +1,6 @@
-# ADD 更高级的复制文件
+## ADD 更高级的复制文件
-## 基本语法
+### 基本语法
```docker
ADD [选项] <源路径>... <目标路径>
@@ -13,7 +13,7 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
---
-## ADD vs COPY
+### ADD vs COPY
| 特性 | COPY | ADD |
|------|------|-----|
@@ -27,12 +27,12 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
---
-## 自动解压功能
+### 自动解压功能
-### 基本用法
+#### 基本用法
```docker
-# 自动解压 tar.gz 到目标目录
+## 自动解压 tar.gz 到目标目录
ADD app.tar.gz /app/
```
@@ -42,7 +42,7 @@ ADD 会识别并解压以下格式:
- `.tar.bz2` / `.tbz2`
- `.tar.xz` / `.txz`
-### 实际应用
+#### 实际应用
官方基础镜像通常使用 ADD 解压根文件系统:
@@ -51,7 +51,7 @@ FROM scratch
ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
```
-### 解压过程
+#### 解压过程
```
ADD app.tar.gz /app/
@@ -68,16 +68,16 @@ app.tar.gz 包含: /app/ 目录结果:
---
-## URL 下载功能(不推荐)
+### URL 下载功能(不推荐)
-### 基本用法
+#### 基本用法
```docker
-# 从 URL 下载文件
+## 从 URL 下载文件
ADD https://example.com/app.zip /app/app.zip
```
-### 为什么不推荐
+#### 为什么不推荐
| 问题 | 说明 |
|------|------|
@@ -86,14 +86,14 @@ ADD https://example.com/app.zip /app/app.zip
| 缓存问题 | URL 内容变化时不会重新下载 |
| 层数增加 | 需要额外 RUN 清理 |
-### 推荐替代方案
+#### 推荐替代方案
```docker
-# ❌ 不推荐:使用 ADD 下载
+## ❌ 不推荐:使用 ADD 下载
ADD https://example.com/app.tar.gz /tmp/
RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz
-# ✅ 推荐:使用 RUN + curl
+## ✅ 推荐:使用 RUN + curl
RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
```
@@ -104,7 +104,7 @@ RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
---
-## 修改文件所有者
+### 修改文件所有者
```docker
ADD --chown=node:node app.tar.gz /app/
@@ -113,43 +113,43 @@ ADD --chown=1000:1000 files/ /app/
---
-## 何时使用 ADD
+### 何时使用 ADD
-### ✅ 适合使用 ADD
+#### ✅ 适合使用 ADD
```docker
-# 解压本地 tar 文件
+## 解压本地 tar 文件
FROM scratch
ADD rootfs.tar.gz /
-# 解压应用包
+## 解压应用包
ADD dist.tar.gz /app/
```
-### ❌ 不适合使用 ADD
+#### ❌ 不适合使用 ADD
```docker
-# 复制普通文件(用 COPY)
+## 复制普通文件(用 COPY)
ADD package.json /app/ # ❌
COPY package.json /app/ # ✅
-# 下载文件(用 RUN + curl)
+## 下载文件(用 RUN + curl)
ADD https://example.com/file / # ❌
RUN curl -fsSL ... -o /file # ✅
-# 需要保留 tar 不解压(用 COPY)
+## 需要保留 tar 不解压(用 COPY)
ADD archive.tar.gz /archives/ # ❌ 会解压
COPY archive.tar.gz /archives/ # ✅ 保持原样
```
---
-## 缓存行为
+### 缓存行为
ADD 可能导致构建缓存失效:
```docker
-# 如果 app.tar.gz 内容变化,此层及后续层都需重建
+## 如果 app.tar.gz 内容变化,此层及后续层都需重建
ADD app.tar.gz /app/
RUN npm install
```
@@ -157,46 +157,46 @@ RUN npm install
**优化建议**:
```docker
-# 先复制依赖文件
+## 先复制依赖文件
COPY package*.json /app/
RUN npm install
-# 再添加应用代码
+## 再添加应用代码
ADD app.tar.gz /app/
```
---
-## 最佳实践
+### 最佳实践
-### 1. 默认使用 COPY
+#### 1. 默认使用 COPY
```docker
-# ✅ 大多数场景使用 COPY
+## ✅ 大多数场景使用 COPY
COPY . /app/
```
-### 2. 仅在需要解压时使用 ADD
+#### 2. 仅在需要解压时使用 ADD
```docker
-# ✅ 自动解压场景
+## ✅ 自动解压场景
ADD app.tar.gz /app/
```
-### 3. 不要用 ADD 下载文件
+#### 3. 不要用 ADD 下载文件
```docker
-# ❌ 避免
+## ❌ 避免
ADD https://example.com/file.tar.gz /tmp/
-# ✅ 推荐
+## ✅ 推荐
RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
```
-### 4. 解压后清理
+#### 4. 解压后清理
```docker
-# 如果需要控制解压过程
+## 如果需要控制解压过程
COPY app.tar.gz /tmp/
RUN tar -xzf /tmp/app.tar.gz -C /app && \
rm /tmp/app.tar.gz
@@ -204,7 +204,7 @@ RUN tar -xzf /tmp/app.tar.gz -C /app && \
---
-## 本章小结
+### 本章小结
| 场景 | 推荐指令 |
|------|---------|
@@ -214,8 +214,8 @@ RUN tar -xzf /tmp/app.tar.gz -C /app && \
| 从 URL 下载 | `RUN curl` |
| 保持 tar 不解压 | `COPY` |
-## 延伸阅读
+### 延伸阅读
- [COPY 复制文件](copy.md):基本复制操作
- [多阶段构建](../multistage-builds.md):减少镜像体积
-- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 编写指南
+- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 编写指南
diff --git a/04_image/dockerfile/arg.md b/04_image/dockerfile/arg.md
index f15f252..3c670ef 100644
--- a/04_image/dockerfile/arg.md
+++ b/04_image/dockerfile/arg.md
@@ -1,6 +1,6 @@
-# ARG 构建参数
+## ARG 构建参数
-## 基本语法
+### 基本语法
```docker
ARG <参数名>[=<默认值>]
@@ -10,7 +10,7 @@ ARG <参数名>[=<默认值>]
---
-## ARG vs ENV
+### ARG vs ENV
| 特性 | ARG | ENV |
|------|-----|-----|
@@ -31,79 +31,79 @@ ARG <参数名>[=<默认值>]
---
-## 基本用法
+### 基本用法
-### 定义和使用
+#### 定义和使用
```docker
-# 定义有默认值的 ARG
+## 定义有默认值的 ARG
ARG NODE_VERSION=20
-# 使用 ARG
+## 使用 ARG
FROM node:${NODE_VERSION}-alpine
RUN echo "Using Node.js $NODE_VERSION"
```
-### 构建时覆盖
+#### 构建时覆盖
```bash
-# 使用默认值
+## 使用默认值
$ docker build -t myapp .
-# 覆盖默认值
+## 覆盖默认值
$ docker build --build-arg NODE_VERSION=18 -t myapp .
```
---
-## ARG 的作用域
+### ARG 的作用域
-### FROM 之前的 ARG
+#### FROM 之前的 ARG
```docker
-# FROM 之前的 ARG 只能用于 FROM 指令
+## FROM 之前的 ARG 只能用于 FROM 指令
ARG REGISTRY=docker.io
ARG IMAGE_NAME=node
FROM ${REGISTRY}/${IMAGE_NAME}:20
-# ❌ 这里无法使用上面的 ARG
+## ❌ 这里无法使用上面的 ARG
RUN echo $REGISTRY # 输出空
```
-### FROM 之后重新声明
+#### FROM 之后重新声明
```docker
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
-# 需要再次声明才能使用
+## 需要再次声明才能使用
ARG NODE_VERSION
RUN echo "Node version: $NODE_VERSION"
```
-### 多阶段构建中的 ARG
+#### 多阶段构建中的 ARG
```docker
ARG BASE_VERSION=alpine
FROM node:20-${BASE_VERSION} AS builder
-# 需要重新声明
+## 需要重新声明
ARG NODE_VERSION=20
RUN echo "Building with Node $NODE_VERSION"
FROM node:20-${BASE_VERSION}
-# 每个阶段都需要重新声明
+## 每个阶段都需要重新声明
ARG NODE_VERSION=20
RUN echo "Running with Node $NODE_VERSION"
```
---
-## 常见使用场景
+### 常见使用场景
-### 1. 控制基础镜像版本
+#### 1. 控制基础镜像版本
```docker
ARG ALPINE_VERSION=3.19
@@ -114,7 +114,7 @@ FROM alpine:${ALPINE_VERSION}
$ docker build --build-arg ALPINE_VERSION=3.18 .
```
-### 2. 设置软件版本
+#### 2. 设置软件版本
```docker
ARG NGINX_VERSION=1.25.0
@@ -122,7 +122,7 @@ ARG NGINX_VERSION=1.25.0
RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -xz
```
-### 3. 配置构建环境
+#### 3. 配置构建环境
```docker
ARG BUILD_ENV=production
@@ -135,7 +135,7 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
fi
```
-### 4. 配置私有仓库
+#### 4. 配置私有仓库
```docker
ARG NPM_TOKEN
@@ -146,29 +146,29 @@ RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \
```
```bash
-# 构建时传入 token
+## 构建时传入 token
$ docker build --build-arg NPM_TOKEN=xxx .
```
---
-## 将 ARG 传递给 ENV
+### 将 ARG 传递给 ENV
如果需要在运行时使用 ARG 的值:
```docker
ARG VERSION=1.0.0
-# 将 ARG 传递给 ENV
+## 将 ARG 传递给 ENV
ENV APP_VERSION=$VERSION
-# 运行时可用
+## 运行时可用
CMD echo "App version: $APP_VERSION"
```
---
-## 预定义 ARG
+### 预定义 ARG
Docker 提供了一些预定义的 ARG,无需声明即可使用:
@@ -180,47 +180,47 @@ Docker 提供了一些预定义的 ARG,无需声明即可使用:
| `FTP_PROXY` | FTP 代理 |
```bash
-# 构建时使用代理
+## 构建时使用代理
$ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
```
---
-## 最佳实践
+### 最佳实践
-### 1. 为 ARG 提供合理默认值
+#### 1. 为 ARG 提供合理默认值
```docker
-# ✅ 好:有默认值
+## ✅ 好:有默认值
ARG NODE_VERSION=20
-# ⚠️ 需要每次传入
+## ⚠️ 需要每次传入
ARG NODE_VERSION
```
-### 2. 不要用 ARG 存储敏感信息
+#### 2. 不要用 ARG 存储敏感信息
```docker
-# ❌ 错误:密码会被记录在镜像历史中
+## ❌ 错误:密码会被记录在镜像历史中
ARG DB_PASSWORD
RUN echo "password=$DB_PASSWORD" > /app/.env
-# ✅ 正确:使用 secrets 或运行时环境变量
+## ✅ 正确:使用 secrets 或运行时环境变量
```
-### 3. 使用 ARG 提高构建灵活性
+#### 3. 使用 ARG 提高构建灵活性
```docker
ARG BASE_IMAGE=python:3.12-slim
FROM ${BASE_IMAGE}
-# 可以构建不同基础镜像的版本
-# docker build --build-arg BASE_IMAGE=python:3.11-alpine .
+## 可以构建不同基础镜像的版本
+## docker build --build-arg BASE_IMAGE=python:3.11-alpine .
```
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -231,8 +231,8 @@ FROM ${BASE_IMAGE}
| **vs ENV** | ARG 仅构建时,ENV 构建+运行时 |
| **安全** | 不要存储敏感信息 |
-## 延伸阅读
+### 延伸阅读
- [ENV 设置环境变量](env.md):运行时环境变量
-- [FROM 指令](../../04_image/build.md):基础镜像指定
+- [FROM 指令](../../04_image/4.5_build.md):基础镜像指定
- [多阶段构建](../multistage-builds.md):复杂构建场景
diff --git a/04_image/dockerfile/cmd.md b/04_image/dockerfile/cmd.md
index bd80779..e63da2e 100644
--- a/04_image/dockerfile/cmd.md
+++ b/04_image/dockerfile/cmd.md
@@ -1,6 +1,6 @@
-# CMD 容器启动命令
+## CMD 容器启动命令
-## 什么是 CMD
+### 什么是 CMD
`CMD` 指令用于指定容器启动时默认执行的命令。它定义了容器的"主进程"。
@@ -8,7 +8,7 @@
---
-## 语法格式
+### 语法格式
CMD 有三种格式:
@@ -18,7 +18,7 @@ CMD 有三种格式:
| **shell 格式** | `CMD 命令 参数1 参数2` | ⚠️ 简单场景 |
| **参数格式** | `CMD ["参数1", "参数2"]` | 配合 ENTRYPOINT |
-### exec 格式(推荐)
+#### exec 格式(推荐)
```docker
CMD ["nginx", "-g", "daemon off;"]
@@ -31,7 +31,7 @@ CMD ["node", "server.js"]
- 正确接收信号(如 SIGTERM)
- 无需 shell 解析
-### shell 格式
+#### shell 格式
```docker
CMD echo "Hello World"
@@ -41,10 +41,10 @@ CMD nginx -g "daemon off;"
**实际执行**:会被包装为 `sh -c`
```docker
-# 你写的
+## 你写的
CMD echo $HOME
-# 实际执行的
+## 实际执行的
CMD ["sh", "-c", "echo $HOME"]
```
@@ -53,7 +53,7 @@ CMD ["sh", "-c", "echo $HOME"]
---
-## exec 格式 vs shell 格式
+### exec 格式 vs shell 格式
| 特性 | exec 格式 | shell 格式 |
|------|----------|-----------|
@@ -62,27 +62,27 @@ CMD ["sh", "-c", "echo $HOME"]
| 环境变量 | ❌ 需要 shell 包装 | ✅ 自动解析 |
| 推荐使用 | ✅ 大多数场景 | 需要 shell 特性时 |
-### 信号传递问题示例
+#### 信号传递问题示例
```docker
-# ❌ shell 格式:docker stop 会超时
+## ❌ shell 格式:docker stop 会超时
CMD node server.js
-# 实际是 sh -c "node server.js"
-# SIGTERM 发给 sh,不会传递给 node
+## 实际是 sh -c "node server.js"
+## SIGTERM 发给 sh,不会传递给 node
-# ✅ exec 格式:docker stop 正常工作
+## ✅ exec 格式:docker stop 正常工作
CMD ["node", "server.js"]
-# SIGTERM 直接发给 node
+## SIGTERM 直接发给 node
```
---
-## 运行时覆盖 CMD
+### 运行时覆盖 CMD
`docker run` 后的命令会覆盖 Dockerfile 中的 CMD:
```bash
-# ubuntu 默认 CMD 是 /bin/bash
+## ubuntu 默认 CMD 是 /bin/bash
$ docker run -it ubuntu # 进入 bash
$ docker run ubuntu cat /etc/os-release # 覆盖为 cat 命令
```
@@ -98,16 +98,16 @@ CMD ["/bin/bash"] + cat /etc/os-release
---
-## 经典错误:容器立即退出
+### 经典错误:容器立即退出
-### 错误示例
+#### 错误示例
```docker
-# ❌ 容器启动后立即退出
+## ❌ 容器启动后立即退出
CMD service nginx start
```
-### 原因分析
+#### 原因分析
```
1. CMD service nginx start
@@ -123,26 +123,26 @@ CMD service nginx start
6. 容器主进程(sh)退出 → 容器停止
```
-### 正确做法
+#### 正确做法
```docker
-# ✅ 让 nginx 在前台运行
+## ✅ 让 nginx 在前台运行
CMD ["nginx", "-g", "daemon off;"]
```
---
-## CMD vs ENTRYPOINT
+### CMD vs ENTRYPOINT
| 指令 | 用途 | 运行时行为 |
|------|------|-----------|
| **CMD** | 默认命令 | `docker run` 参数会**覆盖**它 |
| **ENTRYPOINT** | 入口点 | `docker run` 参数会**追加**到它后面 |
-### 单独使用 CMD
+#### 单独使用 CMD
```docker
-# Dockerfile
+## Dockerfile
CMD ["curl", "-s", "http://example.com"]
```
@@ -151,10 +151,10 @@ $ docker run myimage # 执行默认命令
$ docker run myimage curl -v ... # 完全覆盖
```
-### 搭配 ENTRYPOINT
+#### 搭配 ENTRYPOINT
```docker
-# Dockerfile
+## Dockerfile
ENTRYPOINT ["curl", "-s"]
CMD ["http://example.com"]
```
@@ -168,57 +168,57 @@ $ docker run myimage http://other.com # curl -s http://other.com(参数覆盖
---
-## 最佳实践
+### 最佳实践
-### 1. 优先使用 exec 格式
+#### 1. 优先使用 exec 格式
```docker
-# ✅ 推荐
+## ✅ 推荐
CMD ["python", "app.py"]
-# ⚠️ 仅在需要 shell 特性时使用
+## ⚠️ 仅在需要 shell 特性时使用
CMD ["sh", "-c", "echo $PATH && python app.py"]
```
-### 2. 确保应用在前台运行
+#### 2. 确保应用在前台运行
```docker
-# ✅ 前台运行
+## ✅ 前台运行
CMD ["nginx", "-g", "daemon off;"]
CMD ["apache2ctl", "-D", "FOREGROUND"]
CMD ["java", "-jar", "app.jar"]
-# ❌ 不要使用后台服务命令
+## ❌ 不要使用后台服务命令
CMD service nginx start
CMD systemctl start nginx
```
-### 3. 使用双引号
+#### 3. 使用双引号
```docker
-# ✅ 正确:双引号
+## ✅ 正确:双引号
CMD ["node", "server.js"]
-# ❌ 错误:单引号(JSON 不支持)
+## ❌ 错误:单引号(JSON 不支持)
CMD ['node', 'server.js']
```
-### 4. 配合 ENTRYPOINT 使用
+#### 4. 配合 ENTRYPOINT 使用
```docker
-# 用于可配置参数的场景
+## 用于可配置参数的场景
ENTRYPOINT ["python", "app.py"]
CMD ["--port", "8080"]
-# 运行时可以覆盖端口
+## 运行时可以覆盖端口
$ docker run myapp --port 9000
```
---
-## 常见问题
+### 常见问题
-### Q: CMD 可以写多个吗?
+#### Q: CMD 可以写多个吗?
不可以。多个 CMD 只有最后一个生效:
@@ -227,31 +227,31 @@ CMD ["echo", "first"]
CMD ["echo", "second"] # 只有这个生效
```
-### Q: 如何在 CMD 中使用环境变量?
+#### Q: 如何在 CMD 中使用环境变量?
```docker
-# 方法1:使用 shell 格式
+## 方法1:使用 shell 格式
CMD echo "Port is $PORT"
-# 方法2:显式使用 sh -c
+## 方法2:显式使用 sh -c
CMD ["sh", "-c", "echo Port is $PORT"]
```
-### Q: 为什么我的容器不响应 Ctrl+C?
+#### Q: 为什么我的容器不响应 Ctrl+C?
可能是使用了 shell 格式,信号被 sh 吃掉了:
```docker
-# ❌ 信号无法传递
+## ❌ 信号无法传递
CMD python app.py
-# ✅ 信号正确传递
+## ✅ 信号正确传递
CMD ["python", "app.py"]
```
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -261,8 +261,8 @@ CMD ["python", "app.py"]
| **与 ENTRYPOINT** | CMD 作为 ENTRYPOINT 的默认参数 |
| **核心原则** | 应用必须在前台运行 |
-## 延伸阅读
+### 延伸阅读
- [ENTRYPOINT 入口点](entrypoint.md):固定的启动命令
-- [后台运行](../../05_container/daemon.md):容器前台/后台概念
-- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 编写指南
+- [后台运行](../../05_container/5.2_daemon.md):容器前台/后台概念
+- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 编写指南
diff --git a/04_image/dockerfile/copy.md b/04_image/dockerfile/copy.md
index d9bcc53..880310c 100644
--- a/04_image/dockerfile/copy.md
+++ b/04_image/dockerfile/copy.md
@@ -1,6 +1,6 @@
-# COPY 复制文件
+## COPY 复制文件
-## 基本语法
+### 基本语法
```docker
COPY [选项] <源路径>... <目标路径>
@@ -11,33 +11,33 @@ COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
---
-## 基本用法
+### 基本用法
-### 复制单个文件
+#### 复制单个文件
```docker
-# 复制文件到指定目录
+## 复制文件到指定目录
COPY package.json /app/
-# 复制文件并重命名
+## 复制文件并重命名
COPY config.json /app/settings.json
```
-### 复制多个文件
+#### 复制多个文件
```docker
-# 复制多个指定文件
+## 复制多个指定文件
COPY package.json package-lock.json /app/
-# 使用通配符
+## 使用通配符
COPY *.json /app/
COPY src/*.js /app/src/
```
-### 复制目录
+#### 复制目录
```docker
-# 复制整个目录的内容(不是目录本身)
+## 复制整个目录的内容(不是目录本身)
COPY src/ /app/src/
```
@@ -52,7 +52,7 @@ src/ /app/src/
---
-## 通配符规则
+### 通配符规则
COPY 支持 Go 的 `filepath.Match` 通配符规则:
@@ -71,15 +71,15 @@ COPY app[0-9].js /app/ # app0.js ~ app9.js
---
-## 目标路径
+### 目标路径
-### 绝对路径
+#### 绝对路径
```docker
COPY app.js /usr/src/app/
```
-### 相对路径(基于 WORKDIR)
+#### 相对路径(基于 WORKDIR)
```docker
WORKDIR /app
@@ -87,29 +87,29 @@ COPY package.json ./ # 复制到 /app/package.json
COPY src/ ./src/ # 复制到 /app/src/
```
-### 自动创建目录
+#### 自动创建目录
如果目标目录不存在,Docker 会自动创建:
```docker
-# /app/config/ 不存在也会自动创建
+## /app/config/ 不存在也会自动创建
COPY settings.json /app/config/
```
---
-## 修改文件所有者
+### 修改文件所有者
使用 `--chown` 选项设置文件的用户和组:
```docker
-# 使用用户名和组名
+## 使用用户名和组名
COPY --chown=node:node package.json /app/
-# 使用 UID 和 GID
+## 使用 UID 和 GID
COPY --chown=1000:1000 . /app/
-# 只指定用户
+## 只指定用户
COPY --chown=node . /app/
```
@@ -117,7 +117,7 @@ COPY --chown=node . /app/
---
-## 保留文件元数据
+### 保留文件元数据
COPY 会保留源文件的元数据:
- 读、写、执行权限
@@ -126,13 +126,13 @@ COPY 会保留源文件的元数据:
这对于脚本文件特别重要:
```docker
-# start.sh 的可执行权限会被保留
+## start.sh 的可执行权限会被保留
COPY start.sh /app/
```
---
-## COPY vs ADD
+### COPY vs ADD
| 特性 | COPY | ADD |
|------|------|-----|
@@ -142,11 +142,11 @@ COPY start.sh /app/
| 推荐程度 | ✅ **推荐** | ⚠️ 特殊场景使用 |
```docker
-# 推荐:使用 COPY
+## 推荐:使用 COPY
COPY app.tar.gz /app/
RUN tar -xzf /app/app.tar.gz
-# ADD 会自动解压(行为不明显,不推荐)
+## ADD 会自动解压(行为不明显,不推荐)
ADD app.tar.gz /app/
```
@@ -154,12 +154,12 @@ ADD app.tar.gz /app/
---
-## 多阶段构建中的 COPY
+### 多阶段构建中的 COPY
-### 从其他构建阶段复制
+#### 从其他构建阶段复制
```docker
-# 构建阶段
+## 构建阶段
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
@@ -167,15 +167,15 @@ RUN npm install
COPY . .
RUN npm run build
-# 生产阶段
+## 生产阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
```
-### 使用 --link 优化缓存(BuildKit)
+#### 使用 --link 优化缓存(BuildKit)
```docker
-# 使用 --link 后,文件以独立层添加,不依赖前序指令
+## 使用 --link 后,文件以独立层添加,不依赖前序指令
COPY --link --from=builder /app/dist /usr/share/nginx/html
```
@@ -186,12 +186,12 @@ COPY --link --from=builder /app/dist /usr/share/nginx/html
---
-## .dockerignore
+### .dockerignore
使用 `.dockerignore` 排除不需要复制的文件:
```gitignore
-# .dockerignore
+## .dockerignore
node_modules
.git
.env
@@ -207,43 +207,43 @@ Dockerfile
---
-## 最佳实践
+### 最佳实践
-### 1. 利用缓存,先复制依赖文件
+#### 1. 利用缓存,先复制依赖文件
```docker
-# ✅ 好:先复制依赖定义,再安装,最后复制代码
+## ✅ 好:先复制依赖定义,再安装,最后复制代码
COPY package.json package-lock.json ./
RUN npm install
COPY . .
-# ❌ 差:一次性复制所有文件,代码变更会导致重新 npm install
+## ❌ 差:一次性复制所有文件,代码变更会导致重新 npm install
COPY . .
RUN npm install
```
-### 2. 使用 .dockerignore
+#### 2. 使用 .dockerignore
```docker
-# 确保 node_modules 不被复制
+## 确保 node_modules 不被复制
COPY . .
-# .dockerignore 中应包含 node_modules
+## .dockerignore 中应包含 node_modules
```
-### 3. 明确复制路径
+#### 3. 明确复制路径
```docker
-# ✅ 好:明确的路径
+## ✅ 好:明确的路径
COPY src/ /app/src/
COPY package.json /app/
-# ❌ 差:过于宽泛
+## ❌ 差:过于宽泛
COPY . .
```
---
-## 本章小结
+### 本章小结
| 操作 | 示例 |
|------|------|
@@ -253,9 +253,9 @@ COPY . .
| 修改所有者 | `COPY --chown=node:node . /app/` |
| 从构建阶段复制 | `COPY --from=builder /app/dist ./` |
-## 延伸阅读
+### 延伸阅读
- [ADD 指令](add.md):复制和解压
- [WORKDIR 指令](workdir.md):设置工作目录
- [多阶段构建](../multistage-builds.md):优化镜像大小
-- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 编写指南
+- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 编写指南
diff --git a/04_image/dockerfile/entrypoint.md b/04_image/dockerfile/entrypoint.md
index ba15c50..46973d9 100644
--- a/04_image/dockerfile/entrypoint.md
+++ b/04_image/dockerfile/entrypoint.md
@@ -1,6 +1,6 @@
-# ENTRYPOINT 入口点
+## ENTRYPOINT 入口点
-## 什么是 ENTRYPOINT
+### 什么是 ENTRYPOINT
`ENTRYPOINT` 指定容器启动时运行的入口程序。与 CMD 不同,ENTRYPOINT 定义的命令不会被 `docker run` 的参数覆盖,而是**接收这些参数**。
@@ -8,7 +8,7 @@
---
-## 语法格式
+### 语法格式
| 格式 | 语法 | 推荐程度 |
|------|------|---------|
@@ -16,18 +16,18 @@
| **shell 格式** | `ENTRYPOINT 命令 参数` | ⚠️ 不推荐 |
```docker
-# exec 格式(推荐)
+## exec 格式(推荐)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
-# shell 格式(不推荐)
+## shell 格式(不推荐)
ENTRYPOINT nginx -g "daemon off;"
```
---
-## ENTRYPOINT vs CMD
+### ENTRYPOINT vs CMD
-### 核心区别
+#### 核心区别
| 特性 | ENTRYPOINT | CMD |
|------|------------|-----|
@@ -36,10 +36,10 @@ ENTRYPOINT nginx -g "daemon off;"
| **覆盖方式** | `--entrypoint` | 直接指定命令 |
| **适用场景** | 把镜像当命令用 | 提供默认行为 |
-### 行为对比
+#### 行为对比
```docker
-# 只用 CMD
+## 只用 CMD
CMD ["curl", "-s", "http://example.com"]
```
@@ -50,7 +50,7 @@ $ docker run myimage curl -v ... # curl -v ...(完全替换)
```
```docker
-# 只用 ENTRYPOINT
+## 只用 ENTRYPOINT
ENTRYPOINT ["curl", "-s"]
```
@@ -60,7 +60,7 @@ $ docker run myimage http://example.com # curl -s http://example.com ✓
```
```docker
-# ENTRYPOINT + CMD 组合(推荐)
+## ENTRYPOINT + CMD 组合(推荐)
ENTRYPOINT ["curl", "-s"]
CMD ["http://example.com"]
```
@@ -73,13 +73,13 @@ $ docker run myimage -v http://other.com # curl -s -v http://other.com ✓
---
-## 场景一:让镜像像命令一样使用
+### 场景一:让镜像像命令一样使用
-### 需求
+#### 需求
创建一个查询公网 IP 的"命令"镜像。
-### 使用 CMD 的问题
+#### 使用 CMD 的问题
```docker
FROM ubuntu:24.04
@@ -93,10 +93,10 @@ $ docker run myip # ✓ 正常工作
$ docker run myip -i # ✗ 错误!
exec: "-i": executable file not found
-# -i 替换了整个 CMD,被当作可执行文件
+## -i 替换了整个 CMD,被当作可执行文件
```
-### 使用 ENTRYPOINT 解决
+#### 使用 ENTRYPOINT 解决
```docker
FROM ubuntu:24.04
@@ -114,7 +114,7 @@ HTTP/1.1 200 OK
当前 IP:61.148.226.66
```
-### 交互图示
+#### 交互图示
```
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
@@ -129,13 +129,13 @@ curl -s http://myip.ipip.net -i
---
-## 场景二:启动前的准备工作
+### 场景二:启动前的准备工作
-### 需求
+#### 需求
在启动主服务前执行初始化脚本(如数据库迁移、权限设置)。
-### 实现方式
+#### 实现方式
```docker
FROM redis:7-alpine
@@ -150,20 +150,20 @@ CMD ["redis-server"]
#!/bin/sh
set -e
-# 准备工作
+## 准备工作
echo "Initializing..."
-# 如果第一个参数是 redis-server,以 redis 用户运行
+## 如果第一个参数是 redis-server,以 redis 用户运行
if [ "$1" = 'redis-server' ]; then
chown -R redis:redis /data
exec gosu redis "$@"
fi
-# 其他命令直接执行
+## 其他命令直接执行
exec "$@"
```
-### 工作流程
+#### 工作流程
```
docker run redis docker run redis bash
@@ -177,7 +177,7 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
(以 redis 用户运行) (以 root 用户运行)
```
-### 关键点
+#### 关键点
1. **exec "$@"**:用传入的参数替换当前进程,确保信号正确传递
2. **条件判断**:根据 CMD 不同执行不同逻辑
@@ -185,7 +185,7 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
---
-## 场景三:带参数的应用
+### 场景三:带参数的应用
```docker
FROM python:3.12-slim
@@ -198,39 +198,39 @@ CMD ["--host", "0.0.0.0", "--port", "8080"]
```
```bash
-# 使用默认参数
+## 使用默认参数
$ docker run myapp
-# 执行: python app.py --host 0.0.0.0 --port 8080
+## 执行: python app.py --host 0.0.0.0 --port 8080
-# 覆盖参数
+## 覆盖参数
$ docker run myapp --host 0.0.0.0 --port 9000
-# 执行: python app.py --host 0.0.0.0 --port 9000
+## 执行: python app.py --host 0.0.0.0 --port 9000
-# 完全不同的参数
+## 完全不同的参数
$ docker run myapp --help
-# 执行: python app.py --help
+## 执行: python app.py --help
```
---
-## 覆盖 ENTRYPOINT
+### 覆盖 ENTRYPOINT
使用 `--entrypoint` 参数覆盖:
```bash
-# 正常运行
+## 正常运行
$ docker run myimage
-# 覆盖 ENTRYPOINT 进入 shell 调试
+## 覆盖 ENTRYPOINT 进入 shell 调试
$ docker run --entrypoint /bin/sh myimage
-# 覆盖 ENTRYPOINT 并传入参数
+## 覆盖 ENTRYPOINT 并传入参数
$ docker run --entrypoint /bin/cat myimage /etc/os-release
```
---
-## ENTRYPOINT 与 CMD 组合表
+### ENTRYPOINT 与 CMD 组合表
| ENTRYPOINT | CMD | 最终执行命令 |
|------------|-----|-------------|
@@ -244,36 +244,36 @@ $ docker run --entrypoint /bin/cat myimage /etc/os-release
---
-## 最佳实践
+### 最佳实践
-### 1. 使用 exec 格式
+#### 1. 使用 exec 格式
```docker
-# ✅ 推荐
+## ✅ 推荐
ENTRYPOINT ["python", "app.py"]
-# ❌ 避免 shell 格式
+## ❌ 避免 shell 格式
ENTRYPOINT python app.py
```
-### 2. 提供有意义的默认参数
+#### 2. 提供有意义的默认参数
```docker
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
```
-### 3. 入口脚本使用 exec
+#### 3. 入口脚本使用 exec
```bash
#!/bin/sh
-# 准备工作...
+## 准备工作...
-# 使用 exec 替换当前进程
+## 使用 exec 替换当前进程
exec "$@"
```
-### 4. 处理信号
+#### 4. 处理信号
确保 ENTRYPOINT 脚本能正确传递信号:
@@ -281,17 +281,17 @@ exec "$@"
#!/bin/bash
trap 'kill -TERM $PID' TERM INT
-# 启动应用
+## 启动应用
app "$@" &
PID=$!
-# 等待应用退出
+## 等待应用退出
wait $PID
```
---
-## 本章小结
+### 本章小结
| ENTRYPOINT | CMD | 适用场景 |
|------------|-----|---------|
@@ -299,8 +299,8 @@ wait $PID
| ✗ | ✓ | 简单的默认命令 |
| ✓ | ✓ | **推荐**:固定命令 + 可配置参数 |
-## 延伸阅读
+### 延伸阅读
- [CMD 容器启动命令](cmd.md):默认命令
-- [最佳实践](../../15_appendix/best_practices.md):启动命令设计
-- [后台运行](../../05_container/daemon.md):前台/后台概念
+- [最佳实践](../../15_appendix/15.1_best_practices.md):启动命令设计
+- [后台运行](../../05_container/5.2_daemon.md):前台/后台概念
diff --git a/04_image/dockerfile/env.md b/04_image/dockerfile/env.md
index cb52c57..f747a80 100644
--- a/04_image/dockerfile/env.md
+++ b/04_image/dockerfile/env.md
@@ -1,27 +1,27 @@
-# ENV 设置环境变量
+## ENV 设置环境变量
-## 基本语法
+### 基本语法
```docker
-# 格式一:单个变量
+## 格式一:单个变量
ENV
-# 格式二:多个变量(推荐)
+## 格式二:多个变量(推荐)
ENV = = ...
```
---
-## 基本用法
+### 基本用法
-### 设置单个变量
+#### 设置单个变量
```docker
ENV NODE_VERSION 20.10.0
ENV APP_ENV production
```
-### 设置多个变量
+#### 设置多个变量
```docker
ENV NODE_VERSION=20.10.0 \
@@ -33,26 +33,26 @@ ENV NODE_VERSION=20.10.0 \
---
-## 环境变量的作用
+### 环境变量的作用
-### 1. 后续指令中使用
+#### 1. 后续指令中使用
```docker
ENV NODE_VERSION=20.10.0
-# 在 RUN 中使用
+## 在 RUN 中使用
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz \
| tar -xJ -C /usr/local --strip-components=1
-# 在 WORKDIR 中使用
+## 在 WORKDIR 中使用
ENV APP_HOME=/app
WORKDIR $APP_HOME
-# 在 COPY 中使用
+## 在 COPY 中使用
COPY . $APP_HOME
```
-### 2. 容器运行时使用
+#### 2. 容器运行时使用
```docker
ENV DATABASE_URL=postgres://localhost/mydb
@@ -71,7 +71,7 @@ const dbUrl = process.env.DATABASE_URL;
---
-## 支持环境变量的指令
+### 支持环境变量的指令
以下指令可以使用 `$变量名` 或 `${变量名}` 格式:
@@ -91,25 +91,25 @@ const dbUrl = process.env.DATABASE_URL;
---
-## 运行时覆盖
+### 运行时覆盖
使用 `-e` 或 `--env` 覆盖 Dockerfile 中定义的环境变量:
```bash
-# 覆盖单个变量
+## 覆盖单个变量
$ docker run -e APP_ENV=development myimage
-# 覆盖多个变量
+## 覆盖多个变量
$ docker run -e APP_ENV=development -e DEBUG=true myimage
-# 从环境变量文件读取
+## 从环境变量文件读取
$ docker run --env-file .env myimage
```
-### .env 文件格式
+#### .env 文件格式
```bash
-# .env
+## .env
APP_ENV=development
DEBUG=true
DATABASE_URL=postgres://localhost/mydb
@@ -117,7 +117,7 @@ DATABASE_URL=postgres://localhost/mydb
---
-## ENV vs ARG
+### ENV vs ARG
| 特性 | ENV | ARG |
|------|-----|-----|
@@ -126,53 +126,53 @@ DATABASE_URL=postgres://localhost/mydb
| **覆盖方式** | `docker run -e` | `docker build --build-arg` |
| **适用场景** | 应用配置 | 构建参数(如版本号) |
-### 组合使用
+#### 组合使用
```docker
-# ARG 接收构建时参数
+## ARG 接收构建时参数
ARG NODE_VERSION=20
-# ENV 保存到运行时
+## ENV 保存到运行时
ENV NODE_VERSION=$NODE_VERSION
-# 后续指令使用
+## 后续指令使用
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/...
```
```bash
-# 构建时指定版本
+## 构建时指定版本
$ docker build --build-arg NODE_VERSION=18 -t myapp .
```
---
-## 最佳实践
+### 最佳实践
-### 1. 统一管理版本号
+#### 1. 统一管理版本号
```docker
-# ✅ 好:版本集中管理
+## ✅ 好:版本集中管理
ENV NGINX_VERSION=1.25.0 \
NODE_VERSION=20.10.0 \
PYTHON_VERSION=3.12.0
RUN apt-get install nginx=${NGINX_VERSION}
-# ❌ 差:版本分散在各处
+## ❌ 差:版本分散在各处
RUN apt-get install nginx=1.25.0
```
-### 2. 不要存储敏感信息
+#### 2. 不要存储敏感信息
```docker
-# ❌ 错误:密码写入镜像
+## ❌ 错误:密码写入镜像
ENV DB_PASSWORD=secret123
-# ✅ 正确:运行时传入
-# docker run -e DB_PASSWORD=xxx myimage
+## ✅ 正确:运行时传入
+## docker run -e DB_PASSWORD=xxx myimage
```
-### 3. 为应用提供合理默认值
+#### 3. 为应用提供合理默认值
```docker
ENV APP_ENV=production \
@@ -180,50 +180,50 @@ ENV APP_ENV=production \
LOG_LEVEL=info
```
-### 4. 使用有意义的变量名
+#### 4. 使用有意义的变量名
```docker
-# ✅ 好:清晰的命名
+## ✅ 好:清晰的命名
ENV REDIS_HOST=localhost \
REDIS_PORT=6379
-# ❌ 差:模糊的命名
+## ❌ 差:模糊的命名
ENV HOST=localhost \
PORT=6379
```
---
-## 常见问题
+### 常见问题
-### Q: 环境变量在 CMD 中不展开
+#### Q: 环境变量在 CMD 中不展开
exec 格式不会自动展开环境变量:
```docker
-# ❌ 不会展开 $PORT
+## ❌ 不会展开 $PORT
CMD ["python", "app.py", "--port", "$PORT"]
-# ✅ 使用 shell 格式或显式调用 sh
+## ✅ 使用 shell 格式或显式调用 sh
CMD ["sh", "-c", "python app.py --port $PORT"]
```
-### Q: 如何查看容器的环境变量
+#### Q: 如何查看容器的环境变量
```bash
$ docker inspect mycontainer --format '{{json .Config.Env}}'
$ docker exec mycontainer env
```
-### Q: 多行 ENV 还是多个 ENV
+#### Q: 多行 ENV 还是多个 ENV
```docker
-# ✅ 推荐:减少层数
+## ✅ 推荐:减少层数
ENV VAR1=value1 \
VAR2=value2 \
VAR3=value3
-# ⚠️ 多个 ENV 会创建多层
+## ⚠️ 多个 ENV 会创建多层
ENV VAR1=value1
ENV VAR2=value2
ENV VAR3=value3
@@ -231,7 +231,7 @@ ENV VAR3=value3
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -241,8 +241,8 @@ ENV VAR3=value3
| **与 ARG** | ARG 仅构建时,ENV 持久化到运行时 |
| **安全** | 不要存储敏感信息 |
-## 延伸阅读
+### 延伸阅读
- [ARG 构建参数](arg.md):构建时变量
-- [Compose 环境变量](../../compose/compose_file.md):Compose 中的环境变量
-- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 编写指南
+- [Compose 环境变量](../../compose/9.5_compose_file.md):Compose 中的环境变量
+- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 编写指南
diff --git a/04_image/dockerfile/expose.md b/04_image/dockerfile/expose.md
index 2743ddd..966bbff 100644
--- a/04_image/dockerfile/expose.md
+++ b/04_image/dockerfile/expose.md
@@ -1,6 +1,6 @@
-# EXPOSE 声明端口
+## EXPOSE 声明端口
-## 基本语法
+### 基本语法
```docker
EXPOSE <端口> [<端口>/<协议>...]
@@ -10,45 +10,45 @@ EXPOSE <端口> [<端口>/<协议>...]
---
-## 基本用法
+### 基本用法
```docker
-# 声明单个端口
+## 声明单个端口
EXPOSE 80
-# 声明多个端口
+## 声明多个端口
EXPOSE 80 443
-# 声明 TCP 和 UDP 端口
+## 声明 TCP 和 UDP 端口
EXPOSE 80/tcp
EXPOSE 53/udp
```
---
-## EXPOSE 的作用
+### EXPOSE 的作用
-### 1. 文档说明
+#### 1. 文档说明
告诉镜像使用者,容器将在哪些端口提供服务:
```docker
-# 使用者一看就知道这是 web 应用
+## 使用者一看就知道这是 web 应用
EXPOSE 80 443
```
```bash
-# 查看镜像暴露的端口
+## 查看镜像暴露的端口
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
map[80/tcp:{}]
```
-### 2. 配合 -P 使用
+#### 2. 配合 -P 使用
使用 `docker run -P` 时,Docker 会自动映射 EXPOSE 的端口到宿主机随机端口:
```docker
-# Dockerfile
+## Dockerfile
EXPOSE 80
```
@@ -60,7 +60,7 @@ $ docker port $(docker ps -q)
---
-## EXPOSE vs -p
+### EXPOSE vs -p
| 特性 | EXPOSE | -p |
|------|--------|-----|
@@ -85,27 +85,27 @@ $ docker port $(docker ps -q)
└────────────────────────────────────────────────────────────┘
```
-### 没有 EXPOSE 也能 -p
+#### 没有 EXPOSE 也能 -p
```docker
-# 即使没有 EXPOSE,也可以使用 -p
+## 即使没有 EXPOSE,也可以使用 -p
FROM nginx
-# 没有 EXPOSE
+## 没有 EXPOSE
```
```bash
-# 仍然可以映射端口
+## 仍然可以映射端口
$ docker run -p 8080:80 mynginx
```
---
-## 常见误解
+### 常见误解
-### 误解:EXPOSE 会打开端口
+#### 误解:EXPOSE 会打开端口
```docker
-# ❌ 错误理解:这不会让容器可从外部访问
+## ❌ 错误理解:这不会让容器可从外部访问
EXPOSE 80
```
@@ -116,68 +116,68 @@ EXPOSE 不会:
EXPOSE 只是元数据声明。容器是否实际监听该端口,取决于容器内的应用。
-### 正确理解
+#### 正确理解
```docker
-# Dockerfile
+## Dockerfile
FROM nginx
EXPOSE 80 # 1. 声明:这个容器会在 80 端口提供服务
```
```bash
-# 运行:需要 -p 才能从外部访问
+## 运行:需要 -p 才能从外部访问
$ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
```
---
-## 最佳实践
+### 最佳实践
-### 1. 总是声明应用使用的端口
+#### 1. 总是声明应用使用的端口
```docker
-# Web 服务
+## Web 服务
FROM nginx
EXPOSE 80 443
-# 数据库
+## 数据库
FROM postgres
EXPOSE 5432
-# Redis
+## Redis
FROM redis
EXPOSE 6379
```
-### 2. 使用明确的协议
+#### 2. 使用明确的协议
```docker
-# 默认是 TCP
+## 默认是 TCP
EXPOSE 80
-# 明确指定 UDP
+## 明确指定 UDP
EXPOSE 53/udp
-# 同时支持 TCP 和 UDP
+## 同时支持 TCP 和 UDP
EXPOSE 53/tcp 53/udp
```
-### 3. 与应用实际端口保持一致
+#### 3. 与应用实际端口保持一致
```docker
-# ✅ 好:EXPOSE 与应用端口一致
+## ✅ 好:EXPOSE 与应用端口一致
ENV PORT=3000
EXPOSE 3000
CMD ["node", "server.js"]
-# ❌ 差:EXPOSE 与应用端口不一致(误导)
+## ❌ 差:EXPOSE 与应用端口不一致(误导)
EXPOSE 80
CMD ["node", "server.js"] # 实际监听 3000
```
---
-## 使用环境变量
+### 使用环境变量
```docker
ARG PORT=80
@@ -186,7 +186,7 @@ EXPOSE $PORT
---
-## 在 Compose 中
+### 在 Compose 中
```yaml
services:
@@ -202,7 +202,7 @@ services:
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -212,8 +212,8 @@ services:
| **外部访问** | 需要 `-p 宿主机端口:容器端口` |
| **语法** | `EXPOSE 80` 或 `EXPOSE 80/tcp` |
-## 延伸阅读
+### 延伸阅读
- [网络配置](../../network/README.md):Docker 网络详解
- [端口映射](../../network/port_bindingbindingbinding.md):-p 参数详解
-- [Compose 端口](../../compose/compose_file.md):Compose 中的端口配置
+- [Compose 端口](../../compose/9.5_compose_file.md):Compose 中的端口配置
diff --git a/04_image/dockerfile/healthcheck.md b/04_image/dockerfile/healthcheck.md
index 2e52f8d..a4bbc66 100644
--- a/04_image/dockerfile/healthcheck.md
+++ b/04_image/dockerfile/healthcheck.md
@@ -1,6 +1,6 @@
-# HEALTHCHECK 健康检查
+## HEALTHCHECK 健康检查
-## 基本语法
+### 基本语法
```docker
HEALTHCHECK [选项] CMD <命令>
@@ -11,7 +11,7 @@ HEALTHCHECK NONE
---
-## 为什么需要 HEALTHCHECK
+### 为什么需要 HEALTHCHECK
在没有 HEALTHCHECK 之前,Docker 只能通过**进程退出码**来判断容器状态。
@@ -32,9 +32,9 @@ Starting ──成功──> Healthy ──失败N次──> Unhealthy
---
-## 基本用法
+### 基本用法
-### Web 服务检查
+#### Web 服务检查
```docker
FROM nginx
@@ -44,13 +44,13 @@ HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -fs http://localhost/ || exit 1
```
-### 命令返回值
+#### 命令返回值
- `0`: 成功 (healthy)
- `1`: 失败 (unhealthy)
- `2`: 保留值 (不使用)
-### 常用选项
+#### 常用选项
| 选项 | 说明 | 默认值 |
|------|------|--------|
@@ -61,7 +61,7 @@ HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
---
-## 屏蔽健康检查
+### 屏蔽健康检查
如果基础镜像定义了 HEALTHCHECK,但你不想使用它:
@@ -72,31 +72,31 @@ HEALTHCHECK NONE
---
-## 常见检查脚本
+### 常见检查脚本
-### HTTP 服务
+#### HTTP 服务
使用 `curl` 或 `wget`:
```docker
-# 使用 curl
+## 使用 curl
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
-# 使用 wget (Alpine 默认包含)
+## 使用 wget (Alpine 默认包含)
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
```
-### 数据库
+#### 数据库
```docker
-# MySQL
+## MySQL
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
-# Redis
+## Redis
HEALTHCHECK CMD redis-cli ping || exit 1
```
-### 自定义脚本
+#### 自定义脚本
```docker
COPY healthcheck.sh /usr/local/bin/
@@ -105,7 +105,7 @@ HEALTHCHECK CMD ["healthcheck.sh"]
---
-## 在 Compose 中使用
+### 在 Compose 中使用
可以在 `docker-compose.yml` 中覆盖或定义健康检查:
@@ -137,16 +137,16 @@ services:
---
-## 查看健康状态
+### 查看健康状态
```bash
-# 查看容器状态(包含健康信息)
+## 查看容器状态(包含健康信息)
$ docker ps
CONTAINER ID STATUS
abc123 Up 1 minute (healthy)
def456 Up 2 minutes (unhealthy)
-# 查看详细健康日志
+## 查看详细健康日志
$ docker inspect --format '{{json .State.Health}}' mycontainer | jq
{
"Status": "healthy",
@@ -164,32 +164,32 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
---
-## 最佳实践
+### 最佳实践
-### 1. 避免副作用
+#### 1. 避免副作用
健康检查会被频繁执行,不要在检查脚本中进行写操作或消耗大量资源的操作。
-### 2. 使用轻量级工具
+#### 2. 使用轻量级工具
优先使用镜像中已有的工具(如 `wget`),避免为了健康检查安装庞大的依赖(如 `curl`)。
-### 3. 设置合理的 Start Period
+#### 3. 设置合理的 Start Period
应用启动可能需要时间(如 Java 应用)。设置 `--start-period` 可以防止在启动阶段因检查失败而误判。
```docker
-# 给应用 1 分钟启动时间
+## 给应用 1 分钟启动时间
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
```
-### 4. 只检查核心依赖
+#### 4. 只检查核心依赖
健康检查应主要关注**当前服务**是否可用,而不是检查其下游依赖(数据库等)。下游依赖的检查应由应用逻辑处理。
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -199,8 +199,8 @@ HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
| **Compose** | 支持 `condition: service_healthy` 依赖 |
| **注意** | 避免副作用,节省资源 |
-## 延伸阅读
+### 延伸阅读
- [CMD 容器启动命令](cmd.md):启动主进程
-- [Compose 模板文件](../../compose/compose_file.md):Compose 中的健康检查
-- [Docker 调试](../../15_appendix/debug.md):容器排障
+- [Compose 模板文件](../../compose/9.5_compose_file.md):Compose 中的健康检查
+- [Docker 调试](../../15_appendix/15.2_debug.md):容器排障
diff --git a/04_image/dockerfile/label.md b/04_image/dockerfile/label.md
index fab296a..ab0ca5c 100644
--- a/04_image/dockerfile/label.md
+++ b/04_image/dockerfile/label.md
@@ -1,6 +1,6 @@
-# LABEL 为镜像添加元数据
+## LABEL 为镜像添加元数据
-## 基本语法
+### 基本语法
```docker
LABEL = = ...
@@ -10,7 +10,7 @@ LABEL = = ...
---
-## 为什么需要 LABEL
+### 为什么需要 LABEL
1. **版本管理**:记录版本号、构建时间、Git Commit ID
2. **联系信息**:维护者邮箱、文档地址、支持渠道
@@ -19,16 +19,16 @@ LABEL = = ...
---
-## 基本用法
+### 基本用法
-### 定义单个标签
+#### 定义单个标签
```docker
LABEL version="1.0"
LABEL description="这是一个 Web 应用服务器"
```
-### 定义多个标签(推荐)
+#### 定义多个标签(推荐)
```docker
LABEL maintainer="user@example.com" \
@@ -41,7 +41,7 @@ LABEL maintainer="user@example.com" \
---
-## 常用标签规范 (OCI Annotations)
+### 常用标签规范 (OCI Annotations)
为了标准和互操作性,推荐使用 [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys) 定义的标准标签:
@@ -57,7 +57,7 @@ LABEL maintainer="user@example.com" \
| `org.opencontainers.image.title` | 镜像标题 | `My App` |
| `org.opencontainers.image.description` | 描述 | `Production ready web server` |
-### 示例
+#### 示例
```docker
LABEL org.opencontainers.image.authors="yeasy" \
@@ -68,27 +68,27 @@ LABEL org.opencontainers.image.authors="yeasy" \
---
-## MAINTAINER 指令(已废弃)
+### MAINTAINER 指令(已废弃)
旧版本的 Dockerfile 中常看到 `MAINTAINER` 指令:
```docker
-# ❌ 已弃用
+## ❌ 已弃用
MAINTAINER user@example.com
```
现在推荐使用 `LABEL`:
```docker
-# ✅ 推荐
+## ✅ 推荐
LABEL maintainer="user@example.com"
-# 或
+## 或
LABEL org.opencontainers.image.authors="user@example.com"
```
---
-## 动态标签
+### 动态标签
配合 `ARG` 使用,可以在构建时动态注入标签:
@@ -111,9 +111,9 @@ $ docker build \
---
-## 查看标签
+### 查看标签
-### docker inspect
+#### docker inspect
查看镜像的标签信息:
@@ -124,21 +124,21 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq
}
```
-### 过滤器
+#### 过滤器
可以使用标签过滤镜像:
```bash
-# 列出作者是 yeasy 的所有镜像
+## 列出作者是 yeasy 的所有镜像
$ docker images --filter "label=org.opencontainers.image.authors=yeasy"
-# 删除所有带有特定标签的镜像
+## 删除所有带有特定标签的镜像
$ docker rmi $(docker images -q --filter "label=stage=builder")
```
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -148,7 +148,7 @@ $ docker rmi $(docker images -q --filter "label=stage=builder")
| **弃用** | 不要再使用 `MAINTAINER` |
| **查看** | `docker inspect` |
-## 延伸阅读
+### 延伸阅读
- [OCI 标签规范](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
-- [Dockerfile 最佳实践](../../15_appendix/best_practices.md)
+- [Dockerfile 最佳实践](../../15_appendix/15.1_best_practices.md)
diff --git a/04_image/dockerfile/onbuild.md b/04_image/dockerfile/onbuild.md
index 8c8de16..e3c2de6 100644
--- a/04_image/dockerfile/onbuild.md
+++ b/04_image/dockerfile/onbuild.md
@@ -1,6 +1,6 @@
-# ONBUILD 为他人做嫁衣裳
+## ONBUILD 为他人做嫁衣裳
-## 基本语法
+### 基本语法
```docker
ONBUILD <其它指令>
@@ -10,11 +10,11 @@ ONBUILD <其它指令>
---
-## 为什么需要 ONBUILD
+### 为什么需要 ONBUILD
`ONBUILD` 主要用于制作**语言栈基础镜像**或**框架基础镜像**。
-### 场景:维护 Node.js 项目
+#### 场景:维护 Node.js 项目
假设你有多个 Node.js 项目,它们的构建流程都一样:
1. 创建目录
@@ -25,7 +25,7 @@ ONBUILD <其它指令>
如果不使用 `ONBUILD`,每个项目的 Dockerfile 都要重复这些步骤,且通过 `COPY` 复制文件时,基础镜像无法预知子项目的文件名。
-### 使用 ONBUILD 的解决方案
+#### 使用 ONBUILD 的解决方案
**基础镜像 (my-node-base)**:
@@ -33,7 +33,7 @@ ONBUILD <其它指令>
FROM node:20-alpine
WORKDIR /app
-# 这些指令将在子镜像构建时执行
+## 这些指令将在子镜像构建时执行
ONBUILD COPY package*.json ./
ONBUILD RUN npm install
ONBUILD COPY . .
@@ -45,13 +45,13 @@ CMD ["npm", "start"]
```docker
FROM my-node-base
-# 只需要一行!
-# 构建时会自动执行 COPY 和 RUN
+## 只需要一行!
+## 构建时会自动执行 COPY 和 RUN
```
---
-## 执行机制
+### 执行机制
```
基础镜像构建:
@@ -64,59 +64,59 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
---
-## 常见使用场景
+### 常见使用场景
-### 1. 自动处理依赖安装
+#### 1. 自动处理依赖安装
```docker
-# Python 基础镜像
+## Python 基础镜像
ONBUILD COPY requirements.txt ./
ONBUILD RUN pip install -r requirements.txt
```
-### 2. 自动编译代码
+#### 2. 自动编译代码
```docker
-# Go 基础镜像
+## Go 基础镜像
ONBUILD COPY . .
ONBUILD RUN go build -o app main.go
```
-### 3. 处理静态资源
+#### 3. 处理静态资源
```docker
-# Nginx 静态网站基础镜像
+## Nginx 静态网站基础镜像
ONBUILD COPY dist/ /usr/share/nginx/html/
```
---
-## 注意事项
+### 注意事项
-### 1. 继承性限制
+#### 1. 继承性限制
`ONBUILD` 指令**只会继承一次**。
- 镜像 A (含 ONBUILD)
- 镜像 B (FROM A) -> 触发 ONBUILD
- 镜像 C (FROM B) -> **不会**再次触发 ONBUILD
-### 2. 构建上下文
+#### 2. 构建上下文
子镜像构建时,`ONBUILD COPY . .` 中的 `.` 指的是**子项目**的构建上下文,而不是基础镜像的上下文。
-### 3. 不允许级联
+#### 3. 不允许级联
`ONBUILD ONBUILD` 是非法的。你不能写 `ONBUILD ONBUILD COPY ...`。
-### 4. 可能会导致构建失败
+#### 4. 可能会导致构建失败
由于 `ONBUILD` 实际上是在子镜像中执行指令,如果子项目的上下文不满足要求(例如缺少 `package.json`),会导致子镜像构建失败,且错误信息可能比较隐晦。
---
-## 最佳实践
+### 最佳实践
-### 1. 命名规范
+#### 1. 命名规范
建议在镜像标签中添加 `-onbuild` 后缀,明确告知使用者该镜像包含触发器。
@@ -125,17 +125,17 @@ node:20-onbuild
python:3.12-onbuild
```
-### 2. 避免执行耗时操作
+#### 2. 避免执行耗时操作
尽量不要在 `ONBUILD` 中执行过于耗时或不确定的操作(如更新系统软件),这会让子镜像构建变得缓慢且不可控。
-### 3. 清理工作
+#### 3. 清理工作
如果 `ONBUILD` 指令产生了临时文件,最好在同一个指令链中清理,或者提供机制让子镜像清理。
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -145,7 +145,7 @@ python:3.12-onbuild
| **限制** | 只继承一次,不可级联 |
| **规范** | 建议使用 `-onbuild` 标签后缀 |
-## 延伸阅读
+### 延伸阅读
- [COPY 指令](copy.md):文件复制
-- [Dockerfile 最佳实践](../../15_appendix/best_practices.md):基础镜像设计
+- [Dockerfile 最佳实践](../../15_appendix/15.1_best_practices.md):基础镜像设计
diff --git a/04_image/dockerfile/references.md b/04_image/dockerfile/references.md
index b9edb4f..5d5974d 100644
--- a/04_image/dockerfile/references.md
+++ b/04_image/dockerfile/references.md
@@ -1,4 +1,4 @@
-# 参考文档
+## 参考文档
* `Dockerfile` 官方文档:https://docs.docker.com/engine/reference/builder/
diff --git a/04_image/dockerfile/run.md b/04_image/dockerfile/run.md
index 7a36a13..29871aa 100644
--- a/04_image/dockerfile/run.md
+++ b/04_image/dockerfile/run.md
@@ -1,6 +1,6 @@
-# RUN 执行命令
+## RUN 执行命令
-## 基本语法
+### 基本语法
```docker
RUN
@@ -11,9 +11,9 @@ RUN ["executable", "param1", "param2"]
---
-## 两种格式对比
+### 两种格式对比
-### 1. Shell 格式
+#### 1. Shell 格式
```docker
RUN apt-get update
@@ -26,7 +26,7 @@ RUN apt-get update
RUN echo "Hello" > /test.txt
```
-### 2. Exec 格式
+#### 2. Exec 格式
```docker
RUN ["apt-get", "update"]
@@ -38,9 +38,9 @@ RUN ["apt-get", "update"]
---
-## 常见最佳实践
+### 常见最佳实践
-### 1. 组合命令(减少层数)
+#### 1. 组合命令(减少层数)
每一个 `RUN` 指令都会新建一层镜像。为了减少镜像体积和层数,应使用 `&&` 连接命令。
@@ -60,7 +60,7 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/*
```
-### 2. 清理缓存
+#### 2. 清理缓存
在安装完软件后,立即清除缓存,可以显著减小镜像体积。
@@ -74,14 +74,14 @@ RUN apt-get update && \
RUN apk add --no-cache package-bar
```
-### 3. 使用 `set -e` 和 `pipefail`
+#### 3. 使用 `set -e` 和 `pipefail`
默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个 `RUN` 就视为成功。
**❌ 隐蔽的错误**:
```docker
-# 如果下载失败,gzip 可能会报错,但如果不影响后续,构建可能继续
+## 如果下载失败,gzip 可能会报错,但如果不影响后续,构建可能继续
RUN wget http://error-url | gzip -d > file
```
@@ -94,9 +94,9 @@ RUN wget http://url | gzip -d > file
---
-## 常见问题
+### 常见问题
-### Q: 为什么 `RUN cd /app` 不生效?
+#### Q: 为什么 `RUN cd /app` 不生效?
```docker
RUN cd /app
@@ -114,7 +114,7 @@ WORKDIR /app
RUN touch hello.txt
```
-### Q: 环境变量不生效?
+#### Q: 环境变量不生效?
```docker
RUN export MY_VAR=hello
@@ -134,26 +134,26 @@ RUN echo $MY_VAR
---
-## 高级技巧
+### 高级技巧
-### 1. 使用 BuildKit 的挂载缓存
+#### 1. 使用 BuildKit 的挂载缓存
BuildKit 支持在 `RUN` 指令中使用 `--mount` 挂载缓存,加速构建。
```docker
-# 缓存 apt 包
+## 缓存 apt 包
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y gcc
```
```docker
-# 缓存 Go 模块
+## 缓存 Go 模块
RUN --mount=type=cache,target=/go/pkg/mod \
go build -o app
```
-### 2. 挂载密钥
+#### 2. 挂载密钥
安全地使用 SSH 密钥或 Token,而不将其记录在镜像中。
@@ -164,7 +164,7 @@ RUN --mount=type=secret,id=mysecret \
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -174,8 +174,8 @@ RUN --mount=type=secret,id=mysecret \
| **陷阱** | `cd` 不持久,环境变量不持久 |
| **进阶** | 使用 Cache Mount 加速构建 |
-## 延伸阅读
+### 延伸阅读
- [CMD 容器启动命令](cmd.md):容器启动时的命令
- [WORKDIR 指定工作目录](workdir.md):改变目录
-- [Dockerfile 最佳实践](../../15_appendix/best_practices.md)
+- [Dockerfile 最佳实践](../../15_appendix/15.1_best_practices.md)
diff --git a/04_image/dockerfile/shell.md b/04_image/dockerfile/shell.md
index 2487c9c..5a9dd70 100644
--- a/04_image/dockerfile/shell.md
+++ b/04_image/dockerfile/shell.md
@@ -1,6 +1,6 @@
-# SHELL 指令
+## SHELL 指令
-## 基本语法
+### 基本语法
```docker
SHELL ["executable", "parameters"]
@@ -14,83 +14,83 @@ SHELL ["executable", "parameters"]
---
-## 为什么要用 SHELL 指令
+### 为什么要用 SHELL 指令
-### 1. 使用 bash 特性
+#### 1. 使用 bash 特性
默认的 `/bin/sh`(通常是 dash 或 alpine 的 ash)功能有限。如果你需要使用 bash 的特有功能(如数组、`{}` 扩展、`pipefail` 等),可以切换 shell。
```docker
FROM ubuntu:24.04
-# 切换到 bash
+## 切换到 bash
SHELL ["/bin/bash", "-c"]
-# 现在可以使用 bash 特性了
+## 现在可以使用 bash 特性了
RUN echo {a..z}
```
-### 2. 增强错误处理 (pipefail)
+#### 2. 增强错误处理 (pipefail)
默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个指令就视为成功。这可能掩盖构建错误。
```docker
-# ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
+## ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
RUN wget -O - https://invalid-url | tar xz
```
使用 `SHELL` 启用 `pipefail`:
```docker
-# ✅ 启用 pipefail
+## ✅ 启用 pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
-# 如果 wget 失败,整个 RUN 就会失败
+## 如果 wget 失败,整个 RUN 就会失败
RUN wget -O - https://invalid-url | tar xz
```
-### 3. Windows 环境
+#### 3. Windows 环境
在 Windows 容器中,经常需要在 `cmd` 和 `powershell` 之间切换。
```docker
FROM mcr.microsoft.com/windows/servercore:ltsc2022
-# 默认是 cmd
+## 默认是 cmd
RUN echo Default shell is cmd
-# 切换到 powershell
+## 切换到 powershell
SHELL ["powershell", "-command"]
RUN Write-Host "Hello from PowerShell"
-# 切回 cmd
+## 切回 cmd
SHELL ["cmd", "/S", "/C"]
```
---
-## 作用范围
+### 作用范围
`SHELL` 指令可以出现多次,每次只影响其后的指令:
```docker
FROM ubuntu:24.04
-# 使用默认 sh
+## 使用默认 sh
RUN echo "Using sh"
SHELL ["/bin/bash", "-c"]
-# 使用 bash
+## 使用 bash
RUN echo "Using bash"
SHELL ["/bin/sh", "-c"]
-# 回到 sh
+## 回到 sh
RUN echo "Using sh again"
```
---
-## 对其他指令的影响
+### 对其他指令的影响
`SHELL` 影响的是所有使用 **shell 格式** 的指令:
@@ -105,9 +105,9 @@ RUN echo "Using sh again"
---
-## 最佳实践
+### 最佳实践
-### 1. 推荐开启 pipefail
+#### 1. 推荐开启 pipefail
对于使用 bash 的镜像,强烈建议开启 `pipefail`,以确保构建过程中的错误能被及时捕获。
@@ -115,17 +115,17 @@ RUN echo "Using sh again"
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
```
-### 2. 明确意图
+#### 2. 明确意图
如果由于脚本需求必须更改 shell,最好在 Dockerfile 中显式声明,而不是依赖默认行为。
-### 3. 尽量保持一致
+#### 3. 尽量保持一致
避免在 Dockerfile 中频繁切换 SHELL,这会使构建过程难以理解和调试。尽量在头部定义一次即可。
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -135,7 +135,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
| **推荐用法** | `SHELL ["/bin/bash", "-o", "pipefail", "-c"]` |
| **影响范围** | 后续所有使用 shell 格式的指令 |
-## 延伸阅读
+### 延伸阅读
-- [RUN 指令](../../04_image/build.md):执行命令
-- [Dockerfile 最佳实践](../../15_appendix/best_practices.md):错误处理与调试
+- [RUN 指令](../../04_image/4.5_build.md):执行命令
+- [Dockerfile 最佳实践](../../15_appendix/15.1_best_practices.md):错误处理与调试
diff --git a/04_image/dockerfile/user.md b/04_image/dockerfile/user.md
index abdc60a..068aaa6 100644
--- a/04_image/dockerfile/user.md
+++ b/04_image/dockerfile/user.md
@@ -1,6 +1,6 @@
-# USER 指定当前用户
+## USER 指定当前用户
-## 基本语法
+### 基本语法
```docker
USER <用户名>[:<用户组>]
@@ -11,7 +11,7 @@ USER [:]
---
-## 为什么要使用 USER
+### 为什么要使用 USER
> 笔者强调:以非 root 用户运行容器是最重要的安全实践之一。
@@ -33,52 +33,52 @@ root 用户运行的风险:
---
-## 基本用法
+### 基本用法
-### 创建并切换用户
+#### 创建并切换用户
```docker
FROM node:20-alpine
-# 1. 创建用户和组
+## 1. 创建用户和组
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
-# 2. 设置目录权限
+## 2. 设置目录权限
WORKDIR /app
COPY --chown=appuser:appgroup . .
-# 3. 切换用户
+## 3. 切换用户
USER appuser
-# 4. 后续命令以 appuser 身份运行
+## 4. 后续命令以 appuser 身份运行
CMD ["node", "server.js"]
```
-### 使用 UID/GID
+#### 使用 UID/GID
```docker
-# 也可以使用数字
+## 也可以使用数字
USER 1001:1001
```
---
-## 用户必须已存在
+### 用户必须已存在
`USER` 指令只能切换到**已存在**的用户:
```docker
-# ❌ 错误:用户不存在
+## ❌ 错误:用户不存在
USER nonexistent
-# Error: unable to find user nonexistent
+## Error: unable to find user nonexistent
-# ✅ 正确:先创建用户
+## ✅ 正确:先创建用户
RUN useradd -r -s /bin/false appuser
USER appuser
```
-### 创建用户的方式
+#### 创建用户的方式
**Debian/Ubuntu**:
@@ -104,19 +104,19 @@ RUN addgroup -g 1001 -S appgroup && \
---
-## 运行时切换用户
+### 运行时切换用户
-### 使用 gosu(推荐)
+#### 使用 gosu(推荐)
在 ENTRYPOINT 脚本中切换用户时,不要使用 `su` 或 `sudo`,应使用 [gosu](https://github.com/tianon/gosu):
```docker
FROM debian:bookworm
-# 创建用户
+## 创建用户
RUN groupadd -r redis && useradd -r -g redis redis
-# 安装 gosu
+## 安装 gosu
RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/*
COPY docker-entrypoint.sh /usr/local/bin/
@@ -130,14 +130,14 @@ CMD ["redis-server"]
#!/bin/bash
set -e
-# 以 root 执行初始化
+## 以 root 执行初始化
chown -R redis:redis /data
-# 用 gosu 切换到 redis 用户运行服务
+## 用 gosu 切换到 redis 用户运行服务
exec gosu redis "$@"
```
-### 为什么不用 su/sudo
+#### 为什么不用 su/sudo
| 问题 | su/sudo | gosu |
|------|---------|------|
@@ -148,38 +148,38 @@ exec gosu redis "$@"
---
-## 运行时覆盖用户
+### 运行时覆盖用户
使用 `-u` 或 `--user` 参数:
```bash
-# 以指定用户运行
+## 以指定用户运行
$ docker run -u 1001:1001 myimage
-# 以 root 运行(调试时)
+## 以 root 运行(调试时)
$ docker run -u root myimage
```
---
-## 文件权限处理
+### 文件权限处理
切换用户后,确保应用有权访问文件:
```docker
FROM node:20-alpine
-# 创建用户
+## 创建用户
RUN adduser -D -u 1001 appuser
WORKDIR /app
-# 方式1:使用 --chown
+## 方式1:使用 --chown
COPY --chown=appuser:appuser . .
-# 方式2:手动 chown(减少层数)
-# COPY . .
-# RUN chown -R appuser:appuser /app
+## 方式2:手动 chown(减少层数)
+## COPY . .
+## RUN chown -R appuser:appuser /app
USER appuser
CMD ["node", "server.js"]
@@ -187,41 +187,41 @@ CMD ["node", "server.js"]
---
-## 最佳实践
+### 最佳实践
-### 1. 始终使用非 root 用户
+#### 1. 始终使用非 root 用户
```docker
-# ✅ 推荐
+## ✅ 推荐
RUN adduser -D appuser
USER appuser
CMD ["myapp"]
-# ❌ 避免
+## ❌ 避免
CMD ["myapp"] # 以 root 运行
```
-### 2. 使用固定 UID/GID
+#### 2. 使用固定 UID/GID
便于在宿主机和容器间共享文件:
```docker
-# 使用常见的非 root UID
+## 使用常见的非 root UID
RUN addgroup -g 1000 -S appgroup && \
adduser -u 1000 -S -G appgroup appuser
USER 1000:1000
```
-### 3. 多阶段构建中的 USER
+#### 3. 多阶段构建中的 USER
```docker
-# 构建阶段可以用 root
+## 构建阶段可以用 root
FROM node:20 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
-# 生产阶段用非 root
+## 生产阶段用非 root
FROM node:20-alpine
RUN adduser -D appuser
WORKDIR /app
@@ -232,9 +232,9 @@ CMD ["node", "server.js"]
---
-## 常见问题
+### 常见问题
-### Q: 权限被拒绝
+#### Q: 权限被拒绝
```bash
permission denied: '/app/data.log'
@@ -246,7 +246,7 @@ permission denied: '/app/data.log'
RUN mkdir -p /app/data && chown appuser:appuser /app/data
```
-### Q: 无法绑定低于 1024 的端口
+#### Q: 无法绑定低于 1024 的端口
非 root 用户无法绑定 80、443 等端口。
@@ -256,7 +256,7 @@ RUN mkdir -p /app/data && chown appuser:appuser /app/data
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -266,8 +266,8 @@ RUN mkdir -p /app/data && chown appuser:appuser /app/data
| **运行时覆盖** | `docker run -u` |
| **切换工具** | 使用 gosu,不用 su/sudo |
-## 延伸阅读
+### 延伸阅读
- [安全](../../security/README.md):容器安全实践
- [ENTRYPOINT](entrypoint.md):入口脚本中的用户切换
-- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 安全
+- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 安全
diff --git a/04_image/dockerfile/volume.md b/04_image/dockerfile/volume.md
index cc6c0f9..2f49d4a 100644
--- a/04_image/dockerfile/volume.md
+++ b/04_image/dockerfile/volume.md
@@ -1,6 +1,6 @@
-# VOLUME 定义匿名卷
+## VOLUME 定义匿名卷
-## 基本语法
+### 基本语法
```docker
VOLUME ["/路径1", "/路径2"]
@@ -11,7 +11,7 @@ VOLUME /路径
---
-## 为什么使用 VOLUME
+### 为什么使用 VOLUME
> **核心原则**:容器存储层应该保持无状态,任何运行时数据都应该存储在卷中。
@@ -34,16 +34,16 @@ VOLUME /路径
---
-## 基本用法
+### 基本用法
-### 定义单个卷
+#### 定义单个卷
```docker
FROM mysql:8.0
VOLUME /var/lib/mysql
```
-### 定义多个卷
+#### 定义多个卷
```docker
FROM myapp
@@ -52,9 +52,9 @@ VOLUME ["/data", "/logs", "/config"]
---
-## VOLUME 的行为
+### VOLUME 的行为
-### 1. 自动创建匿名卷
+#### 1. 自动创建匿名卷
如果运行时未指定挂载,Docker 会自动创建匿名卷:
@@ -65,23 +65,23 @@ DRIVER VOLUME NAME
local a1b2c3d4e5f6... # 自动创建的匿名卷
```
-### 2. 可被命名卷覆盖
+#### 2. 可被命名卷覆盖
```bash
-# 使用命名卷替代匿名卷
+## 使用命名卷替代匿名卷
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
```
-### 3. 可被 Bind Mount 覆盖
+#### 3. 可被 Bind Mount 覆盖
```bash
-# 使用宿主机目录替代
+## 使用宿主机目录替代
$ docker run -v /my/data:/var/lib/mysql mysql:8.0
```
---
-## VOLUME 在构建时的特殊行为
+### VOLUME 在构建时的特殊行为
> ⚠️ **重要**:VOLUME 之后对该目录的修改会被丢弃!
@@ -89,43 +89,43 @@ $ docker run -v /my/data:/var/lib/mysql mysql:8.0
FROM ubuntu
VOLUME /data
-# ❌ 这个文件不会出现在镜像中!
+## ❌ 这个文件不会出现在镜像中!
RUN echo "hello" > /data/test.txt
```
**原因**:VOLUME 指令之后,Docker 将该目录视为外部挂载点,不再记录对它的修改。
-### 正确做法
+#### 正确做法
```docker
FROM ubuntu
-# ✅ 先写入文件
+## ✅ 先写入文件
RUN mkdir -p /data && echo "hello" > /data/test.txt
-# 再声明 VOLUME
+## 再声明 VOLUME
VOLUME /data
```
---
-## 常见使用场景
+### 常见使用场景
-### 数据库持久化
+#### 数据库持久化
```docker
FROM postgres:15
VOLUME /var/lib/postgresql/data
```
-### 日志目录
+#### 日志目录
```docker
FROM nginx
VOLUME /var/log/nginx
```
-### 上传文件目录
+#### 上传文件目录
```docker
FROM myapp
@@ -134,22 +134,22 @@ VOLUME /app/uploads
---
-## 查看 VOLUME 定义
+### 查看 VOLUME 定义
```bash
-# 查看镜像定义的 VOLUME
+## 查看镜像定义的 VOLUME
$ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
{
"/var/lib/mysql": {}
}
-# 查看容器挂载的卷
+## 查看容器挂载的卷
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
```
---
-## VOLUME vs docker run -v
+### VOLUME vs docker run -v
| 特性 | Dockerfile VOLUME | docker run -v |
|------|-------------------|---------------|
@@ -160,7 +160,7 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq
---
-## 在 Compose 中
+### 在 Compose 中
```yaml
services:
@@ -178,14 +178,14 @@ volumes:
---
-## 安全注意事项
+### 安全注意事项
-### 匿名卷可能导致数据丢失
+#### 匿名卷可能导致数据丢失
```bash
-# 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
+## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
$ docker run --rm mysql:8.0
-# 容器停止后,数据丢失!
+## 容器停止后,数据丢失!
```
**解决**:始终使用命名卷
@@ -196,41 +196,41 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
---
-## 最佳实践
+### 最佳实践
-### 1. 定义必须持久化的路径
+#### 1. 定义必须持久化的路径
```docker
-# 数据库必须使用卷
+## 数据库必须使用卷
FROM postgres:15
VOLUME /var/lib/postgresql/data
```
-### 2. 不要在 VOLUME 后修改目录
+#### 2. 不要在 VOLUME 后修改目录
```docker
-# ❌ 避免
+## ❌ 避免
VOLUME /app/data
RUN cp init-data.json /app/data/
-# ✅ 正确
+## ✅ 正确
RUN mkdir -p /app/data && cp init-data.json /app/data/
VOLUME /app/data
```
-### 3. 文档中说明 VOLUME 用途
+#### 3. 文档中说明 VOLUME 用途
```docker
-# 持久化用户上传的文件
+## 持久化用户上传的文件
VOLUME /app/uploads
-# 持久化数据库数据
+## 持久化数据库数据
VOLUME /var/lib/mysql
```
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -240,8 +240,8 @@ VOLUME /var/lib/mysql
| **覆盖方式** | `docker run -v name:/path` |
| **注意** | VOLUME 之后的修改会丢失 |
-## 延伸阅读
+### 延伸阅读
- [数据卷](../../07_data_network/data/volume.md):卷的管理和使用
- [挂载主机目录](../../07_data_network/data/bind-mounts.md):Bind Mount
-- [Compose 数据管理](../../compose/compose_file.md):Compose 中的卷配置
+- [Compose 数据管理](../../compose/9.5_compose_file.md):Compose 中的卷配置
diff --git a/04_image/dockerfile/workdir.md b/04_image/dockerfile/workdir.md
index 3f89518..e271629 100644
--- a/04_image/dockerfile/workdir.md
+++ b/04_image/dockerfile/workdir.md
@@ -1,6 +1,6 @@
-# WORKDIR 指定工作目录
+## WORKDIR 指定工作目录
-## 基本语法
+### 基本语法
```docker
WORKDIR <工作目录路径>
@@ -10,7 +10,7 @@ WORKDIR <工作目录路径>
---
-## 基本用法
+### 基本用法
```docker
WORKDIR /app
@@ -22,17 +22,17 @@ COPY . . # 复制到 /app/
---
-## 为什么需要 WORKDIR
+### 为什么需要 WORKDIR
-### 常见错误
+#### 常见错误
```docker
-# ❌ 错误:cd 在下一个 RUN 中无效
+## ❌ 错误:cd 在下一个 RUN 中无效
RUN cd /app
RUN echo "hello" > world.txt # 文件在根目录!
```
-### 原因分析
+#### 原因分析
```
RUN cd /app
@@ -47,17 +47,17 @@ RUN echo "hello" > world.txt
每个 RUN 都在新容器中执行,**前一个 RUN 的内存状态(包括工作目录)不会保留**。
-### 正确做法
+#### 正确做法
```docker
-# ✅ 正确:使用 WORKDIR
+## ✅ 正确:使用 WORKDIR
WORKDIR /app
RUN echo "hello" > world.txt # 创建 /app/world.txt
```
---
-## 相对路径
+### 相对路径
WORKDIR 支持相对路径,基于上一个 WORKDIR:
@@ -71,7 +71,7 @@ RUN pwd # 输出 /a/b/c
---
-## 使用环境变量
+### 使用环境变量
```docker
ENV APP_HOME=/app
@@ -82,10 +82,10 @@ RUN pwd # 输出 /app
---
-## 多阶段构建中的 WORKDIR
+### 多阶段构建中的 WORKDIR
```docker
-# 构建阶段
+## 构建阶段
FROM node:20 AS builder
WORKDIR /build
COPY package*.json ./
@@ -93,7 +93,7 @@ RUN npm install
COPY . .
RUN npm run build
-# 生产阶段
+## 生产阶段
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=builder /build/dist .
@@ -101,9 +101,9 @@ COPY --from=builder /build/dist .
---
-## 最佳实践
+### 最佳实践
-### 1. 尽早设置 WORKDIR
+#### 1. 尽早设置 WORKDIR
```docker
FROM node:20
@@ -115,40 +115,40 @@ COPY . .
CMD ["node", "server.js"]
```
-### 2. 使用绝对路径
+#### 2. 使用绝对路径
```docker
-# ✅ 推荐:绝对路径,意图明确
+## ✅ 推荐:绝对路径,意图明确
WORKDIR /app
-# ⚠️ 避免:相对路径可能造成混淆
+## ⚠️ 避免:相对路径可能造成混淆
WORKDIR app
```
-### 3. 不要用 RUN cd
+#### 3. 不要用 RUN cd
```docker
-# ❌ 避免
+## ❌ 避免
RUN cd /app && echo "hello" > world.txt
-# ✅ 推荐
+## ✅ 推荐
WORKDIR /app
RUN echo "hello" > world.txt
```
-### 4. 适时重置 WORKDIR
+#### 4. 适时重置 WORKDIR
```docker
WORKDIR /app
-# ... 应用相关操作 ...
+## ... 应用相关操作 ...
WORKDIR /data
-# ... 数据相关操作 ...
+## ... 数据相关操作 ...
```
---
-## 与其他指令的关系
+### 与其他指令的关系
| 指令 | WORKDIR 的影响 |
|------|---------------|
@@ -168,7 +168,7 @@ CMD ["./start.sh"] # /app/start.sh
---
-## 运行时覆盖
+### 运行时覆盖
使用 `-w` 参数覆盖工作目录:
@@ -179,7 +179,7 @@ $ docker run -w /tmp myimage pwd
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -189,8 +189,8 @@ $ docker run -w /tmp myimage pwd
| **持久性** | 影响后续所有指令,直到下次 WORKDIR |
| **不要用** | `RUN cd /path`(无效) |
-## 延伸阅读
+### 延伸阅读
- [COPY 复制文件](copy.md):文件复制
-- [RUN 执行命令](../../04_image/build.md):执行构建命令
-- [最佳实践](../../15_appendix/best_practices.md):Dockerfile 编写指南
+- [RUN 执行命令](../../04_image/4.5_build.md):执行构建命令
+- [最佳实践](../../15_appendix/15.1_best_practices.md):Dockerfile 编写指南
diff --git a/04_image/multistage-builds/README.md b/04_image/multistage-builds/README.md
index b446c82..be1b375 100644
--- a/04_image/multistage-builds/README.md
+++ b/04_image/multistage-builds/README.md
@@ -1,10 +1,10 @@
-# 多阶段构建
+## 多阶段构建
-## 之前的做法
+### 之前的做法
在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式:
-### 全部放入一个 Dockerfile
+#### 全部放入一个 Dockerfile
一种方式是将所有的构建过程编包含在一个 `Dockerfile` 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:
@@ -51,7 +51,7 @@ CMD ["./app"]
$ docker build -t go/helloworld:1 -f Dockerfile.one .
```
-### 分散到多个 Dockerfile
+#### 分散到多个 Dockerfile
另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。
@@ -120,7 +120,7 @@ go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
```
-## 使用多阶段构建
+### 使用多阶段构建
为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`:
@@ -169,7 +169,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。
-### 只构建某一阶段的镜像
+#### 只构建某一阶段的镜像
我们可以使用 `as` 来为某一阶段命名,例如
@@ -183,7 +183,7 @@ FROM golang:alpine as builder
$ docker build --target builder -t username/imagename:tag .
```
-### 构建时从其他镜像复制文件
+#### 构建时从其他镜像复制文件
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
diff --git a/04_image/multistage-builds/laravel.md b/04_image/multistage-builds/laravel.md
index c8cc7bc..a858d36 100644
--- a/04_image/multistage-builds/laravel.md
+++ b/04_image/multistage-builds/laravel.md
@@ -1,8 +1,8 @@
-# 实战多阶段构建 Laravel 镜像
+## 实战多阶段构建 Laravel 镜像
> 本节适用于 PHP 开发者阅读。`Laravel` 基于 8.x 版本,各个版本的文件结构可能会有差异,请根据实际自行修改。
-## 准备
+### 准备
新建一个 `Laravel` 项目或在已有的 `Laravel` 项目根目录下新建 `Dockerfile` `.dockerignore` `laravel.conf` 文件。
@@ -25,7 +25,7 @@ yarn-error.log
bootstrap/cache/*
storage/
-# 自行添加其他需要排除的文件,例如 .env.* 文件
+## 自行添加其他需要排除的文件,例如 .env.* 文件
```
在 `laravel.conf` 文件中写入 nginx 配置。
@@ -51,7 +51,7 @@ server {
}
```
-## 前端构建
+### 前端构建
第一阶段进行前端构建。
@@ -72,7 +72,7 @@ RUN set -x ; cd /app \
&& npm run production
```
-## 安装 Composer 依赖
+### 安装 Composer 依赖
第二阶段安装 Composer 依赖。
@@ -92,7 +92,7 @@ RUN set -x ; cd /app \
--prefer-dist
```
-## 整合以上阶段所生成的文件
+### 整合以上阶段所生成的文件
第三阶段对以上阶段生成的文件进行整合。
@@ -118,7 +118,7 @@ RUN set -x ; cd ${LARAVEL_PATH} \
&& php artisan package:discover
```
-## 最后一个阶段构建 NGINX 镜像
+### 最后一个阶段构建 NGINX 镜像
```docker
FROM nginx:alpine as nginx
@@ -129,7 +129,7 @@ COPY laravel.conf /etc/nginx/conf.d/
COPY --from=laravel ${LARAVEL_PATH}/public ${LARAVEL_PATH}/public
```
-## 构建 Laravel 及 Nginx 镜像
+### 构建 Laravel 及 Nginx 镜像
使用 `docker build` 命令构建镜像。
@@ -139,7 +139,7 @@ $ docker build -t my/laravel --target=laravel .
$ docker build -t my/nginx --target=nginx .
```
-## 启动容器并测试
+### 启动容器并测试
新建 Docker 网络
@@ -163,13 +163,13 @@ $ docker run -dit --rm --network=laravel -p 8080:80 my/nginx
> 也许 Laravel 项目依赖其他外部服务,例如 redis、MySQL,请自行启动这些服务之后再进行测试,本小节不再赘述。
-## 生产环境优化
+### 生产环境优化
本小节内容为了方便测试,将配置文件直接放到了镜像中,实际在使用时 **建议** 将配置文件作为 `config` 或 `secret` 挂载到容器中,请读者自行学习 `Kubernetes` 的相关内容。
由于篇幅所限本小节只是简单列出,更多内容可以参考 https://github.com/khs1994-docker/laravel-demo 项目。
-## 附录
+### 附录
完整的 `Dockerfile` 文件如下。
diff --git a/05_container/run.md b/05_container/5.1_run.md
similarity index 83%
rename from 05_container/run.md
rename to 05_container/5.1_run.md
index 564b3b9..cc8a95c 100644
--- a/05_container/run.md
+++ b/05_container/5.1_run.md
@@ -1,6 +1,6 @@
-# 启动容器
+## 启动容器
-## 启动方式概述
+### 启动方式概述
启动容器有两种方式:
- **新建并启动**:基于镜像创建新容器
@@ -8,15 +8,15 @@
由于 Docker 容器非常轻量,实际使用中常常是随时删除和新建容器,而不是反复重启同一个容器。
-## 新建并启动
+### 新建并启动
-### 基本语法
+#### 基本语法
```bash
docker run [选项] 镜像 [命令] [参数...]
```
-### 最简单的例子
+#### 最简单的例子
输出 "Hello World" 后容器自动终止:
@@ -27,7 +27,7 @@ Hello world
这与直接执行 `/bin/echo 'Hello world'` 几乎没有区别,但实际上已经启动了一个完整的 Ubuntu 容器来执行这条命令。
-### 交互式容器
+#### 交互式容器
启动一个可以交互的 bash 终端:
@@ -54,7 +54,7 @@ bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr
root@af8bae53bdd3:/# exit # 退出容器
```
-## docker run 的完整流程
+### docker run 的完整流程
执行 `docker run` 时,Docker 在后台完成以下操作:
@@ -84,9 +84,9 @@ root@af8bae53bdd3:/# exit # 退出容器
└─────────────────────────────────────────────────────────────────────┘
```
-## 常用启动选项
+### 常用启动选项
-### 基础选项
+#### 基础选项
| 选项 | 说明 | 示例 |
|------|------|------|
@@ -95,70 +95,70 @@ root@af8bae53bdd3:/# exit # 退出容器
| `--name` | 指定容器名称 | `docker run --name myapp nginx` |
| `--rm` | 退出后自动删除容器 | `docker run --rm ubuntu echo hi` |
-### 端口映射
+#### 端口映射
```bash
-# 将容器的 80 端口映射到宿主机的 8080 端口
+## 将容器的 80 端口映射到宿主机的 8080 端口
$ docker run -d -p 8080:80 nginx
-# 随机映射端口
+## 随机映射端口
$ docker run -d -P nginx
-# 只绑定到 localhost
+## 只绑定到 localhost
$ docker run -d -p 127.0.0.1:8080:80 nginx
```
-### 数据卷挂载
+#### 数据卷挂载
```bash
-# 挂载命名卷
+## 挂载命名卷
$ docker run -v mydata:/data nginx
-# 挂载宿主机目录
+## 挂载宿主机目录
$ docker run -v /host/path:/container/path nginx
-# 只读挂载
+## 只读挂载
$ docker run -v /host/path:/container/path:ro nginx
```
-### 环境变量
+#### 环境变量
```bash
-# 设置单个环境变量
+## 设置单个环境变量
$ docker run -e MYSQL_ROOT_PASSWORD=secret mysql
-# 从文件加载环境变量
+## 从文件加载环境变量
$ docker run --env-file .env myapp
```
-### 资源限制
+#### 资源限制
```bash
-# 限制内存
+## 限制内存
$ docker run -m 512m nginx
-# 限制 CPU
+## 限制 CPU
$ docker run --cpus=1.5 nginx
```
-## 启动已终止容器
+### 启动已终止容器
使用 `docker start` 重新启动已停止的容器:
```bash
-# 查看所有容器(包括已停止的)
+## 查看所有容器(包括已停止的)
$ docker ps -a
CONTAINER ID IMAGE STATUS NAMES
af8bae53bdd3 ubuntu Exited (0) 2 minutes ago myubuntu
-# 重新启动
+## 重新启动
$ docker start myubuntu
-# 启动并附加终端
+## 启动并附加终端
$ docker start -ai myubuntu
```
-## 容器内进程的特点
+### 容器内进程的特点
容器内只运行指定的应用程序及其必需资源:
@@ -171,48 +171,48 @@ root@ba267838cc1b:/# ps
可见容器中仅运行了 `bash` 进程。这种特点使得 Docker 对资源的利用率极高。
-> 💡 笔者提示:容器内的 PID 1 进程很重要——它是容器的主进程,该进程退出则容器停止。详见[后台运行](daemon.md)章节。
+> 💡 笔者提示:容器内的 PID 1 进程很重要——它是容器的主进程,该进程退出则容器停止。详见[后台运行](5.2_daemon.md)章节。
-## 常见问题
+### 常见问题
-### Q: 容器启动后立即退出
+#### Q: 容器启动后立即退出
**原因**:主进程执行完毕或无法保持运行
```bash
-# 这个容器会立即退出(echo 执行完就结束了)
+## 这个容器会立即退出(echo 执行完就结束了)
$ docker run ubuntu echo "hello"
-# 解决:使用能持续运行的命令
+## 解决:使用能持续运行的命令
$ docker run -d nginx # nginx 是持续运行的服务
```
-详细解释见[后台运行](daemon.md)。
+详细解释见[后台运行](5.2_daemon.md)。
-### Q: 无法连接容器内的服务
+#### Q: 无法连接容器内的服务
**原因**:未正确映射端口
```bash
-# 错误:没有 -p 参数,外部无法访问
+## 错误:没有 -p 参数,外部无法访问
$ docker run -d nginx
-# 正确:映射端口
+## 正确:映射端口
$ docker run -d -p 80:80 nginx
```
-### Q: 容器内修改的文件丢失
+#### Q: 容器内修改的文件丢失
**原因**:未使用数据卷,数据保存在容器存储层
```bash
-# 使用数据卷持久化
+## 使用数据卷持久化
$ docker run -v mydata:/app/data myapp
```
详见[数据管理](../07_data_network/README.md)。
-## 本章小结
+### 本章小结
| 操作 | 命令 | 说明 |
|------|------|------|
@@ -221,9 +221,9 @@ $ docker run -v mydata:/app/data myapp
| 后台运行 | `docker run -d` | 用于服务类应用 |
| 启动已停止的容器 | `docker start` | 重用已有容器 |
-## 延伸阅读
+### 延伸阅读
-- [后台运行](daemon.md):理解 `-d` 参数和容器生命周期
-- [进入容器](attach_exec.md):操作运行中的容器
+- [后台运行](5.2_daemon.md):理解 `-d` 参数和容器生命周期
+- [进入容器](5.4_attach_exec.md):操作运行中的容器
- [网络配置](../network/README.md):理解端口映射的原理
- [数据管理](../07_data_network/README.md):数据持久化方案
diff --git a/05_container/daemon.md b/05_container/5.2_daemon.md
similarity index 81%
rename from 05_container/daemon.md
rename to 05_container/5.2_daemon.md
index adcd442..5cec654 100644
--- a/05_container/daemon.md
+++ b/05_container/5.2_daemon.md
@@ -1,8 +1,8 @@
-# 后台运行
+## 后台运行
在生产环境中,我们通常需要容器持续运行,不受终端关闭的影响。本节将深入讲解如何让容器在后台运行,以及理解容器生命周期的核心概念。
-## 核心概念:前台 vs 后台
+### 核心概念:前台 vs 后台
当你在终端运行一个程序时,有两种模式:
@@ -11,9 +11,9 @@
Docker 容器默认是**前台运行**的。使用 `-d`(detach)参数可以让容器在后台运行。
-## 基本使用
+### 基本使用
-### 前台运行(默认)
+#### 前台运行(默认)
```bash
$ docker run ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
@@ -28,7 +28,7 @@ hello world
- 按 `Ctrl+C` 会终止容器
- 关闭终端窗口,容器也会停止
-### 后台运行(使用 -d 参数)
+#### 后台运行(使用 -d 参数)
```bash
$ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
@@ -41,7 +41,7 @@ $ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep
- 终端立即释放,可以继续执行其他命令
- 输出不会直接显示(需要用 `docker logs` 查看)
-## 深入理解:容器为什么会"立即退出"?
+### 深入理解:容器为什么会"立即退出"?
> **这是初学者最常遇到的困惑。** 理解这个问题,你就理解了 Docker 的核心设计理念。
@@ -53,7 +53,7 @@ $ docker run -d ubuntu:24.04
然后用 `docker ps` 查看,发现容器根本不在运行!这是为什么?
-### 核心原理:容器的生命周期与主进程绑定
+#### 核心原理:容器的生命周期与主进程绑定
```
┌─────────────────────────────────────────────────────────────────────┐
@@ -75,7 +75,7 @@ $ docker run -d ubuntu:24.04
- ❌ `-d` 参数**不是**让容器"一直运行"
- ✅ `-d` 参数是让容器"在后台运行",能运行多久取决于主进程
-### 常见的"立即退出"场景
+#### 常见的"立即退出"场景
| 场景 | 原因 | 解决方案 |
|------|------|---------|
@@ -83,9 +83,9 @@ $ docker run -d ubuntu:24.04
| `docker run -d nginx` 后改了配置 | 配置错误导致 nginx 启动失败 | 查看 `docker logs` |
| 自定义镜像容器启动即退 | Dockerfile 的 CMD 执行完毕 | 确保 CMD 是前台进程 |
-## 查看后台容器
+### 查看后台容器
-### 查看运行中的容器
+#### 查看运行中的容器
```bash
$ docker container ls
@@ -93,7 +93,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS PO
77b2dc01fe0f ubuntu:24.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
```
-### 查看容器输出日志
+#### 查看容器输出日志
```bash
$ docker container logs 77b2dc01fe0f
@@ -109,7 +109,7 @@ hello world
$ docker container logs -f 77b2dc01fe0f
```
-### 查看已停止的容器
+#### 查看已停止的容器
```bash
$ docker container ls -a
@@ -117,59 +117,59 @@ $ docker container ls -a
加上 `-a` 参数可以看到所有容器,包括已停止的。这对于调试"容器启动即退出"的问题非常有用。
-## 最佳实践
+### 最佳实践
-### 1. 长期运行的服务使用 -d
+#### 1. 长期运行的服务使用 -d
```bash
-# Web 服务器
+## Web 服务器
$ docker run -d -p 80:80 nginx
-# 数据库
+## 数据库
$ docker run -d -p 3306:3306 mysql:8
-# 缓存服务
+## 缓存服务
$ docker run -d -p 6379:6379 redis
```
-### 2. 调试时先用前台模式
+#### 2. 调试时先用前台模式
当容器启动有问题时,**去掉 `-d` 参数**可以直接看到输出和错误:
```bash
-# 有问题的容器,先前台运行看看发生了什么
+## 有问题的容器,先前台运行看看发生了什么
$ docker run myimage:latest
```
-### 3. 使用 --rm 自动清理
+#### 3. 使用 --rm 自动清理
对于一次性任务,使用 `--rm` 参数让容器退出后自动删除:
```bash
$ docker run --rm ubuntu:24.04 echo "Hello, World!"
Hello, World!
-# 容器执行完后自动删除
+## 容器执行完后自动删除
```
-### 4. 配合日志查看
+#### 4. 配合日志查看
```bash
-# 后台启动
+## 后台启动
$ docker run -d --name myapp myimage:latest
-# 查看最近 100 行日志
+## 查看最近 100 行日志
$ docker logs --tail 100 myapp
-# 实时跟踪日志
+## 实时跟踪日志
$ docker logs -f myapp
-# 查看带时间戳的日志
+## 查看带时间戳的日志
$ docker logs -t myapp
```
-## 常见问题排查
+### 常见问题排查
-### Q: 容器启动后立即退出
+#### Q: 容器启动后立即退出
1. **查看退出状态码**:
```bash
@@ -188,7 +188,7 @@ $ docker logs -t myapp
# 进入容器手动执行命令,查找问题
```
-### Q: 容器在后台运行但无法访问服务
+#### Q: 容器在后台运行但无法访问服务
1. **检查端口映射**:
```bash
@@ -200,7 +200,7 @@ $ docker logs -t myapp
$ docker exec mycontainer ps aux
```
-### Q: 如何让已经在后台运行的容器回到前台?
+#### Q: 如何让已经在后台运行的容器回到前台?
使用 `docker attach`:
@@ -210,9 +210,9 @@ $ docker attach mycontainer
> **注意**:`attach` 会连接到容器的主进程。如果主进程不是交互式的,你可能只能看到输出。使用 `Ctrl+P` `Ctrl+Q` 可以安全退出而不停止容器。
-## 延伸阅读
+### 延伸阅读
-- [进入容器](attach_exec.md):如何进入正在运行的容器执行命令
-- [容器日志](../15_appendix/best_practices.md):生产环境的日志管理最佳实践
+- [进入容器](5.4_attach_exec.md):如何进入正在运行的容器执行命令
+- [容器日志](../15_appendix/15.1_best_practices.md):生产环境的日志管理最佳实践
- [HEALTHCHECK 健康检查](../04_image/dockerfile/healthcheck.md):自动检测容器内服务是否正常
- [Docker Compose](../compose/README.md):管理多个后台容器的更好方式
diff --git a/05_container/stop.md b/05_container/5.3_stop.md
similarity index 81%
rename from 05_container/stop.md
rename to 05_container/5.3_stop.md
index f1dbb7d..ef5baf8 100644
--- a/05_container/stop.md
+++ b/05_container/5.3_stop.md
@@ -1,6 +1,6 @@
-# 终止容器
+## 终止容器
-## 终止方式概述
+### 终止方式概述
终止容器有三种方式:
@@ -12,15 +12,15 @@
---
-## docker stop(推荐)
+### docker stop(推荐)
-### 基本用法
+#### 基本用法
```bash
$ docker stop 容器名或ID
```
-### 工作原理
+#### 工作原理
```
docker stop mycontainer
@@ -35,71 +35,71 @@ docker stop mycontainer
└─────────────────────────────────────────────────────────────────┘
```
-### 自定义超时时间
+#### 自定义超时时间
```bash
-# 等待 30 秒后强制终止
+## 等待 30 秒后强制终止
$ docker stop -t 30 mycontainer
-# 立即发送 SIGKILL(相当于 docker kill)
+## 立即发送 SIGKILL(相当于 docker kill)
$ docker stop -t 0 mycontainer
```
-### 停止多个容器
+#### 停止多个容器
```bash
-# 停止多个指定容器
+## 停止多个指定容器
$ docker stop container1 container2 container3
-# 停止所有运行中的容器
+## 停止所有运行中的容器
$ docker stop $(docker ps -q)
```
---
-## docker kill
+### docker kill
-### 基本用法
+#### 基本用法
```bash
$ docker kill 容器名或ID
```
-### 与 stop 的区别
+#### 与 stop 的区别
| 命令 | 信号 | 使用场景 |
|------|------|---------|
| `docker stop` | SIGTERM → SIGKILL | 正常停止,让应用优雅退出 |
| `docker kill` | SIGKILL | 应用无响应,强制终止 |
-### 发送自定义信号
+#### 发送自定义信号
```bash
-# 发送 SIGHUP(让进程重新加载配置)
+## 发送 SIGHUP(让进程重新加载配置)
$ docker kill -s HUP mycontainer
-# 发送 SIGTERM
+## 发送 SIGTERM
$ docker kill -s TERM mycontainer
```
---
-## 容器自动终止
+### 容器自动终止
容器的生命周期与主进程绑定。主进程退出时,容器自动停止:
```bash
-# 主进程是交互式 bash
+## 主进程是交互式 bash
$ docker run -it ubuntu bash
root@abc123:/# exit # 退出 bash → 容器停止
-# 主进程执行完毕
+## 主进程执行完毕
$ docker run ubuntu echo "Hello" # echo 执行完 → 容器停止
```
---
-## 查看已停止的容器
+### 查看已停止的容器
```bash
$ docker ps -a
@@ -120,30 +120,30 @@ c5d3a5e8f7b2 nginx "nginx" Up 5 minutes mynginx
---
-## 重新启动容器
+### 重新启动容器
-### 启动已停止的容器
+#### 启动已停止的容器
```bash
$ docker start 容器名或ID
-# 启动并附加终端
+## 启动并附加终端
$ docker start -ai 容器名
```
-### 重启运行中的容器
+#### 重启运行中的容器
```bash
-# 先停止再启动
+## 先停止再启动
$ docker restart 容器名
-# 自定义停止超时
+## 自定义停止超时
$ docker restart -t 30 容器名
```
---
-## 生命周期状态图
+### 生命周期状态图
```
docker create
@@ -182,21 +182,21 @@ $ docker restart -t 30 容器名
---
-## 批量操作
+### 批量操作
-### 停止所有容器
+#### 停止所有容器
```bash
$ docker stop $(docker ps -q)
```
-### 删除所有已停止的容器
+#### 删除所有已停止的容器
```bash
$ docker container prune
```
-### 停止并删除所有容器
+#### 停止并删除所有容器
```bash
$ docker stop $(docker ps -q) && docker container prune -f
@@ -204,9 +204,9 @@ $ docker stop $(docker ps -q) && docker container prune -f
---
-## 常见问题
+### 常见问题
-### Q: 容器停止很慢
+#### Q: 容器停止很慢
原因:应用没有正确处理 SIGTERM 信号,需要等待超时后强制终止。
@@ -215,31 +215,31 @@ $ docker stop $(docker ps -q) && docker container prune -f
2. 使用 `docker stop -t 0` 立即终止
3. 检查 Dockerfile 中的 `STOPSIGNAL` 配置
-### Q: 如何让容器优雅退出
+#### Q: 如何让容器优雅退出
确保容器主进程正确处理信号:
```dockerfile
-# Dockerfile 示例
+## Dockerfile 示例
FROM node:22
...
-# 使用 exec 形式确保信号能传递给 node 进程
+## 使用 exec 形式确保信号能传递给 node 进程
CMD ["node", "server.js"]
```
-### Q: 容器无法停止
+#### Q: 容器无法停止
```bash
-# 强制终止
+## 强制终止
$ docker kill 容器名
-# 如果仍无法停止,检查系统资源
+## 如果仍无法停止,检查系统资源
$ docker inspect 容器名
```
---
-## 本章小结
+### 本章小结
| 操作 | 命令 | 说明 |
|------|------|------|
@@ -249,8 +249,8 @@ $ docker inspect 容器名
| 重启 | `docker restart` | 停止后立即启动 |
| 停止全部 | `docker stop $(docker ps -q)` | 停止所有运行中容器 |
-## 延伸阅读
+### 延伸阅读
-- [启动容器](run.md):容器启动详解
-- [删除容器](rm.md):清理容器
+- [启动容器](5.1_run.md):容器启动详解
+- [删除容器](4.3_rm.md):清理容器
- [容器日志](logs.md):排查停止原因
diff --git a/05_container/attach_exec.md b/05_container/5.4_attach_exec.md
similarity index 82%
rename from 05_container/attach_exec.md
rename to 05_container/5.4_attach_exec.md
index b11db5c..3cd0a33 100644
--- a/05_container/attach_exec.md
+++ b/05_container/5.4_attach_exec.md
@@ -1,6 +1,6 @@
-# 进入容器
+## 进入容器
-## 为什么需要进入容器
+### 为什么需要进入容器
使用 `-d` 参数启动容器后,容器在后台运行。以下场景需要进入容器内部操作:
@@ -11,7 +11,7 @@
| **检查状态** | 查看进程、网络连接、文件系统 |
| **开发测试** | 交互式测试命令、验证环境 |
-## 两种进入方式
+### 两种进入方式
Docker 提供两种进入容器的命令:
@@ -22,19 +22,19 @@ Docker 提供两种进入容器的命令:
---
-## docker exec(推荐)
+### docker exec(推荐)
-### 基本用法
+#### 基本用法
```bash
-# 进入容器并启动交互式 shell
+## 进入容器并启动交互式 shell
$ docker exec -it 容器名 /bin/bash
-# 或使用 sh(适用于 Alpine 等精简镜像)
+## 或使用 sh(适用于 Alpine 等精简镜像)
$ docker exec -it 容器名 /bin/sh
```
-### 参数说明
+#### 参数说明
| 参数 | 作用 |
|------|------|
@@ -45,44 +45,44 @@ $ docker exec -it 容器名 /bin/sh
| `-w` | 指定工作目录 |
| `-e` | 设置环境变量 |
-### 示例
+#### 示例
```bash
-# 启动一个后台容器
+## 启动一个后台容器
$ docker run -dit --name myubuntu ubuntu
69d137adef7a...
-# 进入容器(交互式 shell)
+## 进入容器(交互式 shell)
$ docker exec -it myubuntu bash
root@69d137adef7a:/# ls
bin boot dev etc home lib ...
root@69d137adef7a:/# exit
-# 容器仍在运行!
+## 容器仍在运行!
$ docker ps
CONTAINER ID IMAGE STATUS NAMES
69d137adef7a ubuntu Up 2 minutes myubuntu
```
-### 执行单条命令
+#### 执行单条命令
不进入交互模式,直接执行命令:
```bash
-# 查看容器内进程
+## 查看容器内进程
$ docker exec myubuntu ps aux
-# 查看配置文件
+## 查看配置文件
$ docker exec myubuntu cat /etc/nginx/nginx.conf
-# 以 root 用户执行
+## 以 root 用户执行
$ docker exec -u root myubuntu apt update
```
-### 只用 -i 不用 -t 的区别
+#### 只用 -i 不用 -t 的区别
```bash
-# 只用 -i:可以执行命令,但没有提示符
+## 只用 -i:可以执行命令,但没有提示符
$ docker exec -i myubuntu bash
ls # 输入命令
bin # 输出结果
@@ -90,7 +90,7 @@ boot
dev
...
-# 用 -it:有完整的终端体验
+## 用 -it:有完整的终端体验
$ docker exec -it myubuntu bash
root@69d137adef7a:/# # 有提示符
```
@@ -99,15 +99,15 @@ root@69d137adef7a:/# # 有提示符
---
-## docker attach(谨慎使用)
+### docker attach(谨慎使用)
-### 基本用法
+#### 基本用法
```bash
$ docker attach 容器名
```
-### 工作原理
+#### 工作原理
`attach` 会附加到容器的**主进程**(PID 1)的标准输入输出:
@@ -121,19 +121,19 @@ $ docker attach 容器名
└─────────────────────────────────────────┘
```
-### 示例
+#### 示例
```bash
-# 启动容器
+## 启动容器
$ docker run -dit --name myubuntu ubuntu
243c32535da7...
-# 附加到容器
+## 附加到容器
$ docker attach myubuntu
root@243c32535da7:/#
```
-### ⚠️ 重要警告
+#### ⚠️ 重要警告
**从 attach 会话中输入 `exit` 或按 `Ctrl+D` 会导致容器停止!**
@@ -148,14 +148,14 @@ CONTAINER ID IMAGE STATUS NAMES
**原因**:attach 附加到主进程,退出主进程就等于退出容器。
-### 安全退出 attach
+#### 安全退出 attach
使用 `Ctrl+P` 然后 `Ctrl+Q` 可以从 attach 会话中**分离**,而不停止容器:
```bash
$ docker attach myubuntu
root@243c32535da7:/#
-# 按 Ctrl+P 然后 Ctrl+Q
+## 按 Ctrl+P 然后 Ctrl+Q
read escape sequence
$ docker ps # 容器仍在运行
@@ -165,7 +165,7 @@ CONTAINER ID IMAGE STATUS NAMES
---
-## exec vs attach 对比
+### exec vs attach 对比
| 特性 | docker exec | docker attach |
|------|-------------|---------------|
@@ -190,50 +190,50 @@ docker exec docker attach
---
-## 最佳实践
+### 最佳实践
-### 1. 首选 docker exec
+#### 1. 首选 docker exec
```bash
-# 进入容器调试
+## 进入容器调试
$ docker exec -it myapp bash
-# 查看日志
+## 查看日志
$ docker exec myapp tail -f /var/log/app.log
-# 执行数据库迁移
+## 执行数据库迁移
$ docker exec myapp python manage.py migrate
```
-### 2. 生产环境避免进入容器
+#### 2. 生产环境避免进入容器
笔者建议:生产环境应尽量避免进入容器直接操作,而是通过:
- 日志系统查看日志(如 `docker logs` 或集中式日志)
- 监控系统查看状态
- 重新部署而非手动修改
-### 3. 无 shell 镜像的处理
+#### 3. 无 shell 镜像的处理
某些精简镜像(如基于 `scratch` 或 `distroless`)没有 shell:
```bash
-# 这会失败
+## 这会失败
$ docker exec -it myapp bash
OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found
-# 解决方案:使用调试容器(Docker Desktop 或 Kubernetes debug)
+## 解决方案:使用调试容器(Docker Desktop 或 Kubernetes debug)
$ docker debug myapp
```
---
-## 常见问题
+### 常见问题
-### Q: exec 进入后看不到其他终端的操作
+#### Q: exec 进入后看不到其他终端的操作
这是正常的。exec 启动的是独立进程,多个 exec 会话互不影响。
-### Q: 容器没有 bash
+#### Q: 容器没有 bash
尝试使用 sh:
@@ -241,7 +241,7 @@ $ docker debug myapp
$ docker exec -it myapp /bin/sh
```
-### Q: 需要 root 权限
+#### Q: 需要 root 权限
```bash
$ docker exec -u root -it myapp bash
@@ -249,7 +249,7 @@ $ docker exec -u root -it myapp bash
---
-## 本章小结
+### 本章小结
| 需求 | 推荐命令 |
|------|---------|
@@ -257,8 +257,8 @@ $ docker exec -u root -it myapp bash
| 执行单条命令 | `docker exec 容器名 命令` |
| 查看主进程输出 | `docker attach 容器名`(慎用) |
-## 延伸阅读
+### 延伸阅读
-- [后台运行](daemon.md):理解容器主进程
+- [后台运行](5.2_daemon.md):理解容器主进程
- [查看容器](ls.md):列出和过滤容器
- [容器日志](logs.md):查看容器输出
diff --git a/05_container/import_export.md b/05_container/5.5_import_export.md
similarity index 95%
rename from 05_container/import_export.md
rename to 05_container/5.5_import_export.md
index 6f71668..b5154e9 100644
--- a/05_container/import_export.md
+++ b/05_container/5.5_import_export.md
@@ -1,6 +1,6 @@
-# 导出和导入容器
+## 导出和导入容器
-## 导出容器
+### 导出容器
如果要导出本地某个容器,可以使用 `docker export` 命令。
```bash
@@ -12,7 +12,7 @@ $ docker export 7691a814370e > ubuntu.tar
这样将导出容器快照到本地文件。
-## 导入容器快照
+### 导入容器快照
可以使用 `docker import` 从容器快照文件中再导入为镜像,例如
diff --git a/05_container/rm.md b/05_container/5.6_rm.md
similarity index 70%
rename from 05_container/rm.md
rename to 05_container/5.6_rm.md
index 99be069..c2578bf 100644
--- a/05_container/rm.md
+++ b/05_container/5.6_rm.md
@@ -1,6 +1,6 @@
-# 删除容器
+## 删除容器
-## 基本用法
+### 基本用法
使用 `docker rm` 删除已停止的容器:
@@ -12,7 +12,7 @@ $ docker rm 容器名或ID
---
-## 删除选项
+### 删除选项
| 选项 | 说明 | 示例 |
|------|------|------|
@@ -20,31 +20,31 @@ $ docker rm 容器名或ID
| `-f` | 强制删除运行中的容器 | `docker rm -f mycontainer` |
| `-v` | 同时删除关联的匿名卷 | `docker rm -v mycontainer` |
-### 删除已停止的容器
+#### 删除已停止的容器
```bash
$ docker rm mycontainer
mycontainer
```
-### 强制删除运行中的容器
+#### 强制删除运行中的容器
```bash
-# 不加 -f 会报错
+## 不加 -f 会报错
$ docker rm running_container
Error: cannot remove running container
-# 加 -f 强制删除
+## 加 -f 强制删除
$ docker rm -f running_container
running_container
```
> ⚠️ 强制删除会向容器发送 SIGKILL 信号,可能导致数据丢失。建议先 `docker stop` 优雅停止。
-### 删除容器及其数据卷
+#### 删除容器及其数据卷
```bash
-# 删除容器时同时删除其匿名卷
+## 删除容器时同时删除其匿名卷
$ docker rm -v mycontainer
```
@@ -52,12 +52,12 @@ $ docker rm -v mycontainer
---
-## 批量删除
+### 批量删除
-### 删除所有已停止的容器
+#### 删除所有已停止的容器
```bash
-# 方式一:使用 prune 命令(推荐)
+## 方式一:使用 prune 命令(推荐)
$ docker container prune
WARNING! This will remove all stopped containers.
@@ -67,37 +67,37 @@ abc123...
def456...
Total reclaimed space: 150MB
-# 方式二:不提示确认
+## 方式二:不提示确认
$ docker container prune -f
```
-### 删除所有容器(包括运行中的)
+#### 删除所有容器(包括运行中的)
```bash
-# 先停止所有容器,再删除
+## 先停止所有容器,再删除
$ docker stop $(docker ps -q)
$ docker rm $(docker ps -aq)
-# 或者直接强制删除
+## 或者直接强制删除
$ docker rm -f $(docker ps -aq)
```
-### 按条件删除
+#### 按条件删除
```bash
-# 删除所有已退出的容器
+## 删除所有已退出的容器
$ docker rm $(docker ps -aq -f status=exited)
-# 删除名称包含 "test" 的容器
+## 删除名称包含 "test" 的容器
$ docker rm $(docker ps -aq -f name=test)
-# 删除 24 小时前创建的容器
+## 删除 24 小时前创建的容器
$ docker container prune --filter "until=24h"
```
---
-## 常用过滤条件
+### 常用过滤条件
`docker ps` 的过滤条件可以配合 `rm` 使用:
@@ -110,62 +110,62 @@ $ docker container prune --filter "until=24h"
| `before=xxx` | 在某容器之前创建 | `-f before=mycontainer` |
| `since=xxx` | 在某容器之后创建 | `-f since=mycontainer` |
-### 示例
+#### 示例
```bash
-# 删除所有基于 nginx 镜像的容器
+## 删除所有基于 nginx 镜像的容器
$ docker rm $(docker ps -aq -f ancestor=nginx)
-# 删除所有创建后未启动的容器
+## 删除所有创建后未启动的容器
$ docker rm $(docker ps -aq -f status=created)
```
---
-## 容器与镜像的依赖关系
+### 容器与镜像的依赖关系
> 有容器依赖的镜像无法删除。
```bash
-# 尝试删除有容器依赖的镜像
+## 尝试删除有容器依赖的镜像
$ docker image rm nginx
Error: image is being used by stopped container abc123
-# 需要先删除依赖该镜像的容器
+## 需要先删除依赖该镜像的容器
$ docker rm abc123
$ docker image rm nginx
```
---
-## 清理策略建议
+### 清理策略建议
-### 开发环境
+#### 开发环境
```bash
-# 定期清理已停止的容器
+## 定期清理已停止的容器
$ docker container prune -f
-# 一键清理所有未使用资源
+## 一键清理所有未使用资源
$ docker system prune -f
```
-### 生产环境
+#### 生产环境
```bash
-# 使用 --rm 参数运行临时容器
+## 使用 --rm 参数运行临时容器
$ docker run --rm ubuntu echo "Hello"
-# 容器退出后自动删除
+## 容器退出后自动删除
-# 定期清理(设置保留时间)
+## 定期清理(设置保留时间)
$ docker container prune --filter "until=168h" # 保留 7 天内的
```
-### 完整清理脚本
+#### 完整清理脚本
```bash
#!/bin/bash
-# cleanup.sh - Docker 资源清理脚本
+## cleanup.sh - Docker 资源清理脚本
echo "清理已停止的容器..."
docker container prune -f
@@ -185,9 +185,9 @@ docker system df
---
-## 常见问题
+### 常见问题
-### Q: 容器无法删除
+#### Q: 容器无法删除
```bash
Error: container is running
@@ -198,11 +198,11 @@ Error: container is running
```bash
$ docker stop mycontainer
$ docker rm mycontainer
-# 或
+## 或
$ docker rm -f mycontainer
```
-### Q: 删除后磁盘空间没释放
+#### Q: 删除后磁盘空间没释放
可能原因:
1. 容器的数据卷未删除(使用 `-v` 参数)
@@ -212,16 +212,16 @@ $ docker rm -f mycontainer
解决:
```bash
-# 查看空间占用
+## 查看空间占用
$ docker system df
-# 完整清理
+## 完整清理
$ docker system prune -a --volumes
```
---
-## 本章小结
+### 本章小结
| 操作 | 命令 |
|------|------|
@@ -231,8 +231,8 @@ $ docker system prune -a --volumes
| 清理所有已停止容器 | `docker container prune` |
| 删除所有容器 | `docker rm -f $(docker ps -aq)` |
-## 延伸阅读
+### 延伸阅读
-- [终止容器](stop.md):优雅停止容器
-- [删除镜像](../04_image/rm.md):清理镜像
+- [终止容器](5.3_stop.md):优雅停止容器
+- [删除镜像](../04_image/4.3_rm.md):清理镜像
- [数据卷](../07_data_network/data/volume.md):数据卷管理
diff --git a/05_container/README.md b/05_container/README.md
index a7bfeff..9199a7d 100644
--- a/05_container/README.md
+++ b/05_container/README.md
@@ -1,4 +1,4 @@
-# 操作 Docker 容器
+# 第五章 操作容器
容器是 Docker 又一核心概念。
diff --git a/06_repository/dockerhub.md b/06_repository/6.1_dockerhub.md
similarity index 82%
rename from 06_repository/dockerhub.md
rename to 06_repository/6.1_dockerhub.md
index 18203b4..aebee21 100644
--- a/06_repository/dockerhub.md
+++ b/06_repository/6.1_dockerhub.md
@@ -1,6 +1,6 @@
-# Docker Hub
+## Docker Hub
-## 什么是 Docker Hub
+### 什么是 Docker Hub
[Docker Hub](https://hub.docker.com/) 是 Docker 官方维护的公共镜像仓库,也是全球最大的容器镜像库。
@@ -12,9 +12,9 @@
---
-## 核心功能
+### 核心功能
-### 1. 搜索镜像
+#### 1. 搜索镜像
除了网页搜索,也可以使用命令行:
@@ -26,36 +26,36 @@ centos The official build of CentOS. 7000+ [OK]
> **技巧**:始终优先使用 `OFFICIAL` 标记为 `[OK]` 的镜像,安全性更有保障。
-### 2. 拉取镜像
+#### 2. 拉取镜像
```bash
$ docker pull nginx:alpine
```
-### 3. 推送镜像
+#### 3. 推送镜像
需要先登录:
```bash
$ docker login
-# 输入用户名和密码
+## 输入用户名和密码
```
打标签并推送:
```bash
-# 1. 标记镜像
+## 1. 标记镜像
$ docker tag myapp:v1 username/myapp:v1
-# 2. 推送
+## 2. 推送
$ docker push username/myapp:v1
```
---
-## 限制与配额(重要)
+### 限制与配额(重要)
-### 镜像拉取限制 (Rate Limiting)
+#### 镜像拉取限制 (Rate Limiting)
自 2020 年 11 月起,Docker Hub 对匿名和免费用户实施了拉取速率限制:
@@ -72,13 +72,13 @@ $ docker push username/myapp:v1
---
-## 安全最佳实践
+### 安全最佳实践
-### 1. 启用 2FA (双因素认证)
+#### 1. 启用 2FA (双因素认证)
在 Account Settings -> Security 中启用 2FA,保护账号安全。启用后,CLI 登录需要使用 **Access Token** 而非密码。
-### 2. 使用 Access Token
+#### 2. 使用 Access Token
不要在脚本或 CI/CD 中直接使用登录密码。
1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token。
@@ -88,13 +88,13 @@ $ docker push username/myapp:v1
$ docker login -u username -p dckr_pat_xxxxxxx
```
-### 3. 关注镜像漏洞
+#### 3. 关注镜像漏洞
Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜像标签页可以看到漏洞扫描结果。
---
-## Webhooks
+### Webhooks
当镜像被推送时,可以自动触发 HTTP 回调(例如通知 CI 系统部署)。
@@ -103,7 +103,7 @@ Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜
---
-## 自动构建 (Automated Builds)
+### 自动构建 (Automated Builds)
> ⚠️ 目前仅限付费用户 (Pro/Team) 使用。
@@ -111,7 +111,7 @@ Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜
---
-## 本章小结
+### 本章小结
| 功能 | 说明 |
|------|------|
@@ -120,7 +120,7 @@ Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜
| **安全** | 推荐开启 2FA 并使用 Access Token |
| **自动化** | 支持 Webhooks 和自动构建 |
-## 延伸阅读
+### 延伸阅读
-- [私有仓库](registry.md):搭建自己的 Registry
-- [镜像加速器](../install/mirror.md):加速下载
+- [私有仓库](6.2_registry.md):搭建自己的 Registry
+- [镜像加速器](../install/3.9_mirror.md):加速下载
diff --git a/06_repository/registry.md b/06_repository/6.2_registry.md
similarity index 95%
rename from 06_repository/registry.md
rename to 06_repository/6.2_registry.md
index 6e50ef2..b3c0f26 100644
--- a/06_repository/registry.md
+++ b/06_repository/6.2_registry.md
@@ -1,4 +1,4 @@
-# 私有仓库
+## 私有仓库
有时候使用 Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。
@@ -6,9 +6,9 @@
[`docker-registry`](https://docs.docker.com/registry/) 是官方提供的工具,可以用于构建私有的镜像仓库。本文内容基于 [`docker-registry`](https://github.com/docker/distribution) v2.x 版本。
-## 安装运行 docker-registry
+### 安装运行 docker-registry
-### 容器运行
+#### 容器运行
你可以使用官方 `registry` 镜像来运行。
@@ -25,7 +25,7 @@ $ docker run -d \
registry
```
-## 在私有仓库上传、搜索、下载镜像
+### 在私有仓库上传、搜索、下载镜像
创建好私有仓库之后,就可以使用 `docker tag` 来标记一个镜像,然后推送它到仓库。例如私有仓库地址为 `127.0.0.1:5000`。
@@ -91,13 +91,13 @@ REPOSITORY TAG IMAGE ID CREAT
127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
```
-## 配置非 https 仓库地址
+### 配置非 https 仓库地址
如果你不想使用 `127.0.0.1:5000` 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 `192.168.199.100:5000` 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。
这是因为 Docker 默认不允许非 `HTTPS` 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 `HTTPS` 访问的私有仓库。
-### Linux (systemd)
+#### Linux (systemd)
对于使用 `systemd` 的系统,请在 `/etc/docker/daemon.json` 中写入如下内容(如果文件不存在请新建该文件)
@@ -115,6 +115,6 @@ REPOSITORY TAG IMAGE ID CREAT
>注意:该文件必须符合 `json` 规范,否则 Docker 将不能启动。
-## 其他
+### 其他
对于 Docker Desktop for Windows 、 Docker Desktop for Mac 在设置中的 `Docker Engine` 中进行编辑 ,增加和上边一样的字符串即可。
diff --git a/06_repository/registry_auth.md b/06_repository/6.3_registry_auth.md
similarity index 96%
rename from 06_repository/registry_auth.md
rename to 06_repository/6.3_registry_auth.md
index e39167c..8d316c6 100644
--- a/06_repository/registry_auth.md
+++ b/06_repository/6.3_registry_auth.md
@@ -1,10 +1,10 @@
-# 私有仓库高级配置
+## 私有仓库高级配置
上一节我们搭建了一个具有基础功能的私有仓库,本小节我们来使用 `Docker Compose` 搭建一个拥有权限认证、TLS 的私有仓库。
新建一个文件夹,以下步骤均在该文件夹中进行。
-## 准备站点证书
+### 准备站点证书
如果你拥有一个域名,国内各大云服务商均提供免费的站点证书。你也可以使用 `openssl` 自行签发证书。
@@ -82,7 +82,7 @@ $ openssl x509 -req -days 750 -in "site.csr" -sha256 \
新建 `ssl` 文件夹并将 `docker.domain.com.key` `docker.domain.com.crt` `root-ca.crt` 这三个文件移入,删除其他文件。
-## 配置私有仓库
+### 配置私有仓库
私有仓库默认的配置文件位于 `/etc/docker/registry/config.yml`,我们先在本地编辑 `config.yml`,之后挂载到容器中。
@@ -123,7 +123,7 @@ health:
threshold: 3
```
-## 生成 http 认证文件
+### 生成 http 认证文件
```bash
$ mkdir auth
@@ -136,7 +136,7 @@ $ docker run --rm \
> 将上面的 `username` `password` 替换为你自己的用户名和密码。
-## 编辑 `docker-compose.yml`
+### 编辑 `docker-compose.yml`
```yaml
@@ -154,7 +154,7 @@ volumes:
registry-data:
```
-## 修改 hosts
+### 修改 hosts
编辑 `/etc/hosts`
@@ -162,7 +162,7 @@ volumes:
127.0.0.1 docker.domain.com
```
-## 启动
+### 启动
```bash
$ docker compose up -d
@@ -170,7 +170,7 @@ $ docker compose up -d
这样我们就搭建好了一个具有权限认证、TLS 的私有仓库,接下来我们测试其功能是否正常。
-## 测试私有仓库功能
+### 测试私有仓库功能
由于自行签发的 CA 根证书不被系统信任,所以我们需要将 CA 根证书 `ssl/root-ca.crt` 移入 `/etc/docker/certs.d/docker.domain.com` 文件夹中。
@@ -212,6 +212,6 @@ no basic auth credentials
发现会提示没有登录,不能将镜像推送到私有仓库中。
-## 注意事项
+### 注意事项
如果你本机占用了 `443` 端口,你可以配置 [Nginx 代理](https://docs.docker.com/registry/recipes/nginx/),这里不再赘述。
diff --git a/06_repository/nexus3_registry.md b/06_repository/6.4_nexus3_registry.md
similarity index 92%
rename from 06_repository/nexus3_registry.md
rename to 06_repository/6.4_nexus3_registry.md
index d82224a..172a50a 100644
--- a/06_repository/nexus3_registry.md
+++ b/06_repository/6.4_nexus3_registry.md
@@ -1,8 +1,8 @@
-# Nexus 3
+## Nexus 3
使用 Docker 官方的 Registry 创建的仓库面临一些维护问题。比如某些镜像删除以后空间默认是不会回收的,需要一些命令去回收空间然后重启 Registry。在企业中把内部的一些工具包放入 `Nexus` 中是比较常见的做法,最新版本 `Nexus3.x` 全面支持 Docker 的私有镜像。所以使用 [`Nexus3.x`](https://www.sonatype.com/product/repository-oss-download) 一个软件来管理 `Docker` , `Maven` , `Yum` , `PyPI` 等是一个明智的选择。
-## 启动 Nexus 容器
+### 启动 Nexus 容器
```bash
$ docker run -d --name nexus3 --restart=always \
@@ -38,7 +38,7 @@ $ docker exec nexus3 cat /nexus-data/admin.password
登录之后可以点击页面上方的齿轮按钮按照下面的方法进行设置。
-## 创建仓库
+### 创建仓库
创建一个私有仓库的方法: `Repository->Repositories` 点击右边菜单 `Create repository` 选择 `docker (hosted)`
@@ -48,7 +48,7 @@ $ docker exec nexus3 cat /nexus-data/admin.password
其它的仓库创建方法请各位自己摸索,还可以创建一个 `docker (proxy)` 类型的仓库链接到 DockerHub 上。再创建一个 `docker (group)` 类型的仓库把刚才的 `hosted` 与 `proxy` 添加在一起。主机在访问的时候默认下载私有仓库中的镜像,如果没有将链接到 DockerHub 中下载并缓存到 Nexus 中。
-## 添加访问权限
+### 添加访问权限
菜单 `Security->Realms` 把 Docker Bearer Token Realm 移到右边的框中保存。
@@ -56,9 +56,9 @@ $ docker exec nexus3 cat /nexus-data/admin.password
添加用户:菜单 `Security->Users`->`Create local user` 在 `Roles` 选项中选中刚才创建的规则移动到右边的窗口保存。
-## NGINX 加密代理
+### NGINX 加密代理
-证书的生成请参见 [`私有仓库高级配置`](registry_auth.md) 里面证书生成一节。
+证书的生成请参见 [`私有仓库高级配置`](6.3_registry_auth.md) 里面证书生成一节。
NGINX 示例配置如下
@@ -111,9 +111,9 @@ server {
}
```
-## Docker 主机访问镜像仓库
+### Docker 主机访问镜像仓库
-如果不启用 SSL 加密可以通过 [前面章节](registry.md) 的方法添加非 https 仓库地址到 Docker 的配置文件中然后重启 Docker。
+如果不启用 SSL 加密可以通过 [前面章节](6.2_registry.md) 的方法添加非 https 仓库地址到 Docker 的配置文件中然后重启 Docker。
使用 SSL 加密以后程序需要访问就不能采用修改配置的方式了。具体方法如下:
diff --git a/06_repository/README.md b/06_repository/README.md
index 52df443..7f86d38 100644
--- a/06_repository/README.md
+++ b/06_repository/README.md
@@ -1,4 +1,4 @@
-# 访问仓库
+# 第六章 访问仓库
仓库(`Repository`)是集中存放镜像的地方。
diff --git a/07_data_network/README.md b/07_data_network/README.md
index cfb4f2c..bf4960f 100644
--- a/07_data_network/README.md
+++ b/07_data_network/README.md
@@ -1,4 +1,4 @@
-# 数据与网络管理
+# 第七章 数据与网络管理
本章将介绍 Docker 中的数据管理与网络配置。
diff --git a/07_data_network/data/README.md b/07_data_network/data/README.md
index 46ae43e..8756576 100644
--- a/07_data_network/data/README.md
+++ b/07_data_network/data/README.md
@@ -1,4 +1,4 @@
-# 数据管理
+## 数据管理

diff --git a/07_data_network/data/bind-mounts.md b/07_data_network/data/bind-mounts.md
index 4011d92..b934e6e 100644
--- a/07_data_network/data/bind-mounts.md
+++ b/07_data_network/data/bind-mounts.md
@@ -1,6 +1,6 @@
-# 挂载主机目录(Bind Mounts)
+## 挂载主机目录(Bind Mounts)
-## 什么是 Bind Mount
+### 什么是 Bind Mount
Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容器中。容器可以读写宿主机的文件系统。
@@ -16,7 +16,7 @@ Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容
---
-## Bind Mount vs Volume
+### Bind Mount vs Volume
| 特性 | Bind Mount | Volume |
|------|------------|--------|
@@ -27,7 +27,7 @@ Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容
| **适用场景** | 开发环境、配置文件 | 生产数据持久化 |
| **备份** | 直接访问文件 | 需要通过 Docker |
-### 选择建议
+#### 选择建议
```
需求 推荐方案
@@ -42,9 +42,9 @@ Bind Mount(绑定挂载)将**宿主机的目录或文件**直接挂载到容
---
-## 基本语法
+### 基本语法
-### 使用 --mount(推荐)
+#### 使用 --mount(推荐)
```bash
$ docker run -d \
@@ -52,7 +52,7 @@ $ docker run -d \
nginx
```
-### 使用 -v(简写)
+#### 使用 -v(简写)
```bash
$ docker run -d \
@@ -60,7 +60,7 @@ $ docker run -d \
nginx
```
-### 两种语法对比
+#### 两种语法对比
| 特性 | --mount | -v |
|------|---------|-----|
@@ -70,44 +70,44 @@ $ docker run -d \
---
-## 使用场景
+### 使用场景
-### 场景一:开发环境代码同步
+#### 场景一:开发环境代码同步
```bash
-# 将本地代码目录挂载到容器
+## 将本地代码目录挂载到容器
$ docker run -d \
-p 8080:80 \
--mount type=bind,source=$(pwd)/src,target=/usr/share/nginx/html \
nginx
-# 修改本地文件,容器内立即生效(热更新)
+## 修改本地文件,容器内立即生效(热更新)
$ echo "Hello" > src/index.html
-# 浏览器刷新即可看到变化
+## 浏览器刷新即可看到变化
```
-### 场景二:配置文件挂载
+#### 场景二:配置文件挂载
```bash
-# 挂载自定义 nginx 配置
+## 挂载自定义 nginx 配置
$ docker run -d \
--mount type=bind,source=/path/to/nginx.conf,target=/etc/nginx/nginx.conf,readonly \
nginx
```
-### 场景三:日志收集
+#### 场景三:日志收集
```bash
-# 将容器日志输出到宿主机目录
+## 将容器日志输出到宿主机目录
$ docker run -d \
--mount type=bind,source=/var/log/myapp,target=/app/logs \
myapp
```
-### 场景四:共享 SSH 密钥
+#### 场景四:共享 SSH 密钥
```bash
-# 挂载 SSH 密钥(只读)
+## 挂载 SSH 密钥(只读)
$ docker run --rm -it \
--mount type=bind,source=$HOME/.ssh,target=/root/.ssh,readonly \
alpine ssh user@remote
@@ -115,17 +115,17 @@ $ docker run --rm -it \
---
-## 只读挂载
+### 只读挂载
防止容器修改宿主机文件:
```bash
-# --mount 语法
+## --mount 语法
$ docker run -d \
--mount type=bind,source=/config,target=/app/config,readonly \
myapp
-# -v 语法
+## -v 语法
$ docker run -d \
-v /config:/app/config:ro \
myapp
@@ -140,15 +140,15 @@ touch: /app/config/new.txt: Read-only file system
---
-## 挂载单个文件
+### 挂载单个文件
```bash
-# 挂载 bash 历史记录
+## 挂载 bash 历史记录
$ docker run --rm -it \
--mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
ubuntu bash
-# 挂载自定义配置文件
+## 挂载自定义配置文件
$ docker run -d \
--mount type=bind,source=/path/to/my.cnf,target=/etc/mysql/my.cnf \
mysql
@@ -158,7 +158,7 @@ $ docker run -d \
---
-## 查看挂载信息
+### 查看挂载信息
```bash
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
@@ -189,9 +189,9 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq
---
-## 常见问题
+### 常见问题
-### Q: 路径不存在报错
+#### Q: 路径不存在报错
```bash
$ docker run --mount type=bind,source=/not/exist,target=/app nginx
@@ -201,27 +201,27 @@ bind source path does not exist: /not/exist
**解决**:确保源路径存在,或改用 `-v`(会自动创建)
-### Q: 权限问题
+#### Q: 权限问题
容器内用户可能无权访问挂载的文件:
```bash
-# 方法1:确保宿主机文件权限允许容器用户访问
+## 方法1:确保宿主机文件权限允许容器用户访问
$ chmod -R 755 /path/to/data
-# 方法2:以 root 运行容器
+## 方法2:以 root 运行容器
$ docker run -u root ...
-# 方法3:使用相同的 UID
+## 方法3:使用相同的 UID
$ docker run -u $(id -u):$(id -g) ...
```
-### Q: macOS/Windows 性能问题
+#### Q: macOS/Windows 性能问题
在 Docker Desktop 上,Bind Mount 性能较差(需要跨文件系统同步):
```bash
-# 使用 :cached 或 :delegated 提高性能(macOS)
+## 使用 :cached 或 :delegated 提高性能(macOS)
$ docker run -v /host/path:/container/path:cached myapp
```
@@ -233,41 +233,41 @@ $ docker run -v /host/path:/container/path:cached myapp
---
-## 最佳实践
+### 最佳实践
-### 1. 开发环境使用 Bind Mount
+#### 1. 开发环境使用 Bind Mount
```bash
-# 代码热更新
+## 代码热更新
$ docker run -v $(pwd):/app -p 3000:3000 node npm run dev
```
-### 2. 生产环境使用 Volume
+#### 2. 生产环境使用 Volume
```bash
-# 数据持久化
+## 数据持久化
$ docker run -v mysql_data:/var/lib/mysql mysql
```
-### 3. 配置文件使用只读挂载
+#### 3. 配置文件使用只读挂载
```bash
$ docker run -v /config/nginx.conf:/etc/nginx/nginx.conf:ro nginx
```
-### 4. 注意路径安全
+#### 4. 注意路径安全
```bash
-# ❌ 危险:挂载根目录或敏感目录
+## ❌ 危险:挂载根目录或敏感目录
$ docker run -v /:/host ...
-# ✅ 只挂载必要的目录
+## ✅ 只挂载必要的目录
$ docker run -v /app/data:/data ...
```
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -277,8 +277,8 @@ $ docker run -v /app/data:/data ...
| **适用场景** | 开发环境、配置文件、日志 |
| **vs Volume** | Bind 更灵活,Volume 更适合生产 |
-## 延伸阅读
+### 延伸阅读
- [数据卷](volume.md):Docker 管理的持久化存储
- [tmpfs 挂载](tmpfs.md):内存临时存储
-- [Compose 数据管理](../compose/compose_file.md):Compose 中的挂载配置
+- [Compose 数据管理](../compose/9.5_compose_file.md):Compose 中的挂载配置
diff --git a/07_data_network/data/volume.md b/07_data_network/data/volume.md
index dbcb363..07468e8 100644
--- a/07_data_network/data/volume.md
+++ b/07_data_network/data/volume.md
@@ -1,6 +1,6 @@
-# 数据卷
+## 数据卷
-## 为什么需要数据卷
+### 为什么需要数据卷
容器的存储层有一个关键问题:**容器删除后,数据就没了**。
@@ -15,7 +15,7 @@ flowchart LR
---
-## 数据卷的特性
+### 数据卷的特性
| 特性 | 说明 |
|------|------|
@@ -27,9 +27,9 @@ flowchart LR
---
-## 数据卷 vs 容器存储层
+### 数据卷 vs 容器存储层
-#### 容器存储层(不推荐存储重要数据)
+##### 容器存储层(不推荐存储重要数据)
```mermaid
graph TD
@@ -43,7 +43,7 @@ graph TD
Delete[容器删除] -->|导致| DataLost[数据丢失 ❌]
```
-#### 数据卷(推荐)
+##### 数据卷(推荐)
```mermaid
graph TD
@@ -61,15 +61,15 @@ graph TD
---
-## 数据卷基本操作
+### 数据卷基本操作
-### 创建数据卷
+#### 创建数据卷
```bash
$ docker volume create my-vol
```
-### 列出所有数据卷
+#### 列出所有数据卷
```bash
$ docker volume ls
@@ -79,7 +79,7 @@ local postgres_data
local redis_data
```
-### 查看数据卷详情
+#### 查看数据卷详情
```bash
$ docker volume inspect my-vol
@@ -102,9 +102,9 @@ $ docker volume inspect my-vol
---
-## 挂载数据卷
+### 挂载数据卷
-### 方式一:--mount(推荐)
+#### 方式一:--mount(推荐)
```bash
$ docker run -d \
@@ -121,7 +121,7 @@ $ docker run -d \
| `target` | 容器内挂载路径 |
| `readonly` | 可选,只读挂载 |
-### 方式二:-v(简写)
+#### 方式二:-v(简写)
```bash
$ docker run -d \
@@ -132,7 +132,7 @@ $ docker run -d \
**格式**:`-v 数据卷名:容器路径[:选项]`
-### 两种方式对比
+#### 两种方式对比
| 特性 | --mount | -v |
|------|---------|-----|
@@ -140,15 +140,15 @@ $ docker run -d \
| 自动创建卷 | source 不存在会报错 | 自动创建 |
| 推荐程度 | ✅ 推荐(更明确) | 常用(更简洁) |
-### 只读挂载
+#### 只读挂载
```bash
-# --mount 方式
+## --mount 方式
$ docker run -d \
--mount source=my-vol,target=/data,readonly \
nginx
-# -v 方式
+## -v 方式
$ docker run -d \
-v my-vol:/data:ro \
nginx
@@ -156,25 +156,25 @@ $ docker run -d \
---
-## 使用场景示例
+### 使用场景示例
-### 场景一:数据库持久化
+#### 场景一:数据库持久化
```bash
-# 创建数据卷
+## 创建数据卷
$ docker volume create postgres_data
-# 启动 PostgreSQL,数据存储在数据卷中
+## 启动 PostgreSQL,数据存储在数据卷中
$ docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
-v postgres_data:/var/lib/postgresql/data \
postgres:16
-# 即使删除容器,数据仍然保留
+## 即使删除容器,数据仍然保留
$ docker rm -f postgres
-# 重新启动,数据还在
+## 重新启动,数据还在
$ docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
@@ -182,27 +182,27 @@ $ docker run -d \
postgres:16
```
-### 场景二:多容器共享数据
+#### 场景二:多容器共享数据
```bash
-# 创建共享数据卷
+## 创建共享数据卷
$ docker volume create shared-data
-# 容器 A 写入数据
+## 容器 A 写入数据
$ docker run -d --name writer \
-v shared-data:/data \
alpine sh -c "while true; do date >> /data/log.txt; sleep 5; done"
-# 容器 B 读取数据
+## 容器 B 读取数据
$ docker run --rm \
-v shared-data:/data \
alpine cat /data/log.txt
```
-### 场景三:配置文件持久化
+#### 场景三:配置文件持久化
```bash
-# 将 nginx 配置存储在数据卷中
+## 将 nginx 配置存储在数据卷中
$ docker run -d \
-v nginx-config:/etc/nginx/conf.d \
-v nginx-logs:/var/log/nginx \
@@ -212,28 +212,28 @@ $ docker run -d \
---
-## 数据卷管理
+### 数据卷管理
-### 删除数据卷
+#### 删除数据卷
```bash
-# 删除指定数据卷
+## 删除指定数据卷
$ docker volume rm my-vol
-# 删除容器时同时删除数据卷
+## 删除容器时同时删除数据卷
$ docker rm -v container_name
```
-### 清理未使用的数据卷
+#### 清理未使用的数据卷
```bash
-# 查看未被任何容器使用的数据卷
+## 查看未被任何容器使用的数据卷
$ docker volume ls -f dangling=true
-# 删除所有未使用的数据卷
+## 删除所有未使用的数据卷
$ docker volume prune
-# 强制删除(不提示确认)
+## 强制删除(不提示确认)
$ docker volume prune -f
```
@@ -241,12 +241,12 @@ $ docker volume prune -f
---
-## 数据卷备份与恢复
+### 数据卷备份与恢复
-### 备份数据卷
+#### 备份数据卷
```bash
-# 使用临时容器挂载数据卷,打包备份
+## 使用临时容器挂载数据卷,打包备份
$ docker run --rm \
-v my-vol:/source:ro \
-v $(pwd):/backup \
@@ -259,24 +259,24 @@ $ docker run --rm \
3. 挂载当前目录到 `/backup`
4. 使用 tar 打包
-### 恢复数据卷
+#### 恢复数据卷
```bash
-# 创建新数据卷
+## 创建新数据卷
$ docker volume create my-vol-restored
-# 解压备份到新数据卷
+## 解压备份到新数据卷
$ docker run --rm \
-v my-vol-restored:/target \
-v $(pwd):/backup:ro \
alpine tar xzf /backup/my-vol-backup.tar.gz -C /target
```
-### 备份脚本示例
+#### 备份脚本示例
```bash
#!/bin/bash
-# backup-volume.sh
+## backup-volume.sh
VOLUME_NAME=$1
BACKUP_DIR=${2:-/backups}
@@ -292,7 +292,7 @@ echo "Backed up ${VOLUME_NAME} to ${BACKUP_DIR}/${VOLUME_NAME}_${TIMESTAMP}.tar.
---
-## 数据卷 vs 绑定挂载
+### 数据卷 vs 绑定挂载
Docker 有两种主要的数据持久化方式:
@@ -305,10 +305,10 @@ Docker 有两种主要的数据持久化方式:
| **备份** | 需要工具 | 直接访问文件 |
```bash
-# 数据卷
+## 数据卷
$ docker run -v mydata:/app/data nginx
-# 绑定挂载
+## 绑定挂载
$ docker run -v /host/path:/app/data nginx
```
@@ -316,27 +316,27 @@ $ docker run -v /host/path:/app/data nginx
---
-## 常见问题
+### 常见问题
-### Q: 如何知道容器使用了哪些数据卷?
+#### Q: 如何知道容器使用了哪些数据卷?
```bash
$ docker inspect container_name --format '{{json .Mounts}}' | jq
```
-### Q: 数据卷的数据在哪里?
+#### Q: 数据卷的数据在哪里?
```bash
-# 查看数据卷详情
+## 查看数据卷详情
$ docker volume inspect my-vol
-# Mountpoint 字段显示实际路径
+## Mountpoint 字段显示实际路径
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data"
```
> ⚠️ **注意**:不建议直接修改 Mountpoint 中的文件,应通过容器操作。
-### Q: 如何在不同机器间迁移数据卷?
+#### Q: 如何在不同机器间迁移数据卷?
1. 在源机器备份:`docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/data.tar.gz -C /data .`
2. 传输 tar.gz 文件
@@ -344,7 +344,7 @@ $ docker volume inspect my-vol
---
-## 本章小结
+### 本章小结
| 操作 | 命令 |
|------|------|
@@ -355,8 +355,8 @@ $ docker volume inspect my-vol
| 清理未用 | `docker volume prune` |
| 挂载数据卷 | `-v name:/path` 或 `--mount source=name,target=/path` |
-## 延伸阅读
+### 延伸阅读
- [绑定挂载](bind-mounts.md):挂载宿主机目录
- [tmpfs 挂载](tmpfs.md):内存中的临时存储
-- [存储驱动](../13_implementation/ufs.md):Docker 存储的底层原理
+- [存储驱动](../13_implementation/13.4_ufs.md):Docker 存储的底层原理
diff --git a/07_data_network/network/README.md b/07_data_network/network/README.md
index bcefdce..45b09a7 100644
--- a/07_data_network/network/README.md
+++ b/07_data_network/network/README.md
@@ -1,6 +1,6 @@
-# 网络配置
+## 网络配置
-## Docker 网络概述
+### Docker 网络概述
Docker 容器需要网络来:
- 与外部世界通信(访问互联网、被外部访问)
@@ -9,7 +9,7 @@ Docker 容器需要网络来:
Docker 在安装时会自动配置网络基础设施,大多数情况下开箱即用。
-## 默认网络架构
+### 默认网络架构
Docker 启动时自动创建以下网络组件:
@@ -36,7 +36,7 @@ graph TD
Internet((互联网)) <--> eth0
```
-### 核心组件
+#### 核心组件
| 组件 | 说明 |
|------|------|
@@ -45,7 +45,7 @@ graph TD
| **容器 eth0** | 容器内的网卡 |
| **IP 地址** | 自动从 172.17.0.0/16 网段分配 |
-### 数据流向
+#### 数据流向
```
容器 A (172.17.0.2) → docker0 → 容器 B (172.17.0.3) (容器间通信)
@@ -55,7 +55,7 @@ graph TD
---
-## Docker 网络类型
+### Docker 网络类型
查看默认网络:
@@ -77,9 +77,9 @@ ghi789... none null local
---
-## 用户自定义网络(推荐)
+### 用户自定义网络(推荐)
-### 为什么要用自定义网络
+#### 为什么要用自定义网络
默认 bridge 网络的局限:
@@ -89,30 +89,30 @@ ghi789... none null local
| 所有容器在同一网络 | 更好的隔离性 |
| 需要 --link(已废弃) | 原生支持服务发现 |
-### 创建自定义网络
+#### 创建自定义网络
```bash
-# 创建网络
+## 创建网络
$ docker network create mynet
-# 查看网络详情
+## 查看网络详情
$ docker network inspect mynet
```
-### 使用自定义网络
+#### 使用自定义网络
```bash
-# 启动容器并连接到自定义网络
+## 启动容器并连接到自定义网络
$ docker run -d --name web --network mynet nginx
$ docker run -d --name db --network mynet postgres
-# 在 web 容器中可以直接用容器名访问 db
+## 在 web 容器中可以直接用容器名访问 db
$ docker exec web ping db
PING db (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.083 ms
```
-### 容器名 DNS 解析
+#### 容器名 DNS 解析
自定义网络自动提供 DNS 服务:
@@ -131,45 +131,45 @@ PING db (172.18.0.3): 56 data bytes
---
-## 容器互联
+### 容器互联
-### 同一网络内的容器
+#### 同一网络内的容器
同一自定义网络内的容器可以直接通信:
```bash
-# 创建网络
+## 创建网络
$ docker network create app-net
-# 启动应用和数据库
+## 启动应用和数据库
$ docker run -d --name redis --network app-net redis
$ docker run -d --name app --network app-net myapp
-# app 容器中可以用 redis:6379 连接 Redis
+## app 容器中可以用 redis:6379 连接 Redis
```
-### 连接到多个网络
+#### 连接到多个网络
一个容器可以连接到多个网络:
```bash
-# 启动容器
+## 启动容器
$ docker run -d --name multi-net-container --network frontend nginx
-# 再连接到另一个网络
+## 再连接到另一个网络
$ docker network connect backend multi-net-container
-# 查看容器的网络
+## 查看容器的网络
$ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}}'
```
-### ⚠️ --link 已废弃
+#### ⚠️ --link 已废弃
```bash
-# 旧方式(不推荐)
+## 旧方式(不推荐)
$ docker run --link db:database myapp
-# 新方式(推荐)
+## 新方式(推荐)
$ docker network create mynet
$ docker run --network mynet --name db postgres
$ docker run --network mynet --name app myapp
@@ -177,18 +177,18 @@ $ docker run --network mynet --name app myapp
---
-## 端口映射
+### 端口映射
容器默认只能在 Docker 网络内访问。要从外部访问容器,需要端口映射:
-### 基本语法
+#### 基本语法
```bash
-# -p 宿主机端口:容器端口
+## -p 宿主机端口:容器端口
$ docker run -d -p 8080:80 nginx
```
-### 映射方式
+#### 映射方式
| 参数 | 说明 | 示例 |
|------|------|------|
@@ -198,14 +198,14 @@ $ docker run -d -p 8080:80 nginx
| `-p 127.0.0.1:8080:80` | 只绑定本地 | 仅本机可访问 |
| `-p 8080:80/udp` | UDP 端口 | UDP 协议 |
-### 查看端口映射
+#### 查看端口映射
```bash
$ docker port mycontainer
80/tcp -> 0.0.0.0:8080
```
-### 端口映射示意图
+#### 端口映射示意图
```
外部请求 http://宿主机IP:8080
@@ -222,22 +222,22 @@ $ docker port mycontainer
---
-## 网络隔离
+### 网络隔离
不同网络之间默认隔离:
```bash
-# 创建两个网络
+## 创建两个网络
$ docker network create frontend
$ docker network create backend
-# 容器 A 在 frontend
+## 容器 A 在 frontend
$ docker run -d --name web --network frontend nginx
-# 容器 B 在 backend
+## 容器 B 在 backend
$ docker run -d --name db --network backend postgres
-# web 无法直接访问 db(不同网络)
+## web 无法直接访问 db(不同网络)
$ docker exec web ping db
ping: db: Name or service not known
```
@@ -246,34 +246,34 @@ ping: db: Name or service not known
---
-## 常用命令
+### 常用命令
```bash
-# 列出网络
+## 列出网络
$ docker network ls
-# 创建网络
+## 创建网络
$ docker network create mynet
-# 查看网络详情
+## 查看网络详情
$ docker network inspect mynet
-# 连接容器到网络
+## 连接容器到网络
$ docker network connect mynet mycontainer
-# 断开网络连接
+## 断开网络连接
$ docker network disconnect mynet mycontainer
-# 删除网络
+## 删除网络
$ docker network rm mynet
-# 清理未使用的网络
+## 清理未使用的网络
$ docker network prune
```
---
-## 本章小结
+### 本章小结
| 概念 | 要点 |
|------|------|
@@ -283,9 +283,9 @@ $ docker network prune
| **网络隔离** | 不同网络默认隔离,增强安全性 |
| **--link** | 已废弃,使用自定义网络替代 |
-## 延伸阅读
+### 延伸阅读
- [高级网络配置](linking.md):容器互联详解
- [配置 DNS](dns.md):自定义 DNS 设置
- [端口映射](port_bindbindbindport.md):高级端口配置
-- [Compose 网络](../compose/compose_file.md):Compose 中的网络配置
+- [Compose 网络](../compose/9.5_compose_file.md):Compose 中的网络配置
diff --git a/07_data_network/network/dns.md b/07_data_network/network/dns.md
index 20110e8..cf89798 100644
--- a/07_data_network/network/dns.md
+++ b/07_data_network/network/dns.md
@@ -1,6 +1,6 @@
-# 配置 DNS
+## 配置 DNS
-## 容器的 DNS 机制
+### 容器的 DNS 机制
Docker 容器的 DNS 配置有两种情况:
@@ -9,18 +9,18 @@ Docker 容器的 DNS 配置有两种情况:
---
-## 嵌入式 DNS (Embedded DNS)
+### 嵌入式 DNS (Embedded DNS)
这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过"名字"找到彼此,而不需要知道对方的 IP(因为 IP 可能会变)。
```bash
-# 1. 创建自定义网络
+## 1. 创建自定义网络
$ docker network create mynet
-# 2. 启动容器 web 并加入网络
+## 2. 启动容器 web 并加入网络
$ docker run -d --name web --network mynet nginx
-# 3. 启动容器 client 并尝试 ping web
+## 3. 启动容器 client 并尝试 ping web
$ docker run -it --rm --network mynet alpine ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms
@@ -31,11 +31,11 @@ Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器。容器内的
---
-## 配置 DNS 参数
+### 配置 DNS 参数
如果你需要手动配置容器的 DNS(例如使用内网 DNS 服务器),可以在 `docker run` 中使用以下参数:
-### 1. --dns
+#### 1. --dns
指定 DNS 服务器 IP。
@@ -44,7 +44,7 @@ $ docker run -it --dns=114.114.114.114 ubuntu cat /etc/resolv.conf
nameserver 114.114.114.114
```
-### 2. --dns-search
+#### 2. --dns-search
指定 DNS 搜索域。例如设置为 `example.com`,则 `ping host` 会尝试解析 `host.example.com`。
@@ -52,7 +52,7 @@ nameserver 114.114.114.114
$ docker run --dns-search=example.com myapp
```
-### 3. --hostname (-h)
+#### 3. --hostname (-h)
设置容器的主机名。
@@ -62,7 +62,7 @@ $ docker run -h myweb nginx
---
-## 全局 DNS 配置
+### 全局 DNS 配置
如果希望所有容器都使用特定的 DNS 服务器(而不是继承宿主机),可以修改 `/etc/docker/daemon.json`:
@@ -79,9 +79,9 @@ $ docker run -h myweb nginx
---
-## 常见问题
+### 常见问题
-### Q: 容器无法解析域名
+#### Q: 容器无法解析域名
**现象**:`ping www.baidu.com` 失败,但 `ping 8.8.8.8` 成功。
@@ -90,7 +90,7 @@ $ docker run -h myweb nginx
2. 尝试手动指定 DNS:`docker run --dns 8.8.8.8 ...`
3. 检查防火墙是否拦截了 UDP 53 端口。
-### Q: 无法通过容器名通信
+#### Q: 无法通过容器名通信
**现象**:`ping db` 提示 `bad address 'db'`。
@@ -100,7 +100,7 @@ $ docker run -h myweb nginx
---
-## 本章小结
+### 本章小结
| 场景 | DNS 行为 | 备注 |
|------|----------|------|
@@ -108,7 +108,7 @@ $ docker run -h myweb nginx
| **自定义网络** | Docker 嵌入式 DNS | ✅ 支持容器名解析 |
| **手动指定** | 使用 `--dns` | 覆盖默认配置 |
-## 延伸阅读
+### 延伸阅读
- [网络模式](README.md):Docker 网络概览
- [端口映射](port_mapping.md):外部访问
diff --git a/07_data_network/network/port_mapping.md b/07_data_network/network/port_mapping.md
index dbaf757..6498e95 100644
--- a/07_data_network/network/port_mapping.md
+++ b/07_data_network/network/port_mapping.md
@@ -1,6 +1,6 @@
-# 外部访问容器
+## 外部访问容器
-## 为什么要映射端口
+### 为什么要映射端口
容器运行在自己的隔离网络环境中(通常是 Bridge 模式)。这意味着:
- **容器之间**:可以通过 IP 或容器名(自定义网络)互通。
@@ -26,14 +26,14 @@
---
-## 端口映射方式
+### 端口映射方式
-### 1. 指定映射 (-p)
+#### 1. 指定映射 (-p)
使用 `-p <宿主机端口>:<容器端口>` 格式。
```bash
-# 将宿主机的 8080 端口映射到容器的 80 端口
+## 将宿主机的 8080 端口映射到容器的 80 端口
$ docker run -d -p 8080:80 nginx
```
@@ -48,7 +48,7 @@ $ docker run -d -p 8080:80 nginx
| `hostPort:containerPort` | 绑定所有 IP (0.0.0.0) 的特定端口 | `-p 8080:80` (默认) |
| `containerPort` | 绑定所有 IP 的随机端口 | `-p 80` |
-### 2. 随机映射 (-P)
+#### 2. 随机映射 (-P)
使用 `-P` (大写) 参数,Docker 会随机映射 Dockerfile 中 `EXPOSE` 指令暴露的所有端口到宿主机的高端口(49000-49900)。
@@ -68,9 +68,9 @@ abc123456 0.0.0.0:49153->80/tcp
---
-## 查看端口映射
+### 查看端口映射
-### docker port
+#### docker port
```bash
$ docker port mycontainer
@@ -78,7 +78,7 @@ $ docker port mycontainer
80/tcp -> [::]:8080
```
-### docker ps
+#### docker ps
```bash
$ docker ps
@@ -88,20 +88,20 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web
---
-## 最佳实践与安全
+### 最佳实践与安全
-### 1. 限制监听 IP
+#### 1. 限制监听 IP
默认情况下,`-p 8080:80` 会监听 `0.0.0.0:8080`,这意味着任何人只要能连接你的宿主机 IP,就能访问该服务。
如果不希望对外暴露(例如数据库服务),应绑定到 `127.0.0.1`:
```bash
-# 仅允许本机访问
+## 仅允许本机访问
$ docker run -d -p 127.0.0.1:3306:3306 mysql
```
-### 2. 避免端口冲突
+#### 2. 避免端口冲突
如果宿主机 8080 已经被占用了,容器将无法启动。
@@ -109,7 +109,7 @@ $ docker run -d -p 127.0.0.1:3306:3306 mysql
- 更换宿主机端口:`-p 8081:80`
- 让 Docker 自动分配:`-p 80`
-### 3. UDP 映射
+#### 3. UDP 映射
默认是 TCP 协议。如果要映射 UDP 服务(如 DNS, Syslog):
@@ -119,14 +119,14 @@ $ docker run -d -p 53:53/udp dns-server
---
-## 实现原理
+### 实现原理
Docker 使用 `docker-proxy` 进程(用户态)或 `iptables` DNAT 规则(内核态)来实现端口转发。
当流量到达宿主机端口时,iptables 规则将其目标地址修改为容器 IP 并转发:
```bash
-# 简化的 iptables 逻辑
+## 简化的 iptables 逻辑
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
```
@@ -134,7 +134,7 @@ iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.
---
-## 本章小结
+### 本章小结
| 要点 | 说明 |
|------|------|
@@ -143,7 +143,7 @@ iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.
| **安全性** | 默认监听所有 IP,敏感服务应绑定 `127.0.0.1` |
| **查看** | 使用 `docker port` 或 `docker ps` |
-## 延伸阅读
+### 延伸阅读
- [EXPOSE 指令](../04_image/dockerfile/expose.md):在 Dockerfile 中声明端口
- [网络模式](README.md):Host 模式不需要端口映射
diff --git a/08_buildx/buildkit.md b/08_buildx/8.1_buildkit.md
similarity index 89%
rename from 08_buildx/buildkit.md
rename to 08_buildx/8.1_buildkit.md
index 3da8d02..93c1865 100644
--- a/08_buildx/buildkit.md
+++ b/08_buildx/8.1_buildkit.md
@@ -1,4 +1,4 @@
-# 使用 `BuildKit` 构建镜像
+## 使用 `BuildKit` 构建镜像
**BuildKit** 是下一代的镜像构建组件,在 https://github.com/moby/buildkit 开源。
@@ -6,19 +6,19 @@
目前,Docker Hub 自动构建已经支持 BuildKit,具体请参考 https://github.com/docker-practice/docker-hub-buildx
-## `Dockerfile` 新增指令详解
+### `Dockerfile` 新增指令详解
使用 BuildKit 后,我们可以使用下面几个新的 `Dockerfile` 指令来加快镜像构建。
要使用最新的 Dockerfile 语法特性,建议在 Dockerfile 开头添加语法指令:
```docker
-# syntax=docker/dockerfile:1
+## syntax=docker/dockerfile:1
```
这将使用最新的稳定版语法解析器,确保你可以使用所有最新特性。
-### `RUN --mount=type=cache`
+#### `RUN --mount=type=cache`
目前,几乎所有的程序都会使用依赖管理工具,例如 `Go` 中的 `go mod`、`Node.js` 中的 `npm` 等等,当我们构建一个镜像时,往往会重复的从互联网中获取依赖包,难以缓存,大大降低了镜像的构建效率。
@@ -50,7 +50,7 @@ COPY --from=builder /app/dist /app/dist
`BuildKit` 提供了 `RUN --mount=type=cache` 指令,可以实现上边的设想。
```docker
-# syntax=docker/dockerfile:1
+## syntax=docker/dockerfile:1
FROM node:alpine as builder
WORKDIR /app
@@ -64,14 +64,14 @@ RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=loc
COPY src /app/src
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
-# --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \
+## --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \
npm run build
FROM nginx:alpine
-# COPY --from=builder /app/dist /app/dist
+## COPY --from=builder /app/dist /app/dist
-# 为了更直观的说明 from 和 source 指令,这里使用 RUN 指令
+## 为了更直观的说明 from 和 source 指令,这里使用 RUN 指令
RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
# --mount=type=cache,target/tmp/dist,from=my_app_dist,sharing=locked \
mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist
@@ -95,32 +95,32 @@ RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
|`from` | 缓存来源(构建阶段),不填写时为空文件夹。|
|`source` | 来源的文件夹路径。|
-### `RUN --mount=type=bind`
+#### `RUN --mount=type=bind`
该指令可以将一个镜像(或上一构建阶段)的文件挂载到指定位置。
```docker
-# syntax=docker/dockerfile:1
+## syntax=docker/dockerfile:1
RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \
cat /docker-php-entrypoint
```
-### `RUN --mount=type=tmpfs`
+#### `RUN --mount=type=tmpfs`
该指令可以将一个 `tmpfs` 文件系统挂载到指定位置。
```docker
-# syntax=docker/dockerfile:1
+## syntax=docker/dockerfile:1
RUN --mount=type=tmpfs,target=/temp \
mount | grep /temp
```
-### `RUN --mount=type=secret`
+#### `RUN --mount=type=secret`
该指令可以将一个文件(例如密钥)挂载到指定位置。
```docker
-# syntax=docker/dockerfile:1
+## syntax=docker/dockerfile:1
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
cat /root/.aws/credentials
```
@@ -129,12 +129,12 @@ RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
$ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .
```
-### `RUN --mount=type=ssh`
+#### `RUN --mount=type=ssh`
该指令可以挂载 `ssh` 密钥。
```docker
-# syntax=docker/dockerfile:1
+## syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
@@ -148,10 +148,10 @@ $ ssh-add ~/.ssh/id_rsa
$ docker build -t test --ssh default=$SSH_AUTH_SOCK .
```
-## docker compose build 使用 BuildKit
+### docker compose build 使用 BuildKit
自 Docker 23.0 起,BuildKit 已默认启用,无需额外配置。如果使用旧版本,可设置 `DOCKER_BUILDKIT=1` 环境变量启用。
-## 官方文档
+### 官方文档
* https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md
diff --git a/08_buildx/buildx.md b/08_buildx/8.2_buildx.md
similarity index 68%
rename from 08_buildx/buildx.md
rename to 08_buildx/8.2_buildx.md
index e2512ef..d4ea615 100644
--- a/08_buildx/buildx.md
+++ b/08_buildx/8.2_buildx.md
@@ -1,6 +1,6 @@
-# 使用 Buildx 构建镜像
+## 使用 Buildx 构建镜像
-## 使用
+### 使用
你可以直接使用 `docker buildx build` 命令构建镜像。
@@ -10,21 +10,21 @@ $ docker buildx build .
=> ...
```
-Buildx 使用 [BuildKit 引擎](buildkit.md) 进行构建,支持许多新的功能,具体参考 [Buildkit](buildkit.md) 一节。
+Buildx 使用 [BuildKit 引擎](8.1_buildkit.md) 进行构建,支持许多新的功能,具体参考 [Buildkit](8.1_buildkit.md) 一节。
-### 使用 `bake`
+#### 使用 `bake`
`docker buildx bake` 是一个高级构建命令,支持从 HCL、JSON 或 Compose 文件中定义构建目标,实现复杂的流水线构建。
```bash
-# 从 docker-compose.yml 构建所有服务
+## 从 docker-compose.yml 构建所有服务
$ docker buildx bake
-# 仅构建指定目标
+## 仅构建指定目标
$ docker buildx bake web
```
-### 生成 SBOM
+#### 生成 SBOM
Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对于软件供应链安全至关重要。
@@ -34,6 +34,6 @@ $ docker buildx build --sbom=true -t myimage .
该命令会在构建结果中包含 SPDX 或 CycloneDX 格式的 SBOM 数据。
-## 官方文档
+### 官方文档
* https://docs.docker.com/engine/reference/commandline/buildx/
diff --git a/08_buildx/multi-arch-images.md b/08_buildx/8.3_multi-arch-images.md
similarity index 89%
rename from 08_buildx/multi-arch-images.md
rename to 08_buildx/8.3_multi-arch-images.md
index e90dfb7..4235c3e 100644
--- a/08_buildx/multi-arch-images.md
+++ b/08_buildx/8.3_multi-arch-images.md
@@ -1,8 +1,8 @@
-# 构建多种系统架构支持的 Docker 镜像
+## 构建多种系统架构支持的 Docker 镜像
Docker 镜像可以支持多种系统架构,这意味着你可以在 `x86_64`、`arm64` 等不同架构的机器上运行同一个镜像。这是通过一个名为 "manifest list"(或称为 "fat manifest")的文件来实现的。
-## Manifest List 是什么?
+### Manifest List 是什么?
Manifest list 是一个包含了多个指向不同架构镜像的 manifest 的文件。当你拉取一个支持多架构的镜像时,Docker 会自动根据你当前的系统架构选择并拉取对应的镜像。
@@ -38,11 +38,11 @@ $ docker manifest inspect hello-world
}
```
-## 使用 `docker buildx` 构建多架构镜像
+### 使用 `docker buildx` 构建多架构镜像
在 Docker 19.03+ 版本中,`docker buildx` 是推荐的用于构建多架构镜像的工具。它使用 `BuildKit` 作为后端,可以大大简化构建过程。
-### 新建 `builder` 实例
+#### 新建 `builder` 实例
首先,你需要创建一个新的 `builder` 实例,因为它支持同时为多个平台构建。
@@ -51,12 +51,12 @@ $ docker buildx create --name mybuilder --use
$ docker buildx inspect --bootstrap
```
-### 构建和推送
+#### 构建和推送
使用 `docker buildx build` 命令并指定 `--platform` 参数,可以同时构建支持多种架构的镜像。`--push` 参数会将构建好的镜像和 manifest list 推送到 Docker 仓库。
```dockerfile
-# Dockerfile
+## Dockerfile
FROM --platform=$TARGETPLATFORM alpine
RUN uname -a > /os.txt
@@ -70,7 +70,7 @@ $ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t your-us
构建完成后,你就可以在不同架构的机器上拉取并运行 `your-username/multi-arch-image` 这个镜像了。
-### 架构相关的构建参数
+#### 架构相关的构建参数
在 `Dockerfile` 中,你可以使用一些预定义的构建参数来根据目标平台定制构建过程:
@@ -96,26 +96,26 @@ COPY bin/dist-${TARGETOS}-${TARGETARCH} /dist
ENTRYPOINT ["/dist"]
```
-## 使用 `docker manifest` (底层工具)
+### 使用 `docker manifest` (底层工具)
`docker manifest` 是一个更底层的命令,可以用来创建、检查和推送 manifest list。虽然 `docker buildx` 在大多数情况下更方便,但了解 `docker manifest` 仍然有助于理解其工作原理。
-### 创建 manifest list
+#### 创建 manifest list
```bash
-# 首先,为每个架构构建并推送镜像
+## 首先,为每个架构构建并推送镜像
$ docker buildx build --platform linux/amd64 -t your-username/my-app:amd64 . --push
$ docker buildx build --platform linux/arm64 -t your-username/my-app:arm64 . --push
-# 然后,创建一个 manifest list,将它们组合在一起
+## 然后,创建一个 manifest list,将它们组合在一起
$ docker manifest create your-username/my-app:latest \
--amend your-username/my-app:amd64 \
--amend your-username/my-app:arm64
-# 最后,推送 manifest list
+## 最后,推送 manifest list
$ docker manifest push your-username/my-app:latest
```
-### 检查 manifest list
+#### 检查 manifest list
你可以使用 `docker manifest inspect` 来查看一个 manifest list 的详细信息,如上文所示。
\ No newline at end of file
diff --git a/08_buildx/README.md b/08_buildx/README.md
index 1408b3b..e7ce247 100644
--- a/08_buildx/README.md
+++ b/08_buildx/README.md
@@ -1,5 +1,5 @@
-# Docker Buildx
+# 第八章 Docker Buildx
-Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 [Moby BuildKit](buildkit.md) 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。
+Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 [Moby BuildKit](8.1_buildkit.md) 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。
> 该功能仅适用于 Docker v19.03+ 版本
diff --git a/09_compose/introduction.md b/09_compose/9.1_introduction.md
similarity index 98%
rename from 09_compose/introduction.md
rename to 09_compose/9.1_introduction.md
index 146da08..b13dd86 100644
--- a/09_compose/introduction.md
+++ b/09_compose/9.1_introduction.md
@@ -1,4 +1,4 @@
-# Compose 简介
+## Compose 简介
`Compose` 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 `OpenStack` 中的 `Heat` 十分类似。
@@ -10,7 +10,7 @@
`Compose` 恰好满足了这样的需求。它允许用户通过一个单独的 `docker-compose.yml` 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
-## 模板文件规范
+### 模板文件规范
Compose 模板文件采用 YAML 格式,扩展名为 `.yml` 或 `.yaml`。
diff --git a/09_compose/install.md b/09_compose/9.2_install.md
similarity index 94%
rename from 09_compose/install.md
rename to 09_compose/9.2_install.md
index 35e9d7d..42f6261 100644
--- a/09_compose/install.md
+++ b/09_compose/9.2_install.md
@@ -1,4 +1,4 @@
-# 安装与卸载
+## 安装与卸载
`Compose` 是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。
@@ -10,7 +10,7 @@
Linux 系统请使用以下介绍的方法安装。
-## Linux
+### Linux
在 Linux 上,你可以通过下载 `docker-compose` 二进制包来安装。
@@ -32,20 +32,20 @@ $ curl -SL https://github.com/docker/compose/releases/download/v2.40.3/docker-co
$ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
```
-## 测试安装
+### 测试安装
```bash
$ docker compose version
Docker Compose version v2.40.3
```
-## bash 补全命令
+### bash 补全命令
```bash
$ curl -L https://raw.githubusercontent.com/docker/compose/v2.40.3/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
```
-## 卸载
+### 卸载
如果是二进制包方式安装的,删除二进制文件即可。
diff --git a/09_compose/usage.md b/09_compose/9.3_usage.md
similarity index 85%
rename from 09_compose/usage.md
rename to 09_compose/9.3_usage.md
index 466225c..10e2ed4 100644
--- a/09_compose/usage.md
+++ b/09_compose/9.3_usage.md
@@ -1,6 +1,6 @@
-# 使用
+## 使用
-## 术语
+### 术语
首先介绍几个术语。
@@ -10,13 +10,13 @@
可见,一个项目可以由多个服务(容器)关联而成,`Compose` 面向项目进行管理。
-## 场景
+### 场景
最常见的项目是 web 网站,该项目应该包含 web 应用和缓存。
下面我们用 `Python` 来建立一个能够记录页面访问次数的 web 网站。
-### web 应用
+#### web 应用
新建文件夹,在该目录中编写 `app.py` 文件
@@ -36,7 +36,7 @@ if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
```
-### Dockerfile
+#### Dockerfile
编写 `Dockerfile` 文件,内容为
@@ -48,7 +48,7 @@ RUN pip install redis flask
CMD ["python", "app.py"]
```
-### docker-compose.yml
+#### docker-compose.yml
编写 `docker-compose.yml` 文件,这个是 Compose 使用的主模板文件。
@@ -65,7 +65,7 @@ services:
image: "redis:alpine"
```
-### 运行 compose 项目
+#### 运行 compose 项目
```bash
$ docker compose up
@@ -76,19 +76,19 @@ $ docker compose up
按下 `Ctrl-C` 停止项目。
-### 后台运行
+#### 后台运行
```bash
$ docker compose up -d
```
-### 停止
+#### 停止
```bash
$ docker compose stop
```
-### 进入服务
+#### 进入服务
```bash
$ docker compose exec redis sh
@@ -97,37 +97,37 @@ $ docker compose exec redis sh
"9"
```
-### 查看日志
+#### 查看日志
```bash
$ docker compose logs -f
```
-### 构建镜像
+#### 构建镜像
```bash
$ docker compose build
```
-### 启动服务
+#### 启动服务
```bash
$ docker compose start
```
-### 运行一次性命令
+#### 运行一次性命令
```bash
$ docker compose run web python app.py
```
-### 验证 `docker-compose.yml`
+#### 验证 `docker-compose.yml`
```bash
$ docker compose config
```
-### 删除项目
+#### 删除项目
```bash
$ docker compose down
diff --git a/09_compose/commands.md b/09_compose/9.4_commands.md
similarity index 95%
rename from 09_compose/commands.md
rename to 09_compose/9.4_commands.md
index 57e2362..1c786a0 100644
--- a/09_compose/commands.md
+++ b/09_compose/9.4_commands.md
@@ -1,6 +1,6 @@
-# Compose 命令说明
+## Compose 命令说明
-## 命令对象与格式
+### 命令对象与格式
对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。
@@ -12,7 +12,7 @@
docker compose [-f=...] [options] [COMMAND] [ARGS...]
```
-## 命令选项
+### 命令选项
* `-f, --file FILE` 指定使用的 Compose 模板文件,默认为 `docker-compose.yml`,可以多次指定。
@@ -22,9 +22,9 @@ docker compose [-f=...] [options] [COMMAND] [ARGS...]
* `-v, --version` 打印版本并退出。
-## 命令使用说明
+### 命令使用说明
-### `build`
+#### `build`
格式为 `docker compose build [options] [SERVICE...]`。
@@ -42,27 +42,27 @@ docker compose [-f=...] [options] [COMMAND] [ARGS...]
* `--pull` 始终尝试通过 pull 来获取更新版本的镜像。
-### `config`
+#### `config`
验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。
-### `down`
+#### `down`
此命令将会停止 `up` 命令所启动的容器,并移除网络
-### `exec`
+#### `exec`
进入指定的容器。
-### `help`
+#### `help`
获得一个命令的帮助。
-### `images`
+#### `images`
列出 Compose 文件中包含的镜像。
-### `kill`
+#### `kill`
格式为 `docker compose kill [options] [SERVICE...]`。
@@ -74,7 +74,7 @@ docker compose [-f=...] [options] [COMMAND] [ARGS...]
$ docker compose kill -s SIGINT
```
-### `logs`
+#### `logs`
格式为 `docker compose logs [options] [SERVICE...]`。
@@ -82,13 +82,13 @@ $ docker compose kill -s SIGINT
该命令在调试问题的时候十分有用。
-### `pause`
+#### `pause`
格式为 `docker compose pause [SERVICE...]`。
暂停一个服务容器。
-### `port`
+#### `port`
格式为 `docker compose port [options] SERVICE PRIVATE_PORT`。
@@ -100,7 +100,7 @@ $ docker compose kill -s SIGINT
* `--index=index` 如果同一服务存在多个容器,指定命令对象容器的序号(默认为 1)。
-### `ps`
+#### `ps`
格式为 `docker compose ps [options] [SERVICE...]`。
@@ -110,7 +110,7 @@ $ docker compose kill -s SIGINT
* `-q` 只打印容器的 ID 信息。
-### `pull`
+#### `pull`
格式为 `docker compose pull [options] [SERVICE...]`。
@@ -120,11 +120,11 @@ $ docker compose kill -s SIGINT
* `--ignore-pull-failures` 忽略拉取镜像过程中的错误。
-### `push`
+#### `push`
推送服务依赖的镜像到 Docker 镜像仓库。
-### `restart`
+#### `restart`
格式为 `docker compose restart [options] [SERVICE...]`。
@@ -134,7 +134,7 @@ $ docker compose kill -s SIGINT
* `-t, --timeout TIMEOUT` 指定重启前停止容器的超时(默认为 10 秒)。
-### `rm`
+#### `rm`
格式为 `docker compose rm [options] [SERVICE...]`。
@@ -146,7 +146,7 @@ $ docker compose kill -s SIGINT
* `-v` 删除容器所挂载的数据卷。
-### `run`
+#### `run`
格式为 `docker compose run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]`。
在指定服务上执行一个命令。
@@ -199,7 +199,7 @@ $ docker compose run --no-deps web python manage.py shell
* `-T` 不分配伪 tty,意味着依赖 tty 的指令将无法运行。
-### `scale`
+#### `scale`
格式为 `docker compose scale [options] [SERVICE=NUM...]`。
@@ -219,13 +219,13 @@ $ docker compose scale web=3 db=2
* `-t, --timeout TIMEOUT` 停止容器时候的超时(默认为 10 秒)。
-### `start`
+#### `start`
格式为 `docker compose start [SERVICE...]`。
启动已经存在的服务容器。
-### `stop`
+#### `stop`
格式为 `docker compose stop [options] [SERVICE...]`。
@@ -235,17 +235,17 @@ $ docker compose scale web=3 db=2
* `-t, --timeout TIMEOUT` 停止容器时候的超时(默认为 10 秒)。
-### `top`
+#### `top`
查看各个服务容器内运行的进程。
-### `unpause`
+#### `unpause`
格式为 `docker compose unpause [SERVICE...]`。
恢复处于暂停状态中的服务。
-### `up`
+#### `up`
格式为 `docker compose up [options] [SERVICE...]`。
@@ -279,13 +279,13 @@ $ docker compose scale web=3 db=2
* `-t, --timeout TIMEOUT` 停止容器时候的超时(默认为 10 秒)。
-### `version`
+#### `version`
格式为 `docker compose version`。
打印版本信息。
-### `watch`
+#### `watch`
格式为 `docker compose watch [options] [SERVICE...]`。
@@ -314,6 +314,6 @@ services:
* `--quiet` 静默模式。
-## 参考资料
+### 参考资料
* [官方文档](https://docs.docker.com/compose/reference/overview/)
diff --git a/09_compose/compose_file.md b/09_compose/9.5_compose_file.md
similarity index 94%
rename from 09_compose/compose_file.md
rename to 09_compose/9.5_compose_file.md
index 4231efa..87dfb1d 100644
--- a/09_compose/compose_file.md
+++ b/09_compose/9.5_compose_file.md
@@ -1,4 +1,4 @@
-# Compose 模板文件
+## Compose 模板文件
模板文件是使用 `Compose` 的核心,涉及到的指令关键字也比较多。但大家不用担心,这里面大部分指令跟 `docker run` 相关参数的含义都是类似的。
@@ -22,7 +22,7 @@ services:
下面分别介绍各个指令的用法。
-## `build`
+### `build`
指定 `Dockerfile` 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。 `Compose` 将会利用它自动构建这个镜像,然后使用这个镜像。
@@ -62,7 +62,7 @@ build:
- corp/web_app:3.14
```
-## `cap_add, cap_drop`
+### `cap_add, cap_drop`
指定容器的内核能力(capacity)分配。
@@ -80,7 +80,7 @@ cap_drop:
- NET_ADMIN
```
-## `command`
+### `command`
覆盖容器启动后默认执行的命令。
@@ -88,11 +88,11 @@ cap_drop:
command: echo "hello world"
```
-## `configs`
+### `configs`
仅用于 `Swarm mode`(已弃用,推荐使用 Kubernetes)。
-## `cgroup_parent`
+### `cgroup_parent`
指定父 `cgroup` 组,意味着将继承该组的资源限制。
@@ -102,7 +102,7 @@ command: echo "hello world"
cgroup_parent: cgroups_1
```
-## `container_name`
+### `container_name`
指定容器名称。默认将会使用 `项目名称_服务名称_序号` 这样的格式。
@@ -112,11 +112,11 @@ container_name: docker-web-container
>注意: 指定容器名称后,该服务将无法进行扩展(scale),因为 Docker 不允许多个容器具有相同的名称。
-## `deploy`
+### `deploy`
仅用于 `Swarm mode`(已弃用,推荐使用 Kubernetes)。
-## `devices`
+### `devices`
指定设备映射关系。
@@ -125,7 +125,7 @@ devices:
- "/dev/ttyUSB1:/dev/ttyUSB0"
```
-## `depends_on`
+### `depends_on`
解决容器的依赖、启动先后的问题。以下例子中会先启动 `redis` `db` 再启动 `web`
@@ -148,7 +148,7 @@ services:
>注意:`web` 服务不会等待 `redis` `db` 「完全启动」之后才启动。
-## `dns`
+### `dns`
自定义 `DNS` 服务器。可以是一个值,也可以是一个列表。
@@ -160,7 +160,7 @@ dns:
- 114.114.114.114
```
-## `dns_search`
+### `dns_search`
配置 `DNS` 搜索域。可以是一个值,也可以是一个列表。
@@ -172,7 +172,7 @@ dns_search:
- domain2.example.com
```
-## `tmpfs`
+### `tmpfs`
挂载一个 tmpfs 文件系统到容器。
@@ -183,7 +183,7 @@ tmpfs:
- /tmp
```
-## `env_file`
+### `env_file`
从文件中获取环境变量,可以为单独的文件路径或列表。
@@ -203,11 +203,11 @@ env_file:
环境变量文件中每一行必须符合格式,支持 `#` 开头的注释行。
```bash
-# common.env: Set development environment
+## common.env: Set development environment
PROG_ENV=development
```
-## `environment`
+### `environment`
设置环境变量。你可以使用数组或字典两种格式。
@@ -229,7 +229,7 @@ environment:
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
```
-## `expose`
+### `expose`
暴露端口,但不映射到宿主机,只被连接的服务访问。
@@ -241,7 +241,7 @@ expose:
- "8000"
```
-## `external_links`
+### `external_links`
>注意:不建议使用该指令。
@@ -254,7 +254,7 @@ external_links:
- project_db_1:postgresql
```
-## `extra_hosts`
+### `extra_hosts`
类似 Docker 中的 `--add-host` 参数,指定额外的 host 名称映射信息。
@@ -271,7 +271,7 @@ extra_hosts:
52.1.157.61 dockerhub
```
-## `healthcheck`
+### `healthcheck`
通过命令检查容器是否健康运行。
@@ -283,7 +283,7 @@ healthcheck:
retries: 3
```
-## `image`
+### `image`
指定为镜像名称或镜像 ID。如果镜像在本地不存在,`Compose` 将会尝试拉取这个镜像。
@@ -293,7 +293,7 @@ image: orchardup/postgresql
image: a4bc65fd
```
-## `labels`
+### `labels`
为容器添加 Docker 元数据(metadata)信息。例如可以为容器添加辅助说明信息。
@@ -304,11 +304,11 @@ labels:
com.startupteam.release: "rc3 for v1.0"
```
-## `links`
+### `links`
>注意:不推荐使用该指令。容器之间应通过 Docker 网络(networks)进行互联。
-## `logging`
+### `logging`
配置日志选项。
@@ -335,7 +335,7 @@ options:
max-file: "10"
```
-## `network_mode`
+### `network_mode`
设置网络模式。使用和 `docker run` 的 `--network` 参数一样的值。
@@ -347,7 +347,7 @@ network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
```
-## `networks`
+### `networks`
配置容器连接的网络。
@@ -365,7 +365,7 @@ networks:
other-network:
```
-## `pid`
+### `pid`
跟主机系统共享进程命名空间。打开该选项的容器之间,以及容器和宿主机系统之间可以通过进程 ID 来相互访问和操作。
@@ -373,7 +373,7 @@ networks:
pid: "host"
```
-## `ports`
+### `ports`
暴露端口信息。
@@ -389,7 +389,7 @@ ports:
*注意:当使用 `HOST:CONTAINER` 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 `YAML` 会自动解析 `xx:yy` 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。*
-## `secrets`
+### `secrets`
存储敏感数据,例如 `mysql` 服务密码。
@@ -412,7 +412,7 @@ secrets:
external: true
```
-## `security_opt`
+### `security_opt`
指定容器模板标签(label)机制的默认属性(用户、角色、类型、级别等)。例如配置标签的用户名和角色名。
@@ -422,7 +422,7 @@ security_opt:
- label:role:ROLE
```
-## `stop_signal`
+### `stop_signal`
设置另一个信号来停止容器。在默认情况下使用的是 SIGTERM 停止容器。
@@ -430,7 +430,7 @@ security_opt:
stop_signal: SIGUSR1
```
-## `sysctls`
+### `sysctls`
配置容器内核参数。
@@ -444,7 +444,7 @@ sysctls:
- net.ipv4.tcp_syncookies=0
```
-## `ulimits`
+### `ulimits`
指定容器的 ulimits 限制值。
@@ -458,7 +458,7 @@ sysctls:
hard: 40000
```
-## `volumes`
+### `volumes`
数据卷所挂载路径设置。可以设置为宿主机路径(`HOST:CONTAINER`)或者数据卷名称(`VOLUME:CONTAINER`),并且可以设置访问模式 (`HOST:CONTAINER:ro`)。
@@ -486,7 +486,7 @@ volumes:
mysql_data:
```
-## 其它指令
+### 其它指令
此外,还有包括 `domainname, entrypoint, hostname, ipc, mac_address, privileged, read_only, shm_size, restart, stdin_open, tty, user, working_dir` 等指令,基本跟 `docker run` 中对应参数的功能一致。
@@ -546,7 +546,7 @@ stdin_open: true
tty: true
```
-## 读取变量
+### 读取变量
Compose 模板文件支持动态读取主机的系统环境变量和当前目录下的 `.env` 文件中的变量。
@@ -567,13 +567,13 @@ db:
在当前目录新建 `.env` 文件并写入以下内容。
```bash
-# 支持 # 号注释
+## 支持 # 号注释
MONGO_VERSION=3.6
```
执行 `docker-compose up` 则会启动一个 `mongo:3.6` 镜像的容器。
-## 参考资料
+### 参考资料
* [官方文档](https://docs.docker.com/compose/compose-file/)
* [awesome-compose](https://github.com/docker/awesome-compose)
diff --git a/09_compose/django.md b/09_compose/9.6_django.md
similarity index 89%
rename from 09_compose/django.md
rename to 09_compose/9.6_django.md
index 7e4d78f..835aa3d 100644
--- a/09_compose/django.md
+++ b/09_compose/9.6_django.md
@@ -1,10 +1,10 @@
-# 使用 Django
+## 使用 Django
> 本小节内容适合 `Python` 开发人员阅读。
本节将使用 Docker Compose 配置并运行一个 **Django + PostgreSQL** 应用。笔者不仅会介绍具体步骤,还会解释每个配置项的作用,以及开发环境和生产环境的差异。
-## 架构概览
+### 架构概览
在开始之前,让我们先理解我们要构建的架构:
@@ -34,7 +34,7 @@
- 两个服务通过 Docker Compose 自动创建的网络相互通信
- `web` 服务可以通过服务名 `db` 访问数据库(Docker 内置 DNS)
-## 准备工作
+### 准备工作
创建一个项目目录并进入:
@@ -44,24 +44,24 @@ $ mkdir django-docker && cd django-docker
我们需要创建三个文件:`Dockerfile`、`requirements.txt` 和 `docker-compose.yml`。
-## Step 1: 创建 Dockerfile
+### Step 1: 创建 Dockerfile
```docker
FROM python:3.12-slim
-# 防止 Python 缓冲 stdout/stderr,让日志实时输出
+## 防止 Python 缓冲 stdout/stderr,让日志实时输出
ENV PYTHONUNBUFFERED=1
-# 设置工作目录
+## 设置工作目录
WORKDIR /code
-# 先复制依赖文件,利用 Docker 缓存加速构建
+## 先复制依赖文件,利用 Docker 缓存加速构建
COPY requirements.txt /code/
-# 安装依赖
+## 安装依赖
RUN pip install --no-cache-dir -r requirements.txt
-# 复制项目代码
+## 复制项目代码
COPY . /code/
```
@@ -77,7 +77,7 @@ COPY . /code/
> 💡 **笔者建议**:总是将变化频率低的文件先复制,变化频率高的后复制。这样可以最大化利用 Docker 的构建缓存。
-## Step 2: 创建 requirements.txt
+### Step 2: 创建 requirements.txt
```txt
Django>=5.0,<6.0
@@ -93,7 +93,7 @@ gunicorn>=21.0,<22.0
| `psycopg[binary]` | PostgreSQL 数据库驱动(推荐使用 psycopg 3) |
| `gunicorn` | 生产环境 WSGI 服务器(可选,开发时可不用) |
-## Step 3: 创建 docker-compose.yml
+### Step 3: 创建 docker-compose.yml
```yaml
services:
@@ -130,7 +130,7 @@ volumes:
**配置详解**:
-### db 服务
+#### db 服务
```yaml
db:
@@ -148,7 +148,7 @@ db:
> ⚠️ **笔者提醒**:`volumes` 配置很重要!没有它,每次容器重启数据都会丢失。笔者见过不少新手因为忘记这一步,导致开发数据全部丢失。
-### web 服务
+#### web 服务
```yaml
web:
@@ -171,7 +171,7 @@ web:
| `depends_on` + `healthcheck` | 启动顺序 | 确保数据库就绪后 Django 才启动,避免连接错误 |
| `environment` | 环境变量 | 推荐用环境变量管理配置,避免硬编码 |
-## Step 4: 创建 Django 项目
+### Step 4: 创建 Django 项目
运行以下命令创建新的 Django 项目:
@@ -203,7 +203,7 @@ django-docker/
> 💡 **Linux 用户注意**:如果遇到权限问题,执行 `sudo chown -R $USER:$USER .`
-## Step 5: 配置数据库连接
+### Step 5: 配置数据库连接
修改 `mysite/settings.py`,配置数据库连接:
@@ -221,7 +221,7 @@ DATABASES = {
}
}
-# 允许的主机(开发环境)
+## 允许的主机(开发环境)
ALLOWED_HOSTS = ['*']
```
@@ -229,7 +229,7 @@ ALLOWED_HOSTS = ['*']
在 Docker Compose 中,各服务通过服务名相互访问。Docker 内置的 DNS 会将 `db` 解析为 db 服务容器的 IP 地址。这是 Docker Compose 的核心功能之一。
-## Step 6: 启动应用
+### Step 6: 启动应用
```bash
$ docker compose up
@@ -249,29 +249,29 @@ web-1 | Starting development server at http://0.0.0.0:8000/
打开浏览器访问 http://localhost:8000,可以看到 Django 欢迎页面!
-## 常用开发命令
+### 常用开发命令
在另一个终端窗口执行:
```bash
-# 执行数据库迁移
+## 执行数据库迁移
$ docker compose exec web python manage.py migrate
-# 创建超级用户
+## 创建超级用户
$ docker compose exec web python manage.py createsuperuser
-# 进入 Django shell
+## 进入 Django shell
$ docker compose exec web python manage.py shell
-# 进入 PostgreSQL 命令行
+## 进入 PostgreSQL 命令行
$ docker compose exec db psql -U django_user -d django_db
```
> 💡 笔者建议使用 `exec` 而不是 `run`。`exec` 在已运行的容器中执行命令,`run` 会创建新容器。
-## 常见问题排查
+### 常见问题排查
-### Q1: 数据库连接失败
+#### Q1: 数据库连接失败
**错误信息**:`django.db.utils.OperationalError: could not connect to server`
@@ -284,12 +284,12 @@ $ docker compose exec db psql -U django_user -d django_db
| 网络未创建 | 运行 `docker compose down` 后重新 `up` |
```bash
-# 调试:检查数据库是否正常运行
+## 调试:检查数据库是否正常运行
$ docker compose ps
$ docker compose logs db
```
-### Q2: 代码修改没有生效
+#### Q2: 代码修改没有生效
**可能原因**:
@@ -297,14 +297,14 @@ $ docker compose logs db
2. **Volume 挂载问题**:检查 `docker-compose.yml` 中的 volumes 配置
3. **缓存问题**:尝试 `docker compose restart web`
-### Q3: 权限问题(Linux)
+#### Q3: 权限问题(Linux)
```bash
-# 如果容器内创建的文件 root 用户所有
+## 如果容器内创建的文件 root 用户所有
$ sudo chown -R $USER:$USER .
```
-## 开发 vs 生产:关键差异
+### 开发 vs 生产:关键差异
笔者特别提醒,本节的配置是**开发环境**配置。生产环境需要以下调整:
@@ -319,7 +319,7 @@ $ sudo chown -R $USER:$USER .
**生产环境 docker-compose.yml 示例**:
```yaml
-# docker-compose.prod.yml
+## docker-compose.prod.yml
services:
web:
build: .
@@ -331,9 +331,9 @@ services:
# ...
```
-## 延伸阅读
+### 延伸阅读
-- [Compose 模板文件详解](compose_file.md):深入理解 docker-compose.yml 的所有配置项
-- [使用 WordPress](wordpress.md):另一个 Compose 实战案例
-- [Dockerfile 最佳实践](../15_appendix/best_practices.md):构建更小、更安全的镜像
+- [Compose 模板文件详解](9.5_compose_file.md):深入理解 docker-compose.yml 的所有配置项
+- [使用 WordPress](9.8_wordpress.md):另一个 Compose 实战案例
+- [Dockerfile 最佳实践](../15_appendix/15.1_best_practices.md):构建更小、更安全的镜像
- [数据管理](../07_data_network/README.md):Volume 和数据持久化详解
diff --git a/09_compose/rails.md b/09_compose/9.7_rails.md
similarity index 88%
rename from 09_compose/rails.md
rename to 09_compose/9.7_rails.md
index 65813c2..9cf1044 100644
--- a/09_compose/rails.md
+++ b/09_compose/9.7_rails.md
@@ -1,10 +1,10 @@
-# 使用 Rails
+## 使用 Rails
> 本小节内容适合 Ruby 开发人员阅读。
本节使用 Docker Compose 配置并运行一个 **Rails + PostgreSQL** 应用。
-## 架构概览
+### 架构概览
```
┌─────────────────────────────────────────────────────────────┐
@@ -25,7 +25,7 @@
localhost:3000
```
-## 准备工作
+### 准备工作
创建项目目录:
@@ -35,25 +35,25 @@ $ mkdir rails-docker && cd rails-docker
需要创建三个文件:`Dockerfile`、`Gemfile` 和 `docker-compose.yml`。
-## Step 1: 创建 Dockerfile
+### Step 1: 创建 Dockerfile
```docker
FROM ruby:3.2
-# 安装系统依赖
+## 安装系统依赖
RUN apt-get update -qq && \
apt-get install -y build-essential libpq-dev nodejs && \
rm -rf /var/lib/apt/lists/*
-# 设置工作目录
+## 设置工作目录
WORKDIR /myapp
-# 先复制 Gemfile,利用缓存加速构建
+## 先复制 Gemfile,利用缓存加速构建
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
-# 复制应用代码
+## 复制应用代码
COPY . /myapp
```
@@ -66,7 +66,7 @@ COPY . /myapp
| `nodejs` | Rails Asset Pipeline 需要 |
| 先复制 Gemfile | 只有依赖变化时才重新 `bundle install` |
-## Step 2: 创建 Gemfile
+### Step 2: 创建 Gemfile
创建一个初始的 `Gemfile`,稍后会被 `rails new` 覆盖:
@@ -81,7 +81,7 @@ gem 'rails', '~> 7.1'
$ touch Gemfile.lock
```
-## Step 3: 创建 docker-compose.yml
+### Step 3: 创建 docker-compose.yml
```yaml
services:
@@ -117,7 +117,7 @@ volumes:
| `depends_on: db` | 确保数据库先启动 |
| `DATABASE_URL` | Rails 12-factor 风格的数据库配置 |
-## Step 4: 生成 Rails 项目
+### Step 4: 生成 Rails 项目
使用 `docker compose run` 生成项目骨架:
@@ -142,7 +142,7 @@ docker-compose.yml bin db public
> ⚠️ **Linux 用户**:如遇权限问题,执行 `sudo chown -R $USER:$USER .`
-## Step 5: 重新构建镜像
+### Step 5: 重新构建镜像
由于生成了新的 Gemfile,需要重新构建镜像以安装完整依赖:
@@ -150,7 +150,7 @@ docker-compose.yml bin db public
$ docker compose build
```
-## Step 6: 配置数据库连接
+### Step 6: 配置数据库连接
修改 `config/database.yml`:
@@ -174,7 +174,7 @@ production:
> 💡 使用 `DATABASE_URL` 环境变量配置数据库,符合 12-factor 应用原则,便于在不同环境间切换。
-## Step 7: 启动应用
+### Step 7: 启动应用
```bash
$ docker compose up
@@ -192,7 +192,7 @@ web-1 | Puma starting in single mode...
web-1 | * Listening on http://0.0.0.0:3000
```
-## Step 8: 创建数据库
+### Step 8: 创建数据库
在另一个终端执行:
@@ -204,28 +204,28 @@ Created database 'myapp_test'
访问 http://localhost:3000 查看 Rails 欢迎页面。
-## 常用开发命令
+### 常用开发命令
```bash
-# 数据库迁移
+## 数据库迁移
$ docker compose exec web rails db:migrate
-# Rails 控制台
+## Rails 控制台
$ docker compose exec web rails console
-# 运行测试
+## 运行测试
$ docker compose exec web rails test
-# 生成脚手架
+## 生成脚手架
$ docker compose exec web rails generate scaffold Post title:string body:text
-# 进入容器 Shell
+## 进入容器 Shell
$ docker compose exec web bash
```
-## 常见问题
+### 常见问题
-### Q: 数据库连接失败
+#### Q: 数据库连接失败
检查 `DATABASE_URL` 环境变量格式是否正确,确保 db 服务已启动:
@@ -234,7 +234,7 @@ $ docker compose ps
$ docker compose logs db
```
-### Q: server.pid 文件导致启动失败
+#### Q: server.pid 文件导致启动失败
错误信息:`A server is already running`
@@ -244,7 +244,7 @@ $ docker compose logs db
$ docker compose exec web rm -f tmp/pids/server.pid
```
-### Q: Gem 安装失败
+#### Q: Gem 安装失败
可能需要更新 bundler 或清理缓存:
@@ -252,7 +252,7 @@ $ docker compose exec web rm -f tmp/pids/server.pid
$ docker compose run --rm web bundle update
```
-## 开发 vs 生产
+### 开发 vs 生产
| 配置项 | 开发环境 | 生产环境 |
|--------|---------|---------|
@@ -261,8 +261,8 @@ $ docker compose run --rm web bundle update
| 静态资源 | 动态编译 | 预编译 (`rails assets:precompile`) |
| 数据库密码 | 明文配置 | 使用 Secrets 管理 |
-## 延伸阅读
+### 延伸阅读
-- [使用 Django](django.md):Python Web 框架实战
-- [Compose 模板文件](compose_file.md):配置详解
+- [使用 Django](9.6_django.md):Python Web 框架实战
+- [Compose 模板文件](9.5_compose_file.md):配置详解
- [数据管理](../07_data_network/README.md):数据持久化
diff --git a/09_compose/wordpress.md b/09_compose/9.8_wordpress.md
similarity index 89%
rename from 09_compose/wordpress.md
rename to 09_compose/9.8_wordpress.md
index 0a951f5..394760d 100644
--- a/09_compose/wordpress.md
+++ b/09_compose/9.8_wordpress.md
@@ -1,12 +1,12 @@
-# 实战 WordPress
+## 实战 WordPress
-## 简介
+### 简介
WordPress 是全球最流行的内容管理系统(CMS)。使用 Docker Compose 可以在几分钟内搭建一个包含数据库、Web 服务和持久化存储的生产级 WordPress 环境。
---
-## 项目结构
+### 项目结构
```
wordpress/
@@ -18,7 +18,7 @@ wordpress/
---
-## 编写 `docker-compose.yml`
+### 编写 `docker-compose.yml`
这是一个生产可用的最小化配置:
@@ -75,9 +75,9 @@ networks:
---
-## 配置文件详解
+### 配置文件详解
-### 1. 环境变量 (.env)
+#### 1. 环境变量 (.env)
为了安全,不要在 `docker-compose.yml` 中直接写密码。创建 `.env` 文件:
@@ -88,13 +88,13 @@ DB_PASSWORD=somestronguserpassword
Compose 会自动读取此同级目录下的文件。
-### 2. 数据持久化
+#### 2. 数据持久化
我们定义了两个命名卷:
- `db_data`: 确保 MySQL 容器重建后数据不丢失
- `wp_data`: 保存 WordPress 的核心文件、插件、主题和上传的媒体文件
-### 3. PHP 配置优化
+#### 3. PHP 配置优化
默认的 WordPress 镜像上传文件限制较小(通常 2MB)。创建 `uploads.ini`:
@@ -108,7 +108,7 @@ max_execution_time = 600
---
-## 启动与运行
+### 启动与运行
1. 启动服务:
@@ -127,14 +127,14 @@ $ docker compose logs -f
---
-## 生产环境最佳实践
+### 生产环境最佳实践
-### 1. 数据库备份
+#### 1. 数据库备份
不要只依赖 Volume。建议定期备份数据库:
```bash
-# 导出 SQL
+## 导出 SQL
$ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup.sql
```
@@ -158,11 +158,11 @@ $ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup
- wp_net
```
-### 2. 使用 Nginx 反向代理
+#### 2. 使用 Nginx 反向代理
在生产环境中,不要直接暴露 WordPress 端口,而是通过 Nginx 进行反向代理并配置 SSL。
-### 3. 使用 Redis 缓存
+#### 3. 使用 Redis 缓存
WordPress 支持 Redis 缓存以提高性能。
@@ -182,9 +182,9 @@ WordPress 支持 Redis 缓存以提高性能。
---
-## 常见问题
+### 常见问题
-### Q: 数据库连接错误
+#### Q: 数据库连接错误
**现象**:访问页面显示 "Error establishing a database connection"。
@@ -194,7 +194,7 @@ WordPress 支持 Redis 缓存以提高性能。
3. 确认 `WORDPRESS_DB_HOST` 也是 `db`(服务名)
4. MySQL 8.0 可能需要几秒钟启动,WordPress 会自动重试,稍等片刻即可。
-### Q: 无法上传大文件
+#### Q: 无法上传大文件
**解决**:确保挂载了 `uploads.ini` 配置,并且重启了容器:
```bash
@@ -203,8 +203,8 @@ $ docker compose restart wordpress
---
-## 延伸阅读
+### 延伸阅读
-- [Compose 模板文件](compose_file.md):深入了解配置项
+- [Compose 模板文件](9.5_compose_file.md):深入了解配置项
- [数据卷](../07_data_network/data/volume.md):理解数据持久化
- [Docker Hub WordPress](https://hub.docker.com/_/wordpress):官方镜像文档
diff --git a/09_compose/lnmp.md b/09_compose/9.9_lnmp.md
similarity index 87%
rename from 09_compose/lnmp.md
rename to 09_compose/9.9_lnmp.md
index 6e89ed2..1325534 100644
--- a/09_compose/lnmp.md
+++ b/09_compose/9.9_lnmp.md
@@ -1,3 +1,3 @@
-# 使用 compose 搭建 LNMP 环境
+## 使用 compose 搭建 LNMP 环境
本项目的维护者 [khs1994](https://github.com/khs1994) 的开源项目 [khs1994-docker/lnmp](https://github.com/khs1994-docker/lnmp) 使用 Docker Compose 搭建了一套 LNMP 环境,各位开发者可以参考该项目在 Docker 或 Kubernetes 中运行 LNMP。
diff --git a/09_compose/README.md b/09_compose/README.md
index 2e43b1c..159f151 100644
--- a/09_compose/README.md
+++ b/09_compose/README.md
@@ -1,4 +1,4 @@
-# Docker Compose 项目
+# 第九章 Docker Compose
`Docker Compose` 是 Docker 官方编排(Orchestration)项目之一,负责快速的部署分布式应用。
diff --git a/10_ops/README.md b/10_ops/README.md
index f4e3362..05671ac 100644
--- a/10_ops/README.md
+++ b/10_ops/README.md
@@ -1,4 +1,4 @@
-# 运维管理
+# 第十章 运维管理
本章将介绍 Docker 的运维管理,包括监控、日志与安全。
diff --git a/10_ops/logs/README.md b/10_ops/logs/README.md
index b27a7ba..768ed8c 100644
--- a/10_ops/logs/README.md
+++ b/10_ops/logs/README.md
@@ -1,8 +1,8 @@
-# 日志管理
+## 日志管理
在容器化环境中,日志管理比传统环境更为复杂。容器是短暂的,意味着容器内的日志文件可能会随着容器的销毁而丢失。因此,我们需要一种集中式的日志管理方案来收集、存储和分析容器日志。
-## Docker 日志驱动
+### Docker 日志驱动
Docker 提供了多种日志驱动(Log Driver)机制,允许我们将容器日志转发到不同的后端。
@@ -15,7 +15,7 @@ Docker 提供了多种日志驱动(Log Driver)机制,允许我们将容器
* `gelf`: 支持 GELF 协议的日志后端(如 Graylog)。
* `awslogs`: 发送到 Amazon CloudWatch Logs。
-## 日志管理方案
+### 日志管理方案
对于大规模的容器集群,我们通常会采用 EFK (Elasticsearch + Fluentd + Kibana) 或 ELK (Elasticsearch + Logstash + Kibana) 方案。
diff --git a/10_ops/logs/elk.md b/10_ops/logs/elk.md
index 8aafd6b..c505d81 100644
--- a/10_ops/logs/elk.md
+++ b/10_ops/logs/elk.md
@@ -1,8 +1,8 @@
-# ELK/EFK 堆栈
+## ELK/EFK 堆栈
ELK (Elasticsearch, Logstash, Kibana) 是目前业界最流行的开源日志解决方案。而在容器领域,由于 Fluentd 更加轻量级且对容器支持更好,EFK (Elasticsearch, Fluentd, Kibana) 组合也变得非常流行。
-## 方案架构
+### 方案架构
我们将采用以下架构:
@@ -11,9 +11,9 @@ ELK (Elasticsearch, Logstash, Kibana) 是目前业界最流行的开源日志解
3. **Elasticsearch**: 存储从 Fluentd 接收到的日志数据。
4. **Kibana**: 从 Elasticsearch 读取数据并进行可视化展示。
-## 部署流程
+### 部署流程
-### 1. 编写 docker-compose.yml
+#### 1. 编写 docker-compose.yml
```yaml
version: '3'
@@ -68,7 +68,7 @@ networks:
logging:
```
-### 2. 配置 Fluentd
+#### 2. 配置 Fluentd
创建 `fluentd/conf/fluent.conf`:
@@ -99,7 +99,7 @@ networks:
```
-### 3. 配置应用容器使用 fluentd 驱动
+#### 3. 配置应用容器使用 fluentd 驱动
启动一个测试容器,指定日志驱动为 `fluentd`:
@@ -114,7 +114,7 @@ docker run -d \
**注意**: 确保 `fluentd` 容器已经启动并监听在 `localhost:24224`。在生产环境中,如果你是在不同机器上,需要将 `localhost` 替换为运行 fluentd 的主机 IP。
-### 4. 在 Kibana 中查看日志
+#### 4. 在 Kibana 中查看日志
1. 访问 `http://localhost:5601`。
2. 进入 **Management** -> **Kibana** -> **Index Patterns**。
@@ -122,6 +122,6 @@ docker run -d \
4. 选择 `@timestamp` 作为时间字段。
5. 去 **Discover** 页面,你就能看到 Nginx 容器的日志了。
-## 总结
+### 总结
通过 Docker 的日志驱动机制,结合 ELK/EFK 强大的收集和分析能力,我们可以轻松构建一个能够处理海量日志的监控平台,这对于排查生产问题至关重要。
diff --git a/10_ops/monitor/README.md b/10_ops/monitor/README.md
index 502fd63..2b6eea1 100644
--- a/10_ops/monitor/README.md
+++ b/10_ops/monitor/README.md
@@ -1,10 +1,10 @@
-# 容器监控
+## 容器监控
容器化技术的普及使得应用部署变得更加灵活和高效,但也给监控带来了新的挑战。
在传统架构中,我们通常关注主机的 CPU、内存、磁盘 IO 等指标。而在容器环境下,除了主机层面的监控,我们更关注容器级别的资源使用情况、服务的运行状态以及编排系统的健康状况。
-## 常见的监控方案
+### 常见的监控方案
目前主流的容器监控方案包括:
diff --git a/10_ops/monitor/prometheus.md b/10_ops/monitor/prometheus.md
index 72f6ea3..cb08b54 100644
--- a/10_ops/monitor/prometheus.md
+++ b/10_ops/monitor/prometheus.md
@@ -1,8 +1,8 @@
-# Prometheus + Grafana
+## Prometheus + Grafana
[Prometheus](https://prometheus.io/) 是一个开源的系统监控和报警工具包。它受 Google Borgmon 的启发,由 SoundCloud 在 2012 年创建。
-## 架构简介
+### 架构简介
Prometheus 的主要组件包括:
@@ -11,11 +11,11 @@ Prometheus 的主要组件包括:
* **Alertmanager**: 处理报警发送。
* **Pushgateway**: 用于支持短生命周期的 Job 推送数据。
-## 快速部署
+### 快速部署
我们可以使用 Docker Compose 快速部署一套 Prometheus + Grafana 监控环境。
-### 1. 准备配置文件
+#### 1. 准备配置文件
创建 `prometheus.yml`:
@@ -37,7 +37,7 @@ scrape_configs:
- targets: ['cadvisor:8080']
```
-### 2. 编写 Docker Compose 文件
+#### 2. 编写 Docker Compose 文件
创建 `docker-compose.yml`:
@@ -88,7 +88,7 @@ networks:
monitoring:
```
-### 3. 启动服务
+#### 3. 启动服务
```bash
$ docker-compose up -d
@@ -99,7 +99,7 @@ $ docker-compose up -d
* Prometheus: `http://localhost:9090`
* Grafana: `http://localhost:3000` (默认账号密码: admin/admin)
-## 配置 Grafana 面板
+### 配置 Grafana 面板
1. 在 Grafana 中添加 Prometheus 数据源,URL 填写 `http://prometheus:9090`。
2. 导入现成的 Dashboard 模板,例如 [Node Exporter Full](https://grafana.com/grafana/dashboards/1860) (ID: 1860) 和 [Docker Container](https://grafana.com/grafana/dashboards/193) (ID: 193)。
diff --git a/10_ops/security/README.md b/10_ops/security/README.md
index ff593ce..202da67 100644
--- a/10_ops/security/README.md
+++ b/10_ops/security/README.md
@@ -1,8 +1,8 @@
-# 安全
+## 安全
容器安全是生产环境部署的核心考量。本章介绍 Docker 的安全机制和最佳实践。
-## 容器安全的本质
+### 容器安全的本质
> **核心问题**:容器共享宿主机内核,隔离性弱于虚拟机。如何在便利性和安全性之间取得平衡?
@@ -23,9 +23,9 @@
---
-## 核心安全机制
+### 核心安全机制
-### 1. 命名空间(Namespace)
+#### 1. 命名空间(Namespace)
提供进程、网络、文件系统等资源的隔离:
@@ -38,24 +38,24 @@
| IPC | 进程通信 | 隔离共享内存 |
| UTS | 主机名 | 独立主机名 |
-详见 [命名空间](../13_implementation/namespace.md) 章节。
+详见 [命名空间](../13_implementation/13.2_namespace.md) 章节。
-### 2. 控制组(Cgroups)
+#### 2. 控制组(Cgroups)
限制容器的资源使用,防止资源耗尽攻击:
```bash
-# 限制内存(超出会被 OOM Kill)
+## 限制内存(超出会被 OOM Kill)
$ docker run -m 512m myapp
-# 限制 CPU
+## 限制 CPU
$ docker run --cpus=1.5 myapp
-# 限制磁盘 I/O
+## 限制磁盘 I/O
$ docker run --device-write-bps /dev/sda:10mb myapp
```
-### 3. 能力机制(Capabilities)
+#### 3. 能力机制(Capabilities)
Linux 将 root 权限拆分为多个细粒度的能力。Docker 默认禁用危险能力:
@@ -68,78 +68,78 @@ Linux 将 root 权限拆分为多个细粒度的能力。Docker 默认禁用危
| `CAP_NET_BIND_SERVICE` | 绑定低端口 | ✅ 启用 |
```bash
-# 删除所有能力,只添加需要的
+## 删除所有能力,只添加需要的
$ docker run --cap-drop=all --cap-add=NET_BIND_SERVICE myapp
-# 查看容器的能力
+## 查看容器的能力
$ docker exec myapp cat /proc/1/status | grep Cap
```
---
-## 镜像安全
+### 镜像安全
-### 使用可信镜像
+#### 使用可信镜像
```bash
-# ✅ 使用官方镜像
+## ✅ 使用官方镜像
$ docker pull nginx
-# ✅ 使用经过验证的镜像
+## ✅ 使用经过验证的镜像
$ docker pull bitnami/nginx
-# ⚠️ 谨慎使用未知来源镜像
+## ⚠️ 谨慎使用未知来源镜像
$ docker pull randomuser/suspicious-image
```
-### 漏洞扫描
+#### 漏洞扫描
扫描镜像中的已知安全漏洞:
```bash
-# Docker Scout(官方工具)
+## Docker Scout(官方工具)
$ docker scout cves nginx:latest
$ docker scout recommendations nginx:latest
-# Trivy(开源工具)
+## Trivy(开源工具)
$ trivy image nginx:latest
-# Snyk(商业工具)
+## Snyk(商业工具)
$ snyk container test nginx:latest
```
-### 镜像签名验证
+#### 镜像签名验证
使用 Docker Content Trust (DCT) 验证镜像来源:
```bash
-# 启用镜像签名验证
+## 启用镜像签名验证
$ export DOCKER_CONTENT_TRUST=1
-# 此后的 pull/push 会验证签名
+## 此后的 pull/push 会验证签名
$ docker pull myregistry/myimage:latest
```
---
-## 运行时安全
+### 运行时安全
-### 1. 非 root 用户运行
+#### 1. 非 root 用户运行
> 笔者强调:这是最重要的安全实践之一。
```dockerfile
FROM node:22-alpine
-# 创建非 root 用户
+## 创建非 root 用户
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
-# 设置工作目录权限
+## 设置工作目录权限
WORKDIR /app
COPY --chown=appuser:appgroup . .
-# 切换用户
+## 切换用户
USER appuser
CMD ["node", "server.js"]
@@ -151,27 +151,27 @@ CMD ["node", "server.js"]
$ docker run -u 1001:1001 myapp
```
-### 2. 只读文件系统
+#### 2. 只读文件系统
```bash
-# 根文件系统只读
+## 根文件系统只读
$ docker run --read-only myapp
-# 需要写入的目录使用 tmpfs
+## 需要写入的目录使用 tmpfs
$ docker run --read-only --tmpfs /tmp --tmpfs /var/run myapp
```
-### 3. 禁用特权模式
+#### 3. 禁用特权模式
```bash
-# ❌ 绝对不要在生产环境使用
+## ❌ 绝对不要在生产环境使用
$ docker run --privileged myapp
-# ✅ 只添加必要的能力
+## ✅ 只添加必要的能力
$ docker run --cap-add=SYS_TIME myapp
```
-### 4. 限制资源
+#### 4. 限制资源
```bash
$ docker run \
@@ -182,75 +182,75 @@ $ docker run \
myapp
```
-### 5. 网络隔离
+#### 5. 网络隔离
```bash
-# 禁用网络(适用于不需要网络的任务)
+## 禁用网络(适用于不需要网络的任务)
$ docker run --network=none myapp
-# 使用自定义网络隔离
+## 使用自定义网络隔离
$ docker network create --internal isolated_net
$ docker run --network=isolated_net myapp
```
---
-## Dockerfile 安全实践
+### Dockerfile 安全实践
-### 1. 使用精简基础镜像
+#### 1. 使用精简基础镜像
```dockerfile
-# ✅ 好:使用精简镜像
+## ✅ 好:使用精简镜像
FROM node:22-alpine # ~50MB
FROM gcr.io/distroless/nodejs # ~20MB
-# ❌ 差:使用完整镜像
+## ❌ 差:使用完整镜像
FROM node:22 # ~1GB
FROM ubuntu:24.04 # ~78MB
```
-### 2. 多阶段构建
+#### 2. 多阶段构建
```dockerfile
-# 构建阶段
+## 构建阶段
FROM node:22 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
-# 生产阶段(不包含开发依赖和源码)
+## 生产阶段(不包含开发依赖和源码)
FROM node:22-alpine
COPY --from=builder /app/dist /app
USER node
CMD ["node", "/app/server.js"]
```
-### 3. 不存储敏感信息
+#### 3. 不存储敏感信息
```dockerfile
-# ❌ 错误:敏感信息写入镜像
+## ❌ 错误:敏感信息写入镜像
ENV DB_PASSWORD=secret123
COPY .env /app/
-# ✅ 正确:运行时传入
-# docker run -e DB_PASSWORD=xxx 或使用 Docker Secrets
+## ✅ 正确:运行时传入
+## docker run -e DB_PASSWORD=xxx 或使用 Docker Secrets
```
-### 4. 固定依赖版本
+#### 4. 固定依赖版本
```dockerfile
-# ✅ 固定版本
+## ✅ 固定版本
FROM node:22.12.0-alpine3.21
RUN apk add --no-cache curl=8.5.0-r0
-# ❌ 使用 latest
+## ❌ 使用 latest
FROM node:latest
RUN apk add curl
```
---
-## 安全扫描清单
+### 安全扫描清单
部署前检查:
@@ -267,9 +267,9 @@ RUN apk add curl
---
-## 高级安全方案
+### 高级安全方案
-### Seccomp 系统调用过滤
+#### Seccomp 系统调用过滤
限制容器可以使用的系统调用:
@@ -277,7 +277,7 @@ RUN apk add curl
$ docker run --security-opt seccomp=/path/to/profile.json myapp
```
-### AppArmor / SELinux
+#### AppArmor / SELinux
使用强制访问控制:
@@ -285,48 +285,48 @@ $ docker run --security-opt seccomp=/path/to/profile.json myapp
$ docker run --security-opt apparmor=docker-default myapp
```
-### 安全容器(gVisor / Kata)
+#### 安全容器(gVisor / Kata)
需要更强隔离时:
```bash
-# 使用 gVisor 运行时
+## 使用 gVisor 运行时
$ docker run --runtime=runsc myapp
```
---
-## 软件供应链安全
+### 软件供应链安全
随着软件供应链攻击日益频繁,仅保障运行时安全已不足够。
-### 1. SBOM (软件物料清单)
+#### 1. SBOM (软件物料清单)
SBOM 类似于食品的配料表,列出了容器镜像中包含的所有软件包及其版本。
- **生成 SBOM**: 使用 `docker buildx build --sbom` 或 `docker scout sbom`。
- **管理 SBOM**: 确保持续监控 SBOM 中的组件是否存在新披露的漏洞。
-### 2. 镜像签名 (Sigstore / Notary v2)
+#### 2. 镜像签名 (Sigstore / Notary v2)
确保镜像在构建后未被篡改,且确实来自可信的发布者。
- **Cosign**: Sigstore 项目的一部分,用于签署和验证容器镜像。
```bash
-# 签署镜像
+## 签署镜像
$ cosign sign --key cosign.key myimage:tag
-# 验证镜像
+## 验证镜像
$ cosign verify --key cosign.pub myimage:tag
```
-### 3. SLSA (Supply-chain Levels for Software Artifacts)
+#### 3. SLSA (Supply-chain Levels for Software Artifacts)
遵循 SLSA 框架,确保构建过程的完整性,例如使用 GitHub Actions 等受控环境进行构建,而非在开发者本地机器上构建发布。
---
-## 本章小结
+### 本章小结
| 安全措施 | 重要程度 | 实现方式 |
|---------|---------|---------|
@@ -337,8 +337,8 @@ $ cosign verify --key cosign.pub myimage:tag
| 最小能力 | ⭐⭐ | `--cap-drop=all` |
| 镜像签名 | ⭐⭐ | Docker Content Trust |
-## 延伸阅读
+### 延伸阅读
-- [命名空间](../13_implementation/namespace.md):隔离机制详解
-- [控制组](../13_implementation/cgroups.md):资源限制详解
-- [最佳实践](../15_appendix/best_practices.md):Dockerfile 安全配置
+- [命名空间](../13_implementation/13.2_namespace.md):隔离机制详解
+- [控制组](../13_implementation/13.3_cgroups.md):资源限制详解
+- [最佳实践](../15_appendix/15.1_best_practices.md):Dockerfile 安全配置
diff --git a/10_ops/security/control_group.md b/10_ops/security/control_group.md
index 338f5f9..29bfec5 100644
--- a/10_ops/security/control_group.md
+++ b/10_ops/security/control_group.md
@@ -1,4 +1,4 @@
-# 控制组
+## 控制组
控制组是 Linux 容器机制的另外一个关键组件,负责实现资源的审计和限制。
diff --git a/10_ops/security/daemon_sec.md b/10_ops/security/daemon_sec.md
index 81c8627..a8f4251 100644
--- a/10_ops/security/daemon_sec.md
+++ b/10_ops/security/daemon_sec.md
@@ -1,4 +1,4 @@
-# Docker服务端的防护
+## Docker服务端的防护
运行一个容器或应用程序的核心是通过 Docker 服务端。Docker 服务的运行目前需要 root 权限,因此其安全性十分关键。
diff --git a/10_ops/security/kernel_capability.md b/10_ops/security/kernel_capability.md
index 8d48b27..a11528a 100644
--- a/10_ops/security/kernel_capability.md
+++ b/10_ops/security/kernel_capability.md
@@ -1,4 +1,4 @@
-# 内核能力机制
+## 内核能力机制
[能力机制(Capability)](https://man7.org/linux/man-pages/man7/capabilities.7.html) 是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。
Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。
diff --git a/10_ops/security/kernel_ns.md b/10_ops/security/kernel_ns.md
index b14e4c2..ae7f5ff 100644
--- a/10_ops/security/kernel_ns.md
+++ b/10_ops/security/kernel_ns.md
@@ -1,4 +1,4 @@
-# 内核命名空间
+## 内核命名空间
Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。当用 `docker run` 启动一个容器时,在后台 Docker 为容器创建了一个独立的命名空间和控制组集合。
diff --git a/10_ops/security/other_feature.md b/10_ops/security/other_feature.md
index 2486cfe..4f098ce 100644
--- a/10_ops/security/other_feature.md
+++ b/10_ops/security/other_feature.md
@@ -1,4 +1,4 @@
-# 其它安全特性
+## 其它安全特性
除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, Seccomp, SELinux, GRSEC 等。
diff --git a/10_ops/security/summary.md b/10_ops/security/summary.md
index ac78992..4ca50e9 100644
--- a/10_ops/security/summary.md
+++ b/10_ops/security/summary.md
@@ -1,4 +1,4 @@
-# 总结
+## 总结
总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。
diff --git a/11_orchestration/README.md b/11_orchestration/README.md
index 28bcc31..cf2cda0 100644
--- a/11_orchestration/README.md
+++ b/11_orchestration/README.md
@@ -1,4 +1,4 @@
-# 容器编排
+# 第十一章 容器编排
本章将介绍容器编排相关的技术与工具。
diff --git a/11_orchestration/etcd/README.md b/11_orchestration/etcd/README.md
index e5664d5..8eda09c 100644
--- a/11_orchestration/etcd/README.md
+++ b/11_orchestration/etcd/README.md
@@ -1,3 +1,3 @@
-# etcd
+## etcd
`etcd` 是 `CoreOS` 团队发起的一个管理配置信息和服务发现(`Service Discovery`)的项目,在这一章里面,我们将基于 `etcd 3.x` 版本介绍该项目的目标,安装和使用,以及实现的技术。
diff --git a/11_orchestration/etcd/cluster.md b/11_orchestration/etcd/cluster.md
index 3b565b5..ed86779 100644
--- a/11_orchestration/etcd/cluster.md
+++ b/11_orchestration/etcd/cluster.md
@@ -1,4 +1,4 @@
-# etcd 集群
+## etcd 集群
下面我们使用 [Docker Compose](../compose/) 模拟启动一个 3 节点的 `etcd` 集群。
diff --git a/11_orchestration/etcd/etcdctl.md b/11_orchestration/etcd/etcdctl.md
index 29c0f0d..e9d398a 100644
--- a/11_orchestration/etcd/etcdctl.md
+++ b/11_orchestration/etcd/etcdctl.md
@@ -1,4 +1,4 @@
-# 使用 etcdctl
+## 使用 etcdctl
`etcdctl` 是一个命令行客户端,它能提供一些简洁的命令,供用户直接跟 `etcd` 服务打交道,而无需基于 `HTTP API` 方式。这在某些情况下将很方便,例如用户对服务进行测试或者手动修改数据库内容。我们也推荐在刚接触 `etcd` 时通过 `etcdctl` 命令来熟悉相关的操作,这些操作跟 `HTTP API` 实际上是对应的。
@@ -81,7 +81,7 @@ OPTIONS:
-w, --write-out="simple" set the output format (fields, json, protobuf, simple, table)
```
-## 数据库操作
+### 数据库操作
数据库操作围绕对键值和目录的 CRUD (符合 REST 风格的一套操作:Create)完整生命周期的管理。
@@ -89,14 +89,14 @@ etcd 在键的组织上采用了层次化的空间结构(类似于文件系统
>注:CRUD 即 Create, Read, Update, Delete,是符合 REST 风格的一套 API 操作。
-### put
+#### put
```bash
$ etcdctl put /testdir/testkey "Hello world"
OK
```
-### get
+#### get
获取指定键的值。例如
@@ -114,7 +114,7 @@ hello
`--consistent` 将请求发给主节点,保证获取内容的一致性
-### del
+#### del
删除某个键值。例如
@@ -123,9 +123,9 @@ $ etcdctl del testkey
1
```
-## 非数据库操作
+### 非数据库操作
-### watch
+#### watch
监测一个键值的变化,一旦键值发生更新,就会输出最新的值。
@@ -138,7 +138,7 @@ testkey
2
```
-### member
+#### member
通过 `list`、`add`、`update`、`remove` 命令列出、添加、更新、删除 etcd 实例到 etcd 集群中。
diff --git a/11_orchestration/etcd/install.md b/11_orchestration/etcd/install.md
index 5366f1e..cae1960 100644
--- a/11_orchestration/etcd/install.md
+++ b/11_orchestration/etcd/install.md
@@ -1,10 +1,10 @@
-# 安装
+## 安装
`etcd` 基于 `Go` 语言实现,因此,用户可以从 [项目主页](https://github.com/etcd-io/etcd) 下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 `Docker` 镜像文件来体验。
>注意:本章节内容基于 etcd `3.4.x` 版本
-## 二进制文件方式下载
+### 二进制文件方式下载
编译好的二进制文件都在 [github.com/etcd-io/etcd/releases](https://github.com/etcd-io/etcd/releases/) 页面,用户可以选择需要的版本,或通过下载工具下载。
@@ -13,7 +13,7 @@
```bash
$ curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz
-# 国内用户可以使用以下方式加快下载
+## 国内用户可以使用以下方式加快下载
$ curl -L https://download.fastgit.org/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz
$ tar xzvf etcd-v3.4.0-linux-amd64.tar.gz
@@ -60,7 +60,7 @@ hello world
说明 etcd 服务已经成功启动了。
-## Docker 镜像方式运行
+### Docker 镜像方式运行
镜像名称为 `quay.io/coreos/etcd`,可以通过下面的命令启动 `etcd` 服务监听到 `2379` 和 `2380` 端口。
@@ -88,7 +88,7 @@ quay.io/coreos/etcd:v3.4.0 \
打开新的终端按照上一步的方法测试 `etcd` 是否成功启动。
-## macOS 中运行
+### macOS 中运行
```bash
$ brew install etcd
diff --git a/11_orchestration/etcd/intro.md b/11_orchestration/etcd/intro.md
index da808ae..9aba55b 100644
--- a/11_orchestration/etcd/intro.md
+++ b/11_orchestration/etcd/intro.md
@@ -1,4 +1,4 @@
-# 简介
+## 简介

diff --git a/11_orchestration/kubectl/README.md b/11_orchestration/kubectl/README.md
index 19e16a9..493a096 100644
--- a/11_orchestration/kubectl/README.md
+++ b/11_orchestration/kubectl/README.md
@@ -1,4 +1,4 @@
-# kubectl 使用
+## kubectl 使用
[kubectl](https://github.com/kubernetes/kubernetes) 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes。
@@ -8,74 +8,74 @@ kubectl [flags]
kubectl [command]
```
-## get
+### get
显示一个或多个资源
-## describe
+### describe
显示资源详情
-## create
+### create
从文件或标准输入创建资源
-## update
+### update
从文件或标准输入更新资源
-## delete
+### delete
通过文件名、标准输入、资源名或者 label selector 删除资源
-## log
+### log
输出 pod 中一个容器的日志
-## rolling-update
+### rolling-update
对指定的 replication controller 执行滚动升级
-## exec
+### exec
在容器内部执行命令
-## port-forward
+### port-forward
将本地端口转发到Pod
-## proxy
+### proxy
为 Kubernetes API server 启动代理服务器
-## run
+### run
在集群中使用指定镜像启动容器
-## expose
+### expose
将 replication controller service 或 pod 暴露为新的 kubernetes service
-## label
+### label
更新资源的 label
-## config
+### config
修改 kubernetes 配置文件
-## cluster-info
+### cluster-info
显示集群信息
-## api-versions
+### api-versions
以 "组/版本" 的格式输出服务端支持的 API 版本
-## version
+### version
输出服务端和客户端的版本信息
-## help
+### help
显示各个命令的帮助信息
diff --git a/11_orchestration/kubernetes/README.md b/11_orchestration/kubernetes/README.md
index d54cbb5..5362b76 100644
--- a/11_orchestration/kubernetes/README.md
+++ b/11_orchestration/kubernetes/README.md
@@ -1,4 +1,4 @@
-# Kubernetes
+## Kubernetes
`Kubernetes` 是 Google 团队发起并维护的基于 Docker 的开源容器集群管理系统,它不仅支持常见的云平台,而且支持内部数据中心。
diff --git a/11_orchestration/kubernetes/advanced.md b/11_orchestration/kubernetes/advanced.md
index 878afcb..b16b4ca 100644
--- a/11_orchestration/kubernetes/advanced.md
+++ b/11_orchestration/kubernetes/advanced.md
@@ -1,8 +1,8 @@
-# Kubernetes 高级特性
+## Kubernetes 高级特性
掌握了 Kubernetes 的核心概念(Pod, Service, Deployment)后,我们需要了解更多高级特性以构建生产级应用。
-## Helm - 包管理工具
+### Helm - 包管理工具
[Helm](https://helm.sh/) 被称为 Kubernetes 的包管理器(类似于 Linux 的 apt/yum)。它将一组 Kubernetes 资源定义文件打包为一个 **Chart**。
@@ -10,7 +10,7 @@
* **版本管理**:轻松回滚应用的发布版本。
* **模板化**:支持复杂的应用部署逻辑配置。
-## Ingress - 服务的入口
+### Ingress - 服务的入口
Service 虽然提供了负载均衡,但通常是 4 层(TCP/UDP)。**Ingress** 提供了 7 层(HTTP/HTTPS)路由能力,充当集群的网关。
@@ -20,7 +20,7 @@ Service 虽然提供了负载均衡,但通常是 4 层(TCP/UDP)。**Ingres
常见的 Ingress Controller有 Nginx Ingress Controller, Traefik, Istio Gateway 等。
-## Persistent Volume (PV) 与 StorageClass
+### Persistent Volume (PV) 与 StorageClass
容器内的文件是临时的。对于有状态应用(如数据库),需要持久化存储。
@@ -28,7 +28,7 @@ Service 虽然提供了负载均衡,但通常是 4 层(TCP/UDP)。**Ingres
* **PV (Persistent Volume)**:实际的存储资源(NFS, AWS EBS, Ceph 等)。
* **StorageClass**:定义存储类,支持动态创建 PV。
-## Horizontal Pod Autoscaling (HPA)
+### Horizontal Pod Autoscaling (HPA)
HPA 根据 CPU 利用率或其他指标(如内存、自定义指标)自动扩缩 Deployment 或 ReplicaSet 中的 Pod 数量。
@@ -53,7 +53,7 @@ spec:
averageUtilization: 50
```
-## ConfigMap 与 Secret
+### ConfigMap 与 Secret
* **ConfigMap**:存储非机密的配置数据(配置文件、环境变量)。
* **Secret**:存储机密数据(密码、Token、证书),在 Etcd 中加密存储。
diff --git a/11_orchestration/kubernetes/concepts.md b/11_orchestration/kubernetes/concepts.md
index 5587133..f3ca6db 100644
--- a/11_orchestration/kubernetes/concepts.md
+++ b/11_orchestration/kubernetes/concepts.md
@@ -1,4 +1,4 @@
-# 基本概念
+## 基本概念

@@ -13,27 +13,27 @@
* web 界面(`ux`):用户可以通过 web 界面操作 Kubernetes。
* 命令行操作(`cli`):`kubectl`命令。
-## 节点
+### 节点
在 `Kubernetes` 中,节点是实际工作的点,节点可以是虚拟机或者物理机器,依赖于一个集群环境。每个节点都有一些必要的服务以运行容器组,并且它们都可以通过主节点来管理。必要服务包括 Docker,kubelet 和代理服务。
-### 容器状态
+#### 容器状态
容器状态用来描述节点的当前状态。现在,其中包含三个信息:
-#### 主机IP
+##### 主机IP
主机 IP 需要云平台来查询,`Kubernetes` 把它作为状态的一部分来保存。如果 `Kubernetes` 没有运行在云平台上,节点 ID 就是必需的。IP 地址可以变化,并且可以包含多种类型的 IP 地址,如公共 IP,私有 IP,动态 IP,ipv6 等等。
-#### 节点周期
+##### 节点周期
通常来说节点有 `Pending`,`Running`,`Terminated` 三个周期,如果 Kubernetes 发现了一个节点并且其可用,那么 Kubernetes 就把它标记为 `Pending`。然后在某个时刻,Kubernetes 将会标记其为 `Running`。节点的结束周期称为 `Terminated`。一个已经 `Terminated` 的节点不会接受和调度任何请求,并且已经在其上运行的容器组也会删除。
-#### 节点状态
+##### 节点状态
节点的状态主要是用来描述处于 `Running` 的节点。当前可用的有 `NodeReachable` 和 `NodeReady`。以后可能会增加其他状态。`NodeReachable` 表示集群可达。`NodeReady` 表示 kubelet 返回 Status Ok 并且 HTTP 状态检查健康。
-### 节点管理
+#### 节点管理
节点并非 Kubernetes 创建,而是由云平台创建,或者就是物理机器、虚拟机。在 Kubernetes 中,节点仅仅是一条记录,节点创建之后,Kubernetes 会检查其是否可用。在 Kubernetes 中,节点用如下结构保存:
@@ -56,7 +56,7 @@
Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接口可以用来管理节点:节点控制和 Kube 管理。
-### 节点控制
+#### 节点控制
在 Kubernetes 主节点中,节点控制器是用来管理节点的组件。主要包含:
@@ -65,15 +65,15 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
节点控制有一个同步轮询,主要监听所有云平台的虚拟实例,会根据节点状态创建和删除。可以通过 `--node_sync_period`标志来控制该轮询。如果一个实例已经创建,节点控制将会为其创建一个结构。同样的,如果一个节点被删除,节点控制也会删除该结构。在 Kubernetes 启动时可用通过 `--machines`标记来显示指定节点。同样可以使用 `kubectl` 来一条一条的添加节点,两者是相同的。通过设置 `--sync_nodes=false`标记来禁止集群之间的节点同步,你也可以使用 api/kubectl 命令行来增删节点。
-## 容器组
+### 容器组
在 Kubernetes 中,使用的最小单位是容器组,容器组是创建,调度,管理的最小单位。 一个容器组使用相同的 Docker 容器并共享卷(挂载点)。一个容器组是一个特定应用的打包集合,包含一个或多个容器。
和运行的容器类似,一个容器组被认为只有很短的运行周期。容器组被调度到一组节点运行,直到容器的生命周期结束或者其被删除。如果节点死掉,运行在其上的容器组将会被删除而不是重新调度。(也许在将来的版本中会添加容器组的移动)。
-### 容器组设计的初衷
+#### 容器组设计的初衷
-### 资源共享和通信
+#### 资源共享和通信
容器组主要是为了数据共享和它们之间的通信。
@@ -81,11 +81,11 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
容器组有一组存储卷(挂载点),主要是为了让容器在重启之后可以不丢失数据。
-### 容器组管理
+#### 容器组管理
容器组是一个应用管理和部署的高层次抽象,同时也是一组容器的接口。容器组是部署、水平放缩的最小单位。
-### 容器组的使用
+#### 容器组的使用
容器组可以通过组合来构建复杂的应用,其本来的意义包含:
@@ -95,7 +95,7 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
* 代理,网桥
* 控制器,管理,配置以及更新
-### 替代方案
+#### 替代方案
为什么不在一个单一的容器里运行多个程序?
@@ -104,27 +104,27 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
* 3.方便使用。用户不必运行独立的程序管理,也不用担心每个应用程序的退出状态。
* 4.高效。考虑到基础设施有更多的职责,容器必须要轻量化。
-### 容器组的生命状态
+#### 容器组的生命状态
包括若干状态值:`pending`、`running`、`succeeded`、`failed`。
-#### pending
+##### pending
容器组已经被节点接受,但有一个或多个容器还没有运行起来。这将包含某些节点正在下载镜像的时间,这种情形会依赖于网络情况。
-#### running
+##### running
容器组已经被调度到节点,并且所有的容器都已经启动。至少有一个容器处于运行状态(或者处于重启状态)。
-#### succeeded
+##### succeeded
所有的容器都正常退出。
-#### failed
+##### failed
容器组中所有容器都意外中断了。
-### 容器组生命周期
+#### 容器组生命周期
通常来说,如果容器组被创建了就不会自动销毁,除非被某种行为触发,而触发此种情况可能是人为,或者复制控制器所为。唯一例外的是容器组由 succeeded 状态成功退出,或者在一定时间内重试多次依然失败。
@@ -173,16 +173,16 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
* 节点控制器标记容器组 `failed`
* 如果容器组运行在一个控制器下,容器组将会在其他地方重新创建
-## Replication Controllers
+### Replication Controllers
-## 服务
+### 服务
-## 卷
+### 卷
-## 标签
+### 标签
-## 接口权限
+### 接口权限
-## web界面
+### web界面
-## 命令行操作
+### 命令行操作
diff --git a/11_orchestration/kubernetes/design.md b/11_orchestration/kubernetes/design.md
index 45c2a68..b3f5c42 100644
--- a/11_orchestration/kubernetes/design.md
+++ b/11_orchestration/kubernetes/design.md
@@ -1,8 +1,8 @@
-# 架构设计
+## 架构设计
任何优秀的项目都离不开优秀的架构设计。本小节将介绍 Kubernetes 在架构方面的设计考虑。
-## 基本考虑
+### 基本考虑
如果让我们自己从头设计一套容器管理平台,有如下几个方面是很容易想到的:
@@ -11,7 +11,7 @@
* 一套资源调度系统,管理哪个容器该分配到哪个节点上;
* 一套对容器内服务进行抽象和 HA 的系统。
-## 运行原理
+### 运行原理
下面这张图完整展示了 Kubernetes 的运行原理。
@@ -23,9 +23,9 @@
从这张图上,我们没有能发现 Kubernetes 中对于控制平面的分布式实现,但是由于数据后端自身就是一套分布式的数据库 Etcd,因此可以很容易扩展到分布式实现。
-## 控制平面
+### 控制平面
-### 主节点服务
+#### 主节点服务
主节点上需要提供如下的管理服务:
@@ -33,7 +33,7 @@
* `scheduler` 负责对资源进行调度,分配某个 pod 到某个节点上。是 pluggable 的,意味着很容易选择其它实现方式;
* `controller-manager` 负责管理控制器,包括 endpoint-controller(刷新服务和 pod 的关联信息)和 replication-controller(维护某个 pod 的复制为配置的数值)。
-### Etcd
+#### Etcd
这里 Etcd 即作为数据后端,又作为消息中间件。
@@ -41,7 +41,7 @@
组件可以自动的去侦测 Etcd 中的数值变化来获得通知,并且获得更新后的数据来执行相应的操作。
-## 工作节点
+### 工作节点
* kubelet 是工作节点执行操作的 agent,负责具体的容器生命周期管理,根据从数据库中获取的信息来管理容器,并上报 pod 运行状态等;
* kube-proxy 是一个简单的网络访问代理,同时也是一个 Load Balancer。它负责将访问到某个服务的请求具体分配给工作节点上的 Pod(同一类标签)。
diff --git a/11_orchestration/kubernetes/intro.md b/11_orchestration/kubernetes/intro.md
index 625d1a8..d98d220 100644
--- a/11_orchestration/kubernetes/intro.md
+++ b/11_orchestration/kubernetes/intro.md
@@ -1,8 +1,8 @@
-# Kubernetes 简介
+## Kubernetes 简介

-## 什么是 Kubernetes
+### 什么是 Kubernetes
Kubernetes(常简称为 K8s)是 Google 开源的容器编排引擎。如果说 Docker 解决了"如何打包和运送集装箱"的问题,那么 Kubernetes 解决的就是"如何管理海量集装箱的调度、运行和维护"的问题。
@@ -12,7 +12,7 @@ Kubernetes(常简称为 K8s)是 Google 开源的容器编排引擎。如果
---
-## 为什么需要 Kubernetes
+### 为什么需要 Kubernetes
当我们在单机运行几个容器时,Docker Compose 就足够了。但在生产环境中,我们需要面对:
@@ -26,26 +26,26 @@ Kubernetes 完美解决了这些问题。
---
-## 核心概念
+### 核心概念
-### Pod (豆荚)
+#### Pod (豆荚)
Kubernetes 的最小调度单位。一个 Pod 可以包含一个或多个紧密协作的容器(共享网络和存储)。就像豌豆荚里的豌豆一样。
-### Node (节点)
+#### Node (节点)
运行 Pod 的物理机或虚拟机。
-### Deployment (部署)
+#### Deployment (部署)
定义应用的期望状态(如:需要 3 个副本,镜像版本为 v1)。K8s 会持续确保当前状态符合期望状态。
-### Service (服务)
+#### Service (服务)
定义一组 Pod 的访问策略。提供稳定的 Cluster IP 和 DNS 名称,负责负载均衡。
-### Namespace (命名空间)
+#### Namespace (命名空间)
用于多租户资源隔离。
---
-## Docker 用户如何过渡
+### Docker 用户如何过渡
如果你已经熟悉 Docker,学习 K8s 会很容易:
@@ -58,7 +58,7 @@ Kubernetes 的最小调度单位。一个 Pod 可以包含一个或多个紧密
---
-## 架构
+### 架构
Kubernetes 也是 C/S 架构,由 **Master (控制平面)** 和 **Worker (工作节点)** 组成:
@@ -67,7 +67,7 @@ Kubernetes 也是 C/S 架构,由 **Master (控制平面)** 和 **Worker (工
---
-## 学习建议
+### 学习建议
Kubernetes 的学习曲线较陡峭。建议的学习路径:
1. **理解基本概念**:Pod, Deployment, Service
@@ -77,7 +77,7 @@ Kubernetes 的学习曲线较陡峭。建议的学习路径:
---
-## 延伸阅读
+### 延伸阅读
- [Minikube 安装](../kubernetes/setup/README.md):本地体验 K8s
- [Kubernetes 官网](https://kubernetes.io/):官方文档
diff --git a/11_orchestration/kubernetes/practice.md b/11_orchestration/kubernetes/practice.md
index 2313377..abbdcd0 100644
--- a/11_orchestration/kubernetes/practice.md
+++ b/11_orchestration/kubernetes/practice.md
@@ -1,14 +1,14 @@
-# Kubernetes 实战练习
+## Kubernetes 实战练习
本章将通过一个具体的案例:部署一个 Nginx 网站,并为其配置 Service 和 Ingress,来串联前面学到的知识。
-## 目标
+### 目标
1. 部署一个 Nginx Deployment。
2. 创建一个 Service 暴露 Nginx。
3. (可选)通过 Ingress 访问服务。
-## 步骤 1:创建 Deployment
+### 步骤 1:创建 Deployment
创建一个名为 `nginx-deployment.yaml` 的文件:
@@ -42,7 +42,7 @@ spec:
kubectl apply -f nginx-deployment.yaml
```
-## 步骤 2:创建 Service
+### 步骤 2:创建 Service
创建一个名为 `nginx-service.yaml` 的文件:
@@ -75,7 +75,7 @@ kubectl get svc nginx-service
如果输出端口是 `80:30080/TCP`,你可以通过 `http://:30080` 访问 Nginx。
-## 步骤 3:模拟滚动更新 (Rolling Update)
+### 步骤 3:模拟滚动更新 (Rolling Update)
修改 `nginx-deployment.yaml`,将镜像版本改为 `nginx:latest`。
@@ -89,7 +89,7 @@ kubectl apply -f nginx-deployment.yaml
kubectl rollout status deployment/nginx-deployment
```
-## 步骤 4:清理资源
+### 步骤 4:清理资源
练习结束后,记得清理资源:
diff --git a/11_orchestration/setup/README.md b/11_orchestration/setup/README.md
index 4275d0d..101db67 100644
--- a/11_orchestration/setup/README.md
+++ b/11_orchestration/setup/README.md
@@ -1,4 +1,4 @@
-# 部署 Kubernetes
+## 部署 Kubernetes
目前,Kubernetes 支持在多种环境下使用,包括本地主机(Ubuntu、Debian、CentOS、Fedora 等)、云服务([腾讯云](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61)、[阿里云](https://www.aliyun.com/product/kubernetes?source=5176.11533457&userCode=8lx5zmtu&type=copy)、[百度云](https://cloud.baidu.com/product/cce.html) 等)。
diff --git a/11_orchestration/setup/dashboard.md b/11_orchestration/setup/dashboard.md
index 0c51b1c..4170b3c 100644
--- a/11_orchestration/setup/dashboard.md
+++ b/11_orchestration/setup/dashboard.md
@@ -1,10 +1,10 @@
-# Kubernetes Dashboard
+## Kubernetes Dashboard
[Kubernetes Dashboard](https://github.com/kubernetes/dashboard) 是基于网页的 Kubernetes 用户界面。

-## 部署
+### 部署
执行以下命令即可部署 Dashboard:
@@ -12,7 +12,7 @@
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
```
-## 访问
+### 访问
通过命令行代理访问,执行以下命令:
@@ -22,7 +22,7 @@ $ kubectl proxy
到 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 即可访问。
-## 登录
+### 登录
目前,Dashboard 仅支持使用 Bearer 令牌登录。下面教大家如何创建该令牌:
@@ -40,6 +40,6 @@ echo ${DASHBOARD_LOGIN_TOKEN}
将结果粘贴到登录页面,即可登录。
-## 参考文档
+### 参考文档
* [官方文档](https://kubernetes.io/zh/docs/tasks/access-application-cluster/web-ui-dashboard/)
diff --git a/11_orchestration/setup/docker-desktop.md b/11_orchestration/setup/docker-desktop.md
index 559649f..f32b186 100644
--- a/11_orchestration/setup/docker-desktop.md
+++ b/11_orchestration/setup/docker-desktop.md
@@ -1,8 +1,8 @@
-# Docker Desktop 启用 Kubernetes
+## Docker Desktop 启用 Kubernetes
使用 Docker Desktop 可以很方便的启用 Kubernetes。
-## 启用 Kubernetes
+### 启用 Kubernetes
在 Docker Desktop 设置页面,点击 `Kubernetes`,选择 `Enable Kubernetes`,稍等片刻,看到左下方 `Kubernetes` 变为 `running`,Kubernetes 启动成功。
@@ -10,7 +10,7 @@
> 注意:Kubernetes 的镜像存储在 `registry.k8s.io`,如果国内网络无法直接访问,可以在 Docker Desktop 配置中的 `Docker Engine` 处配置镜像加速器,或者利用国内云服务商的镜像仓库手动拉取镜像并 retag。
-## 测试
+### 测试
```bash
$ kubectl version
diff --git a/11_orchestration/setup/k3s.md b/11_orchestration/setup/k3s.md
index cb28050..c750858 100644
--- a/11_orchestration/setup/k3s.md
+++ b/11_orchestration/setup/k3s.md
@@ -1,17 +1,17 @@
-# K3s - 轻量级 Kubernetes
+## K3s - 轻量级 Kubernetes
[K3s](https://k3s.io/) 是一个轻量级的 Kubernetes 发行版,由 Rancher Labs 开发。它专为边缘计算、物联网、CI、ARM 等资源受限的环境设计。K3s 被打包为单个二进制文件,只有不到 100MB,但通过了 CNCF 的一致性测试。
-## 核心特性
+### 核心特性
* **轻量级**:移除过时的、非必须的 Kubernetes 功能(如传统的云提供商插件),使用 SQLite 作为默认数据存储(也支持 Etcd/MySQL/Postgres)。
* **单一二进制**:所有组件(API Server, Controller Manager, Scheduler, Kubelet, Kube-proxy)打包在一个进程中运行。
* **开箱即用**:内置 Helm Controller、Traefik Ingress controller、ServiceLB、Local-Path-Provisioner。
* **安全**:默认启用安全配置,基于 TLS 通信。
-## 安装
+### 安装
-### 脚本安装(Linux)
+#### 脚本安装(Linux)
K3s 提供了极为便捷的安装脚本:
@@ -21,7 +21,7 @@ curl -sfL https://get.k3s.io | sh -
安装完成后,K3s 会自动启动并配置好 `systemd` 服务。
-### 查看状态
+#### 查看状态
```bash
sudo k3s kubectl get nodes
@@ -33,19 +33,19 @@ NAME STATUS ROLES AGE VERSION
k3s-master Ready control-plane,master 1m v1.28.2+k3s1
```
-## 快速使用
+### 快速使用
K3s 内置了 `kubectl` 命令(通过 `k3s kubectl` 调用),为了方便,通常会建立别名或配置 `KUBECONFIG`。
```bash
-# 读取 K3s 的配置文件
+## 读取 K3s 的配置文件
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
-# 现在可以直接使用 kubectl
+## 现在可以直接使用 kubectl
kubectl get pods -A
```
-## 清理卸载
+### 清理卸载
```bash
/usr/local/bin/k3s-uninstall.sh
diff --git a/11_orchestration/setup/kind.md b/11_orchestration/setup/kind.md
index 4fa9ddf..202d481 100644
--- a/11_orchestration/setup/kind.md
+++ b/11_orchestration/setup/kind.md
@@ -1,34 +1,34 @@
-# Kind - Kubernetes IN Docker
+## Kind - Kubernetes IN Docker
[Kind](https://kind.sigs.k8s.io/) (Kubernetes in Docker) 是一个使用 Docker 容器作为节点运行本地 Kubernetes 集群的工具。主要用于测试 Kubernetes 本身,也非常适合本地开发和 CI 环境。
-## 为什么选择 Kind
+### 为什么选择 Kind
* **轻量便捷**:只要有 Docker 环境即可,无需额外虚拟机。
* **多集群支持**:可以轻松在本地启动多个集群。
* **多版本支持**:支持指定 Kubernetes 版本进行测试。
* **HA 支持**:支持模拟高可用集群(多 Control Plane)。
-## 安装 Kind
+### 安装 Kind
-### macOS
+#### macOS
```bash
brew install kind
```
-### Linux / Windows (WSL2)
+#### Linux / Windows (WSL2)
可以下载二进制文件:
```bash
-# Linux AMD64
+## Linux AMD64
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
```
-## 创建集群
+### 创建集群
最简单的创建方式:
@@ -42,7 +42,7 @@ kind create cluster
kind create cluster --name my-cluster
```
-## 与集群交互
+### 与集群交互
Kind 会自动将 kubeconfig 合并到 `~/.kube/config`。
@@ -51,7 +51,7 @@ kubectl cluster-info --context kind-kind
kubectl get nodes
```
-## 高级用法:配置集群
+### 高级用法:配置集群
创建一个 `kind-config.yaml` 来定制集群,例如映射端口到宿主机:
@@ -74,7 +74,7 @@ nodes:
kind create cluster --config kind-config.yaml
```
-## 删除集群
+### 删除集群
```bash
kind delete cluster
diff --git a/11_orchestration/setup/kubeadm-docker.md b/11_orchestration/setup/kubeadm-docker.md
index 9f5b0a2..facfd61 100644
--- a/11_orchestration/setup/kubeadm-docker.md
+++ b/11_orchestration/setup/kubeadm-docker.md
@@ -1,14 +1,14 @@
-# 使用 kubeadm 部署 kubernetes(使用 Docker)
+## 使用 kubeadm 部署 kubernetes(使用 Docker)
`kubeadm` 提供了 `kubeadm init` 以及 `kubeadm join` 这两个命令作为快速创建 `kubernetes` 集群的最佳实践。
-## 安装 Docker
+### 安装 Docker
参考 [安装 Docker](../../install) 一节安装 Docker。
-## 安装 **kubelet** **kubeadm** **kubectl**
+### 安装 **kubelet** **kubeadm** **kubectl**
-### Ubuntu/Debian
+#### Ubuntu/Debian
```bash
$ apt-get update && apt-get install -y apt-transport-https
@@ -22,7 +22,7 @@ $ apt-get update
$ apt-get install -y kubelet kubeadm kubectl
```
-### CentOS/Fedora
+#### CentOS/Fedora
```bash
$ cat < **版本说明**:Kubernetes 版本更新较快(约每 4 个月一个新版本),本文档基于 Kubernetes 1.35 编写。请访问 [Kubernetes 官方发布页](https://kubernetes.io/releases/) 获取最新版本信息。
-## 安装 containerd
+### 安装 containerd
参考 [安装 Docker](../../install) 一节添加 apt/yum 源,之后执行如下命令。
```bash
-# debian 系
+## debian 系
$ sudo apt install containerd.io
-# rhel 系
+## rhel 系
$ sudo yum install containerd.io
```
-## 配置 containerd
+### 配置 containerd
新建 `/etc/systemd/system/cri-containerd.service` 文件
@@ -35,13 +35,13 @@ Delegate=yes
KillMode=process
Restart=always
RestartSec=5
-# Having non-zero Limit*s causes performance problems due to accounting overhead
-# in the kernel. We recommend using cgroups to do container-local accounting.
+## Having non-zero Limit*s causes performance problems due to accounting overhead
+## in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
-# Comment TasksMax if your systemd version does not supports it.
-# Only systemd 226 and above support this version.
+## Comment TasksMax if your systemd version does not supports it.
+## Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
@@ -53,14 +53,14 @@ WantedBy=multi-user.target
```toml
version = 2
-# persistent data location
+## persistent data location
root = "/var/lib/cri-containerd"
-# runtime state information
+## runtime state information
state = "/run/cri-containerd"
plugin_dir = ""
disabled_plugins = []
required_plugins = []
-# set containerd's OOM score
+## set containerd's OOM score
oom_score = 0
[grpc]
@@ -201,9 +201,9 @@ oom_score = 0
async_remove = false
```
-## 安装 **kubelet** **kubeadm** **kubectl** **cri-tools** **kubernetes-cni**
+### 安装 **kubelet** **kubeadm** **kubectl** **cri-tools** **kubernetes-cni**
-### Ubuntu/Debian
+#### Ubuntu/Debian
```bash
$ apt-get update && apt-get install -y apt-transport-https
@@ -217,7 +217,7 @@ $ apt-get update
$ apt-get install -y kubelet kubeadm kubectl
```
-### CentOS/Fedora
+#### CentOS/Fedora
```bash
$ cat < example.ign
```
-## 挂载 ISO 启动虚拟机并安装
+### 挂载 ISO 启动虚拟机并安装
> 虚拟机需要分配 3GB 以上内存,否则会无法启动。
@@ -39,7 +39,7 @@ $ sudo coreos-installer install /dev/sda --ignition-file example.ign
安装之后重新启动即可使用。
-## 使用
+### 使用
```bash
$ ssh core@虚拟机IP
@@ -47,6 +47,6 @@ $ ssh core@虚拟机IP
$ docker --version
```
-## 参考链接
+### 参考链接
* [官方文档](https://docs.fedoraproject.org/en-US/fedora-coreos/bare-metal/)
diff --git a/12_ecosystem/coreos/intro.md b/12_ecosystem/coreos/intro.md
index 5540d94..47799c3 100644
--- a/12_ecosystem/coreos/intro.md
+++ b/12_ecosystem/coreos/intro.md
@@ -1,28 +1,28 @@
-# Fedora CoreOS 介绍
+## Fedora CoreOS 介绍
[Fedora CoreOS](https://getfedora.org/coreos/) 是一个自动更新的,最小的,整体的,以容器为中心的操作系统,不仅适用于集群,而且可独立运行,并针对运行 Kubernetes 进行了优化。它旨在结合 CoreOS Container Linux 和 Fedora Atomic Host 的优点,将 Container Linux 中的 [Ignition](https://github.com/coreos/ignition) 与 [rpm-ostree](https://github.com/coreos/rpm-ostree) 和 Project Atomic 中的 SELinux 强化等技术相集成。其目标是提供最佳的容器主机,以安全,大规模地运行容器化的工作负载。
-## FCOS 特性
+### FCOS 特性
-### 一个最小化操作系统
+#### 一个最小化操作系统
FCOS 被设计成一个基于容器的最小化的现代操作系统。它比现有的 Linux 安装平均节省 40% 的 RAM(大约 114M )并允许从 PXE 或 iPXE 非常快速的启动。
-### 系统初始化
+#### 系统初始化
Ignition 是一种配置实用程序,可读取配置文件(JSON 格式)并根据该配置配置 FCOS 系统。可配置的组件包括存储,文件系统,systemd 和用户。
Ignition 在系统首次启动期间(在 initramfs 中)仅运行一次。由于 Ignition 在启动过程中的早期运行,因此它可以在用户空间开始启动之前重新对磁盘分区,格式化文件系统,创建用户并写入文件。当 systemd 启动时,systemd 服务已被写入磁盘,从而加快了启动时间。
-### 自动更新
+#### 自动更新
FCOS 使用 rpm-ostree 系统进行事务性升级。无需像 yum 升级那样升级单个软件包,而是 rpm-ostree 将 OS 升级作为一个原子单元进行。新的 OS 部署在升级期间进行,并在下次重新引导时生效。如果升级出现问题,则一次回滚和重新启动会使系统返回到先前的状态。确保了系统升级对群集容量的影响降到最小。
-### 容器工具
+#### 容器工具
对于诸如构建,复制和其他管理容器的任务,FCOS 用一组容器工具代替了 **Docker CLI**。**podman CLI** 工具支持许多容器运行时功能,例如运行,启动,停止,列出和删除容器和镜像。**skopeo CLI** 工具可以复制,认证和签名镜像。您还可以使用 **crictl CLI** 工具来处理 CRI-O 容器引擎中的容器和镜像。
-## 参考文档
+### 参考文档
* [官方文档](https://docs.fedoraproject.org/en-US/fedora-coreos/)
* [openshift 官方文档](https://docs.openshift.com/container-platform/4.3/architecture/architecture-rhcos.html)
diff --git a/12_ecosystem/podman/README.md b/12_ecosystem/podman/README.md
index af55139..15c2958 100644
--- a/12_ecosystem/podman/README.md
+++ b/12_ecosystem/podman/README.md
@@ -1,8 +1,8 @@
-# podman
+## podman
[`podman`](https://github.com/containers/podman) 是一个无守护进程、与 Docker 命令高度兼容的下一代 Linux 容器工具。它由 Red Hat 开发,旨在提供一个更安全的容器运行环境。
-## Podman vs Docker
+### Podman vs Docker
| 特性 | Docker | Podman |
| :--- | :--- | :--- |
@@ -11,15 +11,15 @@
| **生态** | 完整的生态系统 (Compose, Swarm) | 专注单机容器,配合 Kubernetes 使用 |
| **镜像构建** | `docker build` | `podman build` 或 `buildah` |
-## 安装
+### 安装
-### CentOS / RHEL
+#### CentOS / RHEL
```bash
$ sudo yum -y install podman
```
-### macOS
+#### macOS
macOS 上需要安装 Podman Desktop 或通过 Homebrew 安装:
@@ -29,67 +29,67 @@ $ podman machine init
$ podman machine start
```
-## 使用
+### 使用
`podman` 的命令行几乎与 `docker` 完全兼容,大多数情况下,你只需将 `docker` 替换为 `podman` 即可。
-### 运行容器
+#### 运行容器
```bash
-# $ docker run -d -p 80:80 nginx:alpine
+## $ docker run -d -p 80:80 nginx:alpine
$ podman run -d -p 80:80 nginx:alpine
```
-### 列出容器
+#### 列出容器
```bash
$ podman ps
```
-### 构建镜像
+#### 构建镜像
```bash
$ podman build -t myimage .
```
-## Pods 的概念
+### Pods 的概念
与 Docker 不同,Podman 支持 "Pod" 的概念(类似于 Kubernetes 的 Pod),允许你在同一个网络命名空间中运行多个容器。
```bash
-# 创建一个 Pod
+## 创建一个 Pod
$ podman pod create --name mypod -p 8080:80
-# 在 Pod 中运行容器
+## 在 Pod 中运行容器
$ podman run -d --pod mypod --name webbing nginx
```
-## 迁移到 Podman
+### 迁移到 Podman
如果你习惯使用 `docker` 命令,可以简单地设置别名:
$ alias docker=podman
```
-## 进阶用法
+### 进阶用法
-### Systemd 集成
+#### Systemd 集成
Podman 可以生成 systemd 单元文件,让容器像普通系统服务一样管理。
```bash
-# 创建容器
+## 创建容器
$ podman run -d --name myweb -p 8080:80 nginx
-# 生成 systemd 文件
+## 生成 systemd 文件
$ podman generate systemd --name myweb --files --new
-# 启用并启动服务
+## 启用并启动服务
$ systemctl --user enable --now container-myweb.service
```
-### Podman Compose
+#### Podman Compose
虽然 Podman 兼容 Docker Compose,但在某些场景下你可能需要明确使用 `podman-compose`。
@@ -98,7 +98,7 @@ $ pip3 install podman-compose
$ podman-compose up -d
```
-## 参考
+### 参考
* [Podman 官方网站](https://podman.io/)
* [Podman GitHub 仓库](https://github.com/containers/podman)
diff --git a/13_implementation/arch.md b/13_implementation/13.1_arch.md
similarity index 90%
rename from 13_implementation/arch.md
rename to 13_implementation/13.1_arch.md
index 0dd5ddf..906b245 100644
--- a/13_implementation/arch.md
+++ b/13_implementation/13.1_arch.md
@@ -1,6 +1,6 @@
-# 基本架构
+## 基本架构
-## 核心架构图
+### 核心架构图
Docker 采用了 **C/S (客户端/服务端)** 架构。Client 向 Daemon 发送请求,Daemon 负责构建、运行和分发容器。
@@ -21,33 +21,33 @@ graph LR
---
-## 组件详解
+### 组件详解
Docker 的内部架构如同洋葱一样分层,每一层专注解决特定问题:
-### 1. Docker CLI (客户端)
+#### 1. Docker CLI (客户端)
用户与 Docker 交互的主要方式。它将用户命令(如 `docker run`)转换为 API 请求发送给 dockerd。
-### 2. Dockerd (守护进程)
+#### 2. Dockerd (守护进程)
Docker 的大脑。
- 监听 API 请求
- 管理 Docker 对象(镜像、容器、网络、卷)
- 编排下层组件完成工作
-### 3. Containerd (高级运行时)
+#### 3. Containerd (高级运行时)
行业标准的容器运行时(CNCF 毕业项目)。
- 管理容器的完整生命周期(启动、停止)
- 镜像拉取与存储
- **不包含** 复杂的与容器无关的功能(如构建、API)
- Kubernetes 也可以直接使用 containerd(跳过 Docker)
-### 4. Runc (低级运行时)
+#### 4. Runc (低级运行时)
用于创建和运行容器的 CLI 工具。
- 直接与内核交互(Namespaces, Cgroups)
- 遵循 OCI (Open Container Initiative) 规范
- **主要职责**:根据配置启动一个容器,然后退出(将控制权交给容器进程)
-### 5. Shim
+#### 5. Shim
每个容器都有一个 shim 进程。
- **解耦**:允许 dockerd 重启而不影响容器运行
- **保持 IO**:维持容器的标准输入输出
@@ -55,7 +55,7 @@ Docker 的大脑。
---
-## 容器启动流程
+### 容器启动流程
当执行 `docker run -d nginx` 时,内部发生了什么?
@@ -99,7 +99,7 @@ flowchart TD
---
-## Docker Engine v29+ 变化
+### Docker Engine v29+ 变化
从 Docker Engine v29 (2025/2026) 开始,架构进一步简化和标准化:
@@ -108,7 +108,7 @@ flowchart TD
---
-## Docker Desktop 架构
+### Docker Desktop 架构
在 macOS 和 Windows 上,因为内核差异,架构稍微复杂:
@@ -132,7 +132,7 @@ flowchart TD
---
-## 总结
+### 总结
| 组件 | 角色 | 关键职责 |
|------|------|----------|
@@ -142,8 +142,8 @@ flowchart TD
| **Shim** | 监工 | 保持 IO,允许无守护进程重启 |
| **Runc** | 工人 | 真正干活(创建容器),干完就走 |
-## 延伸阅读
+### 延伸阅读
-- [命名空间](./namespace.md):Runc 如何隔离容器
-- [控制组](./cgroups.md):Runc 如何限制资源
-- [联合文件系统](./ufs.md):镜像如何存储
+- [命名空间](./13.2_namespace.md):Runc 如何隔离容器
+- [控制组](./13.3_cgroups.md):Runc 如何限制资源
+- [联合文件系统](./13.4_ufs.md):镜像如何存储
diff --git a/13_implementation/namespace.md b/13_implementation/13.2_namespace.md
similarity index 86%
rename from 13_implementation/namespace.md
rename to 13_implementation/13.2_namespace.md
index 1246127..f01a5bc 100644
--- a/13_implementation/namespace.md
+++ b/13_implementation/13.2_namespace.md
@@ -1,6 +1,6 @@
-# 命名空间
+## 命名空间
-## 什么是 Namespace
+### 什么是 Namespace
> **Namespace 是 Linux 内核提供的资源隔离机制,它让容器内的进程仿佛运行在独立的操作系统中。**
@@ -17,7 +17,7 @@ Namespace 是容器技术的核心基础之一。它回答了一个关键问题
└─────────────────────────┘ └─────────────────────────┘
```
-## Namespace 的类型
+### Namespace 的类型
Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部:
@@ -33,28 +33,28 @@ Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部:
---
-## PID Namespace
+### PID Namespace
-### 作用
+#### 作用
隔离进程 ID,让每个容器有自己的进程编号空间。
-### 效果
+#### 效果
```bash
-# 宿主机上查看进程
+## 宿主机上查看进程
$ ps aux | grep nginx
root 12345 0.0 0.1 nginx: master process
root 12346 0.0 0.1 nginx: worker process
-# 容器内查看进程
+## 容器内查看进程
$ docker exec mycontainer ps aux
PID USER COMMAND
1 root nginx: master process ← 在容器内是 PID 1
2 root nginx: worker process
```
-### 关键点
+#### 关键点
- 容器内的 PID 1 进程特殊重要——它是容器的主进程,退出则容器停止
- 容器内无法看到宿主机或其他容器的进程
@@ -62,13 +62,13 @@ PID USER COMMAND
---
-## NET Namespace
+### NET Namespace
-### 作用
+#### 作用
隔离网络栈,每个容器拥有独立的网络环境。
-### 效果
+#### 效果
```
宿主机 容器
@@ -79,7 +79,7 @@ PID USER COMMAND
└─────────────────────┘ └─────────────────────┘
```
-### 关键点
+#### 关键点
- 每个容器有独立的网卡、IP、路由表、iptables 规则
- 多个容器可以监听相同端口(如都监听 80)
@@ -87,13 +87,13 @@ PID USER COMMAND
---
-## MNT Namespace
+### MNT Namespace
-### 作用
+#### 作用
隔离文件系统挂载点,每个容器有自己的根目录。
-### 效果
+#### 效果
```
宿主机文件系统: 容器内看到的:
@@ -108,7 +108,7 @@ PID USER COMMAND
└── ... └── ...
```
-### 与 chroot 的区别
+#### 与 chroot 的区别
| 特性 | chroot | MNT Namespace |
|------|--------|---------------|
@@ -118,20 +118,20 @@ PID USER COMMAND
---
-## UTS Namespace
+### UTS Namespace
-### 作用
+#### 作用
隔离主机名和域名,让每个容器可以有自己的主机名。
-### 效果
+#### 效果
```bash
-# 宿主机
+## 宿主机
$ hostname
my-server
-# 容器内
+## 容器内
$ docker run --hostname mycontainer ubuntu hostname
mycontainer
```
@@ -140,32 +140,32 @@ UTS = "UNIX Time-sharing System",是历史遗留的名称。
---
-## IPC Namespace
+### IPC Namespace
-### 作用
+#### 作用
隔离 System V IPC 和 POSIX 消息队列。
-### 隔离的资源
+#### 隔离的资源
- 信号量(semaphores)
- 消息队列(message queues)
- 共享内存(shared memory)
-### 关键点
+#### 关键点
- 同一容器内的进程可以通过 IPC 通信
- 不同容器的进程无法通过 IPC 通信(除非显式共享)
---
-## USER Namespace
+### USER Namespace
-### 作用
+#### 作用
隔离用户和组 ID,实现权限隔离。
-### 效果
+#### 效果
```
容器内 宿主机
@@ -175,7 +175,7 @@ UTS = "UNIX Time-sharing System",是历史遗留的名称。
└─────────────────┘ └─────────────────┘
```
-### 安全意义
+#### 安全意义
容器内的 root 用户可以映射为宿主机上的普通用户,即使容器被突破,攻击者在宿主机上也只有普通权限。
@@ -183,50 +183,50 @@ UTS = "UNIX Time-sharing System",是历史遗留的名称。
---
-## 动手实验:体验 Namespace
+### 动手实验:体验 Namespace
使用 `unshare` 命令可以在不使用 Docker 的情况下体验 Namespace:
-### 实验 1:UTS Namespace
+#### 实验 1:UTS Namespace
```bash
-# 创建新的 UTS namespace 并启动 shell
+## 创建新的 UTS namespace 并启动 shell
$ sudo unshare --uts /bin/bash
-# 修改主机名(只影响这个 namespace)
+## 修改主机名(只影响这个 namespace)
$ hostname container-test
$ hostname
container-test
-# 退出后查看宿主机主机名(未改变)
+## 退出后查看宿主机主机名(未改变)
$ exit
$ hostname
my-server
```
-### 实验 2:PID Namespace
+#### 实验 2:PID Namespace
```bash
-# 创建新的 PID 和 MNT namespace
+## 创建新的 PID 和 MNT namespace
$ sudo unshare --pid --mount --fork /bin/bash
-# 挂载新的 /proc
+## 挂载新的 /proc
$ mount -t proc proc /proc
-# 查看进程(只能看到当前 shell)
+## 查看进程(只能看到当前 shell)
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 8960 4516 pts/0 S 10:00 0:00 /bin/bash
root 8 0.0 0.0 10072 3200 pts/0 R+ 10:00 0:00 ps aux
```
-### 实验 3:NET Namespace
+#### 实验 3:NET Namespace
```bash
-# 创建新的网络 namespace
+## 创建新的网络 namespace
$ sudo unshare --net /bin/bash
-# 查看网络接口(只有 lo)
+## 查看网络接口(只有 lo)
$ ip addr
1: lo: mtu 65536 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
@@ -234,7 +234,7 @@ $ ip addr
---
-## Namespace 的局限性
+### Namespace 的局限性
Namespace 提供了隔离但不是安全边界:
@@ -248,7 +248,7 @@ Namespace 提供了隔离但不是安全边界:
---
-## 本章小结
+### 本章小结
| Namespace | 隔离内容 | 一句话说明 |
|-----------|---------|-----------|
@@ -259,9 +259,9 @@ Namespace 提供了隔离但不是安全边界:
| IPC | 进程间通信 | 容器间 IPC 隔离 |
| USER | 用户 ID | 容器 root ≠ 宿主机 root |
-## 延伸阅读
+### 延伸阅读
-- [控制组(Cgroups)](cgroups.md):资源限制机制
-- [联合文件系统](ufs.md):分层存储的实现
+- [控制组(Cgroups)](13.3_cgroups.md):资源限制机制
+- [联合文件系统](13.4_ufs.md):分层存储的实现
- [安全](../security/README.md):容器安全实践
- [Linux Namespace 官方文档](https://man7.org/linux/man-pages/man7/namespaces.7.html)
diff --git a/13_implementation/cgroups.md b/13_implementation/13.3_cgroups.md
similarity index 78%
rename from 13_implementation/cgroups.md
rename to 13_implementation/13.3_cgroups.md
index 6eb5fa3..f103c6d 100644
--- a/13_implementation/cgroups.md
+++ b/13_implementation/13.3_cgroups.md
@@ -1,6 +1,6 @@
-# 控制组
+## 控制组
-## 什么是控制组
+### 什么是控制组
控制组(Control Groups,简称 cgroups)是 Linux 内核的一个特性,用于**限制、记录和隔离**进程组的资源使用(CPU、内存、磁盘 I/O、网络等)。
@@ -21,7 +21,7 @@
---
-## cgroups 的历史
+### cgroups 的历史
| 时间 | 事件 |
|------|------|
@@ -32,7 +32,7 @@
---
-## cgroups 可以限制的资源
+### cgroups 可以限制的资源
| 资源类型 | 子系统 | 说明 |
|---------|--------|------|
@@ -44,18 +44,18 @@
---
-## Docker 中的资源限制
+### Docker 中的资源限制
-### 内存限制
+#### 内存限制
```bash
-# 限制容器最多使用 512MB 内存
+## 限制容器最多使用 512MB 内存
$ docker run -m 512m myapp
-# 限制内存 + swap
+## 限制内存 + swap
$ docker run -m 512m --memory-swap 1g myapp
-# 软限制(超过时警告,不会 OOM Kill)
+## 软限制(超过时警告,不会 OOM Kill)
$ docker run --memory-reservation 256m myapp
```
@@ -66,16 +66,16 @@ $ docker run --memory-reservation 256m myapp
| `--memory-reservation` | 软限制(内存竞争时生效) |
| `--oom-kill-disable` | 禁用 OOM Killer(谨慎使用) |
-### CPU 限制
+#### CPU 限制
```bash
-# 限制使用 1.5 个 CPU 核心
+## 限制使用 1.5 个 CPU 核心
$ docker run --cpus=1.5 myapp
-# 限制使用 CPU 0 和 1
+## 限制使用 CPU 0 和 1
$ docker run --cpuset-cpus="0,1" myapp
-# 设置 CPU 使用权重(相对值,默认 1024)
+## 设置 CPU 使用权重(相对值,默认 1024)
$ docker run --cpu-shares=512 myapp
```
@@ -86,77 +86,77 @@ $ docker run --cpu-shares=512 myapp
| `--cpu-shares` | CPU 时间片权重(相对值) |
| `--cpu-period` / `--cpu-quota` | 精细控制 CPU 配额 |
-### 磁盘 I/O 限制
+#### 磁盘 I/O 限制
```bash
-# 限制设备写入速度为 10MB/s
+## 限制设备写入速度为 10MB/s
$ docker run --device-write-bps /dev/sda:10mb myapp
-# 限制设备读取速度
+## 限制设备读取速度
$ docker run --device-read-bps /dev/sda:10mb myapp
-# 限制 IOPS
+## 限制 IOPS
$ docker run --device-write-iops /dev/sda:100 myapp
```
-### 进程数限制
+#### 进程数限制
```bash
-# 限制最多 100 个进程
+## 限制最多 100 个进程
$ docker run --pids-limit=100 myapp
```
---
-## 查看容器资源使用
+### 查看容器资源使用
```bash
-# 实时监控所有容器的资源使用
+## 实时监控所有容器的资源使用
$ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
abc123 web 0.50% 45.5MiB / 512MiB 8.89% 1.2kB / 0B 0B / 0B
def456 db 2.30% 256MiB / 1GiB 25.00% 5.6kB / 3.2kB 4.1MB / 2.3MB
-# 查看特定容器
+## 查看特定容器
$ docker stats mycontainer
-# 查看容器的 cgroup 配置
+## 查看容器的 cgroup 配置
$ docker inspect mycontainer --format '{{json .HostConfig}}' | jq
```
---
-## 资源限制的效果
+### 资源限制的效果
-### 内存超限
+#### 内存超限
```bash
-# 启动限制 100MB 内存的容器
+## 启动限制 100MB 内存的容器
$ docker run -m 100m stress --vm 1 --vm-bytes 200M
-# 容器会被 OOM Killer 杀死
+## 容器会被 OOM Killer 杀死
$ docker ps -a
CONTAINER ID STATUS NAMES
abc123 Exited (137) 5 seconds ago hopeful_darwin
-# 137 = 128 + 9,表示被 SIGKILL (9) 杀死
+## 137 = 128 + 9,表示被 SIGKILL (9) 杀死
```
-### CPU 限制验证
+#### CPU 限制验证
```bash
-# 不限制 CPU
+## 不限制 CPU
$ docker run --rm stress --cpu 4
-# 占满所有 CPU
+## 占满所有 CPU
-# 限制为 1 个核心
+## 限制为 1 个核心
$ docker run --rm --cpus=1 stress --cpu 4
-# 只能使用约 100% CPU(1 个核心)
+## 只能使用约 100% CPU(1 个核心)
```
---
-## cgroups v1 vs v2
+### cgroups v1 vs v2
| 特性 | cgroups v1 | cgroups v2 |
|------|-----------|-----------|
@@ -166,15 +166,15 @@ $ docker run --rm --cpus=1 stress --cpu 4
| PSI(压力监控) | ❌ | ✅ |
| rootless 容器 | 部分支持 | 完整支持 |
-### 检查系统使用的版本
+#### 检查系统使用的版本
```bash
-# 查看 cgroup 版本
+## 查看 cgroup 版本
$ mount | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
-# 如果显示 cgroup2 表示 v2
+## 如果显示 cgroup2 表示 v2
-# 或者
+## 或者
$ cat /proc/filesystems | grep cgroup
nodev cgroup
nodev cgroup2
@@ -182,7 +182,7 @@ nodev cgroup2
---
-## 在 Compose 中设置限制
+### 在 Compose 中设置限制
```yaml
services:
@@ -200,25 +200,25 @@ services:
---
-## 最佳实践
+### 最佳实践
-### 1. 始终设置内存限制
+#### 1. 始终设置内存限制
```bash
-# 防止 OOM 影响宿主机
+## 防止 OOM 影响宿主机
$ docker run -m 1g myapp
```
-### 2. 为关键应用设置 CPU 保证
+#### 2. 为关键应用设置 CPU 保证
```bash
$ docker run --cpus=2 --cpu-shares=2048 critical-app
```
-### 3. 监控资源使用
+#### 3. 监控资源使用
```bash
-# 配合 Prometheus + cAdvisor 监控
+## 配合 Prometheus + cAdvisor 监控
$ docker run -d --name cadvisor \
-v /:/rootfs:ro \
-v /var/run:/var/run:ro \
@@ -229,7 +229,7 @@ $ docker run -d --name cadvisor \
---
-## 本章小结
+### 本章小结
| 资源 | 限制参数 | 示例 |
|------|---------|------|
@@ -239,8 +239,8 @@ $ docker run -d --name cadvisor \
| **磁盘 I/O** | `--device-write-bps` | `--device-write-bps /dev/sda:10mb` |
| **进程数** | `--pids-limit` | `--pids-limit=100` |
-## 延伸阅读
+### 延伸阅读
-- [命名空间](namespace.md):资源隔离
+- [命名空间](13.2_namespace.md):资源隔离
- [安全](../security/README.md):容器安全概述
- [Docker Stats](../05_container/README.md):监控容器资源
diff --git a/13_implementation/ufs.md b/13_implementation/13.4_ufs.md
similarity index 91%
rename from 13_implementation/ufs.md
rename to 13_implementation/13.4_ufs.md
index 922e9e2..3df7e1a 100644
--- a/13_implementation/ufs.md
+++ b/13_implementation/13.4_ufs.md
@@ -1,6 +1,6 @@
-# 联合文件系统
+## 联合文件系统
-## 什么是联合文件系统
+### 什么是联合文件系统
联合文件系统(UnionFS)是一种**分层、轻量级**的文件系统,它将多个目录"联合"挂载到同一个虚拟目录,形成一个统一的文件系统视图。
@@ -29,9 +29,9 @@
---
-## 为什么 Docker 使用联合文件系统
+### 为什么 Docker 使用联合文件系统
-### 1. 镜像分层复用
+#### 1. 镜像分层复用
```
nginx:alpine myapp:latest
@@ -44,7 +44,7 @@ nginx:alpine myapp:latest
多个镜像共享相同的底层,节省磁盘空间。
-### 2. 快速构建
+#### 2. 快速构建
每个 Dockerfile 指令创建一层,只有变化的层需要重建:
@@ -57,7 +57,7 @@ COPY . . # 层4:应用代码
代码变化时,只需重建层4,层1-3 使用缓存。
-### 3. 容器启动快
+#### 3. 容器启动快
容器启动时不需要复制镜像,只需:
1. 在镜像层上创建一个薄的可写层
@@ -65,7 +65,7 @@ COPY . . # 层4:应用代码
---
-## Copy-on-Write(写时复制)
+### Copy-on-Write(写时复制)
当容器修改只读层中的文件时:
@@ -88,7 +88,7 @@ COPY . . # 层4:应用代码
---
-## Docker 支持的存储驱动
+### Docker 支持的存储驱动
Docker 可使用多种联合文件系统实现:
@@ -101,7 +101,7 @@ Docker 可使用多种联合文件系统实现:
| **devicemapper** | 块设备级存储 | 遗留系统 |
| **vfs** | 不使用 CoW,每层完整复制 | 仅测试 |
-### 各发行版推荐
+#### 各发行版推荐
| Linux 发行版 | 推荐存储驱动 |
|-------------|-------------|
@@ -111,7 +111,7 @@ Docker 可使用多种联合文件系统实现:
| RHEL 8+ | overlay2 |
| Fedora | overlay2 |
-### 查看当前存储驱动
+#### 查看当前存储驱动
```bash
$ docker info | grep "Storage Driver"
@@ -120,7 +120,7 @@ Storage Driver: overlay2
---
-## overlay2 工作原理
+### overlay2 工作原理
overlay2 是目前最推荐的存储驱动:
@@ -148,7 +148,7 @@ overlay2 是目前最推荐的存储驱动:
- **workdir**:OverlayFS 的工作目录
- **merged**:联合挂载后的视图
-### 文件操作行为
+#### 文件操作行为
| 操作 | 行为 |
|------|------|
@@ -159,10 +159,10 @@ overlay2 是目前最推荐的存储驱动:
---
-## 查看镜像层
+### 查看镜像层
```bash
-# 查看镜像的层信息
+## 查看镜像的层信息
$ docker history nginx:alpine
IMAGE CREATED CREATED BY SIZE
a6eb2a334a9f 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
@@ -172,7 +172,7 @@ a6eb2a334a9f 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
2 weeks ago COPY 30-tune-worker-processes.sh /docker-ent… 4.62kB
...
-# 查看层的存储位置
+## 查看层的存储位置
$ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
{
"LowerDir": "/var/lib/docker/overlay2/.../diff:/var/lib/docker/overlay2/.../diff",
@@ -184,29 +184,29 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
---
-## 最佳实践
+### 最佳实践
-### 1. 减少镜像层数
+#### 1. 减少镜像层数
```docker
-# ❌ 每条命令创建一层
+## ❌ 每条命令创建一层
RUN apt-get update
RUN apt-get install -y nginx
RUN rm -rf /var/lib/apt/lists/*
-# ✅ 合并为一层
+## ✅ 合并为一层
RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
```
-### 2. 避免在容器中写入大量数据
+#### 2. 避免在容器中写入大量数据
容器层的写入性能低于直接写入。大量数据应使用:
- 数据卷(Volume)
- 绑定挂载(Bind Mount)
-### 3. 使用 .dockerignore
+#### 3. 使用 .dockerignore
排除不需要的文件可以:
- 减小构建上下文
@@ -214,7 +214,7 @@ RUN apt-get update && \
---
-## 本章小结
+### 本章小结
| 概念 | 说明 |
|------|------|
@@ -223,8 +223,8 @@ RUN apt-get update && \
| **overlay2** | Docker 默认推荐的存储驱动 |
| **分层好处** | 镜像复用、快速构建、快速启动 |
-## 延伸阅读
+### 延伸阅读
-- [镜像](../02_basic_concept/image.md):理解镜像分层
-- [容器](../02_basic_concept/container.md):容器存储层
-- [构建镜像](../04_image/build.md):Dockerfile 层的创建
+- [镜像](../02_basic_concept/2.1_image.md):理解镜像分层
+- [容器](../02_basic_concept/2.2_container.md):容器存储层
+- [构建镜像](../04_image/4.5_build.md):Dockerfile 层的创建
diff --git a/13_implementation/container_format.md b/13_implementation/13.5_container_format.md
similarity index 95%
rename from 13_implementation/container_format.md
rename to 13_implementation/13.5_container_format.md
index 1f943aa..3c0a9e3 100644
--- a/13_implementation/container_format.md
+++ b/13_implementation/13.5_container_format.md
@@ -1,3 +1,3 @@
-# 容器格式
+## 容器格式
最初,Docker 采用了 `LXC` 中的容器格式。从 0.7 版本以后开始去除 LXC,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer),从 1.11 开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。
diff --git a/13_implementation/network.md b/13_implementation/13.6_network.md
similarity index 98%
rename from 13_implementation/network.md
rename to 13_implementation/13.6_network.md
index cec496c..4a0c200 100644
--- a/13_implementation/network.md
+++ b/13_implementation/13.6_network.md
@@ -1,8 +1,8 @@
-# Docker 网络实现
+## Docker 网络实现
Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备(特别是 veth pair)。建议先熟悉了解这两部分的基本概念再阅读本章。
-## 基本原理
+### 基本原理
首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。
Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。
@@ -10,7 +10,7 @@ Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据
Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 `veth pair`)。
-## 创建网络参数
+### 创建网络参数
Docker 创建一个容器的时候,会执行如下操作:
* 创建一对虚拟接口,分别放到本地主机和新容器中;
* 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;
@@ -25,7 +25,7 @@ Docker 创建一个容器的时候,会执行如下操作:
* `--net=container:NAME_or_ID` 让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过 `lo` 环回接口通信。
* `--net=none` 让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。
-## 网络配置细节
+### 网络配置细节
用户使用 `--net=none` 后,可以自行配置网络,让容器达到跟平常一样具有访问网络的权限。通过这个过程,可以了解 Docker 配置网络的细节。
首先,启动一个 `/bin/bash` 容器,指定 `--net=none` 参数。
diff --git a/13_implementation/README.md b/13_implementation/README.md
index cea56a3..608be25 100644
--- a/13_implementation/README.md
+++ b/13_implementation/README.md
@@ -1,4 +1,4 @@
-# 底层实现
+# 第十三章 底层实现
Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。
diff --git a/14_cases/README.md b/14_cases/README.md
index 3f5b251..9064df2 100644
--- a/14_cases/README.md
+++ b/14_cases/README.md
@@ -1,4 +1,4 @@
-# 实战案例
+# 第十四章 实战案例
本章将介绍 Docker 在不同场景下的实战案例。
diff --git a/14_cases/ci/README.md b/14_cases/ci/README.md
index e304f68..49155c9 100644
--- a/14_cases/ci/README.md
+++ b/14_cases/ci/README.md
@@ -1,4 +1,4 @@
-# CI/CD
+## CI/CD
**持续集成(Continuous integration)** 是一种软件开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
diff --git a/14_cases/ci/actions/README.md b/14_cases/ci/actions/README.md
index 2048652..9ca67a3 100644
--- a/14_cases/ci/actions/README.md
+++ b/14_cases/ci/actions/README.md
@@ -1,4 +1,4 @@
-# GitHub Actions
+## GitHub Actions
GitHub [Actions](https://github.com/features/actions) 是 GitHub 推出的一款 CI/CD 工具。
@@ -23,6 +23,6 @@ jobs:
args: go version
```
-## 参考资料
+### 参考资料
* [Actions Docs](https://docs.github.com/en/actions)
diff --git a/14_cases/ci/devops_workflow.md b/14_cases/ci/devops_workflow.md
index 64550cd..b72905a 100644
--- a/14_cases/ci/devops_workflow.md
+++ b/14_cases/ci/devops_workflow.md
@@ -1,8 +1,8 @@
-# DevOps 工作流完整示例
+## DevOps 工作流完整示例
本章将演示一个基于 Docker, Kubernetes 和 Jenkins/GitLab CI 的完整 DevOps 工作流。
-## 工作流概览
+### 工作流概览
1. **Code**: 开发人员提交代码到 GitLab。
2. **Build**: GitLab CI 触发构建任务。
@@ -12,25 +12,25 @@
6. **Verify**: 人工或自动化验证。
7. **Release (Production)**: 审批后自动部署到生产环境。
-## 关键配置示例
+### 关键配置示例
-### 1. Dockerfile (多阶段构建)
+#### 1. Dockerfile (多阶段构建)
```dockerfile
-# Build stage
+## Build stage
FROM golang:1.18 AS builder
WORKDIR /app
COPY . .
RUN go build -o main .
-# Final stage
+## Final stage
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/main .
CMD ["./main"]
```
-### 2. GitLab CI (.gitlab-ci.yml)
+#### 2. GitLab CI (.gitlab-ci.yml)
```yaml
stages:
@@ -67,7 +67,7 @@ deploy_staging:
- develop
```
-## 最佳实践
+### 最佳实践
1. **不可变基础设施**: 一旦镜像构建完成,在各个环境(Dev, Staging, Prod)中都应该使用同一个镜像 tag (通常是 commit hash),而不是重新构建。
2. **配置分离**: 使用 ConfigMap 和 Secret 管理环境特定的配置,不要打包进镜像。
diff --git a/14_cases/ci/drone/README.md b/14_cases/ci/drone/README.md
index 0ab5cb0..9585430 100644
--- a/14_cases/ci/drone/README.md
+++ b/14_cases/ci/drone/README.md
@@ -1,4 +1,4 @@
-# Drone
+## Drone
基于 `Docker` 的 `CI/CD` 工具 `Drone` 所有编译、测试的流程都在 `Docker` 容器中进行。
@@ -6,13 +6,13 @@
本小节以 `GitHub` + `Drone` 来演示 `Drone` 的工作流程。当然在实际开发过程中,你的代码也许不在 GitHub 托管,那么你可以尝试使用 `Gogs` + `Drone` 来进行 `CI/CD`。
-## Drone 关联项目
+### Drone 关联项目
在 Github 新建一个名为 `drone-demo` 的仓库。
-打开我们已经 [部署好的 Drone 网站](install.md) 或者 [Drone Cloud](https://cloud.drone.io),使用 GitHub 账号登录,在界面中关联刚刚新建的 `drone-demo` 仓库。
+打开我们已经 [部署好的 Drone 网站](9.2_install.md) 或者 [Drone Cloud](https://cloud.drone.io),使用 GitHub 账号登录,在界面中关联刚刚新建的 `drone-demo` 仓库。
-## 编写项目源代码
+### 编写项目源代码
初始化一个 git 仓库
@@ -72,7 +72,7 @@ trigger:
└── app.go
```
-## 推送项目源代码到 GitHub
+### 推送项目源代码到 GitHub
```bash
$ git add .
@@ -82,7 +82,7 @@ $ git commit -m "test drone ci"
$ git push origin master
```
-## 查看项目构建过程及结果
+### 查看项目构建过程及结果
打开我们部署好的 `Drone` 网站或者 Drone Cloud,即可看到构建结果。
@@ -92,7 +92,7 @@ $ git push origin master
本书 GitBook 也使用 Drone 进行 CI/CD,具体配置信息请查看本书根目录 [`.drone.yml`](../../../.drone.yml) 文件。
-## 参考链接
+### 参考链接
* [Drone Github](https://github.com/drone/drone)
* [Drone 文档](https://docs.drone.io/)
diff --git a/14_cases/ci/drone/install.md b/14_cases/ci/drone/install.md
index 7d1288c..aca3845 100644
--- a/14_cases/ci/drone/install.md
+++ b/14_cases/ci/drone/install.md
@@ -1,6 +1,6 @@
-# 部署 Drone
+## 部署 Drone
-## 要求
+### 要求
* 拥有公网 IP、域名 (如果你不满足要求,可以尝试在本地使用 Gogs + Drone)
@@ -12,7 +12,7 @@
* 对 `CI/CD` 有一定了解
-## 新建 GitHub 应用
+### 新建 GitHub 应用
登录 GitHub,在 https://github.com/settings/applications/new 新建一个应用。
@@ -20,7 +20,7 @@
接下来查看这个应用的详情,记录 `Client ID` 和 `Client Secret`,之后配置 Drone 会用到。
-## 配置 Drone
+### 配置 Drone
我们通过使用 `Docker Compose` 来启动 `Drone`,编写 `docker-compose.yml` 文件。
@@ -68,18 +68,18 @@ volumes:
新建 `.env` 文件,输入变量及其值
```bash
-# 必填 服务器地址,例如 drone.domain.com
+## 必填 服务器地址,例如 drone.domain.com
DRONE_SERVER_HOST=
DRONE_SERVER_PROTO=https
DRONE_RPC_SECRET=secret
HOSTNAME=demo
-# 必填 在 GitHub 应用页面查看
+## 必填 在 GitHub 应用页面查看
DRONE_GITHUB_CLIENT_ID=
-# 必填 在 GitHub 应用页面查看
+## 必填 在 GitHub 应用页面查看
DRONE_GITHUB_CLIENT_SECRET=
```
-### 启动 Drone
+#### 启动 Drone
```bash
$ docker-compose up -d
diff --git a/14_cases/ide/README.md b/14_cases/ide/README.md
index a0bb743..e402d8f 100644
--- a/14_cases/ide/README.md
+++ b/14_cases/ide/README.md
@@ -1,3 +1,3 @@
-# 在 IDE 中使用 Docker
+## 在 IDE 中使用 Docker
使用 IDE 进行开发,往往要求本地安装好工具链。一些 IDE 支持 Docker 容器中的工具链,这样充分利用了 Docker 的优点,而无需在本地安装。
diff --git a/14_cases/ide/vsCode.md b/14_cases/ide/vsCode.md
index 7620776..a85a280 100644
--- a/14_cases/ide/vsCode.md
+++ b/14_cases/ide/vsCode.md
@@ -1,5 +1,5 @@
-# VS Code 中使用 Docker
+## VS Code 中使用 Docker
-## 将 Docker 容器作为远程开发环境
+### 将 Docker 容器作为远程开发环境
无需本地安装开发工具,直接将 Docker 容器作为开发环境,具体参考 [官方文档](https://code.visualstudio.com/docs/remote/containers)。
diff --git a/14_cases/os/README.md b/14_cases/os/README.md
index 2c2d839..2e4da03 100644
--- a/14_cases/os/README.md
+++ b/14_cases/os/README.md
@@ -1,4 +1,4 @@
-# 操作系统
+## 操作系统
目前常用的 Linux 发行版主要包括 `Debian/Ubuntu` 系列和 `CentOS/Fedora` 系列。
diff --git a/14_cases/os/alpine.md b/14_cases/os/alpine.md
index 756f096..acfe7f8 100644
--- a/14_cases/os/alpine.md
+++ b/14_cases/os/alpine.md
@@ -1,6 +1,6 @@
-# Alpine
+## Alpine
-## 简介
+### 简介

@@ -22,7 +22,7 @@ ubuntu latest b39b81afc8ca 188.3 MB
centos latest 8efe422e6104 210 MB
```
-## 获取并使用官方镜像
+### 获取并使用官方镜像
由于镜像很小,下载时间往往很短,读者可以直接使用 `docker run` 指令直接运行一个 `Alpine` 容器,并指定运行的 Linux 指令,例如:
@@ -31,7 +31,7 @@ $ docker run alpine echo '123'
123
```
-## 迁移至 `Alpine` 基础镜像
+### 迁移至 `Alpine` 基础镜像
目前,大部分 Docker 官方镜像都已经支持 `Alpine` 作为基础镜像,可以很容易进行迁移。
@@ -61,7 +61,7 @@ RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories
&& apk add --no-cache
```
-## 相关资源
+### 相关资源
* `Alpine` 官网:https://www.alpinelinux.org/
* `Alpine` 官方仓库:https://github.com/alpinelinux
diff --git a/14_cases/os/busybox.md b/14_cases/os/busybox.md
index cf8cfa5..3d5ebff 100644
--- a/14_cases/os/busybox.md
+++ b/14_cases/os/busybox.md
@@ -1,6 +1,6 @@
-# Busybox
+## Busybox
-## 简介
+### 简介

@@ -8,7 +8,7 @@
`BusyBox` 可运行于多款 `POSIX` 环境的操作系统中,如 `Linux`(包括 `Android`)、`Hurd`、`FreeBSD` 等。
-## 获取官方镜像
+### 获取官方镜像
可以使用 `docker pull` 指令下载 `busybox:latest` 镜像:
@@ -29,7 +29,7 @@ REPOSITORY TAG IMAGE ID CREATED
busybox latest e72ac664f4f0 6 weeks ago 2.433 MB
```
-## 运行 busybox
+### 运行 busybox
启动一个 `busybox` 容器,并在容器中执行 `grep` 命令。
@@ -107,7 +107,7 @@ tmpfs on /sys/firmware type tmpfs (ro,relatime)
`busybox` 镜像虽然小巧,但包括了大量常见的 `Linux` 命令,读者可以用它快速熟悉 `Linux` 命令。
-## 相关资源
+### 相关资源
* `Busybox` 官网:https://busybox.net/
* `Busybox` 官方仓库:https://git.busybox.net/busybox/
diff --git a/14_cases/os/centos.md b/14_cases/os/centos.md
index 4d4a360..5aee0d0 100644
--- a/14_cases/os/centos.md
+++ b/14_cases/os/centos.md
@@ -1,6 +1,6 @@
-# CentOS Fedora
+## CentOS Fedora
-## CentOS 系统简介
+### CentOS 系统简介
`CentOS` 和 `Fedora` 都是基于 `Redhat` 的常见 Linux 分支。`CentOS` 是目前企业级服务器的常用操作系统;`Fedora` 则主要面向个人桌面用户。
@@ -8,7 +8,7 @@
CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统),它是基于 `Red Hat Enterprise Linux` 源代码编译而成。由于 `CentOS` 与 `Redhat Linux` 源于相同的代码基础,所以很多成本敏感且需要高稳定性的公司就使用 `CentOS` 来替代商业版 `Red Hat Enterprise Linux`。`CentOS` 自身不包含闭源软件。
-### 使用 CentOS 官方镜像
+#### 使用 CentOS 官方镜像
**注意:CentOS 8 已于 2021 年 12 月 31 日停止维护(EOL)。对于新部署,推荐使用 CentOS Stream,或 Rocky Linux、AlmaLinux 等替代发行版。**
@@ -25,13 +25,13 @@ Status: Downloaded newer image for centos:latest
CentOS Linux release 7.9.2009 (Core)
```
-## Fedora 系统简介
+### Fedora 系统简介

`Fedora` 由 `Fedora Project` 社区开发,红帽公司赞助的 `Linux` 发行版。它的目标是创建一套新颖、多功能并且自由和开源的操作系统。`Fedora` 的功能对于用户而言,它是一套功能完备的,可以更新的免费操作系统,而对赞助商 `Red Hat` 而言,它是许多新技术的测试平台。被认为可用的技术最终会加入到 `Red Hat Enterprise Linux` 中。
-### 使用 Fedora 官方镜像
+#### 使用 Fedora 官方镜像
使用 `docker run` 命令直接运行 `Fedora` 官方镜像,并登录 `bash`。
@@ -45,7 +45,7 @@ Status: Downloaded newer image for fedora:latest
Fedora release 39 (Thirty Nine)
-## 相关资源
+### 相关资源
* `Fedora` 官网:https://getfedora.org/
* `Fedora` 官方仓库:https://github.com/fedora-infra
diff --git a/14_cases/os/debian.md b/14_cases/os/debian.md
index c7cf451..7443e81 100644
--- a/14_cases/os/debian.md
+++ b/14_cases/os/debian.md
@@ -1,8 +1,8 @@
-# Debian Ubuntu
+## Debian Ubuntu
`Debian` 和 `Ubuntu` 都是目前较为流行的 **Debian 系** 的服务器操作系统,十分适合研发场景。`Docker Hub` 上提供了官方镜像,国内各大容器云服务也基本都提供了相应的支持。
-## Debian 系统简介
+### Debian 系统简介

@@ -12,7 +12,7 @@
众多的 `Linux` 发行版,例如 `Ubuntu`、`Knoppix` 和 `Linspire` 及 `Xandros` 等,都基于 `Debian GNU/Linux`。
-### 使用 Debian 官方镜像
+#### 使用 Debian 官方镜像
官方提供了大家熟知的 `debian` 镜像以及面向科研领域的 `neurodebian` 镜像。可以使用 `docker run` 直接运行 `Debian` 镜像。
@@ -24,13 +24,13 @@ Debian GNU/Linux 8
`Debian` 镜像很适合作为基础镜像,构建自定义镜像。
-## Ubuntu 系统简介
+### Ubuntu 系统简介

`Ubuntu` 是一个以桌面应用为主的 `GNU/Linux` 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词(官方译名“友帮拓”,另有“吾帮托”、“乌班图”、“有奔头”或“乌斑兔”等译名)。`Ubuntu` 意思是“人性”以及“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。 `Ubuntu` 基于 `Debian` 发行版和 `GNOME/Unity` 桌面环境,与 `Debian` 的不同在于它每 6 个月会发布一个新版本,每 2 年推出一个长期支持 **(Long Term Support,LTS)** 版本,一般支持 3 年时间。
-### 使用 Ubuntu 官方镜像
+#### 使用 Ubuntu 官方镜像
下面以 `ubuntu:24.04` 为例,演示如何使用该镜像安装一些常用软件。
@@ -123,7 +123,7 @@ root@7d93de07bf76:/# curl 127.0.0.1
配合使用 `-p` 参数对外映射服务端口,可以允许容器外来访问该服务。
-## 相关资源
+### 相关资源
* `Debian` 官网:https://www.debian.org/
* `Neuro Debian` 官网:http://neuro.debian.net/
diff --git a/14_cases/os/summary.md b/14_cases/os/summary.md
index 48afe04..4b31465 100644
--- a/14_cases/os/summary.md
+++ b/14_cases/os/summary.md
@@ -1,4 +1,4 @@
-# 本章小结
+## 本章小结
本章讲解了典型操作系统镜像的下载和使用。
diff --git a/15_appendix/best_practices.md b/15_appendix/15.1_best_practices.md
similarity index 96%
rename from 15_appendix/best_practices.md
rename to 15_appendix/15.1_best_practices.md
index 4f680bb..36b97af 100644
--- a/15_appendix/best_practices.md
+++ b/15_appendix/15.1_best_practices.md
@@ -1,36 +1,36 @@
-# Dockerfile 最佳实践
+## Dockerfile 最佳实践
本附录是笔者对 Docker 官方文档中 [Best practices for writing Dockerfiles](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) 的理解与翻译。
-## 一般性的指南和建议
+### 一般性的指南和建议
-### 容器应该是短暂的
+#### 容器应该是短暂的
通过 `Dockerfile` 构建的镜像所启动的容器应该尽可能短暂(生命周期短)。「短暂」意味着可以停止和销毁容器,并且创建一个新容器并部署好所需的设置和配置工作量应该是极小的。
-### 使用 `.dockerignore` 文件
+#### 使用 `.dockerignore` 文件
使用 `Dockerfile` 构建镜像时最好是将 `Dockerfile` 放置在一个新建的空目录下。然后将构建镜像所需要的文件添加到该目录中。为了提高构建镜像的效率,你可以在目录下新建一个 `.dockerignore` 文件来指定要忽略的文件和目录。`.dockerignore` 文件的排除模式语法和 Git 的 `.gitignore` 文件相似。
-### 使用多阶段构建
+#### 使用多阶段构建
在 `Docker 17.05` 以上版本中,你可以使用 [多阶段构建](../04_image/multistage-builds.md) 来减少所构建镜像的大小。
-### 避免安装不必要的包
+#### 避免安装不必要的包
为了降低复杂性、减少依赖、减小文件大小、节约构建时间,你应该避免安装任何不必要的包。例如,不要在数据库镜像中包含一个文本编辑器。
-### 一个容器只运行一个进程
+#### 一个容器只运行一个进程
应该保证在一个容器中只运行一个进程。将多个应用解耦到不同容器中,保证了容器的横向扩展和复用。例如 web 应用应该包含三个容器:web应用、数据库、缓存。
如果容器互相依赖,你可以使用 [Docker 自定义网络](../network/README.md) 来把这些容器连接起来。
-### 镜像层数尽可能少
+#### 镜像层数尽可能少
你需要在 `Dockerfile` 可读性(也包括长期的可维护性)和减少层数之间做一个平衡。
-### 将多行参数排序
+#### 将多行参数排序
将多行参数按字母顺序排序(比如要安装多个包时)。这可以帮助你避免重复包含同一个包,更新包列表时也更容易。也便于 `PRs` 阅读和审查。建议在反斜杠符号 `\` 之前添加一个空格,以增加可读性。
@@ -45,7 +45,7 @@ RUN apt-get update && apt-get install -y \
subversion
```
-### 构建缓存
+#### 构建缓存
在镜像的构建过程中,Docker 会遍历 `Dockerfile` 文件中的指令,然后按顺序执行。在执行每条指令之前,Docker 都会在缓存中查找是否已经存在可重用的镜像,如果有就使用现存的镜像,不再重复创建。如果你不想在构建过程中使用缓存,你可以在 `docker build` 命令中使用 `--no-cache=true` 选项。
@@ -58,22 +58,22 @@ RUN apt-get update && apt-get install -y \
一旦缓存失效,所有后续的 `Dockerfile` 指令都将产生新的镜像,缓存不会被使用。
-## Dockerfile 指令
+### Dockerfile 指令
下面针对 `Dockerfile` 中各种指令的最佳编写方式给出建议。
-### FROM
+#### FROM
尽可能使用当前官方仓库作为你构建镜像的基础。推荐使用 [Alpine](https://hub.docker.com/_/alpine/) 镜像,因为它被严格控制并保持最小尺寸(目前小于 5 MB),但它仍然是一个完整的发行版。
-### LABEL
+#### LABEL
你可以给镜像添加标签来帮助组织镜像、记录许可信息、辅助自动化构建等。每个标签一行,由 `LABEL` 开头加上一个或多个标签对。下面的示例展示了各种不同的可能格式。`#` 开头的行是注释内容。
>注意:如果你的字符串中包含空格,必须将字符串放入引号中或者对空格使用转义。如果字符串内容本身就包含引号,必须对引号使用转义。
```docker
-# Set one or more individual labels
+## Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor="ACME Incorporated"
@@ -86,7 +86,7 @@ LABEL com.example.version.is-production=""
一个镜像可以包含多个标签,但建议将多个标签放入到一个 `LABEL` 指令中。
```docker
-# Set multiple labels at once, using line-continuation characters to break long lines
+## Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production="" \
@@ -96,11 +96,11 @@ LABEL vendor=ACME\ Incorporated \
关于标签可以接受的键值对,参考 [Understanding object labels](https://docs.docker.com/config/labels-custom-metadata/)。关于查询标签信息,参考 [Managing labels on objects](https://docs.docker.com/config/labels-custom-metadata/)。
-### RUN
+#### RUN
为了保持 `Dockerfile` 文件的可读性,可理解性,以及可维护性,建议将长的或复杂的 `RUN` 指令用反斜杠 `\` 分割成多行。
-#### apt-get
+##### apt-get
`RUN` 指令最常见的用法是安装包用的 `apt-get`。因为 `RUN apt-get` 指令会安装包,所以有几个问题需要注意。
@@ -170,19 +170,19 @@ RUN apt-get update && apt-get install -y \
> 注意:官方的 Debian 和 Ubuntu 镜像会自动运行 apt-get clean,所以不需要显式的调用 apt-get clean。
-### CMD
+#### CMD
`CMD` 指令用于执行目标镜像中包含的软件,可以包含参数。`CMD` 大多数情况下都应该以 `CMD ["executable", "param1", "param2"...]` 的形式使用。因此,如果创建镜像的目的是为了部署某个服务(比如 `Apache`),你可能会执行类似于 `CMD ["apache2", "-DFOREGROUND"]` 形式的命令。我们建议任何服务镜像都使用这种形式的命令。
多数情况下,`CMD` 都需要一个交互式的 `shell` (bash, Python, perl 等),例如 `CMD ["perl", "-de0"]`,或者 `CMD ["PHP", "-a"]`。使用这种形式意味着,当你执行类似 `docker run -it python` 时,你会进入一个准备好的 `shell` 中。`CMD` 应该在极少的情况下才能以 `CMD ["param", "param"]` 的形式与 `ENTRYPOINT` 协同使用,除非你和你的镜像使用者都对 `ENTRYPOINT` 的工作方式十分熟悉。
-### EXPOSE
+#### EXPOSE
`EXPOSE` 指令用于指定容器将要监听的端口。因此,你应该为你的应用程序使用常见的端口。例如,提供 `Apache` web 服务的镜像应该使用 `EXPOSE 80`,而提供 `MongoDB` 服务的镜像使用 `EXPOSE 27017`。
对于外部访问,用户可以在执行 `docker run` 时使用一个标志来指示如何将指定的端口映射到所选择的端口。
-### ENV
+#### ENV
为了方便新程序运行,你可以使用 `ENV` 来为容器中安装的程序更新 `PATH` 环境变量。例如使用 `ENV PATH /usr/local/nginx/bin:$PATH` 来确保 `CMD ["nginx"]` 能正确运行。
@@ -202,7 +202,7 @@ ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
类似于程序中的常量,这种方法可以让你只需改变 `ENV` 指令来自动的改变容器中的软件版本。
-### ADD 和 COPY
+#### ADD 和 COPY
虽然 `ADD` 和 `COPY` 功能类似,但一般优先使用 `COPY`。因为它比 `ADD` 更透明。`COPY` 只支持简单将本地文件拷贝到容器中,而 `ADD` 有一些并不明显的功能(比如本地 tar 提取和远程 URL 支持)。因此,`ADD` 的最佳用例是将本地 tar 文件自动提取到镜像中,例如 `ADD rootfs.tar.xz`。
@@ -241,7 +241,7 @@ RUN mkdir -p /usr/src/things \
对于其他不需要 `ADD` 的自动提取功能的文件或目录,你应该使用 `COPY`。
-### ENTRYPOINT
+#### ENTRYPOINT
`ENTRYPOINT` 的最佳用处是设置镜像的主命令,允许将镜像当成命令本身来运行(用 `CMD` 提供默认选项)。
@@ -318,11 +318,11 @@ $ docker run postgres postgres --help
$ docker run --rm -it postgres bash
```
-### VOLUME
+#### VOLUME
`VOLUME` 指令用于暴露任何数据库存储文件,配置文件,或容器创建的文件和目录。强烈建议使用 `VOLUME` 来管理镜像中的可变部分和用户可以改变的部分。
-### USER
+#### USER
如果某个服务不需要特权执行,建议使用 `USER` 指令切换到非 root 用户。先在 `Dockerfile` 中使用类似 `RUN groupadd -r postgres && useradd -r -g postgres postgres` 的指令创建用户和用户组。
@@ -332,10 +332,10 @@ $ docker run --rm -it postgres bash
最后,为了减少层数和复杂度,避免频繁地使用 `USER` 来回切换用户。
-### WORKDIR
+#### WORKDIR
为了清晰性和可靠性,你应该总是在 `WORKDIR` 中使用绝对路径。另外,你应该使用 `WORKDIR` 来替代类似于 `RUN cd ... && do-something` 的指令,后者难以阅读、排错和维护。
-## 官方镜像示例
+### 官方镜像示例
这些官方镜像的 Dockerfile 都是参考典范:https://github.com/docker-library/docs
diff --git a/15_appendix/debug.md b/15_appendix/15.2_debug.md
similarity index 85%
rename from 15_appendix/debug.md
rename to 15_appendix/15.2_debug.md
index ae89bff..55aab31 100644
--- a/15_appendix/debug.md
+++ b/15_appendix/15.2_debug.md
@@ -1,6 +1,6 @@
-# 如何调试 Docker
+## 如何调试 Docker
-## 开启 Debug 模式
+### 开启 Debug 模式
在 dockerd 配置文件 daemon.json(默认位于 /etc/docker/)中添加
@@ -18,14 +18,14 @@ $ sudo kill -SIGHUP $(pidof dockerd)
此时 dockerd 会在日志中输入更多信息供分析。
-## 检查内核日志
+### 检查内核日志
```bash
$ sudo dmesg |grep dockerd
$ sudo dmesg |grep runc
```
-## Docker 不响应时处理
+### Docker 不响应时处理
可以杀死 dockerd 进程查看其堆栈调用情况。
@@ -33,16 +33,16 @@ $ sudo dmesg |grep runc
$ sudo kill -SIGUSR1 $(pidof dockerd)
```
-## 重置 Docker 本地数据
+### 重置 Docker 本地数据
*注意,本操作会移除所有的 Docker 本地数据,包括镜像和容器等。*
$ sudo rm -rf /var/lib/docker
```
-## 常见故障排查
+### 常见故障排查
-### 容器启动失败
+#### 容器启动失败
如果容器启动后立即退出,可以使用 `docker logs` 查看原因。
@@ -52,21 +52,21 @@ $ sudo rm -rf /var/lib/docker
* 调整容器内存限制 (`--memory`)。
* **Exit Code 127**: 命令未找到。可能是 `ENTRYPOINT` 或 `CMD` 指定的命令不存在。
-### 网络连接问题
+#### 网络连接问题
-#### 容器内部无法联网
+##### 容器内部无法联网
1. 检查 Docker DNS 配置 (`/etc/docker/daemon.json`)。
2. 检查宿主机防火墙 (iptables/firewalld) 是否拦截了转发。
3. 容器内测试: `ping 8.8.8.8` (测试连通性), `nslookup google.com` (测试 DNS)。
-#### 端口映射不通
+##### 端口映射不通
1. 检查容器端口是否正确监听: `netstat -tunlp` (宿主机) 或 `docker exec netstat -tunlp`。
2. 确认应用监听地址是 `0.0.0.0` 而不是 `127.0.0.1`。
* 如果应用监听在 `127.0.0.1`,只有容器内部能访问,映射到宿主机外部也无法被外部请求访问。
-### 镜像拉取失败
+#### 镜像拉取失败
* **connection refused**: 检查网络或代理设置。
* **image not found**: 检查镜像名称和 Tag 拼写。
diff --git a/15_appendix/resources.md b/15_appendix/15.3_resources.md
similarity index 92%
rename from 15_appendix/resources.md
rename to 15_appendix/15.3_resources.md
index ee2f2b2..cba5f1c 100644
--- a/15_appendix/resources.md
+++ b/15_appendix/15.3_resources.md
@@ -1,6 +1,6 @@
-# 资源链接
+## 资源链接
-## 官方网站
+### 官方网站
* Docker 官方主页:https://www.docker.com
* Docker 官方博客:https://www.docker.com/blog/
@@ -12,18 +12,18 @@
* Docker 常见问题:https://docs.docker.com/engine/faq/
* Docker 远端应用 API:https://docs.docker.com/develop/sdk/
-## 实践参考
+### 实践参考
* Dockerfile 参考:https://docs.docker.com/engine/reference/builder/
* Dockerfile 最佳实践:https://docs.docker.com/build/building/best-practices/
-## 技术交流
+### 技术交流
* Docker 邮件列表: https://groups.google.com/forum/#!forum/docker-user
* Docker 社区 Slack:https://dockercommunity.slack.com/
* Docker Community Discord: https://discord.gg/docker
* Docker 的 Twitter 主页:https://twitter.com/docker
-## 其它
+### 其它
* Docker 的 StackOverflow 问答主页:https://stackoverflow.com/search?q=docker
diff --git a/15_appendix/README.md b/15_appendix/README.md
index 8c38302..44fbe62 100644
--- a/15_appendix/README.md
+++ b/15_appendix/README.md
@@ -1,4 +1,4 @@
-# 附录
+# 第十五章 附录
本章包含了 Docker 相关的参考资料、常见问题解答以及最佳实践指南,旨在为读者提供便捷的查阅工具。
@@ -7,6 +7,6 @@
* [**常见问题总结 (FAQ)**](faq/README.md):汇总了学习和使用 Docker 过程中的常见问题与错误解决方案。
* [**热门镜像介绍**](repo/README.md):详细介绍了 Nginx, MySQL, Redis 等常用官方镜像的使用方法。
* [**Docker 命令查询**](command/README.md):速查 Docker 客户端和服务端的常用命令。
-* [**Dockerfile 最佳实践**](best_practices.md):提供编写高效、安全 Dockerfile 的指导原则。
-* [**如何调试 Docker**](debug.md):介绍 Docker 调试技巧和工具。
-* [**资源链接**](resources.md):推荐更多 Docker 相关的学习资源。
\ No newline at end of file
+* [**Dockerfile 最佳实践**](15.1_best_practices.md):提供编写高效、安全 Dockerfile 的指导原则。
+* [**如何调试 Docker**](15.2_debug.md):介绍 Docker 调试技巧和工具。
+* [**资源链接**](15.3_resources.md):推荐更多 Docker 相关的学习资源。
\ No newline at end of file
diff --git a/15_appendix/command/README.md b/15_appendix/command/README.md
index 5bea731..be0a563 100644
--- a/15_appendix/command/README.md
+++ b/15_appendix/command/README.md
@@ -1,6 +1,6 @@
-# Docker 命令查询
+## Docker 命令查询
-## 基本语法
+### 基本语法
Docker 命令有两大类,客户端命令和服务端命令。前者是主要的操作接口,后者用来启动 Docker Daemon。
diff --git a/15_appendix/command/docker.md b/15_appendix/command/docker.md
index f8da822..a1e63b3 100644
--- a/15_appendix/command/docker.md
+++ b/15_appendix/command/docker.md
@@ -1,6 +1,6 @@
-# 客户端命令 - docker
+## 客户端命令 - docker
-## 客户端命令选项
+### 客户端命令选项
* `--config=""`:指定客户端配置文件,默认为 `~/.docker`;
* `-D=true|false`:是否使用 debug 模式。默认不开启;
@@ -12,7 +12,7 @@
* `--tlscert=/.docker/key.pem`:TLS 密钥文件路径;
* `--tlsverify=true|false`:启用 TLS 校验,默认为否。
-## 客户端命令
+### 客户端命令
可以通过 `docker COMMAND --help` 来查看这些命令的具体用法。
@@ -62,10 +62,10 @@
* `volume`:管理 Docker volume,包括查看、创建、删除等;
* `wait`:阻塞直到一个容器终止,然后输出它的退出符。
-## 一张图总结 Docker 的命令
+### 一张图总结 Docker 的命令

-## 参考
+### 参考
* [官方文档](https://docs.docker.com/engine/reference/commandline/cli/)
diff --git a/15_appendix/command/dockerd.md b/15_appendix/command/dockerd.md
index 7b30c79..365ec51 100644
--- a/15_appendix/command/dockerd.md
+++ b/15_appendix/command/dockerd.md
@@ -1,6 +1,6 @@
-# 服务端命令(dockerd)
+## 服务端命令(dockerd)
-## dockerd 命令选项
+### dockerd 命令选项
* `--api-cors-header=""`:CORS 头部域,默认不允许 CORS,要允许任意的跨域访问,可以指定为 "*";
* `--authorization-plugin=""`:载入认证的插件;
@@ -53,6 +53,6 @@
* `--userland-proxy=true|false`:是否使用用户态代理来实现容器间和出容器的回环通信,默认为 true;
* `--userns-remap=default|uid:gid|user:group|user|uid`:指定容器的用户命名空间,默认是创建新的 UID 和 GID 映射到容器内进程。
-## 参考
+### 参考
* [官方文档](https://docs.docker.com/engine/reference/commandline/dockerd/)
diff --git a/15_appendix/faq/README.md b/15_appendix/faq/README.md
index b0b7d75..b98a3fe 100644
--- a/15_appendix/faq/README.md
+++ b/15_appendix/faq/README.md
@@ -1,20 +1,20 @@
-# 附录一:常见问题总结
+## 附录一:常见问题总结
-## 镜像相关
+### 镜像相关
-### 如何批量清理临时镜像文件?
+#### 如何批量清理临时镜像文件?
答:可以使用 `docker image prune` 命令。
-### 如何查看镜像支持的环境变量?
+#### 如何查看镜像支持的环境变量?
答:可以使用 `docker run IMAGE env` 命令。
-### 本地的镜像文件都存放在哪里?
+#### 本地的镜像文件都存放在哪里?
答:与 Docker 相关的本地资源默认存放在 `/var/lib/docker/` 目录下,以 `overlay2` 文件系统为例,其中 `containers` 目录存放容器信息,`image` 目录存放镜像信息,`overlay2` 目录下存放具体的镜像层文件。
-### 构建 Docker 镜像应该遵循哪些原则?
+#### 构建 Docker 镜像应该遵循哪些原则?
答:整体原则上,尽量保持镜像功能的明确和内容的精简,要点包括
@@ -25,27 +25,27 @@
* 如果安装应用时候需要配置一些特殊的环境变量,在安装后要还原不需要保持的变量值;
* 使用 Dockerfile 创建镜像时候要添加 .dockerignore 文件或使用干净的工作目录。
-更多内容请查看 [Dockerfile 最佳实践](../best_practices.md)
+更多内容请查看 [Dockerfile 最佳实践](../15.1_best_practices.md)
-### 碰到网络问题,无法 pull 镜像,命令行指定 http\_proxy 无效?
+#### 碰到网络问题,无法 pull 镜像,命令行指定 http\_proxy 无效?
答:在 Docker 配置文件中添加 `export http_proxy="http://:"`,之后重启 Docker 服务即可。
-## 容器相关
+### 容器相关
-### 容器退出后,通过 docker container ls 命令查看不到,数据会丢失么?
+#### 容器退出后,通过 docker container ls 命令查看不到,数据会丢失么?
答:容器退出后会处于终止(exited)状态,此时可以通过 `docker container ls -a` 查看。其中的数据也不会丢失,还可以通过 `docker start` 命令来启动它。只有删除掉容器才会清除所有数据。
-### 如何停止所有正在运行的容器?
+#### 如何停止所有正在运行的容器?
答:可以使用 `docker stop $(docker container ls -q)` 命令。
-### 如何批量清理已经停止的容器?
+#### 如何批量清理已经停止的容器?
答:可以使用 `docker container prune` 命令。
-### 如何获取某个容器的 PID 信息?
+#### 如何获取某个容器的 PID 信息?
答:可以使用
@@ -53,7 +53,7 @@
docker inspect --format '{{ .State.Pid }}'
```
-### 如何获取某个容器的 IP 地址?
+#### 如何获取某个容器的 IP 地址?
答:可以使用
@@ -61,7 +61,7 @@ docker inspect --format '{{ .State.Pid }}'
docker inspect --format '{{ .NetworkSettings.IPAddress }}'
```
-### 如何给容器指定一个固定 IP 地址,而不是每次重启容器 IP 地址都会变?
+#### 如何给容器指定一个固定 IP 地址,而不是每次重启容器 IP 地址都会变?
答:使用以下命令启动容器可以使容器 IP 固定不变
@@ -71,40 +71,40 @@ $ docker network create -d bridge --subnet 172.25.0.0/16 my-net
$ docker run --network=my-net --ip=172.25.3.3 -itd --name=my-container busybox
```
-### 如何临时退出一个正在交互的容器的终端,而不终止它?
+#### 如何临时退出一个正在交互的容器的终端,而不终止它?
答:按 `Ctrl-p Ctrl-q`。如果按 `Ctrl-c` 往往会让容器内应用进程终止,进而会终止容器。
-### 使用 `docker port` 命令映射容器的端口时,系统报错“Error: No public port '80' published for xxx”?
+#### 使用 `docker port` 命令映射容器的端口时,系统报错“Error: No public port '80' published for xxx”?
答:
* 创建镜像时 `Dockerfile` 要通过 `EXPOSE` 指定正确的开放端口;
* 容器启动时指定 `PublishAllPort = true`。
-### 可以在一个容器中同时运行多个应用进程么?
+#### 可以在一个容器中同时运行多个应用进程么?
答:一般并不推荐在同一个容器内运行多个应用进程。如果有类似需求,可以通过一些额外的进程管理机制,比如 `supervisord` 来管理所运行的进程。可以参考 https://docs.docker.com/config/containers/multi-service\_container/ 。
-### 如何控制容器占用系统资源(CPU、内存)的份额?
+#### 如何控制容器占用系统资源(CPU、内存)的份额?
答:在使用 `docker create` 命令创建容器或使用 `docker run` 创建并启动容器的时候,可以使用 -c|--cpu-shares\[=0] 参数来调整容器使用 CPU 的权重;使用 -m|--memory\[=MEMORY] 参数来调整容器使用内存的大小。
-## 仓库相关
+### 仓库相关
-### 仓库(Repository)、注册服务器(Registry)、注册索引(Index) 有何关系?
+#### 仓库(Repository)、注册服务器(Registry)、注册索引(Index) 有何关系?
首先,仓库是存放一组关联镜像的集合,比如同一个应用的不同版本的镜像。
注册服务器是存放实际的镜像文件的地方。注册索引则负责维护用户的账号、权限、搜索、标签等的管理。因此,注册服务器利用注册索引来实现认证等管理。
-## 配置相关
+### 配置相关
-### Docker 的配置文件放在哪里,如何修改配置?
+#### Docker 的配置文件放在哪里,如何修改配置?
答:使用 `systemd` 的系统(如 Ubuntu 16.04、Centos 等)的配置文件在 `/etc/docker/daemon.json`。
-### 如何更改 Docker 的默认存储位置?
+#### 如何更改 Docker 的默认存储位置?
答:Docker 的默认存储位置是 `/var/lib/docker`,如果希望将 Docker 的本地文件存储到其他分区,可以使用 Linux 软连接的方式来完成,或者在启动 daemon 时通过 `-g` 参数指定,或者修改配置文件 `/etc/docker/daemon.json` 的 "data-root" 项 。可以使用 `docker system info | grep "Root Dir"` 查看当前使用的存储位置。
@@ -127,7 +127,7 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker
[root@s26 lib]# service docker start
```
-### 使用内存和 swap 限制启动容器时候报警告:"WARNING: Your kernel does not support cgroup swap limit. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded."?
+#### 使用内存和 swap 限制启动容器时候报警告:"WARNING: Your kernel does not support cgroup swap limit. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded."?
答:这是因为系统默认没有开启对内存和 swap 使用的统计功能,引入该功能会带来性能的下降。要开启该功能,可以采取如下操作:
@@ -135,9 +135,9 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker
* 更新 grub:`$ sudo update-grub`
* 重启系统,即可。
-## Docker 与虚拟化
+### Docker 与虚拟化
-### Docker 与 LXC(Linux Container)有何不同?
+#### Docker 与 LXC(Linux Container)有何不同?
答:LXC 利用 Linux 上相关技术实现了容器。Docker 则在如下的几个方面进行了改进:
@@ -147,7 +147,7 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker
* 仓库系统:仓库系统大大降低了镜像的分发和管理的成本;
* 周边工具:各种现有工具(配置管理、云平台)对 Docker 的支持,以及基于 Docker的 PaaS、CI 等系统,让 Docker 的应用更加方便和多样化。
-### Docker 与 Vagrant 有何不同?
+#### Docker 与 Vagrant 有何不同?
答:两者的定位完全不同。
@@ -156,7 +156,7 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker
简单说:Vagrant 适合用来管理虚拟机,而 Docker 适合用来管理应用环境。
-### 开发环境中 Docker 和 Vagrant 该如何选择?
+#### 开发环境中 Docker 和 Vagrant 该如何选择?
答:Docker 不是虚拟机,而是进程隔离,对于资源的消耗很少,但是目前需要 Linux 环境支持。Vagrant 是虚拟机上做的封装,虚拟机本身会消耗资源。
@@ -164,17 +164,17 @@ lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker
如果本地使用的是 macOS 或者 Windows 环境,那就需要开虚拟机,单一开发环境下 Vagrant 更简单;多环境开发下推荐在 Vagrant 里面再使用 Docker 进行环境隔离。
-## 其它
+### 其它
-### Docker 能在非 Linux 平台(比如 Windows 或 macOS )上运行么?
+#### Docker 能在非 Linux 平台(比如 Windows 或 macOS )上运行么?
答:完全可以。安装方法请查看 [安装 Docker](../../install/) 一节
-### 如何将一台宿主主机的 Docker 环境迁移到另外一台宿主主机?
+#### 如何将一台宿主主机的 Docker 环境迁移到另外一台宿主主机?
答:停止 Docker 服务。将整个 Docker 存储文件夹复制到另外一台宿主主机,然后调整另外一台宿主主机的配置即可。
-### 如何进入 Docker 容器的网络命名空间?
+#### 如何进入 Docker 容器的网络命名空间?
答:Docker 在创建容器后,删除了宿主主机上 `/var/run/netns` 目录中的相关的网络命名空间文件。因此,在宿主主机上是无法看到或访问容器的网络命名空间的。
@@ -206,7 +206,7 @@ $ sudo ip netns show
$ sudo ip netns exec 1234 ifconfig eth0 172.17.0.100/16
```
-### 如何获取容器绑定到本地那个 veth 接口上?
+#### 如何获取容器绑定到本地那个 veth 接口上?
答:Docker 容器启动后,会通过 veth 接口对连接到本地网桥,veth 接口命名跟容器命名毫无关系,十分难以找到对应关系。
diff --git a/15_appendix/faq/errors.md b/15_appendix/faq/errors.md
index 4503a8c..04bc1cb 100644
--- a/15_appendix/faq/errors.md
+++ b/15_appendix/faq/errors.md
@@ -1,11 +1,11 @@
-# 常见错误速查表
+## 常见错误速查表
| 错误信息 / 现象 | 可能原因 | 解决方案 |
| :--- | :--- | :--- |
| `Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?` | Docker 服务未启动 | Linux: `sudo systemctl start docker`
Mac/Win: 启动 Docker Desktop |
| `permission denied while trying to connect to the Docker daemon socket` | 当前用户不在 `docker` 用户组 | `sudo usermod -aG docker $USER` (需重新登录) |
| `manifest for ... not found: manifest unknown` | 镜像 tag 不存在 | 检查 Docker Hub 该镜像是否存在该 tag,或拼写是否正确 |
-| `connection refused` (pull image) | 网络不通或镜像源无法访问 | 检查网络,配置[镜像加速器](../../install/mirror.md) |
+| `connection refused` (pull image) | 网络不通或镜像源无法访问 | 检查网络,配置[镜像加速器](../../install/3.9_mirror.md) |
| `Bind for 0.0.0.0:8080 failed: port is already allocated` | 端口被占用 | 检查占用端口的进程 (`lsof -i:8080`) 并杀掉,或换个端口映射 (`-p 8081:80`) |
| `exec user process caused "exec format error"` | 架构不匹配 (如在 x86 上跑 ARM 镜像) | 使用 `docker buildx` 构建多架构镜像,或拉取对应架构的镜像 |
| `standard_init_linux.go:211: exec user process caused "no such file or directory"` | 找不到解释器或依赖库 | 检查 `ENTRYPOINT`/`CMD` 脚本开头的 shebang (`#!/bin/sh` vs `#!/bin/bash`),或确认二进制文件是否依赖缺失 (Alpine 常见缺少 glibc) |
diff --git a/15_appendix/repo/README.md b/15_appendix/repo/README.md
index bc840d2..61efbbe 100644
--- a/15_appendix/repo/README.md
+++ b/15_appendix/repo/README.md
@@ -1,3 +1,3 @@
-# 热门镜像介绍
+## 热门镜像介绍
本章将介绍一些热门镜像的功能,使用方法等。包括 Ubuntu、CentOS、MySQL、MongoDB、Redis、Nginx、Wordpress、Node.js 等。
diff --git a/15_appendix/repo/centos.md b/15_appendix/repo/centos.md
index 9f6b7f3..12e69c9 100644
--- a/15_appendix/repo/centos.md
+++ b/15_appendix/repo/centos.md
@@ -1,6 +1,6 @@
-# [CentOS](https://hub.docker.com/_/centos)
+## [CentOS](https://hub.docker.com/_/centos)
-## 基本信息
+### 基本信息
[CentOS](https://en.wikipedia.org/wiki/CentOS) 是流行的 Linux 发行版,其软件包大多跟 RedHat 系列保持一致。
@@ -13,7 +13,7 @@
该仓库位于 `https://hub.docker.com/_/centos`,提供了 CentOS 从 5 ~ 8 各个版本的镜像(仅作为历史归档,不再更新)。
-## 使用方法
+### 使用方法
使用 Rocky Linux 9 替代(**推荐**):
@@ -27,6 +27,6 @@ $ docker run --name rocky -it rockylinux:9 bash
$ docker run --name centos -it centos:7 bash
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/centos 查看。
diff --git a/15_appendix/repo/minio.md b/15_appendix/repo/minio.md
index 627100d..2aef900 100644
--- a/15_appendix/repo/minio.md
+++ b/15_appendix/repo/minio.md
@@ -1,4 +1,4 @@
-# minio
+## minio
**MinIO** 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb 到最大 5T 不等。
@@ -6,7 +6,7 @@ MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合
[官方文档](https://docs.min.io/)
-## 简单使用
+### 简单使用
测试、开发环境下不考虑数据存储的情况下可以使用下面的命令快速开启服务。
@@ -14,11 +14,11 @@ MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合
$ docker run -d -p 9000:9000 -p 9090:9090 minio/minio server /data --console-address ':9090'
```
-## 离线部署
+### 离线部署
许多生产环境是一般是没有公网资源的,这就需要从有公网资源的服务器上把镜像导出,然后导入到需要运行镜像的内网服务器。
-### 导出镜像
+#### 导出镜像
在有公网资源的服务器上下载好`minio/minio`镜像
@@ -28,7 +28,7 @@ $ docker save -o minio.tar minio/minio:latest
> 使用docker save 的时候,也可以使用image id 来导出,但是那样导出的时候,就会丢失原来的镜像名称,推荐,还是使用镜像名字+tag来导出镜像
-### 导入镜像
+#### 导入镜像
把压缩文件复制到内网服务器上,使用下面的命令导入镜像
@@ -36,7 +36,7 @@ $ docker save -o minio.tar minio/minio:latest
$ docker load minio.tar
```
-### 运行 minio
+#### 运行 minio
- 把 `/mnt/data` 改成要替换的数据目录
- 替换 `MINIO_ROOT_USER` 的值
@@ -53,6 +53,6 @@ $ sudo docker run -d -p 9000:9000 -p 9090:9090 --name minio1 \
minio/minio server /data --console-address ':9090'
```
-### 访问 web 管理页面
+#### 访问 web 管理页面
http://x.x.x.x:9090
diff --git a/15_appendix/repo/mongodb.md b/15_appendix/repo/mongodb.md
index ec2cf45..2d25ec5 100644
--- a/15_appendix/repo/mongodb.md
+++ b/15_appendix/repo/mongodb.md
@@ -1,12 +1,12 @@
-# [MongoDB](https://hub.docker.com/_/mongo/)
+## [MongoDB](https://hub.docker.com/_/mongo/)
-## 基本信息
+### 基本信息
[MongoDB](https://en.wikipedia.org/wiki/MongoDB) 是开源的 NoSQL 数据库实现。
该仓库位于 `https://hub.docker.com/_/mongo/` ,提供了 MongoDB 2.x ~ 4.x 各个版本的镜像。
-## 使用方法
+### 使用方法
默认会在 `27017` 端口启动数据库。
@@ -39,6 +39,6 @@ $ docker run -it --rm \
```
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/mongo 查看。
diff --git a/15_appendix/repo/mysql.md b/15_appendix/repo/mysql.md
index 53ce97c..4412058 100644
--- a/15_appendix/repo/mysql.md
+++ b/15_appendix/repo/mysql.md
@@ -1,12 +1,12 @@
-# [MySQL](https://hub.docker.com/_/mysql/)
+## [MySQL](https://hub.docker.com/_/mysql/)
-## 基本信息
+### 基本信息
[MySQL](https://en.wikipedia.org/wiki/MySQL) 是开源的关系数据库实现。
该仓库位于 `https://hub.docker.com/_/mysql/` ,提供了 MySQL 5.5 ~ 8.x 各个版本的镜像。
-## 使用方法
+### 使用方法
默认会在 `3306` 端口启动数据库。
@@ -41,6 +41,6 @@ $ docker run -it --rm \
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/mysql 查看
diff --git a/15_appendix/repo/nginx.md b/15_appendix/repo/nginx.md
index 84a3396..2eccfb8 100644
--- a/15_appendix/repo/nginx.md
+++ b/15_appendix/repo/nginx.md
@@ -1,12 +1,12 @@
-# [Nginx](https://hub.docker.com/_/nginx/)
+## [Nginx](https://hub.docker.com/_/nginx/)
-## 基本信息
+### 基本信息
[Nginx](https://en.wikipedia.org/wiki/Nginx) 是开源的高效的 Web 服务器实现,支持 HTTP、HTTPS、SMTP、POP3、IMAP 等协议。
该仓库位于 `https://hub.docker.com/_/nginx/` ,提供了 Nginx 1.0 ~ 1.19.x 各个版本的镜像。
-## 使用方法
+### 使用方法
下面的命令将作为一个静态页面服务器启动。
@@ -44,6 +44,6 @@ $ docker run -d \
nginx
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/nginx 查看。
diff --git a/15_appendix/repo/nodejs.md b/15_appendix/repo/nodejs.md
index 9af57c1..1b52611 100644
--- a/15_appendix/repo/nodejs.md
+++ b/15_appendix/repo/nodejs.md
@@ -1,18 +1,18 @@
-# [Node.js](https://hub.docker.com/_/node/)
+## [Node.js](https://hub.docker.com/_/node/)
-## 基本信息
+### 基本信息
[Node.js](https://en.wikipedia.org/wiki/Node.js) 是基于 JavaScript 的可扩展服务端和网络软件开发平台。
该仓库位于 `https://hub.docker.com/_/node/` ,提供了 Node.js 0.10 ~ 14.x 各个版本的镜像。
-## 使用方法
+### 使用方法
在项目中创建一个 Dockerfile。
```docker
FROM node:12
-# replace this with your application's default port
+## replace this with your application's default port
EXPOSE 8888
```
@@ -35,6 +35,6 @@ $ docker run -it --rm \
node your-daemon-or-script.js
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/node 查看。
diff --git a/15_appendix/repo/php.md b/15_appendix/repo/php.md
index 5ef53b8..2c9ab8b 100644
--- a/15_appendix/repo/php.md
+++ b/15_appendix/repo/php.md
@@ -1,12 +1,12 @@
-# [PHP](https://hub.docker.com/_/php/)
+## [PHP](https://hub.docker.com/_/php/)
-## 基本信息
+### 基本信息
[PHP](https://en.wikipedia.org/wiki/Php)(Hypertext Preprocessor 超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML 中,尤其适合 web 开发。
该仓库位于 `https://hub.docker.com/_/php/` ,提供了 PHP 5.x ~ 8.x 各个版本的镜像。
-## 使用方法
+### 使用方法
下面的命令将运行一个已有的 PHP 脚本。
@@ -14,6 +14,6 @@
$ docker run -it --rm -v "$PWD":/app -w /app php:alpine php your-script.php
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/php 查看。
diff --git a/15_appendix/repo/redis.md b/15_appendix/repo/redis.md
index 77a53f7..85a2b7c 100644
--- a/15_appendix/repo/redis.md
+++ b/15_appendix/repo/redis.md
@@ -1,12 +1,12 @@
-# [Redis](https://hub.docker.com/_/redis/)
+## [Redis](https://hub.docker.com/_/redis/)
-## 基本信息
+### 基本信息
[Redis](https://en.wikipedia.org/wiki/Redis) 是开源的内存 Key-Value 数据库实现。
该仓库位于 `https://hub.docker.com/_/redis/` ,提供了 Redis 3.x ~ 6.x 各个版本的镜像。
-## 使用方法
+### 使用方法
默认会在 `6379` 端口启动数据库。
@@ -46,6 +46,6 @@ $ docker run -it --rm \
sh -c 'exec redis-cli -h some-redis'
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/redis 查看。
diff --git a/15_appendix/repo/ubuntu.md b/15_appendix/repo/ubuntu.md
index c2f534e..2d8d38e 100644
--- a/15_appendix/repo/ubuntu.md
+++ b/15_appendix/repo/ubuntu.md
@@ -1,12 +1,12 @@
-# [Ubuntu](https://hub.docker.com/_/ubuntu/)
+## [Ubuntu](https://hub.docker.com/_/ubuntu/)
-## 基本信息
+### 基本信息
[Ubuntu](https://en.wikipedia.org/wiki/Ubuntu) 是流行的 Linux 发行版,其自带软件版本往往较新一些。
该仓库位于 `https://hub.docker.com/_/ubuntu/` ,提供了 Ubuntu 从 12.04 ~ 20.04 各个版本的镜像。
-## 使用方法
+### 使用方法
默认会启动一个最小化的 Ubuntu 环境。
@@ -15,6 +15,6 @@ $ docker run --name some-ubuntu -it ubuntu:20.04
root@523c70904d54:/#
```
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/ubuntu 查看。
diff --git a/15_appendix/repo/wordpress.md b/15_appendix/repo/wordpress.md
index 1989e6f..4312c14 100644
--- a/15_appendix/repo/wordpress.md
+++ b/15_appendix/repo/wordpress.md
@@ -1,12 +1,12 @@
-# [WordPress](https://hub.docker.com/_/wordpress/)
+## [WordPress](https://hub.docker.com/_/wordpress/)
-## 基本信息
+### 基本信息
[WordPress](https://en.wikipedia.org/wiki/WordPress) 是开源的 Blog 和内容管理系统框架,它基于 PHP 和 MySQL。
该仓库位于 `https://hub.docker.com/_/wordpress/` ,提供了 WordPress 4.x ~ 5.x 版本的镜像。
-## 使用方法
+### 使用方法
启动容器需要 MySQL 的支持,默认端口为 `80`。
@@ -33,6 +33,6 @@ $ docker run --name some-wordpress -d --network my-wordpress-net -e WORDPRESS_DB
* `WORDPRESS_DB_NAME`: WordPress 要使用的数据库名
-## Dockerfile
+### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/wordpress 查看。
diff --git a/README.md b/README.md
index 589b958..4513748 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[](https://github.com/yeasy/docker_practice) [](https://github.com/yeasy/docker_practice/releases) [](https://github.com/docker/docker-ce) [][1]
-**v1.5.0**
+**v1.5.1**
[Docker](https://www.docker.com) 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!
diff --git a/SUMMARY.md b/SUMMARY.md
index 77162bd..a43116d 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -7,32 +7,32 @@
## 第一部分: 入门篇
* [第一章 Docker 简介](01_introduction/README.md)
- * [快速上手](01_introduction/quickstart.md)
- * [什么是 Docker](01_introduction/what.md)
- * [为什么要用 Docker](01_introduction/why.md)
+ * [快速上手](01_introduction/1.1_quickstart.md)
+ * [什么是 Docker](01_introduction/1.2_what.md)
+ * [为什么要用 Docker](01_introduction/1.3_why.md)
* [第二章 基本概念](02_basic_concept/README.md)
- * [镜像](02_basic_concept/image.md)
- * [容器](02_basic_concept/container.md)
- * [仓库](02_basic_concept/repository.md)
+ * [镜像](02_basic_concept/2.1_image.md)
+ * [容器](02_basic_concept/2.2_container.md)
+ * [仓库](02_basic_concept/2.3_repository.md)
* [第三章 安装 Docker](03_install/README.md)
- * [Ubuntu](03_install/ubuntu.md)
- * [Debian](03_install/debian.md)
- * [Fedora](03_install/fedora.md)
- * [CentOS](03_install/centos.md)
- * [Raspberry Pi](03_install/raspberry-pi.md)
- * [Linux 离线安装](03_install/offline.md)
- * [macOS](03_install/mac.md)
- * [Windows 10/11](03_install/windows.md)
- * [镜像加速器](03_install/mirror.md)
- * [开启实验特性](03_install/experimental.md)
+ * [Ubuntu](03_install/3.1_ubuntu.md)
+ * [Debian](03_install/3.2_debian.md)
+ * [Fedora](03_install/3.3_fedora.md)
+ * [CentOS](03_install/3.4_centos.md)
+ * [Raspberry Pi](03_install/3.5_raspberry-pi.md)
+ * [Linux 离线安装](03_install/3.6_offline.md)
+ * [macOS](03_install/3.7_mac.md)
+ * [Windows 10/11](03_install/3.8_windows.md)
+ * [镜像加速器](03_install/3.9_mirror.md)
+ * [开启实验特性](03_install/3.10_experimental.md)
* [第四章 使用镜像](04_image/README.md)
- * [获取镜像](04_image/pull.md)
- * [列出镜像](04_image/list.md)
- * [删除本地镜像](04_image/rm.md)
- * [利用 commit 理解镜像构成](04_image/commit.md)
- * [使用 Dockerfile 定制镜像](04_image/build.md)
+ * [获取镜像](04_image/4.1_pull.md)
+ * [列出镜像](04_image/4.2_list.md)
+ * [删除本地镜像](04_image/4.3_rm.md)
+ * [利用 commit 理解镜像构成](04_image/4.4_commit.md)
+ * [使用 Dockerfile 定制镜像](04_image/4.5_build.md)
* [Dockerfile 指令详解](04_image/dockerfile/README.md)
- * [RUN 执行命令](04_image/dockerfile/run.md)
+ * [RUN 执行命令](04_image/dockerfile/5.1_run.md)
* [COPY 复制文件](04_image/dockerfile/copy.md)
* [ADD 更高级的复制文件](04_image/dockerfile/add.md)
* [CMD 容器启动命令](04_image/dockerfile/cmd.md)
@@ -50,20 +50,20 @@
* [参考文档](04_image/dockerfile/references.md)
* [Dockerfile 多阶段构建](04_image/multistage-builds/README.md)
* [实战多阶段构建 Laravel 镜像](04_image/multistage-builds/laravel.md)
- * [其它制作镜像的方式](04_image/other.md)
- * [实现原理](04_image/internal.md)
+ * [其它制作镜像的方式](04_image/4.6_other.md)
+ * [实现原理](04_image/4.7_internal.md)
* [第五章 操作容器](05_container/README.md)
- * [启动](05_container/run.md)
- * [守护态运行](05_container/daemon.md)
- * [终止](05_container/stop.md)
- * [进入容器](05_container/attach_exec.md)
- * [导出和导入](05_container/import_export.md)
- * [删除](05_container/rm.md)
+ * [启动](05_container/5.1_run.md)
+ * [守护态运行](05_container/5.2_daemon.md)
+ * [终止](05_container/5.3_stop.md)
+ * [进入容器](05_container/5.4_attach_exec.md)
+ * [导出和导入](05_container/5.5_import_export.md)
+ * [删除](05_container/4.3_rm.md)
* [第六章 访问仓库](06_repository/README.md)
- * [Docker Hub](06_repository/dockerhub.md)
- * [私有仓库](06_repository/registry.md)
- * [私有仓库高级配置](06_repository/registry_auth.md)
- * [Nexus 3](06_repository/nexus3_registry.md)
+ * [Docker Hub](06_repository/6.1_dockerhub.md)
+ * [私有仓库](06_repository/6.2_registry.md)
+ * [私有仓库高级配置](06_repository/6.3_registry_auth.md)
+ * [Nexus 3](06_repository/6.4_nexus3_registry.md)
## 第二部分: 进阶篇
@@ -75,19 +75,19 @@
* [配置 DNS](07_data_network/network/dns.md)
* [外部访问容器](07_data_network/network/port_mapping.md)
* [第八章 Docker Buildx](08_buildx/README.md)
- * [BuildKit](08_buildx/buildkit.md)
- * [使用 buildx 构建镜像](08_buildx/buildx.md)
- * [使用 buildx 构建多种系统架构支持的 Docker 镜像](08_buildx/multi-arch-images.md)
+ * [BuildKit](08_buildx/8.1_buildkit.md)
+ * [使用 buildx 构建镜像](08_buildx/8.2_buildx.md)
+ * [使用 buildx 构建多种系统架构支持的 Docker 镜像](08_buildx/8.3_multi-arch-images.md)
* [第九章 Docker Compose](09_compose/README.md)
- * [简介](09_compose/introduction.md)
- * [安装与卸载](09_compose/install.md)
- * [使用](09_compose/usage.md)
- * [命令说明](09_compose/commands.md)
- * [Compose 模板文件](09_compose/compose_file.md)
- * [实战 Django](09_compose/django.md)
- * [实战 Rails](09_compose/rails.md)
- * [实战 WordPress](09_compose/wordpress.md)
- * [实战 LNMP](09_compose/lnmp.md)
+ * [简介](09_compose/9.1_introduction.md)
+ * [安装与卸载](09_compose/9.2_install.md)
+ * [使用](09_compose/9.3_usage.md)
+ * [命令说明](09_compose/9.4_commands.md)
+ * [Compose 模板文件](09_compose/9.5_compose_file.md)
+ * [实战 Django](09_compose/9.6_django.md)
+ * [实战 Rails](09_compose/9.7_rails.md)
+ * [实战 WordPress](09_compose/9.8_wordpress.md)
+ * [实战 LNMP](09_compose/9.9_lnmp.md)
* [第十章 运维管理](10_ops/README.md)
* [容器监控](10_ops/monitor/README.md)
* [Prometheus](10_ops/monitor/prometheus.md)
@@ -106,7 +106,7 @@
* [第十一章 容器编排](11_orchestration/README.md)
* [Etcd 项目](11_orchestration/etcd/README.md)
* [简介](11_orchestration/etcd/intro.md)
- * [安装](11_orchestration/etcd/install.md)
+ * [安装](11_orchestration/etcd/9.2_install.md)
* [集群](11_orchestration/etcd/cluster.md)
* [使用 etcdctl](11_orchestration/etcd/etcdctl.md)
* [Kubernetes - 开源容器编排引擎](11_orchestration/kubernetes/README.md)
@@ -127,7 +127,7 @@
* [第十二章 容器生态](12_ecosystem/README.md)
* [Fedora CoreOS](12_ecosystem/coreos/README.md)
* [简介](12_ecosystem/coreos/intro.md)
- * [安装](12_ecosystem/coreos/install.md)
+ * [安装](12_ecosystem/coreos/9.2_install.md)
* [容器与云计算](12_ecosystem/cloud/README.md)
* [简介](12_ecosystem/cloud/intro.md)
* [腾讯云](12_ecosystem/cloud/tencentCloud.md)
@@ -137,12 +137,12 @@
* [多云部署策略](12_ecosystem/cloud/multicloud.md)
* [podman - 下一代 Linux 容器工具](12_ecosystem/podman/README.md)
* [第十三章 底层实现](13_implementation/README.md)
- * [基本架构](13_implementation/arch.md)
- * [命名空间](13_implementation/namespace.md)
- * [控制组](13_implementation/cgroups.md)
- * [联合文件系统](13_implementation/ufs.md)
- * [容器格式](13_implementation/container_format.md)
- * [网络](13_implementation/network.md)
+ * [基本架构](13_implementation/13.1_arch.md)
+ * [命名空间](13_implementation/13.2_namespace.md)
+ * [控制组](13_implementation/13.3_cgroups.md)
+ * [联合文件系统](13_implementation/13.4_ufs.md)
+ * [容器格式](13_implementation/13.5_container_format.md)
+ * [网络](13_implementation/13.6_network.md)
## 第四部分: 实战篇
@@ -150,33 +150,33 @@
* [实战案例 - 操作系统](14_cases/os/README.md)
* [Busybox](14_cases/os/busybox.md)
* [Alpine](14_cases/os/alpine.md)
- * [Debian Ubuntu](14_cases/os/debian.md)
- * [CentOS Fedora](14_cases/os/centos.md)
+ * [Debian Ubuntu](14_cases/os/3.2_debian.md)
+ * [CentOS Fedora](14_cases/os/3.4_centos.md)
* [本章小结](14_cases/os/summary.md)
* [实战案例 - CI/CD](14_cases/ci/README.md)
* [DevOps 完整工作流](14_cases/ci/devops_workflow.md)
* [GitHub Actions](14_cases/ci/actions/README.md)
* [Drone](14_cases/ci/drone/README.md)
- * [部署 Drone](14_cases/ci/drone/install.md)
+ * [部署 Drone](14_cases/ci/drone/9.2_install.md)
* [在 IDE 中使用 Docker](14_cases/ide/README.md)
* [VS Code](14_cases/ide/vsCode.md)
* [第十五章 附录](15_appendix/README.md)
* [附录一:常见问题总结](15_appendix/faq/README.md)
* [常见错误速查表](15_appendix/faq/errors.md)
* [附录二:热门镜像介绍](15_appendix/repo/README.md)
- * [Ubuntu](15_appendix/repo/ubuntu.md)
- * [CentOS](15_appendix/repo/centos.md)
+ * [Ubuntu](15_appendix/repo/3.1_ubuntu.md)
+ * [CentOS](15_appendix/repo/3.4_centos.md)
* [Nginx](15_appendix/repo/nginx.md)
* [PHP](15_appendix/repo/php.md)
* [Node.js](15_appendix/repo/nodejs.md)
* [MySQL](15_appendix/repo/mysql.md)
- * [WordPress](15_appendix/repo/wordpress.md)
+ * [WordPress](15_appendix/repo/9.8_wordpress.md)
* [MongoDB](15_appendix/repo/mongodb.md)
* [Redis](15_appendix/repo/redis.md)
* [Minio](15_appendix/repo/minio.md)
* [附录三:Docker 命令查询](15_appendix/command/README.md)
* [客户端命令 - docker](15_appendix/command/docker.md)
* [服务端命令 - dockerd](15_appendix/command/dockerd.md)
- * [附录四:Dockerfile 最佳实践](15_appendix/best_practices.md)
- * [附录五:如何调试 Docker](15_appendix/debug.md)
- * [附录六:资源链接](15_appendix/resources.md)
+ * [附录四:Dockerfile 最佳实践](15_appendix/15.1_best_practices.md)
+ * [附录五:如何调试 Docker](15_appendix/15.2_debug.md)
+ * [附录六:资源链接](15_appendix/15.3_resources.md)