diff --git a/01_introduction/1.1_quickstart.md b/01_introduction/1.1_quickstart.md
index e3aa5fa..581443b 100644
--- a/01_introduction/1.1_quickstart.md
+++ b/01_introduction/1.1_quickstart.md
@@ -9,7 +9,6 @@
```html
Hello, Docker!
```
-
### 1.1.2 编写 Dockerfile
在同级目录下创建一个名为 `Dockerfile` (无后缀) 的文件:
@@ -18,7 +17,6 @@
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
```
-
### 1.1.3 构建镜像
打开终端,进入该目录,执行构建命令:
@@ -26,7 +24,6 @@ COPY index.html /usr/share/nginx/html/index.html
```bash
$ docker build -t my-hello-world .
```
-
* `docker build`:构建命令
* `-t my-hello-world`:给镜像起个名字 (标签)
* `.`:指定上下文路径为当前目录
@@ -38,7 +35,6 @@ $ docker build -t my-hello-world .
```bash
$ docker run -d -p 8080:80 my-hello-world
```
-
* `docker run`:运行命令
* `-d`:后台运行
* `-p 8080:80`:将宿主机的 8080 端口映射到容器的 80 端口
@@ -52,7 +48,6 @@ $ docker run -d -p 8080:80 my-hello-world
停止并删除容器:
```bash
-
## 查看正在运行的容器 ID
$ docker ps
@@ -65,5 +60,4 @@ $ docker stop
$ docker rm
```
-
恭喜!你已经完成了第一次 Docker 实战。接下来请阅读 [Docker 核心概念](../02_basic_concept/README.md)做深入了解。
diff --git a/01_introduction/1.2_what.md b/01_introduction/1.2_what.md
index 3785057..a2a0537 100644
--- a/01_introduction/1.2_what.md
+++ b/01_introduction/1.2_what.md
@@ -26,7 +26,6 @@ flowchart LR
end
A -.->|不一致| C
```
-
有了 Docker:
```mermaid
@@ -41,7 +40,6 @@ flowchart LR
end
A == 一致 ==> C
```
-
### 1.2.3 Docker vs 虚拟机
很多人第一次接触 Docker 时会问:**“这不就是虚拟机吗?”** 答案是:**不是,而且差别很大。**
@@ -94,7 +92,6 @@ flowchart LR
runC --> OCI["OCI
标准化"]
end
```
-
- **LXC** (2013):Docker 最初基于 Linux Containers
- **libcontainer** (2014,v0.7):Docker 自研的容器运行时
- **runC** (2015,v1.11):捐献给 OCI 的标准容器运行时
diff --git a/01_introduction/1.3_why.md b/01_introduction/1.3_why.md
index e04b9c6..c110c41 100644
--- a/01_introduction/1.3_why.md
+++ b/01_introduction/1.3_why.md
@@ -15,7 +15,6 @@
│ └── 测试:"这个功能在测试环境跑不起来"
└── 开发者:"不可能,在我电脑上明明能跑啊……"
```
-
笔者统计过,这个问题通常由以下原因导致:
- Python/Node/Java 版本不一致
@@ -34,7 +33,6 @@
├── Day 4:问老同事怎么配的,他也忘了
└── Day 5:终于能跑起来了!但不知道为什么……
```
-
#### 场景三:服务器迁移的恐惧
```bash
@@ -43,7 +41,6 @@
运维:"当时是一个已经离职的同事配的……"
所有人:😱
```
-
### 1.3.2 Docker 如何解决这些问题
Docker 的出现为上述问题提供了完美的解决方案。它通过 “一次构建,到处运行” 的核心理念,从根本上改变了软件交付的方式。
@@ -57,7 +54,6 @@ flowchart LR
test -- "有问题
反馈修改和更新" --> dev
test -- "没问题
发布" --> prod["生产环境"]
```
-
### 1.3.3 Docker 的核心优势
除了解决上述痛点,Docker 还拥有诸多显著的技术优势,包括环境一致性、秒级启动、高效的资源利用等。
@@ -71,7 +67,6 @@ Docker 镜像包含了应用运行所需的 **一切**:代码、运行时、
- ✅ 新人入职,一条命令就能启动开发环境
```bash
-
## 新同事入职第一天
$ git clone https://github.com/company/project.git
@@ -81,7 +76,6 @@ $ docker compose up
...
```
-
#### 2. 秒级启动
传统虚拟机启动需要几分钟 (引导操作系统),而 Docker 容器启动通常只需要 **几秒甚至几百毫秒**。
@@ -132,7 +126,6 @@ flowchart TD
Server2 --- Containers
end
```
-
#### 4. 持续交付和部署
Docker 完美契合 DevOps 的工作流程:
@@ -143,7 +136,6 @@ flowchart LR
B --> C["自动测试
(容器内运行测试)"]
C --> D["自动部署
(容器滚动更新)"]
```
-
使用 [Dockerfile](../04_image/4.5_build.md) 定义镜像构建过程,使得:
- 构建过程 **可重复、可追溯**
@@ -190,7 +182,6 @@ flowchart TD
Worker --> DB
end
```
-
### 1.3.4 Docker 不适合的场景
笔者认为,技术选型要客观。Docker 并非银弹,以下场景可能不太适合:
diff --git a/02_basic_concept/2.1_image.md b/02_basic_concept/2.1_image.md
index 7388aa1..c39ede0 100644
--- a/02_basic_concept/2.1_image.md
+++ b/02_basic_concept/2.1_image.md
@@ -24,7 +24,6 @@ flowchart TD
UserSpace --- KernelSpace
```
-
对于 Linux 而言,内核启动后会挂载 `root` 文件系统来提供用户空间支持。**Docker 镜像** 本质上就是一个 `root` 文件系统。
例如,官方镜像 `ubuntu:24.04` 包含了一套完整的 Ubuntu 24.04 最小系统的 root 文件系统——但 **不包含 Linux 内核** (因为容器共享宿主机的内核)。
@@ -80,7 +79,6 @@ flowchart TD
AppC --> Ubuntu
end
```
-
#### 分层是如何工作的?
笔者用一个实际的 Dockerfile 来解释分层:
@@ -91,7 +89,6 @@ RUN apt-get update # 第 2 层:更新包索引
RUN apt-get install nginx # 第 3 层:安装 nginx
COPY app.conf /etc/nginx/ # 第 4 层:复制配置文件
```
-
构建后的镜像结构:
```mermaid
@@ -103,7 +100,6 @@ flowchart TD
Layer4 --> Layer3 --> Layer2 --> Layer1
```
-
每一层的特点:
- **只读**:构建完成后不可修改
@@ -115,7 +111,6 @@ flowchart TD
> ⚠️ **笔者特别提醒**:理解这一点可以帮你避免构建出臃肿的镜像。**关键原理**:每一层的文件变化会被记录,但 **删除操作只是标记,不会真正减小镜像体积**。
```docker
-
## 错误示范 ❌
FROM ubuntu:24.04
@@ -126,9 +121,7 @@ RUN apt-get remove build-essential # 试图删除编译工具
## 结果:镜像仍然包含 200MB 的编译工具!
```
-
```docker
-
## 正确做法 ✅
FROM ubuntu:24.04
@@ -142,11 +135,9 @@ RUN apt-get update && \
## 在同一层完成安装、使用、清理
```
-
#### 查看镜像的分层
```bash
-
## 查看镜像的历史(每层的构建记录)
$ docker history nginx:latest
@@ -159,7 +150,6 @@ a6bd71f48f68 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
2 weeks ago COPY 30-tune-worker-processes.sh /docker-ent… 4.62kB
...
```
-
### 2.1.5 镜像的标识
Docker 镜像有多种标识方式:
@@ -169,7 +159,6 @@ Docker 镜像有多种标识方式:
格式:`[仓库地址/]仓库名[:标签]`
```bash
-
## 完整格式
registry.example.com/myproject/myapp:v1.2.3
@@ -183,7 +172,6 @@ ubuntu:24.04
nginx # 等同于 nginx:latest
```
-
#### 2. 镜像 ID:Content-Addressable 标识
每个镜像有一个基于内容计算的唯一 ID:
@@ -194,7 +182,6 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest a6bd71f48f68 2 weeks ago 187MB
ubuntu 24.04 ca2b0f26964c 3 weeks ago 78.1MB
```
-
#### 3. 镜像摘要
更精确的标识,基于镜像内容的 SHA256 哈希:
@@ -204,7 +191,6 @@ $ docker images --digests
REPOSITORY TAG DIGEST IMAGE ID
nginx latest sha256:6db391d1c0cfb30588ba0bf72ea999404f2764184d8b8d10d89e8a9c6... a6bd71f48f68
```
-
> 💡 笔者建议:在生产环境使用镜像摘要而非标签,因为标签可以被覆盖,但摘要是不可变的。
### 2.1.6 镜像的来源
diff --git a/02_basic_concept/2.2_container.md b/02_basic_concept/2.2_container.md
index 644418f..9b0ef94 100644
--- a/02_basic_concept/2.2_container.md
+++ b/02_basic_concept/2.2_container.md
@@ -26,7 +26,6 @@ flowchart TD
C1["• 独立进程空间
• 独立网络环境
• 独立文件系统
• 独立用户空间"]
end
```
-
这种隔离是通过 Linux 内核的 **Namespace** 技术实现的。具体表现为:
- **进程空间**:容器看不到宿主机上的其他进程。
- **网络**:容器拥有独立的 IP、端口等网络资源。
@@ -67,7 +66,6 @@ flowchart TD
CApp --> CContainer --> CE --> CH --> CHW
end
```
-
| 特性 | 容器 | 虚拟机 |
|------|------|--------|
| **隔离级别** | 进程级 (Namespace)| 硬件级 (Hypervisor)|
@@ -94,7 +92,6 @@ flowchart TD
ContainerLayer --> ImageLayerN --> ImageLayerN1 --> Dots --> ImageLayer1
```
-
#### Copy-on-Write:写时复制
当容器需要修改镜像层中的文件时:
@@ -107,13 +104,11 @@ flowchart TD
读取文件:直接从镜像层读取(共享,高效)
修改文件:复制到容器层,然后修改(只有这个容器能看到修改)
```
-
#### ⚠️ 容器存储层的生命周期
> **笔者特别强调**:这是新手最容易踩的坑!**容器存储层与容器生命周期绑定。容器删除,数据就没了!**
```bash
-
## 创建容器,写入数据
$ docker run -it ubuntu bash
@@ -127,7 +122,6 @@ $ docker rm abc123
## 数据丢了!没有任何办法恢复!
```
-
#### 正确的数据持久化方式
按照 Docker 最佳实践,容器存储层应该保持 **无状态**。需要持久化的数据应该使用:
@@ -138,7 +132,6 @@ $ docker rm abc123
| **[绑定挂载 (Bind Mount) ](../08_data/8.2_bind-mounts.md)** | 挂载宿主机目录 | 开发时共享代码 |
```bash
-
## 使用数据卷(推荐)
$ docker run -v mydata:/var/lib/mysql mysql
@@ -147,7 +140,6 @@ $ docker run -v mydata:/var/lib/mysql mysql
$ docker run -v /host/path:/container/path nginx
```
-
这些位置的读写 **会跳过容器存储层**,直接写入宿主机,性能更好,也不会随容器删除而丢失。
### 2.2.5 容器的生命周期
@@ -169,13 +161,11 @@ stateDiagram-v2
Deleted --> [*]
```
-
图 2-1:容器生命周期状态流转图
#### 常用生命周期命令
```bash
-
## 创建并启动容器(最常用)
$ docker run nginx
@@ -200,23 +190,19 @@ $ docker unpause abc123 # 恢复
$ docker rm abc123 # 删除已停止的容器
$ docker rm -f abc123 # 强制删除运行中的容器
```
-
### 2.2.6 容器与进程的关系
> **核心概念**:容器的生命周期 = 主进程 (PID 1) 的生命周期
```bash
-
## 主进程运行,容器运行
## 主进程退出,容器停止
```
-
这就是为什么:
```bash
-
## 这个容器会立即退出(bash 没有输入就退出了)
$ docker run ubuntu
@@ -225,7 +211,6 @@ $ docker run ubuntu
$ docker run nginx
```
-
详细解释请参考[后台运行](../05_container/5.2_daemon.md)章节。
### 2.2.7 容器的隔离性
diff --git a/02_basic_concept/2.3_repository.md b/02_basic_concept/2.3_repository.md
index 07e1362..71e2c19 100644
--- a/02_basic_concept/2.3_repository.md
+++ b/02_basic_concept/2.3_repository.md
@@ -40,7 +40,6 @@ flowchart TB
RepoNginx ~~~ RepoMysql
end
```
-
图 2-2:Registry、Repository 与 Tag 的层级关系
相关基本概念具体如下:
@@ -58,11 +57,9 @@ flowchart TB
```bash
[registry 地址/][用户名/]仓库名[:标签]
```
-
示例:
```bash
-
## 完整格式
registry.example.com/mycompany/myapp:v1.2.3
@@ -86,7 +83,6 @@ jwilder/nginx-proxy:latest
ghcr.io/username/myapp:v1.0
gcr.io/google-containers/pause:3.6
```
-
> 💡 **笔者提示**:如果不指定 Registry 地址,默认使用 Docker Hub。如果不指定标签,默认使用 `latest`。
### 2.3.3 公共 Registry 服务
@@ -104,7 +100,6 @@ gcr.io/google-containers/pause:3.6
- 付费账户支持私有仓库
```bash
-
## 从 Docker Hub 拉取镜像
$ docker pull nginx # 官方镜像
@@ -115,7 +110,6 @@ $ docker pull bitnami/redis # 第三方镜像
$ docker login
$ docker push username/myapp:v1.0
```
-
#### 其他公共 Registry
除了 Docker Hub,还有以下几个常见的公共 Registry:
@@ -140,7 +134,6 @@ $ docker push username/myapp:v1.0
]
}
```
-
详细配置方法请参考[镜像加速器](../03_install/3.9_mirror.md)章节。
> ⚠️ **笔者提醒**:镜像加速器的可用性经常变化,使用前建议先测试是否可用。
@@ -154,7 +147,6 @@ $ docker push username/myapp:v1.0
Docker 官方提供了 [registry](https://hub.docker.com/_/registry/) 镜像,可以快速搭建私有 Registry:
```bash
-
## 启动一个本地 Registry
$ docker run -d -p 5000:5000 --name registry registry:2
@@ -168,7 +160,6 @@ $ docker push localhost:5000/myapp:v1.0
$ docker pull localhost:5000/myapp:v1.0
```
-
#### 企业级解决方案
官方 Registry 功能较为基础,企业环境常用以下方案:
@@ -208,13 +199,11 @@ $ docker pull localhost:5000/myapp:v1.0
│ │ docker run │
│ │ 运行容器 │
```
-
图 2-3:镜像构建、推送与拉取流程
#### 常用命令
```bash
-
## 登录 Registry
$ docker login # 登录 Docker Hub
@@ -236,7 +225,6 @@ $ docker push registry.example.com/myteam/myapp:v1.0
$ docker logout
```
-
### 2.3.7 镜像的安全性
在使用公共镜像或维护私有镜像时,安全性是不容忽视的重要环节。
@@ -246,7 +234,6 @@ $ docker logout
Docker Hub 的[官方镜像](https://hub.docker.com/search?q=&type=image&image_filter=official) (标有 “Official Image” 标识) 经过 Docker 团队审核,相对更安全。示例如下:
```bash
-
## 官方镜像示例
nginx # ✅ 官方
@@ -258,7 +245,6 @@ redis # ✅ 官方
bitnami/redis # ⚠️ 需要评估
someuser/myapp # ⚠️ 需要评估
```
-
#### 镜像签名
当前更推荐使用 Sigstore / Notation 体系进行镜像签名与验证。`Docker Content Trust (DCT)` 已进入退场阶段,不建议作为新项目主方案。
@@ -266,7 +252,6 @@ someuser/myapp # ⚠️ 需要评估
> 注意:Cosign 默认会把签名写回镜像所在仓库,请使用你有推送权限的镜像地址。
```bash
-
## 准备一个你有写权限的镜像地址
$ export IMAGE=<你的仓库名>/nginx:1.27
$ docker pull nginx:1.27
@@ -280,11 +265,9 @@ $ cosign generate-key-pair
$ cosign sign --key cosign.key $IMAGE
$ cosign verify --key cosign.pub $IMAGE
```
-
#### 漏洞扫描
```bash
-
## 使用 Docker Scout 扫描镜像漏洞
$ docker scout cves nginx:latest
diff --git a/03_install/3.1_ubuntu.md b/03_install/3.1_ubuntu.md
index 560ecaa..a41f7ed 100644
--- a/03_install/3.1_ubuntu.md
+++ b/03_install/3.1_ubuntu.md
@@ -36,7 +36,6 @@ do
sudo apt remove $pkg;
done
```
-
### 3.1.2 使用 APT 安装
由于 `apt` 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
@@ -51,7 +50,6 @@ $ sudo apt install \
gnupg \
lsb-release
```
-
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
为了确认所下载软件包的合法性,需要添加软件源的 `GPG` 密钥。
@@ -62,7 +60,6 @@ $ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --
# 官方源
# $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```
-
然后,我们需要向 `sources.list` 中添加 Docker 软件源
```bash
@@ -75,7 +72,6 @@ $ 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
@@ -87,7 +83,6 @@ $ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io
```
-
### 3.1.3 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
@@ -95,7 +90,6 @@ $ sudo apt install docker-ce docker-ce-cli containerd.io
> 若你想安装测试版的 Docker,请从 test.docker.com 获取脚本
```bash
-
# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
@@ -103,7 +97,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
-
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定 (stable) 版本安装在系统中。
### 3.1.4 启动 Docker
@@ -112,7 +105,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-
### 3.1.5 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -127,13 +119,11 @@ $ sudo systemctl start docker
```bash
$ sudo groupadd docker
```
-
将当前用户加入 `docker` 组:
```bash
$ sudo usermod -aG docker $USER
```
-
退出当前终端并重新登录,进行如下测试。
### 3.1.6 测试 Docker 是否安装正确
@@ -168,7 +158,6 @@ Share images, automate workflows, and more with a free Docker ID:
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
-
若能正常输出以上信息,则说明安装成功。
### 3.1.7 镜像加速
diff --git a/03_install/3.2_debian.md b/03_install/3.2_debian.md
index 0bb944e..02594ac 100644
--- a/03_install/3.2_debian.md
+++ b/03_install/3.2_debian.md
@@ -25,7 +25,6 @@ $ sudo apt-get remove docker \
docker-engine \
docker.io
```
-
### 3.2.2 使用 APT 安装
由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
@@ -40,7 +39,6 @@ $ sudo apt-get install \
gnupg \
lsb-release
```
-
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
为了确认所下载软件包的合法性,需要添加软件源的 GPG 密钥。
@@ -51,7 +49,6 @@ $ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg --
# 官方源
# $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```
-
然后,我们需要向 `sources.list` 中添加 Docker 软件源:
> 在一些基于 Debian 的 Linux 发行版中 `$(lsb_release -cs)` 可能不会返回 Debian 的版本代号,例如 [Kali Linux](https://www.kali.org/docs/policy/kali-linux-relationship-with-debian/)、[BunsenLabs Linux](https://www.bunsenlabs.org/)。在这些发行版中我们需要将下面命令中的 `$(lsb_release -cs)` 替换为 https://mirrors.aliyun.com/docker-ce/linux/debian/dists/ 中支持的 Debian 版本代号,例如 `buster`。
@@ -66,7 +63,6 @@ $ 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
@@ -78,7 +74,6 @@ $ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
```
-
### 3.2.3 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Debian 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
@@ -86,7 +81,6 @@ $ sudo apt-get install docker-ce docker-ce-cli containerd.io
> 若你想安装测试版的 Docker,请从 test.docker.com 获取脚本
```bash
-
# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
@@ -94,7 +88,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
-
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定 (stable) 版本安装在系统中。
### 3.2.4 启动 Docker
@@ -103,7 +96,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-
### 3.2.5 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -118,13 +110,11 @@ $ sudo systemctl start docker
```bash
$ sudo groupadd docker
```
-
将当前用户加入 `docker` 组:
```bash
$ sudo usermod -aG docker $USER
```
-
退出当前终端并重新登录,进行如下测试。
### 3.2.6 测试 Docker 是否安装正确
@@ -159,7 +149,6 @@ Share images, automate workflows, and more with a free Docker ID:
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
-
若能正常输出以上信息,则说明安装成功。
### 3.2.7 镜像加速
diff --git a/03_install/3.3_fedora.md b/03_install/3.3_fedora.md
index 06bcb18..8c8abd7 100644
--- a/03_install/3.3_fedora.md
+++ b/03_install/3.3_fedora.md
@@ -32,7 +32,6 @@ $ sudo dnf remove docker \
docker-engine-selinux \
docker-engine
```
-
### 3.3.2 使用 dnf 安装
使用 dnf 包管理器安装是推荐的方式,便于后续的更行和管理。
@@ -42,7 +41,6 @@ $ sudo dnf remove docker \
```bash
$ sudo dnf -y install dnf-plugins-core
```
-
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
执行下面的命令添加 `dnf` 软件源:
@@ -59,19 +57,16 @@ $ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.r
# --add-repo \
# https://download.docker.com/linux/fedora/docker-ce.repo
```
-
如果需要测试版本的 Docker 请使用以下命令:
```bash
$ sudo dnf config-manager --set-enabled docker-ce-test
```
-
你也可以禁用测试版本的 Docker
```bash
$ sudo dnf config-manager --set-disabled docker-ce-test
```
-
#### 安装 Docker
更新 `dnf` 软件源缓存,并安装 `docker-ce`。
@@ -80,7 +75,6 @@ $ sudo dnf config-manager --set-disabled docker-ce-test
$ sudo dnf update
$ sudo dnf install docker-ce docker-ce-cli containerd.io
```
-
你也可以使用以下命令安装指定版本的 Docker
```bash
@@ -90,7 +84,6 @@ docker-ce.x86_64 18.06.1.ce-3.fc28 docker-ce-stable
$ sudo dnf -y install docker-ce-18.06.1.ce
```
-
### 3.3.3 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Fedora 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
@@ -98,7 +91,6 @@ $ sudo dnf -y install docker-ce-18.06.1.ce
> 若你想安装测试版的 Docker,请从 test.docker.com 获取脚本
```bash
-
# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
@@ -106,7 +98,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
-
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 最新稳定 (stable) 版本安装在系统中。
### 3.3.4 启动 Docker
@@ -115,7 +106,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-
### 3.3.5 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -130,13 +120,11 @@ $ sudo systemctl start docker
```bash
$ sudo groupadd docker
```
-
将当前用户加入 `docker` 组:
```bash
$ sudo usermod -aG docker $USER
```
-
退出当前终端并重新登录,进行如下测试。
### 3.3.6 测试 Docker 是否安装正确
@@ -171,7 +159,6 @@ Share images, automate workflows, and more with a free Docker ID:
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
-
若能正常输出以上信息,则说明安装成功。
### 3.3.7 镜像加速
diff --git a/03_install/3.4_centos.md b/03_install/3.4_centos.md
index e913d43..6dfa4be 100644
--- a/03_install/3.4_centos.md
+++ b/03_install/3.4_centos.md
@@ -34,7 +34,6 @@ $ sudo yum remove docker \
docker-ce-cli \
containerd.io
```
-
### 3.4.2 使用 yum 安装
使用 yum/dnf 安装是管理 Docker 生命周期的标准方式。
@@ -44,7 +43,6 @@ $ sudo yum remove docker \
```bash
$ sudo dnf install -y dnf-utils
```
-
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
执行下面的命令添加 `yum` 软件源:
@@ -61,13 +59,11 @@ $ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.r
# --add-repo \
# https://download.docker.com/linux/centos/docker-ce.repo
```
-
如果需要测试版本的 Docker 请执行以下命令:
```bash
$ sudo dnf config-manager --set-enabled docker-ce-test
```
-
#### 安装 Docker
更新 `dnf` 软件源缓存,并安装 `docker-ce`。
@@ -75,7 +71,6 @@ $ sudo dnf config-manager --set-enabled docker-ce-test
```bash
$ sudo dnf install docker-ce docker-ce-cli containerd.io
```
-
### 3.4.3 CentOS8 额外设置
CentOS 8/Stream 默认使用 `nftables`。Docker 在新版本中已提供 `nftables` 实验支持,但在一些环境下仍可能遇到兼容性问题。若你遇到容器网络异常,可以先切换回 `iptables` 后端:
@@ -83,12 +78,10 @@ CentOS 8/Stream 默认使用 `nftables`。Docker 在新版本中已提供 `nftab
更改 `/etc/firewalld/firewalld.conf`
```bash
-
## FirewallBackend=nftables
FirewallBackend=iptables
```
-
或者执行如下命令:
```bash
@@ -96,7 +89,6 @@ $ firewall-cmd --permanent --zone=trusted --add-interface=docker0
$ firewall-cmd --reload
```
-
### 3.4.4 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
@@ -104,7 +96,6 @@ $ firewall-cmd --reload
> 若你想安装测试版的 Docker,请从 test.docker.com 获取脚本
```bash
-
# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
@@ -113,7 +104,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
-
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定 (stable) 版本安装在系统中。
### 3.4.5 启动 Docker
@@ -122,7 +112,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-
### 3.4.6 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -137,13 +126,11 @@ $ sudo systemctl start docker
```bash
$ sudo groupadd docker
```
-
将当前用户加入 `docker` 组:
```bash
$ sudo usermod -aG docker $USER
```
-
退出当前终端并重新登录,进行如下测试。
### 3.4.7 测试 Docker 是否安装正确
@@ -178,7 +165,6 @@ Share images, automate workflows, and more with a free Docker ID:
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
-
若能正常输出以上信息,则说明安装成功。
### 3.4.8 镜像加速
@@ -193,7 +179,6 @@ For more examples and ideas, visit:
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
```
-
请添加内核配置参数以启用这些功能。
```bash
@@ -202,13 +187,11 @@ net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
```
-
然后重新加载 `sysctl.conf` 即可
```bash
$ sudo sysctl -p
```
-
### 3.4.10 参考文档
* [Docker 官方 CentOS 安装文档](https://docs.docker.com/engine/install/centos/)。
diff --git a/03_install/3.5_raspberry-pi.md b/03_install/3.5_raspberry-pi.md
index 3fc49b2..c98f389 100644
--- a/03_install/3.5_raspberry-pi.md
+++ b/03_install/3.5_raspberry-pi.md
@@ -34,7 +34,6 @@ $ sudo apt-get install \
gnupg \
lsb-release
```
-
鉴于国内网络问题,强烈建议使用国内源,官方源请在注释中查看。
为了确认所下载软件包的合法性,需要添加软件源的 GPG 密钥。
@@ -49,7 +48,6 @@ $ sudo chmod a+r /etc/apt/keyrings/docker.gpg
# $ curl -fsSL https://download.docker.com/linux/raspbian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# $ sudo chmod a+r /etc/apt/keyrings/docker.gpg
```
-
然后,我们需要向 `sources.list` 中添加 Docker 软件源:
```bash
@@ -62,7 +60,6 @@ $ echo \
# "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/raspbian \
# $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
-
> 以上命令会添加稳定版本的 Docker APT 源,如果需要测试版本的 Docker 请将 stable 改为 test。
#### 报错解决办法
@@ -81,7 +78,6 @@ Traceback (most recent call last):
raise NoDistroTemplateException(
aptsources.distro.NoDistroTemplateException: Error: could not find a distribution template for Raspbian/bullseye
```
-
通过以下命令手动添加镜像源到 `/etc/apt/sources.list` 文件中即可解决:
```bash
@@ -93,7 +89,6 @@ $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docke
# $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list
```
-
#### 安装 Docker
更新 apt 软件包缓存,并安装 `docker-ce`。
@@ -103,7 +98,6 @@ $ sudo apt-get update
$ sudo apt-get install docker-ce
```
-
### 3.5.3 使用脚本自动安装
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Raspberry Pi OS 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
@@ -111,7 +105,6 @@ $ sudo apt-get install docker-ce
> 若你想安装测试版的 Docker,请从 test.docker.com 获取脚本
```bash
-
# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
@@ -120,7 +113,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud
```
-
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker 的稳定 (stable) 版本安装在系统中。
### 3.5.4 启动 Docker
@@ -129,7 +121,6 @@ $ sudo sh get-docker.sh --mirror Aliyun
$ sudo systemctl enable docker
$ sudo systemctl start docker
```
-
### 3.5.5 建立 docker 用户组
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
@@ -144,13 +135,11 @@ $ sudo systemctl start docker
```bash
$ sudo groupadd docker
```
-
将当前用户加入 `docker` 组:
```bash
$ sudo usermod -aG docker $USER
```
-
退出当前终端并重新登录,进行如下测试。
### 3.5.6 测试 Docker 是否安装正确
@@ -185,7 +174,6 @@ Share images, automate workflows, and more with a free Docker ID:
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
-
若能正常输出以上信息,则说明安装成功。
*注意:*ARM 平台不能使用 `x86` 镜像,查看 Raspberry Pi OS 可使用镜像请访问 [arm32v7](https://hub.docker.com/u/arm32v7/) 或者 [arm64v8](https://hub.docker.com/u/arm64v8/)。
diff --git a/03_install/3.6_offline.md b/03_install/3.6_offline.md
index 5398602..4e68de8 100644
--- a/03_install/3.6_offline.md
+++ b/03_install/3.6_offline.md
@@ -26,7 +26,6 @@ sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc
yum update
```
-
```bash
sudo yum list docker-ce --showduplicates|sort -r
@@ -42,13 +41,11 @@ docker-ce.x86_64 3:19.03.2-3.el7 docker-ce-stable
docker-ce.x86_64 3:19.03.1-3.el7 docker-ce-stable
....
```
-
##### 下载到指定文件夹
```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
```
-
```bash
Dependencies Resolved
@@ -77,7 +74,6 @@ Background downloading packages, then exiting:
Total 118 MB/s | 87 MB 00:00:00
exiting because "Download Only" specified
```
-
##### 复制到目标服务器之后进入文件夹安装:C-N
* 离线安装时,必须使用 rpm 命令不检查依赖的方式安装
@@ -85,7 +81,6 @@ exiting because "Download Only" specified
```bash
rpm -Uvh *.rpm --nodeps --force
```
-
##### 锁定软件版本:C-N
**下载锁定版本软件**
@@ -95,25 +90,21 @@ rpm -Uvh *.rpm --nodeps --force
```bash
sudo yum install yum-plugin-versionlock
```
-
**锁定软件版本**
```bash
sudo yum versionlock add docker
```
-
**查看锁定列表**
```bash
sudo yum versionlock list
```
-
```bash
Loaded plugins: fastestmirror, versionlock
3:docker-ce-24.0.4-1.el7.*
versionlock list done
```
-
**锁定后无法再更新**
```bash
@@ -124,31 +115,26 @@ Excluding 1 update due to versionlock (use "yum versionlock status" to show it)
Package 3:docker-ce-24.0.4-1.el7.x86_64 already installed and latest version
Nothing to do
```
-
**解锁指定软件**
```bash
sudo yum versionlock delete docker-ce
```
-
```bash
Loaded plugins: fastestmirror, versionlock
Deleting versionlock for: 3:docker-ce-24.0.4-1.el7.*
versionlock deleted: 1
```
-
**解锁所有软件**
```bash
sudo yum versionlock delete all
```
-
#### YUM 本地源服务器搭建安装 Docker
##### 挂载 ISO 镜像搭建本地 File 源
```bash
-
## 删除其他网络源
rm -f /etc/yum.repos.d/*
@@ -157,9 +143,7 @@ rm -f /etc/yum.repos.d/*
mount /dev/cdrom /mnt
```
-
```bash
-
## 添加本地源
cat >/etc/yum.repos.d/local_files.repo<< EOF
@@ -171,19 +155,15 @@ gpgcheck=0
gpgkey=file:///mnt/RPM-GPG-KEY-CentOS-7
EOF
```
-
```bash
-
## 测试刚才的本地源,安装createrepo软件
yum clean all
yum install createrepo -y
```
-
##### 根据本地文件搭建 BASE 网络源
```bash
-
## 安装apache 服务器
yum install httpd -y
@@ -203,21 +183,17 @@ createrepo /var/www/html/base/
systemctl enable httpd
systemctl start httpd
```
-
##### 下载 Docker-CE 镜像仓库
在有网络的服务器上下载 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目录
mkdir /tmp/docker-ce/
@@ -226,20 +202,17 @@ mkdir /tmp/docker-ce/
reposync -r docker-ce-stable -p /tmp/docker-ce/
```
-
##### 创建仓库索引
把下载的 docker-ce 文件夹复制到离线的服务器
```bash
-
## 把docker-ce 文件夹复制到/var/www/html/docker-ce
## 重建索引
createrepo /var/www/html/docker-ce/
```
-
##### YUM 客户端设置:C...N
```bash
@@ -266,7 +239,6 @@ proxy=_none_
EOF
```
-
##### Docker 安装:C...N
```bash
diff --git a/03_install/3.7_mac.md b/03_install/3.7_mac.md
index fea6b1c..f23ad8a 100644
--- a/03_install/3.7_mac.md
+++ b/03_install/3.7_mac.md
@@ -18,7 +18,6 @@ Docker Desktop 为 Mac 用户提供了无缝的 Docker 体验。你可以选择
```bash
$ brew install --cask docker
```
-
#### 手动下载安装
如果需要手动下载,请点击以下[链接](https://desktop.docker.com/mac/main/amd64/Docker.dmg)下载 Docker Desktop for Mac。
@@ -49,13 +48,11 @@ $ brew install --cask docker
$ docker --version
Docker version 27.0.3, build 7d4bcd8
```
-
如果 `docker version`、`docker info` 都正常的话,可以尝试运行一个 [Nginx 服务器](https://hub.docker.com/_/nginx/):
```bash
$ docker run -d -p 80:80 --name webserver nginx
```
-
服务运行后,可以访问 [http://localhost](http://localhost),如果看到了 “Welcome to nginx!”,就说明 Docker Desktop for Mac 安装成功了。

@@ -66,7 +63,6 @@ $ docker run -d -p 80:80 --name webserver nginx
$ docker stop webserver
$ docker rm webserver
```
-
### 3.7.4 镜像加速
如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
diff --git a/03_install/3.8_windows.md b/03_install/3.8_windows.md
index 46bb8f2..40fcd36 100644
--- a/03_install/3.8_windows.md
+++ b/03_install/3.8_windows.md
@@ -22,7 +22,6 @@
```powershell
$ winget install Docker.DockerDesktop
```
-
### 3.8.3 在 WSL2 运行 Docker
若你的 Windows 版本为 Windows 10 专业版或家庭版 v1903 及以上版本可以使用 WSL2 运行 Docker,具体请查看 [Docker Desktop WSL 2 backend](https://docs.docker.com/docker-for-windows/wsl/)。
diff --git a/03_install/3.9_mirror.md b/03_install/3.9_mirror.md
index 60b54cc..5b20448 100644
Binary files a/03_install/3.9_mirror.md and b/03_install/3.9_mirror.md differ
diff --git a/03_install/summary.md b/03_install/summary.md
index 429668a..a506ea6 100644
--- a/03_install/summary.md
+++ b/03_install/summary.md
@@ -19,7 +19,6 @@ Docker 支持在多种平台上安装和使用,选择合适的安装方式是
$ docker version
$ docker run --rm hello-world
```
-
### 延伸阅读
- [镜像加速器](3.9_mirror.md):解决国内拉取镜像慢的问题
diff --git a/04_image/4.1_pull.md b/04_image/4.1_pull.md
index 6de43f0..1162e35 100644
--- a/04_image/4.1_pull.md
+++ b/04_image/4.1_pull.md
@@ -9,7 +9,6 @@
```bash
docker pull [选项] [Registry地址/]仓库名[:标签]
```
-
#### 镜像名称格式
Docker 镜像名称由 Registry 地址、用户名、仓库名和标签组成。其标准格式如下:
@@ -21,7 +20,6 @@ docker.io / library / ubuntu : 24.04
Registry地址 用户名 仓库名 标签
(可省略) (可省略)
```
-
| 组成部分 | 说明 | 默认值 |
|---------|------|--------|
| Registry 地址 | 镜像仓库地址 | `docker.io` (Docker Hub)|
@@ -32,7 +30,6 @@ Registry地址 用户名 仓库名 标签
#### 示例
```bash
-
## 完整格式
$ docker pull docker.io/library/ubuntu:24.04
@@ -57,7 +54,6 @@ $ docker pull bitnami/redis:latest
$ docker pull ghcr.io/username/myapp:v1.0
```
-
---
### 4.1.2 下载过程解析
@@ -74,7 +70,6 @@ Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
Status: Downloaded newer image for ubuntu:24.04
docker.io/library/ubuntu:24.04
```
-
#### 输出解读
| 输出内容 | 说明 |
@@ -98,7 +93,6 @@ flowchart TD
L3 --- L2 --- L1
end
```
-
如果本地已有相同的层,Docker 会跳过下载,节省带宽和时间。
---
@@ -120,7 +114,6 @@ flowchart TD
```bash
$ docker pull --platform linux/amd64 nginx
```
-
---
### 4.1.4 拉取后运行
@@ -128,7 +121,6 @@ $ docker pull --platform linux/amd64 nginx
拉取镜像后,可以基于它启动容器:
```bash
-
## 拉取镜像
$ docker pull ubuntu:24.04
@@ -141,7 +133,6 @@ PRETTY_NAME="Ubuntu 24.04 LTS"
...
root@e7009c6ce357:/# exit
```
-
**参数说明**:
| 参数 | 说明 |
@@ -167,7 +158,6 @@ root@e7009c6ce357:/# exit
]
}
```
-
配置后重启 Docker:
```bash
@@ -175,7 +165,6 @@ $ sudo systemctl restart docker # Linux
## 或在 Docker Desktop 中重启
```
-
详见[镜像加速器](../03_install/3.9_mirror.md)章节。
---
@@ -191,7 +180,6 @@ $ docker images --digests ubuntu
REPOSITORY TAG DIGEST IMAGE ID
ubuntu 24.04 sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26 ca2b0f26964c
```
-
#### 使用摘要拉取
用摘要拉取可确保获取完全相同的镜像:
@@ -199,7 +187,6 @@ ubuntu 24.04 sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
```bash
$ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
```
-
> 笔者建议:生产环境使用摘要而非标签,因为标签可能被覆盖,摘要则是不可变的。
---
@@ -219,7 +206,6 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
```bash
Error: pull access denied, repository does not exist
```
-
可能原因:
- 镜像名拼写错误
@@ -229,7 +215,6 @@ Error: pull access denied, repository does not exist
#### Q:磁盘空间不足
```bash
-
## 清理未使用的镜像
$ docker image prune
@@ -238,5 +223,4 @@ $ docker image prune
$ docker system prune
```
-
---
diff --git a/04_image/4.2_list.md b/04_image/4.2_list.md
index 5ad9feb..91bf5ea 100644
--- a/04_image/4.2_list.md
+++ b/04_image/4.2_list.md
@@ -14,7 +14,6 @@ nginx latest 05a60462f8ba 5 days ago 181MB
ubuntu 24.04 329ed837d508 3 days ago 78MB
ubuntu noble 329ed837d508 3 days ago 78MB
```
-
> 💡 `docker images` 是 `docker image ls` 的简写,两者等效。
---
@@ -59,7 +58,6 @@ ubuntu:24.04 nginx:latest redis:latest
▼ │
共享基础层 ◄───────────────────┘
```
-
因此,`docker image ls` 中各镜像大小之和 > 实际磁盘占用。
#### 查看实际空间占用
@@ -72,7 +70,6 @@ Containers 5 2 100MB 80MB (80%)
Local Volumes 8 2 500MB 400MB (80%)
Build Cache 0 0 0B 0B
```
-
---
### 4.2.4 过滤镜像
@@ -82,7 +79,6 @@ Build Cache 0 0 0B 0B
#### 按仓库名过滤
```bash
-
## 列出所有 ubuntu 镜像
$ docker images ubuntu
@@ -91,7 +87,6 @@ ubuntu 24.04 329ed837d508 78MB
ubuntu noble 329ed837d508 78MB
ubuntu 22.04 a1b2c3d4e5f6 72MB
```
-
#### 按仓库名和标签过滤
```bash
@@ -99,7 +94,6 @@ $ docker images ubuntu:24.04
REPOSITORY TAG IMAGE ID SIZE
ubuntu 24.04 329ed837d508 78MB
```
-
#### 使用过滤器 --filter
| 过滤条件 | 说明 | 示例 |
@@ -111,7 +105,6 @@ ubuntu 24.04 329ed837d508 78MB
| `reference=pattern` | 按名称模式 | `-f reference='*:latest'` |
```bash
-
## 列出 nginx 之后创建的镜像
$ docker images -f since=nginx:latest
@@ -124,7 +117,6 @@ $ docker images -f reference='*:latest'
$ docker images -f label=maintainer=example@email.com
```
-
---
### 4.2.5 虚悬镜像
@@ -140,7 +132,6 @@ $ docker images
REPOSITORY TAG IMAGE ID SIZE
00285df0df87 342MB
```
-
#### 产生原因
1. **镜像重新构建**:新镜像使用了旧镜像的标签,旧镜像标签被移除
@@ -149,7 +140,6 @@ REPOSITORY TAG IMAGE ID SIZE
#### 处理虚悬镜像
```bash
-
## 列出虚悬镜像
$ docker images -f dangling=true
@@ -158,7 +148,6 @@ $ docker images -f dangling=true
$ docker image prune
```
-
---
### 4.2.6 中间层镜像
@@ -170,7 +159,6 @@ $ docker image prune
```bash
$ docker images -a
```
-
会显示很多无标签镜像——这些是构建过程中产生的中间层,被其他镜像依赖。
> ⚠️ 不要删除中间层镜像。它们是其他镜像的依赖,删除会导致上层镜像无法使用。删除顶层镜像时会自动清理不再需要的中间层。
@@ -189,11 +177,9 @@ $ docker images -q
05a60462f8ba
329ed837d508
```
-
常用于配合其他命令:
```bash
-
## 删除所有镜像
$ docker rmi $(docker images -q)
@@ -202,13 +188,11 @@ $ docker rmi $(docker images -q)
$ docker rmi $(docker images -q redis)
```
-
#### 显示完整 ID
```bash
$ docker images --no-trunc
```
-
#### 显示摘要
```bash
@@ -216,13 +200,11 @@ $ docker images --digests
REPOSITORY TAG DIGEST IMAGE ID
nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
```
-
#### 自定义格式
使用 Go 模板语法自定义输出:
```bash
-
## 只显示 ID 和仓库名
$ docker images --format "{{.ID}}: {{.Repository}}"
@@ -238,7 +220,6 @@ redis latest 183MB
nginx latest 181MB
ubuntu 24.04 78MB
```
-
#### 可用模板字段
| 字段 | 说明 |
@@ -256,7 +237,6 @@ ubuntu 24.04 78MB
### 4.2.8 常用命令组合
```bash
-
## 列出所有镜像及其大小,按大小排序(需要系统 sort 命令)
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -h
@@ -269,5 +249,4 @@ $ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | grep -E "^[0-9]
$ docker images --format "{{.Repository}}:{{.Tag}}" > images.txt
```
-
---
diff --git a/04_image/4.3_rm.md b/04_image/4.3_rm.md
index 3048511..70483ba 100644
--- a/04_image/4.3_rm.md
+++ b/04_image/4.3_rm.md
@@ -9,7 +9,6 @@
```bash
$ docker image rm [选项] <镜像1> [<镜像2> ...]
```
-
> 💡 `docker rmi` 是 `docker image rm` 的简写,两者等效。
---
@@ -39,7 +38,6 @@ $ docker rmi 501
Untagged: redis:alpine
Deleted: sha256:501ad78535f0...
```
-
#### 使用镜像名删除
```bash
@@ -47,13 +45,11 @@ $ docker rmi redis:alpine
Untagged: redis:alpine
Deleted: sha256:501ad78535f0...
```
-
#### 使用摘要删除
摘要删除最精确,适用于 CI/CD 场景:
```bash
-
## 查看镜像摘要
$ docker images --digests
@@ -64,7 +60,6 @@ nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
$ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
```
-
---
### 4.3.3 理解输出信息
@@ -81,7 +76,6 @@ Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7
Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
```
-
#### Untagged vs Deleted
| 操作 | 含义 |
@@ -114,7 +108,6 @@ flowchart TD
Step4 -- "未使用" --> Delete["Deleted (删除该层)"]
end
```
-
---
### 4.3.4 批量删除
@@ -126,7 +119,6 @@ flowchart TD
虚悬镜像 (dangling):没有标签的镜像,通常是旧版本被新版本覆盖后产生的
```bash
-
## 查看虚悬镜像
$ docker images -f dangling=true
@@ -139,11 +131,9 @@ $ docker image prune
$ docker image prune -f
```
-
#### 删除所有未使用的镜像
```bash
-
## 删除所有没有被容器使用的镜像
$ docker image prune -a
@@ -152,11 +142,9 @@ $ docker image prune -a
$ docker image prune -a --filter "until=24h"
```
-
#### 按条件删除
```bash
-
## 删除所有 redis 镜像
$ docker rmi $(docker images -q redis)
@@ -169,7 +157,6 @@ $ docker rmi $(docker images -q -f before=mongo:8.0)
$ docker image prune -a --filter "until=168h" # 7天前
```
-
---
### 4.3.5 删除失败的常见原因
@@ -183,11 +170,9 @@ $ docker rmi nginx
Error: conflict: unable to remove repository reference "nginx"
(must force) - container abc123 is using its referenced image
```
-
**解决方案**:
```bash
-
## 方案1:先删除依赖的容器
$ docker rm abc123
@@ -197,7 +182,6 @@ $ docker rmi nginx
$ docker rmi -f nginx
```
-
#### 原因二:多个标签指向同一镜像
```bash
@@ -211,7 +195,6 @@ Untagged: ubuntu:24.04
## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
```
-
当同一个镜像有多个标签时,`docker rmi` 只是删除指定的标签,不会删除镜像本身。
#### 原因三:被其他镜像依赖:中间层
@@ -220,7 +203,6 @@ Untagged: ubuntu:24.04
$ docker rmi some_base_image
Error: image has dependent child images
```
-
中间层镜像被其他镜像依赖,无法删除。需要先删除依赖它的镜像。
---
@@ -244,7 +226,6 @@ Error: image has dependent child images
#### 开发环境
```bash
-
## 定期清理虚悬镜像
$ docker image prune -f
@@ -253,16 +234,13 @@ $ docker image prune -f
$ docker system prune -a
```
-
#### CI/CD 环境
```bash
-
## 只保留最近使用的镜像
$ docker image prune -a --filter "until=72h" -f
```
-
#### 查看空间占用
```bash
@@ -273,5 +251,4 @@ Containers 5 2 100MB 80MB (80%)
Local Volumes 8 2 500MB 400MB (80%)
Build Cache 0 0 0B 0B
```
-
---
diff --git a/04_image/4.4_commit.md b/04_image/4.4_commit.md
index 4559234..346244d 100644
--- a/04_image/4.4_commit.md
+++ b/04_image/4.4_commit.md
@@ -13,7 +13,6 @@
```bash
$ docker run --name webserver -d -p 80:80 nginx
```
-
这条命令会用 `nginx` 镜像启动一个容器,命名为 `webserver`,并且映射了 80 端口,这样我们可以用浏览器去访问这个 `nginx` 服务器。
如果是在本机运行的 Docker,那么可以直接访问:`http://localhost`,如果是在虚拟机、云服务器上安装的 Docker,则需要将 `localhost` 换为虚拟机地址或者实际云服务器地址。
@@ -30,7 +29,6 @@ root@3729b97e8226:/# echo 'Hello, Docker!
' > /usr/share/nginx/html/inde
root@3729b97e8226:/# exit
exit
```
-
我们以交互式终端方式进入 `webserver` 容器,并执行了 `bash` 命令,也就是获得一个可操作的 Shell。
然后,我们用 `Hello, Docker!
` 覆盖了 `/usr/share/nginx/html/index.html` 的内容。
@@ -60,7 +58,6 @@ A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
```
-
现在我们定制好了变化,我们希望能将其保存下来形成镜像。
要知道,当我们运行一个容器的时候 (如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个 `docker commit` 命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。
@@ -70,7 +67,6 @@ A /var/cache/nginx/uwsgi_temp
```bash
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
```
-
我们可以用下面的命令将容器保存为镜像:
```bash
@@ -81,7 +77,6 @@ $ docker commit \
nginx:v2
sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214
```
-
其中 `--author` 是指定修改的作者,而 `--message` 则是记录本次修改的内容。这点和 `git` 版本控制相似,不过这里这些信息可以省略留空。
我们可以在 `docker image ls` 中看到这个新定制的镜像:
@@ -93,7 +88,6 @@ nginx v2 07e334659748 9 seconds ago
nginx 1.27 05a60462f8ba 12 days ago 181.5 MB
nginx latest e43d811ce2f4 4 weeks ago 181.5 MB
```
-
我们还可以用 `docker history` 具体查看镜像内的历史记录,如果比较 `nginx:latest` 的历史记录,我们会发现新增了我们刚刚提交的这一层。
```bash
@@ -109,13 +103,11 @@ e43d811ce2f4 4 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "da
4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
4 weeks ago /bin/sh -c #(nop) ADD file:23aa4f893e3288698c 123 MB
```
-
新的镜像定制好后,我们可以来运行这个镜像。
```bash
docker run --name web2 -d -p 81:80 nginx:v2
```
-
这里我们命名为新的服务为 `web2`,并且映射到 `81` 端口。访问 `http://localhost:81` 看到结果,其内容应该和之前修改后的 `webserver` 一样。
至此,我们第一次完成了定制镜像,使用的是 `docker commit` 命令,手动操作给旧的镜像添加了新的一层,形成新的镜像,对镜像多层存储应该有了更直观的感觉。
diff --git a/04_image/4.5_build.md b/04_image/4.5_build.md
index 76e88dd..cfc96a2 100644
--- a/04_image/4.5_build.md
+++ b/04_image/4.5_build.md
@@ -11,7 +11,6 @@ Docker 提供了 `docker init` 命令,可以根据项目类型自动生成 Doc
```bash
$ docker init
```
-
该命令会交互式地询问项目类型 (如 Go、Node.js、Python、Rust 等),并生成符合最佳实践的配置文件。对于新项目,这是推荐的起步方式。
### 4.5.2 手动创建 Dockerfile
@@ -25,14 +24,12 @@ $ mkdir mynginx
$ cd mynginx
$ touch Dockerfile
```
-
其内容为:
```docker
FROM nginx
RUN echo 'Hello, Docker!
' > /usr/share/nginx/html/index.html
```
-
这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,`FROM` 和 `RUN`。
### 4.5.3 FROM 指定基础镜像
@@ -49,7 +46,6 @@ RUN echo 'Hello, Docker!
' > /usr/share/nginx/html/index.html
FROM scratch
...
```
-
如果你以 `scratch` 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 `FROM scratch` 会让镜像体积更加小巧。使用 [Go 语言](https://golang.google.cn/)开发的应用很多会使用这种方式来制作镜像,这也是有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
@@ -63,7 +59,6 @@ FROM scratch
```docker
RUN echo 'Hello, Docker!
' > /usr/share/nginx/html/index.html
```
-
* *exec* 格式:`RUN [“可执行文件”, “参数1”, “参数2”]`,这更像是函数调用中的格式。
Dockerfile 中每一个指令都会建立一层,`RUN` 也不例外。每一个 `RUN` 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,`commit` 这一层的修改,构成新的镜像。
@@ -93,7 +88,6 @@ Step 2 : RUN echo 'Hello, Docker!
' > /usr/share/nginx/html/index.html
Removing intermediate container 9cdc27646c7b
Successfully built 44aa4490ce2c
```
-
从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 `Step 2` 中,如同我们之前所说的那样,`RUN` 指令启动了一个容器 `9cdc27646c7b`,执行了所要求的命令,并最后提交了这一层 `44aa4490ce2c`,随后删除了所用到的这个容器 `9cdc27646c7b`。
这里我们使用了 `docker build` 命令进行镜像构建。其格式为:
@@ -101,7 +95,6 @@ Successfully built 44aa4490ce2c
```bash
docker build [选项] <上下文路径/URL/->
```
-
在这里我们指定了最终镜像的名称 `-t nginx:v3`,构建成功后,我们可以像之前运行 `nginx:v2` 那样来运行这个镜像,其结果会和 `nginx:v2` 一样。
### 4.5.6 镜像构建上下文
@@ -119,7 +112,6 @@ docker build [选项] <上下文路径/URL/->
```docker
COPY ./package.json /app/
```
-
这并不是要复制执行 `docker build` 命令所在的目录下的 `package.json`,也不是复制 `Dockerfile` 所在目录下的 `package.json`,而是复制 **上下文 (context)** 目录下的 `package.json`。
因此,`COPY` 这类指令中的源文件的路径都是*相对路径*。这也是初学者经常会问的为什么 `COPY ../package.json /app` 或者 `COPY /opt/xxxx /app` 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。
@@ -133,7 +125,6 @@ $ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB
...
```
-
理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 `COPY /opt/xxxx /app` 不工作后,于是干脆将 `Dockerfile` 放到了硬盘根目录去构建,结果发现 `docker build` 执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 `docker build` 打包整个硬盘,这显然是使用错误。
一般来说,应该会将 `Dockerfile` 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 `.gitignore` 一样的语法写一个 `.dockerignore`,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
@@ -151,7 +142,6 @@ Sending build context to Docker daemon 2.048 kB
或许你已经注意到了,`docker build` 还支持从 URL 构建,比如可以直接从 Git repo 中构建:
```bash
-
## $env:DOCKER_BUILDKIT=0
## export DOCKER_BUILDKIT=0
@@ -168,7 +158,6 @@ Removing intermediate container d2a513a760ed
---> 038ad4142d2b
Successfully built 038ad4142d2b
```
-
这行命令指定了构建所需的 Git repo,并且指定分支为 `master`,构建目录为 `/amd64/hello-world/`,然后 Docker 就会自己去 `git clone` 这个项目、切换到指定分支、并进入到指定目录后开始构建。
#### 用给定的 tar 压缩包构建
@@ -176,7 +165,6 @@ Successfully built 038ad4142d2b
```bash
$ docker build http://server/context.tar.gz
```
-
如果所给出的 URL 不是个 Git repo,而是个 `tar` 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
#### 从标准输入中读取 Dockerfile 进行构建
@@ -184,13 +172,11 @@ $ docker build http://server/context.tar.gz
```bash
docker build - < Dockerfile
```
-
或
```bash
cat Dockerfile | docker build -
```
-
如果标准输入传入的是文本文件,则将其视为 `Dockerfile`,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 `COPY` 进镜像之类的事情。
#### 从标准输入中读取上下文压缩包进行构建
@@ -198,5 +184,4 @@ cat Dockerfile | docker build -
```bash
$ docker build - < context.tar.gz
```
-
如果发现标准输入的文件格式是 `gzip`、`bzip2` 以及 `xz` 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。
diff --git a/04_image/4.6_other.md b/04_image/4.6_other.md
index 6fc4885..5174c30 100644
--- a/04_image/4.6_other.md
+++ b/04_image/4.6_other.md
@@ -18,7 +18,6 @@ $ docker import \
Downloading from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz
sha256:412b8fc3e3f786dca0197834a698932b9c51b69bd8cf49e100c35d38c9879213
```
-
这条命令自动下载了 `ubuntu-16.04-x86_64.tar.gz` 文件,并且作为根文件系统展开导入,并保存为镜像 `openvz/ubuntu:16.04`。
导入成功后,我们可以用 `docker image ls` 看到这个导入的镜像:
@@ -28,7 +27,6 @@ $ docker image ls openvz/ubuntu
REPOSITORY TAG IMAGE ID CREATED SIZE
openvz/ubuntu 16.04 412b8fc3e3f7 55 seconds ago 505MB
```
-
如果我们查看其历史的话,会看到描述中有导入的文件链接:
```bash
@@ -36,7 +34,6 @@ $ docker history openvz/ubuntu:16.04
IMAGE CREATED CREATED BY SIZE COMMENT
f477a6e18e98 About a minute ago 214.9 MB Imported from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz
```
-
### 4.6.2 Docker 镜像的导入和导出 `docker save` 和 `docker load`
Docker 还提供了 `docker save` 和 `docker load` 命令,用以将镜像保存为一个文件,然后传输到另一个位置上,再加载进来。这是在没有 Docker Registry 时的做法,现在已经不推荐,镜像迁移应该直接使用 Docker Registry,无论是直接使用 Docker Hub 还是使用内网私有 Registry 都可以。
@@ -52,7 +49,6 @@ $ docker image ls alpine
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest baa5d63471ea 5 weeks ago 4.803 MB
```
-
保存镜像的命令为:
```bash
@@ -60,7 +56,6 @@ $ docker save alpine -o filename
$ file filename
filename: POSIX tar archive
```
-
这里的 filename 可以为任意名称甚至任意后缀名,但文件的本质都是归档文件
**注意:如果同名则会覆盖 (没有警告)**
@@ -70,14 +65,12 @@ filename: POSIX tar archive
```bash
$ docker save alpine | gzip > alpine-latest.tar.gz
```
-
然后我们将 `alpine-latest.tar.gz` 文件复制到了到了另一个机器上,可以用下面这个命令加载镜像:
```bash
$ docker load -i alpine-latest.tar.gz
Loaded image: alpine:latest
```
-
如果我们结合这两个命令以及 `ssh` 甚至 `pv` 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能:
```bash
diff --git a/04_image/4.7_internal.md b/04_image/4.7_internal.md
index aac0d83..b478f23 100644
--- a/04_image/4.7_internal.md
+++ b/04_image/4.7_internal.md
@@ -38,7 +38,6 @@ flowchart TD
end
Note["所有的写操作都在容器层这里"] -.-> L4
```
-
* **读取文件**:当容器需要读取文件时,Docker 会从最上层 (容器层) 开始向下层 (镜像层) 寻找,直到找到该文件为止。
* **修改文件**:当容器需要修改某个文件时,Docker 会从下层镜像中将该文件复制到上层的容器层,然后对副本进行修改。这被称为 **写时复制 (Copy-on-Write,CoW)** 策略。
* **删除文件**:当容器删除某个文件时,Docker 并不是真的去下层删除它 (因为下层是只读的),而是在容器层创建一个特殊的 “白障 (Whiteout)” 文件,用来标记该文件已被删除,从而在容器视图中隐藏它。
diff --git a/05_container/5.1_run.md b/05_container/5.1_run.md
index ae9bb0a..43dfb72 100644
--- a/05_container/5.1_run.md
+++ b/05_container/5.1_run.md
@@ -18,7 +18,6 @@
```bash
docker run [选项] 镜像 [命令] [参数...]
```
-
#### 最简单的例子
输出 “Hello World” 后容器自动终止:
@@ -27,7 +26,6 @@ docker run [选项] 镜像 [命令] [参数...]
$ docker run ubuntu:24.04 /bin/echo 'Hello world'
Hello world
```
-
这与直接执行 `/bin/echo 'Hello world'` 几乎没有区别,但实际上已经启动了一个完整的 Ubuntu 容器来执行这条命令。
#### 交互式容器
@@ -38,7 +36,6 @@ Hello world
$ docker run -it ubuntu:24.04 /bin/bash
root@af8bae53bdd3:/#
```
-
**参数说明**:
| 参数 | 作用 |
@@ -56,7 +53,6 @@ root@af8bae53bdd3:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@af8bae53bdd3:/# exit # 退出容器
```
-
### 5.1.3 docker run 的完整流程
执行 `docker run` 时,Docker 在后台完成以下操作:
@@ -77,7 +73,6 @@ flowchart TD
Step4["4. 启动容器,执行指定命令"] --> Step5
Step5["5. 命令执行完毕,容器停止"]
```
-
### 5.1.4 常用启动选项
#### 基础选项
@@ -92,7 +87,6 @@ flowchart TD
#### 端口映射
```bash
-
## 将容器的 80 端口映射到宿主机的 8080 端口
$ docker run -d -p 8080:80 nginx
@@ -105,11 +99,9 @@ $ docker run -d -P nginx
$ docker run -d -p 127.0.0.1:8080:80 nginx
```
-
#### 数据卷挂载
```bash
-
## 挂载命名卷
$ docker run -v mydata:/data nginx
@@ -122,11 +114,9 @@ $ 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
@@ -135,11 +125,9 @@ $ docker run -e MYSQL_ROOT_PASSWORD=secret mysql
$ docker run --env-file .env myapp
```
-
#### 资源限制
```bash
-
## 限制内存
$ docker run -m 512m nginx
@@ -148,13 +136,11 @@ $ docker run -m 512m nginx
$ docker run --cpus=1.5 nginx
```
-
### 5.1.5 启动已终止容器
使用 `docker start` 重新启动已停止的容器:
```bash
-
## 查看所有容器(包括已停止的)
$ docker ps -a
@@ -169,7 +155,6 @@ $ docker start myubuntu
$ docker start -ai myubuntu
```
-
### 5.1.6 容器内进程的特点
容器内只运行指定的应用程序及其必需资源:
@@ -180,7 +165,6 @@ root@ba267838cc1b:/# ps
1 ? 00:00:00 bash
11 ? 00:00:00 ps
```
-
可见容器中仅运行了 `bash` 进程。这种特点使得 Docker 对资源的利用率极高。
> 💡 笔者提示:容器内的 PID 1 进程很重要——它是容器的主进程,该进程退出则容器停止。详见[后台运行](5.2_daemon.md)章节。
@@ -192,7 +176,6 @@ root@ba267838cc1b:/# ps
**原因**:主进程执行完毕或无法保持运行
```bash
-
## 这个容器会立即退出(echo 执行完就结束了)
$ docker run ubuntu echo "hello"
@@ -201,7 +184,6 @@ $ docker run ubuntu echo "hello"
$ docker run -d nginx # nginx 是持续运行的服务
```
-
详细解释见[后台运行](5.2_daemon.md)。
#### Q:无法连接容器内的服务
@@ -209,7 +191,6 @@ $ docker run -d nginx # nginx 是持续运行的服务
**原因**:未正确映射端口
```bash
-
## 错误:没有 -p 参数,外部无法访问
$ docker run -d nginx
@@ -218,16 +199,13 @@ $ docker run -d nginx
$ docker run -d -p 80:80 nginx
```
-
#### Q:容器内修改的文件丢失
**原因**:未使用数据卷,数据保存在容器存储层
```bash
-
## 使用数据卷持久化
$ docker run -v mydata:/app/data myapp
```
-
详见[数据管理](../08_data/README.md)。
diff --git a/05_container/5.2_daemon.md b/05_container/5.2_daemon.md
index 538a2f9..eb75698 100644
--- a/05_container/5.2_daemon.md
+++ b/05_container/5.2_daemon.md
@@ -22,7 +22,6 @@ hello world
hello world
hello world
```
-
容器会把输出的结果 (STDOUT) 打印到宿主机上面。此时:
- 终端被占用,无法执行其他命令
@@ -35,7 +34,6 @@ hello world
$ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
```
-
使用 `-d` 参数后:
- 容器在后台运行
@@ -52,7 +50,6 @@ $ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep
```bash
$ docker run -d ubuntu:24.04
```
-
然后用 `docker ps` 查看,发现容器根本不在运行!这是为什么?
#### 核心原理:容器的生命周期与主进程绑定
@@ -65,7 +62,6 @@ flowchart TD
Exit["主进程退出"] --> Stop["容器停止"]
end
```
-
当你运行 `docker run -d ubuntu:24.04` 时:
1. 容器启动
@@ -96,7 +92,6 @@ $ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77b2dc01fe0f ubuntu:24.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
```
-
#### 查看容器输出日志
```bash
@@ -106,19 +101,16 @@ hello world
hello world
...
```
-
**实时查看日志** (类似 `tail -f`):
```bash
$ docker container logs -f 77b2dc01fe0f
```
-
#### 查看已停止的容器
```bash
$ docker container ls -a
```
-
加上 `-a` 参数可以看到所有容器,包括已停止的。这对于调试 “容器启动即退出” 的问题非常有用。
### 5.2.5 最佳实践
@@ -126,7 +118,6 @@ $ docker container ls -a
#### 1. 长期运行的服务使用 -d
```bash
-
## Web 服务器
$ docker run -d -p 80:80 nginx
@@ -139,18 +130,15 @@ $ docker run -d -p 3306:3306 mysql:8
$ docker run -d -p 6379:6379 redis
```
-
#### 2. 调试时先用前台模式
当容器启动有问题时,**去掉 `-d` 参数** 可以直接看到输出和错误:
```bash
-
## 有问题的容器,先前台运行看看发生了什么
$ docker run myimage:latest
```
-
#### 3. 使用 --rm 自动清理
对于一次性任务,使用 `--rm` 参数让容器退出后自动删除:
@@ -163,11 +151,9 @@ Hello, World!
...
```
-
#### 4. 配合日志查看
```bash
-
## 后台启动
$ docker run -d --name myapp myimage:latest
@@ -184,7 +170,6 @@ $ docker logs -f myapp
$ docker logs -t myapp
```
-
### 5.2.6 常见问题排查
#### Q:容器启动后立即退出
@@ -227,7 +212,6 @@ $ docker logs -t myapp
```bash
$ docker attach mycontainer
```
-
> **注意**:`attach` 会连接到容器的主进程。如果主进程不是交互式的,你可能只能看到输出。使用 `Ctrl+P` `Ctrl+Q` 可以安全退出而不停止容器。
### 5.2.7 延伸阅读
diff --git a/05_container/5.3_stop.md b/05_container/5.3_stop.md
index 6057555..d605729 100644
--- a/05_container/5.3_stop.md
+++ b/05_container/5.3_stop.md
@@ -21,7 +21,6 @@
```bash
$ docker stop 容器名或ID
```
-
#### 工作原理
```mermaid
@@ -30,11 +29,9 @@ flowchart TD
A --> B["2. 等待容器优雅退出 (默认 10 秒)"]
B --> C["3. 如果超时仍未退出,发送 SIGKILL 强制终止"]
```
-
#### 自定义超时时间
```bash
-
## 等待 30 秒后强制终止
$ docker stop -t 30 mycontainer
@@ -43,11 +40,9 @@ $ docker stop -t 30 mycontainer
$ docker stop -t 0 mycontainer
```
-
#### 停止多个容器
```bash
-
## 停止多个指定容器
$ docker stop container1 container2 container3
@@ -56,7 +51,6 @@ $ docker stop container1 container2 container3
$ docker stop $(docker ps -q)
```
-
---
### 5.3.3 docker kill
@@ -66,7 +60,6 @@ $ docker stop $(docker ps -q)
```bash
$ docker kill 容器名或ID
```
-
#### 与 stop 的区别
| 命令 | 信号 | 使用场景 |
@@ -77,7 +70,6 @@ $ docker kill 容器名或ID
#### 发送自定义信号
```bash
-
## 发送 SIGHUP(让进程重新加载配置)
$ docker kill -s HUP mycontainer
@@ -86,7 +78,6 @@ $ docker kill -s HUP mycontainer
$ docker kill -s TERM mycontainer
```
-
---
### 5.3.4 容器自动终止
@@ -94,7 +85,6 @@ $ docker kill -s TERM mycontainer
容器的生命周期与主进程绑定。主进程退出时,容器自动停止:
```bash
-
## 主进程是交互式 bash
$ docker run -it ubuntu bash
@@ -104,7 +94,6 @@ root@abc123:/# exit # 退出 bash → 容器停止
$ docker run ubuntu echo "Hello" # echo 执行完 → 容器停止
```
-
---
### 5.3.5 查看已停止的容器
@@ -115,7 +104,6 @@ CONTAINER ID IMAGE COMMAND STATUS NAMES
ba267838cc1b ubuntu "/bin/bash" Exited (0) 2 minutes ago myubuntu
c5d3a5e8f7b2 nginx "nginx" Up 5 minutes mynginx
```
-
**STATUS 字段说明**:
| 状态 | 说明 |
@@ -139,11 +127,9 @@ $ docker start 容器名或ID
$ docker start -ai 容器名
```
-
#### 重启运行中的容器
```bash
-
## 先停止再启动
$ docker restart 容器名
@@ -152,7 +138,6 @@ $ docker restart 容器名
$ docker restart -t 30 容器名
```
-
---
### 5.3.7 生命周期状态图
@@ -172,7 +157,6 @@ stateDiagram-v2
Deleted --> [*]
```
-
---
### 5.3.8 批量操作
@@ -182,19 +166,16 @@ stateDiagram-v2
```bash
$ docker stop $(docker ps -q)
```
-
#### 删除所有已停止的容器
```bash
$ docker container prune
```
-
#### 停止并删除所有容器
```bash
$ docker stop $(docker ps -q) && docker container prune -f
```
-
---
### 5.3.9 常见问题
@@ -214,7 +195,6 @@ $ docker stop $(docker ps -q) && docker container prune -f
确保容器主进程正确处理信号:
```dockerfile
-
## Dockerfile 示例
FROM node:22
@@ -224,11 +204,9 @@ FROM node:22
CMD ["node", "server.js"]
```
-
#### Q:容器无法停止
```bash
-
## 强制终止
$ docker kill 容器名
@@ -237,5 +215,4 @@ $ docker kill 容器名
$ docker inspect 容器名
```
-
---
diff --git a/05_container/5.4_attach_exec.md b/05_container/5.4_attach_exec.md
index 4e57fe6..f1c0e5a 100644
--- a/05_container/5.4_attach_exec.md
+++ b/05_container/5.4_attach_exec.md
@@ -27,7 +27,6 @@ Docker 提供两种进入容器的命令:
#### docker exec 基本用法
```bash
-
## 进入容器并启动交互式 shell
$ docker exec -it 容器名 /bin/bash
@@ -36,7 +35,6 @@ $ docker exec -it 容器名 /bin/bash
$ docker exec -it 容器名 /bin/sh
```
-
#### 参数说明
| 参数 | 作用 |
@@ -51,7 +49,6 @@ $ docker exec -it 容器名 /bin/sh
#### docker exec 示例
```bash
-
## 启动一个后台容器
$ docker run -dit --name myubuntu ubuntu
@@ -70,13 +67,11 @@ $ docker ps
CONTAINER ID IMAGE STATUS NAMES
69d137adef7a ubuntu Up 2 minutes myubuntu
```
-
#### 执行单条命令
不进入交互模式,直接执行命令:
```bash
-
## 查看容器内进程
$ docker exec myubuntu ps aux
@@ -89,11 +84,9 @@ $ docker exec myubuntu cat /etc/nginx/nginx.conf
$ docker exec -u root myubuntu apt update
```
-
#### 只用 -i 不用 -t 的区别
```bash
-
## 只用 -i:可以执行命令,但没有提示符
$ docker exec -i myubuntu bash
@@ -108,7 +101,6 @@ dev
$ docker exec -it myubuntu bash
root@69d137adef7a:/# # 有提示符
```
-
> 💡 通常使用 `-it` 组合。只有在脚本中需要通过管道传入命令时才只用 `-i`。
---
@@ -120,7 +112,6 @@ root@69d137adef7a:/# # 有提示符
```bash
$ docker attach 容器名
```
-
#### 工作原理
`attach` 会附加到容器的 **主进程** (PID 1) 的标准输入输出:
@@ -135,11 +126,9 @@ flowchart LR
end
Attach["docker attach"] -->|"附加到这里"| P1
```
-
#### docker attach 示例
```bash
-
## 启动容器
$ docker run -dit --name myubuntu ubuntu
@@ -150,7 +139,6 @@ $ docker run -dit --name myubuntu ubuntu
$ docker attach myubuntu
root@243c32535da7:/#
```
-
#### ⚠️ 重要警告
**从 attach 会话中输入 `exit` 或按 `Ctrl+D` 会导致容器停止!**
@@ -163,7 +151,6 @@ $ docker ps
CONTAINER ID IMAGE STATUS NAMES
243c32535da7 ubuntu Exited (0) 2 seconds ago myubuntu
```
-
**原因**:attach 附加到主进程,退出主进程就等于退出容器。
#### 安全退出 attach
@@ -182,7 +169,6 @@ $ docker ps # 容器仍在运行
CONTAINER ID IMAGE STATUS NAMES
243c32535da7 ubuntu Up 5 minutes myubuntu
```
-
---
### 5.4.5 exec vs attach 对比
@@ -219,7 +205,6 @@ flowchart LR
Container1 -.-> note1
Container2 -.-> note2
```
-
---
### 5.4.6 最佳实践
@@ -227,7 +212,6 @@ flowchart LR
#### 1. 首选 docker exec
```bash
-
## 进入容器调试
$ docker exec -it myapp bash
@@ -240,7 +224,6 @@ $ docker exec myapp tail -f /var/log/app.log
$ docker exec myapp python manage.py migrate
```
-
#### 2. 生产环境避免进入容器
笔者建议:生产环境应尽量避免进入容器直接操作,而是通过:
@@ -254,7 +237,6 @@ $ docker exec myapp python manage.py migrate
某些精简镜像 (如基于 `scratch` 或 `distroless`) 没有 shell:
```bash
-
## 这会失败
$ docker exec -it myapp bash
@@ -264,7 +246,6 @@ OCI runtime exec failed: exec failed: unable to start container process: exec: "
$ docker debug myapp
```
-
---
### 5.4.7 常见问题
@@ -280,11 +261,9 @@ $ docker debug myapp
```bash
$ docker exec -it myapp /bin/sh
```
-
#### Q:需要 root 权限
```bash
$ docker exec -u root -it myapp bash
```
-
---
diff --git a/05_container/5.5_import_export.md b/05_container/5.5_import_export.md
index 6915e26..700a494 100644
--- a/05_container/5.5_import_export.md
+++ b/05_container/5.5_import_export.md
@@ -11,7 +11,6 @@ CONTAINER ID IMAGE COMMAND CREATED
7691a814370e ubuntu:24.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test
$ docker export 7691a814370e > ubuntu.tar
```
-
这样将导出容器快照到本地文件。
### 5.5.2 导入容器快照
@@ -24,11 +23,9 @@ $ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB
```
-
此外,也可以通过指定 URL 或者某个目录来导入,例如
```bash
$ docker import http://example.com/exampleimage.tgz example/imagerepo
```
-
*注:用户既可以使用 `docker load` 来导入镜像存储文件到本地镜像库,也可以使用 `docker import` 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息 (即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。*
diff --git a/05_container/5.6_rm.md b/05_container/5.6_rm.md
index 576c02d..d0d348a 100644
--- a/05_container/5.6_rm.md
+++ b/05_container/5.6_rm.md
@@ -9,7 +9,6 @@
```bash
$ docker rm 容器名或ID
```
-
> 💡 `docker rm` 是 `docker container rm` 的简写,两者等效。
---
@@ -28,11 +27,9 @@ $ docker rm 容器名或ID
$ docker rm mycontainer
mycontainer
```
-
#### 强制删除运行中的容器
```bash
-
## 不加 -f 会报错
$ docker rm running_container
@@ -43,18 +40,15 @@ Error: cannot remove running container
$ docker rm -f running_container
running_container
```
-
> ⚠️ 强制删除会向容器发送 SIGKILL 信号,可能导致数据丢失。建议先 `docker stop` 优雅停止。
#### 删除容器及其数据卷
```bash
-
## 删除容器时同时删除其匿名卷
$ docker rm -v mycontainer
```
-
> 注意:只删除匿名卷,命名卷不会被删除。
---
@@ -64,7 +58,6 @@ $ docker rm -v mycontainer
#### 删除所有已停止的容器
```bash
-
## 方式一:使用 prune 命令(推荐)
$ docker container prune
@@ -80,11 +73,9 @@ Total reclaimed space: 150MB
$ docker container prune -f
```
-
#### 删除所有容器:包括运行中的
```bash
-
## 先停止所有容器,再删除
$ docker stop $(docker ps -q)
@@ -94,11 +85,9 @@ $ docker rm $(docker ps -aq)
$ docker rm -f $(docker ps -aq)
```
-
#### 按条件删除
```bash
-
## 删除所有已退出的容器
$ docker rm $(docker ps -aq -f status=exited)
@@ -111,7 +100,6 @@ $ docker rm $(docker ps -aq -f name=test)
$ docker container prune --filter "until=24h"
```
-
---
### 5.6.4 常用过滤条件
@@ -130,7 +118,6 @@ $ docker container prune --filter "until=24h"
#### 示例
```bash
-
## 删除所有基于 nginx 镜像的容器
$ docker rm $(docker ps -aq -f ancestor=nginx)
@@ -139,7 +126,6 @@ $ docker rm $(docker ps -aq -f ancestor=nginx)
$ docker rm $(docker ps -aq -f status=created)
```
-
---
### 5.6.5 容器与镜像的依赖关系
@@ -147,7 +133,6 @@ $ docker rm $(docker ps -aq -f status=created)
> 有容器依赖的镜像无法删除。
```bash
-
## 尝试删除有容器依赖的镜像
$ docker image rm nginx
@@ -158,7 +143,6 @@ Error: image is being used by stopped container abc123
$ docker rm abc123
$ docker image rm nginx
```
-
---
### 5.6.6 清理策略建议
@@ -166,7 +150,6 @@ $ docker image rm nginx
#### 开发环境
```bash
-
## 定期清理已停止的容器
$ docker container prune -f
@@ -175,11 +158,9 @@ $ docker container prune -f
$ docker system prune -f
```
-
#### 生产环境
```bash
-
## 使用 --rm 参数运行临时容器
$ docker run --rm ubuntu echo "Hello"
@@ -190,7 +171,6 @@ $ docker run --rm ubuntu echo "Hello"
$ docker container prune --filter "until=168h" # 保留 7 天内的
```
-
#### 完整清理脚本
```bash
@@ -213,7 +193,6 @@ docker network prune -f
echo "清理完成!"
docker system df
```
-
---
### 5.6.7 常见问题
@@ -223,7 +202,6 @@ docker system df
```bash
Error: container is running
```
-
解决:先停止容器,或使用 `-f` 强制删除
```bash
@@ -234,7 +212,6 @@ $ docker rm mycontainer
$ docker rm -f mycontainer
```
-
#### Q:删除后磁盘空间没释放
可能原因:
@@ -246,7 +223,6 @@ $ docker rm -f mycontainer
解决:
```bash
-
## 查看空间占用
$ docker system df
@@ -255,5 +231,4 @@ $ docker system df
$ docker system prune -a --volumes
```
-
---
diff --git a/06_repository/6.1_dockerhub.md b/06_repository/6.1_dockerhub.md
index 245a923..b15a2f1 100644
--- a/06_repository/6.1_dockerhub.md
+++ b/06_repository/6.1_dockerhub.md
@@ -30,7 +30,6 @@ $ docker search centos
NAME DESCRIPTION STARS OFFICIAL
centos The official build of CentOS. 7000+ [OK]
```
-
> **技巧**:始终优先使用 `OFFICIAL` 标记为 `[OK]` 的镜像,安全性更有保障。
#### 2. 拉取镜像
@@ -38,7 +37,6 @@ centos The official build of CentOS. 7000+ [OK]
```bash
$ docker pull nginx:alpine
```
-
#### 3. 推送镜像
需要先登录:
@@ -51,11 +49,9 @@ $ docker login
...
```
-
打标签并推送:
```bash
-
## 1. 标记镜像
$ docker tag myapp:v1 username/myapp:v1
@@ -64,7 +60,6 @@ $ docker tag myapp:v1 username/myapp:v1
$ docker push username/myapp:v1
```
-
---
### 6.1.3 限制与配额
@@ -113,7 +108,6 @@ $ docker push username/myapp:v1
```bash
$ echo "dckr_pat_xxxxxxx" | docker login --username username --password-stdin
```
-
#### 3. 关注镜像漏洞
Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜像标签页可以看到漏洞扫描结果。
diff --git a/06_repository/6.2_registry.md b/06_repository/6.2_registry.md
index 0f6f082..3c1f2dc 100644
--- a/06_repository/6.2_registry.md
+++ b/06_repository/6.2_registry.md
@@ -17,7 +17,6 @@
```bash
$ docker run -d -p 5000:5000 --restart=always --name registry registry
```
-
这将使用官方的 `registry` 镜像来启动私有仓库。默认情况下,仓库会被创建在容器的 `/var/lib/registry` 目录下。你可以通过 `-v` 参数来将镜像文件存放在本地的指定路径。例如下面的例子将上传的镜像放到本地的 `/opt/data/registry` 目录。
```bash
@@ -26,7 +25,6 @@ $ docker run -d \
-v /opt/data/registry:/var/lib/registry \
registry
```
-
### 6.2.2 在私有仓库上传、搜索、下载镜像
创建好私有仓库之后,就可以使用 `docker tag` 来标记一个镜像,然后推送它到仓库。例如私有仓库地址为 `127.0.0.1:5000`。
@@ -38,7 +36,6 @@ $ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB
```
-
使用 `docker tag` 将 `ubuntu:latest` 这个镜像标记为 `127.0.0.1:5000/ubuntu:latest`。
格式为 `docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]`。
@@ -50,7 +47,6 @@ REPOSITORY TAG IMAGE ID CREATE
ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB
127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
```
-
使用 `docker push` 上传标记的镜像。
```bash
@@ -64,14 +60,12 @@ b38367233d37: Pushed
2aebd096e0e2: Pushed
latest: digest: sha256:fe4277621f10b5026266932ddf760f5a756d2facd505a94d2da12f4f52f71f5a size: 1568
```
-
用 `curl` 查看仓库中的镜像。
```bash
$ curl 127.0.0.1:5000/v2/_catalog
{"repositories":["ubuntu"]}
```
-
这里可以看到 `{"repositories":["ubuntu"]}`,表明镜像已经被成功上传了。
先删除已有镜像,再尝试从私有仓库中下载这个镜像。
@@ -92,7 +86,6 @@ $ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
```
-
### 6.2.3 配置非 https 仓库地址
如果你不想使用 `127.0.0.1:5000` 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 `192.168.199.100:5000` 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。
@@ -117,7 +110,6 @@ REPOSITORY TAG IMAGE ID CREAT
]
}
```
-
> 注意:该文件必须符合 `json` 规范,否则 Docker 将不能启动。
### 6.2.4 其他
diff --git a/06_repository/6.3_registry_auth.md b/06_repository/6.3_registry_auth.md
index b671538..e06979f 100644
--- a/06_repository/6.3_registry_auth.md
+++ b/06_repository/6.3_registry_auth.md
@@ -15,7 +15,6 @@
```bash
$ openssl genrsa -out "root-ca.key" 4096
```
-
第二步利用私钥创建 `CA` 根证书请求文件。
```bash
@@ -24,7 +23,6 @@ $ openssl req \
-out "root-ca.csr" -sha256 \
-subj '/C=CN/ST=Shanxi/L=Datong/O=Your Company Name/CN=Your Company Name Docker Registry CA'
```
-
> 以上命令中 `-subj` 参数里的 `/C` 表示国家,如 `CN`;`/ST` 表示省;`/L` 表示城市或者地区;`/O` 表示组织名;`/CN` 通用名称。
第三步配置 `CA` 根证书,新建 `root-ca.cnf`。
@@ -35,7 +33,6 @@ basicConstraints = critical,CA:TRUE,pathlen:1
keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
subjectKeyIdentifier=hash
```
-
第四步签发根证书。
```bash
@@ -44,20 +41,17 @@ $ openssl x509 -req -days 3650 -in "root-ca.csr" \
-extfile "root-ca.cnf" -extensions \
root_ca
```
-
第五步生成站点 `SSL` 私钥。
```bash
$ openssl genrsa -out "docker.domain.com.key" 4096
```
-
第六步使用私钥生成证书请求文件。
```bash
$ openssl req -new -key "docker.domain.com.key" -out "site.csr" -sha256 \
-subj '/C=CN/ST=Shanxi/L=Datong/O=Your Company Name/CN=docker.domain.com'
```
-
第七步配置证书,新建 `site.cnf` 文件。
```bash
@@ -69,7 +63,6 @@ keyUsage = critical, digitalSignature, keyEncipherment
subjectAltName = DNS:docker.domain.com, IP:127.0.0.1
subjectKeyIdentifier=hash
```
-
第八步签署站点 `SSL` 证书。
```bash
@@ -77,7 +70,6 @@ $ openssl x509 -req -days 750 -in "site.csr" -sha256 \
-CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
-out "docker.domain.com.crt" -extfile "site.cnf" -extensions server
```
-
这样已经拥有了 `docker.domain.com` 的网站 SSL 私钥 `docker.domain.com.key` 和 SSL 证书 `docker.domain.com.crt` 及 CA 根证书 `root-ca.crt`。
新建 `ssl` 文件夹并将 `docker.domain.com.key` `docker.domain.com.crt` `root-ca.crt` 这三个文件移入,删除其他文件。
@@ -122,7 +114,6 @@ health:
interval: 10s
threshold: 3
```
-
### 6.3.3 生成 http 认证文件
```bash
@@ -133,7 +124,6 @@ $ docker run --rm \
httpd:alpine \
-Bbn username password > auth/nginx.htpasswd
```
-
> 将上面的 `username` `password` 替换为你自己的用户名和密码。
### 6.3.4 编辑 Docker Compose 配置
@@ -153,7 +143,6 @@ services:
volumes:
registry-data:
```
-
### 6.3.5 修改 Hosts 文件
编辑 `/etc/hosts`
@@ -161,13 +150,11 @@ volumes:
```bash
127.0.0.1 docker.domain.com
```
-
### 6.3.6 启动
```bash
$ docker compose up -d
```
-
这样我们就搭建好了一个具有权限认证、TLS 的私有仓库,接下来我们测试其功能是否正常。
### 6.3.7 测试私有仓库功能
@@ -179,13 +166,11 @@ $ sudo mkdir -p /etc/docker/certs.d/docker.domain.com
$ sudo cp ssl/root-ca.crt /etc/docker/certs.d/docker.domain.com/ca.crt
```
-
登录到私有仓库。
```bash
$ docker login docker.domain.com
```
-
尝试推送、拉取镜像。
```bash
@@ -199,7 +184,6 @@ $ docker image rm docker.domain.com/username/ubuntu:24.04
$ docker pull docker.domain.com/username/ubuntu:24.04
```
-
如果我们退出登录,尝试推送镜像。
```bash
@@ -209,7 +193,6 @@ $ docker push docker.domain.com/username/ubuntu:24.04
no basic auth credentials
```
-
发现会提示没有登录,不能将镜像推送到私有仓库中。
### 6.3.8 注意事项
diff --git a/06_repository/6.4_nexus3_registry.md b/06_repository/6.4_nexus3_registry.md
index 8f3aa90..d0dfad9 100644
--- a/06_repository/6.4_nexus3_registry.md
+++ b/06_repository/6.4_nexus3_registry.md
@@ -10,7 +10,6 @@ $ docker run -d --name nexus3 --restart=always \
--mount src=nexus-data,target=/nexus-data \
sonatype/nexus3
```
-
首次运行需等待 3-5 分钟,你可以使用 `docker logs nexus3 -f` 查看日志:
```bash
@@ -23,7 +22,6 @@ Started Sonatype Nexus OSS 3.30.0-01
-------------------------------------------------
```
-
如果你看到以上内容,说明 `Nexus` 已经启动成功,你可以使用浏览器打开 `http://YourIP:8081` 访问 `Nexus` 了。
首次运行请通过以下命令获取初始密码:
@@ -33,7 +31,6 @@ $ docker exec nexus3 cat /nexus-data/admin.password
9266139e-41a2-4abb-92ec-e4142a3532cb
```
-
首次启动 Nexus 的默认账号是 `admin`,密码则是上边命令获取到的,点击右上角登录,首次登录需更改初始密码。
登录之后可以点击页面上方的齿轮按钮按照下面的方法进行设置。
@@ -110,7 +107,6 @@ server {
error_page 500 502 503 504 /50x.html;
}
```
-
### 6.4.5 Docker 主机访问镜像仓库
如果不启用 SSL 加密可以通过[前面章节](6.2_registry.md)的方法添加非 https 仓库地址到 Docker 的配置文件中然后重启 Docker。
@@ -122,5 +118,4 @@ $ openssl s_client -showcerts -connect YourDomainName OR HostIP:443
```
-
`WORKDIR` 指定后续指令的工作目录。如果目录不存在,Docker 会自动创建。
---
@@ -19,7 +18,6 @@ RUN pwd # 输出 /app
RUN echo "hello" > world.txt # 创建 /app/world.txt
COPY . . # 复制到 /app/
```
-
---
### 7.10.3 为什么需要 WORKDIR
@@ -27,13 +25,11 @@ COPY . . # 复制到 /app/
#### 常见错误
```docker
-
## ❌ 错误:cd 在下一个 RUN 中无效
RUN cd /app
RUN echo "hello" > world.txt # 文件在根目录!
```
-
#### 原因分析
```dockerfile
@@ -46,19 +42,16 @@ RUN echo "hello" > world.txt
↓
启动新容器(工作目录在 /)→ 创建 /world.txt
```
-
每个 RUN 都在新容器中执行,**前一个 RUN 的内存状态 (包括工作目录) 不会保留**。
#### 正确做法
```docker
-
## ✅ 正确:使用 WORKDIR
WORKDIR /app
RUN echo "hello" > world.txt # 创建 /app/world.txt
```
-
---
### 7.10.4 相对路径
@@ -72,7 +65,6 @@ WORKDIR c
RUN pwd # 输出 /a/b/c
```
-
---
### 7.10.5 使用环境变量
@@ -83,13 +75,11 @@ WORKDIR $APP_HOME
RUN pwd # 输出 /app
```
-
---
### 7.10.6 多阶段构建中的 WORKDIR
```docker
-
## 构建阶段
FROM node:20 AS builder
@@ -105,7 +95,6 @@ FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=builder /build/dist .
```
-
---
### 7.10.7 最佳实践
@@ -121,11 +110,9 @@ RUN npm install
COPY . .
CMD ["node", "server.js"]
```
-
#### 2. 使用绝对路径
```docker
-
## ✅ 推荐:绝对路径,意图明确
WORKDIR /app
@@ -134,11 +121,9 @@ WORKDIR /app
WORKDIR app
```
-
#### 3. 不要用 RUN cd
```docker
-
## ❌ 避免
RUN cd /app && echo "hello" > world.txt
@@ -148,7 +133,6 @@ RUN cd /app && echo "hello" > world.txt
WORKDIR /app
RUN echo "hello" > world.txt
```
-
#### 4. 适时重置 WORKDIR
```docker
@@ -162,7 +146,6 @@ WORKDIR /data
...
```
-
---
### 7.10.8 与其他指令的关系
@@ -182,7 +165,6 @@ RUN pwd # /app
COPY . . # 复制到 /app
CMD ["./start.sh"] # /app/start.sh
```
-
---
### 7.10.9 运行时覆盖
@@ -193,5 +175,4 @@ CMD ["./start.sh"] # /app/start.sh
$ docker run -w /tmp myimage pwd
/tmp
```
-
---
diff --git a/07_dockerfile/7.11_user.md b/07_dockerfile/7.11_user.md
index 4959bf8..f49df69 100644
--- a/07_dockerfile/7.11_user.md
+++ b/07_dockerfile/7.11_user.md
@@ -6,7 +6,6 @@
USER <用户名>[:<用户组>]
USER [:]
```
-
`USER` 指令切换后续指令 (RUN、CMD、ENTRYPOINT) 的执行用户。
---
@@ -29,7 +28,6 @@ flowchart LR
NR_C -- 权限受限,危害降低 --> NR_Safe["无法控制系统"]
end
```
-
---
### 7.11.3 基本用法
@@ -57,16 +55,13 @@ USER appuser
CMD ["node", "server.js"]
```
-
#### 使用 UID/GID
```docker
-
## 也可以使用数字
USER 1001:1001
```
-
---
### 7.11.4 用户必须已存在
@@ -74,7 +69,6 @@ USER 1001:1001
`USER` 指令只能切换到 **已存在** 的用户:
```docker
-
## ❌ 错误:用户不存在
USER nonexistent
@@ -86,7 +80,6 @@ USER nonexistent
RUN useradd -r -s /bin/false appuser
USER appuser
```
-
#### 创建用户的方式
**Debian/Ubuntu**:
@@ -95,14 +88,12 @@ USER appuser
RUN groupadd -r appgroup && \
useradd -r -g appgroup appuser
```
-
**Alpine**:
```docker
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S -G appgroup appuser
```
-
| 选项 | 说明 |
|------|------|
| `-r` (useradd) / `-S` (adduser) | 创建系统用户 |
@@ -134,7 +125,6 @@ COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["redis-server"]
```
-
**docker-entrypoint.sh**:
```bash
@@ -149,7 +139,6 @@ chown -R redis:redis /data
exec gosu redis "$@"
```
-
#### 为什么不用 su/sudo
| 问题 | su/sudo | gosu |
@@ -166,7 +155,6 @@ exec gosu redis "$@"
使用 `-u` 或 `--user` 参数:
```bash
-
## 以指定用户运行
$ docker run -u 1001:1001 myimage
@@ -175,7 +163,6 @@ $ docker run -u 1001:1001 myimage
$ docker run -u root myimage
```
-
---
### 7.11.7 文件权限处理
@@ -204,7 +191,6 @@ COPY --chown=appuser:appuser . .
USER appuser
CMD ["node", "server.js"]
```
-
---
### 7.11.8 最佳实践
@@ -212,7 +198,6 @@ CMD ["node", "server.js"]
#### 1. 始终使用非 root 用户
```docker
-
## ✅ 推荐
RUN adduser -D appuser
@@ -223,24 +208,20 @@ CMD ["myapp"]
CMD ["myapp"] # 以 root 运行
```
-
#### 2. 使用固定 UID/GID
便于在宿主机和容器间共享文件:
```docker
-
## 使用常见的非 root UID
RUN addgroup -g 1000 -S appgroup && \
adduser -u 1000 -S -G appgroup appuser
USER 1000:1000
```
-
#### 3. 多阶段构建中的 USER
```docker
-
## 构建阶段可以用 root
FROM node:20 AS builder
@@ -257,7 +238,6 @@ COPY --from=builder --chown=appuser:appuser /app/dist .
USER appuser
CMD ["node", "server.js"]
```
-
---
### 7.11.9 常见问题
@@ -267,13 +247,11 @@ CMD ["node", "server.js"]
```bash
permission denied: '/app/data.log'
```
-
**解决**:确保目录权限正确
```docker
RUN mkdir -p /app/data && chown appuser:appuser /app/data
```
-
#### Q:无法绑定低于 1024 的端口
非 root 用户无法绑定 80、443 等端口。
diff --git a/07_dockerfile/7.12_healthcheck.md b/07_dockerfile/7.12_healthcheck.md
index de27255..0598474 100644
--- a/07_dockerfile/7.12_healthcheck.md
+++ b/07_dockerfile/7.12_healthcheck.md
@@ -6,7 +6,6 @@
HEALTHCHECK [选项] CMD <命令>
HEALTHCHECK NONE
```
-
`HEALTHCHECK` 指令告诉 Docker 如何判断容器状态是否正常。这是保障服务高可用的重要机制。
---
@@ -28,7 +27,6 @@ Starting ──成功──> Healthy ──失败N次──> Unhealthy
▲ │
└──────成功──────┘
```
-
---
### 7.12.3 基本用法
@@ -42,7 +40,6 @@ RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -fs http://localhost/ || exit 1
```
-
#### 命令返回值
- `0`:成功 (healthy)
@@ -68,7 +65,6 @@ HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
FROM my-base-image
HEALTHCHECK NONE
```
-
---
### 7.12.5 常见检查脚本
@@ -78,7 +74,6 @@ HEALTHCHECK NONE
使用 `curl` 或 `wget`:
```docker
-
## 使用 curl
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
@@ -87,11 +82,9 @@ HEALTHCHECK CMD curl -f http://localhost/ || exit 1
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
```
-
#### 数据库
```docker
-
## MySQL
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
@@ -100,14 +93,12 @@ HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
HEALTHCHECK CMD redis-cli ping || exit 1
```
-
#### 自定义脚本
```docker
COPY healthcheck.sh /usr/local/bin/
HEALTHCHECK CMD ["healthcheck.sh"]
```
-
---
### 7.12.6 在 Compose 中使用
@@ -125,7 +116,6 @@ services:
retries: 3
start_period: 40s
```
-
带健康检查的依赖启动:
```yaml
@@ -139,13 +129,11 @@ services:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
```
-
---
### 7.12.7 查看健康状态
```bash
-
## 查看容器状态(包含健康信息)
$ docker ps
@@ -169,7 +157,6 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
]
}
```
-
---
### 7.12.8 最佳实践
@@ -187,12 +174,10 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
应用启动可能需要时间 (如 Java 应用)。设置 `--start-period` 可以防止在启动阶段因检查失败而误判。
```docker
-
## 给应用 1 分钟启动时间
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
```
-
#### 4. 只检查核心依赖
健康检查应主要关注 **当前服务** 是否可用,而不是检查其下游依赖 (数据库等)。下游依赖的检查应由应用逻辑处理。
diff --git a/07_dockerfile/7.13_onbuild.md b/07_dockerfile/7.13_onbuild.md
index 698fcfd..8c8fe3f 100644
--- a/07_dockerfile/7.13_onbuild.md
+++ b/07_dockerfile/7.13_onbuild.md
@@ -5,7 +5,6 @@
```docker
ONBUILD <其它指令>
```
-
`ONBUILD` 是一个特殊的指令,它后面跟的是其它指令 (如 `RUN`,`COPY` 等),这些指令 **在当前镜像构建时不会执行**,只有当以当前镜像为基础镜像去构建下一级镜像时才会被执行。
---
@@ -42,7 +41,6 @@ ONBUILD COPY . .
CMD ["npm", "start"]
```
-
**子项目 Dockerfile**:
```docker
@@ -54,7 +52,6 @@ FROM my-node-base
...
```
-
---
### 7.13.3 执行机制
@@ -67,7 +64,6 @@ Dockerfile (含 ONBUILD) ──build──> 基础镜像 (记录了 ONBUILD 触
子镜像构建:
FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行触发器指令 ──> 继续执行子 Dockerfile
```
-
---
### 7.13.4 常见使用场景
@@ -75,32 +71,26 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
#### 1. 自动处理依赖安装
```docker
-
## Python 基础镜像
ONBUILD COPY requirements.txt ./
ONBUILD RUN pip install -r requirements.txt
```
-
#### 2. 自动编译代码
```docker
-
## Go 基础镜像
ONBUILD COPY . .
ONBUILD RUN go build -o app main.go
```
-
#### 3. 处理静态资源
```docker
-
## Nginx 静态网站基础镜像
ONBUILD COPY dist/ /usr/share/nginx/html/
```
-
---
### 7.13.5 注意事项
@@ -137,7 +127,6 @@ ONBUILD COPY dist/ /usr/share/nginx/html/
node:20-onbuild
python:3.12-onbuild
```
-
#### 2. 避免执行耗时操作
尽量不要在 `ONBUILD` 中执行过于耗时或不确定的操作 (如更新系统软件),这会让子镜像构建变得缓慢且不可控。
diff --git a/07_dockerfile/7.14_label.md b/07_dockerfile/7.14_label.md
index b14bd26..4517a8d 100644
--- a/07_dockerfile/7.14_label.md
+++ b/07_dockerfile/7.14_label.md
@@ -5,7 +5,6 @@
```docker
LABEL = = ...
```
-
`LABEL` 指令以键值对的形式给镜像添加元数据。这些数据不会影响镜像的功能,但可以帮助用户理解镜像,或被自动化工具使用。
---
@@ -27,7 +26,6 @@ LABEL = = ...
LABEL version="1.0"
LABEL description="这是一个 Web 应用服务器"
```
-
#### 定义多个标签:推荐
```docker
@@ -36,7 +34,6 @@ LABEL maintainer="user@example.com" \
description="My App Description" \
org.opencontainers.image.authors="Yeasy"
```
-
> 💡 包含空格的值需要用引号括起来。
---
@@ -65,7 +62,6 @@ LABEL org.opencontainers.image.authors="yeasy" \
org.opencontainers.image.source="https://github.com/yeasy/docker_practice" \
org.opencontainers.image.licenses="MIT"
```
-
---
### 7.14.5 MAINTAINER 指令:已废弃
@@ -73,16 +69,13 @@ LABEL org.opencontainers.image.authors="yeasy" \
旧版本的 Dockerfile 中常看到 `MAINTAINER` 指令:
```docker
-
## ❌ 已弃用
MAINTAINER user@example.com
```
-
现在推荐使用 `LABEL`:
```docker
-
## ✅ 推荐
LABEL maintainer="user@example.com"
@@ -91,7 +84,6 @@ LABEL maintainer="user@example.com"
LABEL org.opencontainers.image.authors="user@example.com"
```
-
---
### 7.14.6 动态标签
@@ -105,7 +97,6 @@ ARG VCS_REF
LABEL org.opencontainers.image.created=$BUILD_DATE \
org.opencontainers.image.revision=$VCS_REF
```
-
构建命令:
```bash
@@ -114,7 +105,6 @@ $ docker build \
--build-arg VCS_REF=$(git rev-parse --short HEAD) \
.
```
-
---
### 7.14.7 查看标签
@@ -129,13 +119,11 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq
"maintainer": "NGINX Docker Maintainers "
}
```
-
#### 过滤器
可以使用标签过滤镜像:
```bash
-
## 列出作者是 yeasy 的所有镜像
$ docker images --filter "label=org.opencontainers.image.authors=yeasy"
@@ -144,5 +132,4 @@ $ docker images --filter "label=org.opencontainers.image.authors=yeasy"
$ docker rmi $(docker images -q --filter "label=stage=builder")
```
-
---
diff --git a/07_dockerfile/7.15_shell.md b/07_dockerfile/7.15_shell.md
index 529f423..c953aca 100644
--- a/07_dockerfile/7.15_shell.md
+++ b/07_dockerfile/7.15_shell.md
@@ -5,7 +5,6 @@
```docker
SHELL ["executable", "parameters"]
```
-
`SHELL` 指令允许覆盖 Docker 默认的 shell。
- **Linux 默认**:`["/bin/sh", "-c"]`
@@ -32,22 +31,18 @@ SHELL ["/bin/bash", "-c"]
RUN echo {a..z}
```
-
#### 2. 增强错误处理
默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个指令就视为成功。这可能掩盖构建错误。
```docker
-
## ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
RUN wget -O - https://invalid-url | tar xz
```
-
使用 `SHELL` 启用 `pipefail`:
```docker
-
## ✅ 启用 pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
@@ -56,7 +51,6 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN wget -O - https://invalid-url | tar xz
```
-
#### 3. Windows 环境
在 Windows 容器中,经常需要在 `cmd` 和 `powershell` 之间切换。
@@ -77,7 +71,6 @@ RUN Write-Host "Hello from PowerShell"
SHELL ["cmd", "/S", "/C"]
```
-
---
### 7.15.3 作用范围
@@ -103,7 +96,6 @@ SHELL ["/bin/sh", "-c"]
RUN echo "Using sh again"
```
-
---
### 7.15.4 对其他指令的影响
@@ -130,7 +122,6 @@ RUN echo "Using sh again"
```docker
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
```
-
#### 2. 明确意图
如果由于脚本需求必须更改 shell,最好在 Dockerfile 中显式声明,而不是依赖默认行为。
diff --git a/07_dockerfile/7.17_multistage_builds.md b/07_dockerfile/7.17_multistage_builds.md
index 19d9cc2..5b59282 100644
--- a/07_dockerfile/7.17_multistage_builds.md
+++ b/07_dockerfile/7.17_multistage_builds.md
@@ -21,7 +21,6 @@ func main(){
fmt.Printf("Hello World!");
}
```
-
编写 `Dockerfile.one` 文件
```docker
@@ -42,13 +41,11 @@ WORKDIR /root/
CMD ["./app"]
```
-
构建镜像
```bash
$ docker build -t go/helloworld:1 -f Dockerfile.one .
```
-
### 7.17.2 分散到多个 Dockerfile
另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。
@@ -67,7 +64,6 @@ COPY app.go .
RUN go get -d -v github.com/go-sql-driver/mysql \
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
```
-
编写 `Dockerfile.copy` 文件
```docker
@@ -81,7 +77,6 @@ COPY app .
CMD ["./app"]
```
-
新建 `build.sh`
```bash
@@ -99,7 +94,6 @@ echo Building go/helloworld:2
docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy
rm ./app
```
-
现在运行脚本即可构建镜像
```bash
@@ -107,7 +101,6 @@ $ chmod +x build.sh
$ ./build.sh
```
-
对比两种方式生成的镜像大小
```bash
@@ -117,7 +110,6 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
```
-
### 7.17.3 使用多阶段构建
为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`:
@@ -147,13 +139,11 @@ COPY --from=0 /go/src/github.com/go/helloworld/app .
CMD ["./app"]
```
-
构建镜像
```bash
$ docker build -t go/helloworld:3 .
```
-
对比三个镜像大小
```bash
@@ -164,7 +154,6 @@ go/helloworld 3 d6911ed9c846 7 seconds ago 6.47MB
go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
```
-
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。
### 7.17.4 只构建某一阶段的镜像
@@ -174,13 +163,11 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
```docker
FROM golang:alpine as builder
```
-
例如当我们只想构建 `builder` 阶段的镜像时,增加 `--target=builder` 参数即可
```bash
$ docker build --target builder -t username/imagename:tag .
```
-
### 7.17.5 构建时从其他镜像复制文件
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
diff --git a/07_dockerfile/7.18_multistage_builds_laravel.md b/07_dockerfile/7.18_multistage_builds_laravel.md
index 46c35c5..7374604 100644
--- a/07_dockerfile/7.18_multistage_builds_laravel.md
+++ b/07_dockerfile/7.18_multistage_builds_laravel.md
@@ -29,7 +29,6 @@ storage/
...
```
-
在 `laravel.conf` 文件中写入 nginx 配置。
```nginx
@@ -55,7 +54,6 @@ server {
}
}
```
-
### 7.18.2 前端构建
第一阶段进行前端构建。
@@ -76,7 +74,6 @@ RUN set -x ; cd /app \
&& mkdir -p public \
&& npm run production
```
-
### 7.18.3 安装 Composer 依赖
第二阶段安装 Composer 依赖。
@@ -96,7 +93,6 @@ RUN set -x ; cd /app \
--no-scripts \
--prefer-dist
```
-
### 7.18.4 整合以上阶段所生成的文件
第三阶段对以上阶段生成的文件进行整合。
@@ -122,7 +118,6 @@ RUN set -x ; cd ${LARAVEL_PATH} \
&& chmod -R 777 storage \
&& php artisan package:discover
```
-
### 7.18.5 最后一个阶段构建 NGINX 镜像
```docker
@@ -133,7 +128,6 @@ ARG LARAVEL_PATH=/app/laravel
COPY laravel.conf /etc/nginx/conf.d/
COPY --from=laravel ${LARAVEL_PATH}/public ${LARAVEL_PATH}/public
```
-
### 7.18.6 构建 Laravel 及 Nginx 镜像
使用 `docker build` 命令构建镜像。
@@ -143,7 +137,6 @@ $ docker build -t my/laravel --target=laravel .
$ docker build -t my/nginx --target=nginx .
```
-
### 7.18.7 启动容器并测试
新建 Docker 网络
@@ -151,19 +144,16 @@ $ docker build -t my/nginx --target=nginx .
```bash
$ docker network create laravel
```
-
启动 laravel 容器,`--name=laravel` 参数设定的名字必须与 `nginx` 配置文件中的 `fastcgi_pass laravel:9000;` 一致
```bash
$ docker run -dit --rm --name=laravel --network=laravel my/laravel
```
-
启动 nginx 容器
```bash
$ docker run -dit --rm --network=laravel -p 8080:80 my/nginx
```
-
浏览器访问 `127.0.0.1:8080` 可以看到 Laravel 项目首页。
> 也许 Laravel 项目依赖其他外部服务,例如 redis、MySQL,请自行启动这些服务之后再进行测试,本小节不再赘述。
diff --git a/07_dockerfile/7.1_run.md b/07_dockerfile/7.1_run.md
index 578e43d..03acf58 100644
--- a/07_dockerfile/7.1_run.md
+++ b/07_dockerfile/7.1_run.md
@@ -6,7 +6,6 @@
RUN
RUN ["executable", "param1", "param2"]
```
-
`RUN` 指令是 Dockerfile 中最常用的指令之一。它在 **当前镜像层** 之上创建一个新层,执行指定的命令,并提交结果。
---
@@ -18,7 +17,6 @@ RUN ["executable", "param1", "param2"]
```docker
RUN apt-get update
```
-
- **特点**:默认通过 `/bin/sh -c` 执行。
- **优势**:可以使用环境变量、管道、重定向等 Shell 特性。
- **示例**:
@@ -31,7 +29,6 @@ RUN apt-get update
```docker
RUN ["apt-get", "update"]
```
-
- **特点**:直接调用可执行文件,不经过 Shell。
- **优势**:避免 Shell 字符串解析问题,适用于参数中包含特殊字符的情况。
- **注意**:无法使用 `$VAR` 环境变量替换 (除非显式调用 shell)。
@@ -51,7 +48,6 @@ RUN apt-get update
RUN apt-get install -y nginx
RUN rm -rf /var/lib/apt/lists/*
```
-
**✅ 推荐写法** (创建 1 层):
```docker
@@ -59,7 +55,6 @@ RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
```
-
#### 2. 清理缓存
在安装完软件后,立即清除缓存,可以显著减小镜像体积。
@@ -82,19 +77,16 @@ RUN apt-get update && \
**❌ 隐蔽的错误**:
```docker
-
## 如果下载失败,gzip 可能会报错,但如果不影响后续,构建可能继续
RUN wget http://error-url | gzip -d > file
```
-
**✅ 推荐写法**:
```docker
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN wget http://url | gzip -d > file
```
-
---
### 7.1.4 常见问题
@@ -105,28 +97,24 @@ RUN wget http://url | gzip -d > file
RUN cd /app
RUN touch hello.txt
```
-
**结果**:`hello.txt` 会出现在根目录 `/`,而不是 `/app`。**原因**:每个 `RUN` 都在一个新的 Shell/容器环境中执行。`cd` 只影响当前 `RUN` 的环境。**解决**:使用 `WORKDIR` 指令。
```docker
WORKDIR /app
RUN touch hello.txt
```
-
#### Q:环境变量不生效?
```docker
RUN export MY_VAR=hello
RUN echo $MY_VAR
```
-
**结果**:输出为空。**原因**:同上,环境变量只在当前 `RUN` 有效。**解决**:使用 `ENV` 指令,或在同一行 `RUN` 中导出。
```docker
ENV MY_VAR=hello
RUN echo $MY_VAR
```
-
---
### 7.1.5 高级技巧
@@ -136,22 +124,18 @@ RUN echo $MY_VAR
BuildKit 支持在 `RUN` 指令中使用 `--mount` 挂载缓存,加速构建。
```docker
-
## 缓存 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 模块
RUN --mount=type=cache,target=/go/pkg/mod \
go build -o app
```
-
#### 2. 挂载密钥
安全地使用 SSH 密钥或 Token,而不将其记录在镜像中。
@@ -160,5 +144,4 @@ RUN --mount=type=cache,target=/go/pkg/mod \
RUN --mount=type=secret,id=mysecret \
cat /run/secrets/mysecret
```
-
---
diff --git a/07_dockerfile/7.2_copy.md b/07_dockerfile/7.2_copy.md
index 5691c29..84f813f 100644
--- a/07_dockerfile/7.2_copy.md
+++ b/07_dockerfile/7.2_copy.md
@@ -6,7 +6,6 @@
COPY [选项] <源路径>... <目标路径>
COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
```
-
`COPY` 指令将构建上下文中的文件或目录复制到镜像内。
---
@@ -16,7 +15,6 @@ COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
#### 复制单个文件
```docker
-
## 复制文件到指定目录
COPY package.json /app/
@@ -25,11 +23,9 @@ COPY package.json /app/
COPY config.json /app/settings.json
```
-
#### 复制多个文件
```docker
-
## 复制多个指定文件
COPY package.json package-lock.json /app/
@@ -39,16 +35,13 @@ COPY package.json package-lock.json /app/
COPY *.json /app/
COPY src/*.js /app/src/
```
-
#### 复制目录
```docker
-
## 复制整个目录的内容(不是目录本身)
COPY src/ /app/src/
```
-
> ⚠️ **注意**:复制目录时,复制的是目录的 **内容**,不包含目录本身。
```bash
@@ -57,7 +50,6 @@ src/ /app/src/
├── index.js → ├── index.js
└── utils.js └── utils.js
```
-
---
### 7.2.3 通配符规则
@@ -76,7 +68,6 @@ COPY hom* /mydir/ # home.txt, homework.md 等
COPY hom?.txt /mydir/ # home.txt, homy.txt 等
COPY app[0-9].js /app/ # app0.js ~ app9.js
```
-
---
### 7.2.4 目标路径
@@ -86,7 +77,6 @@ COPY app[0-9].js /app/ # app0.js ~ app9.js
```docker
COPY app.js /usr/src/app/
```
-
#### 相对路径:基于 WORKDIR
```docker
@@ -94,18 +84,15 @@ WORKDIR /app
COPY package.json ./ # 复制到 /app/package.json
COPY src/ ./src/ # 复制到 /app/src/
```
-
#### 自动创建目录
如果目标目录不存在,Docker 会自动创建:
```docker
-
## /app/config/ 不存在也会自动创建
COPY settings.json /app/config/
```
-
---
### 7.2.5 修改文件所有者
@@ -113,7 +100,6 @@ COPY settings.json /app/config/
使用 `--chown` 选项设置文件的用户和组:
```docker
-
## 使用用户名和组名
COPY --chown=node:node package.json /app/
@@ -126,7 +112,6 @@ COPY --chown=1000:1000 . /app/
COPY --chown=node . /app/
```
-
> 💡 结合 `USER` 指令使用,确保应用以非 root 用户运行。
---
@@ -141,12 +126,10 @@ COPY 会保留源文件的元数据:
这对于脚本文件特别重要:
```docker
-
## start.sh 的可执行权限会被保留
COPY start.sh /app/
```
-
---
### 7.2.7 COPY vs ADD
@@ -159,7 +142,6 @@ COPY start.sh /app/
| 推荐程度 | ✅ **推荐** | ⚠️ 特殊场景使用 |
```docker
-
## 推荐:使用 COPY
COPY app.tar.gz /app/
@@ -169,7 +151,6 @@ RUN tar -xzf /app/app.tar.gz
ADD app.tar.gz /app/
```
-
> 笔者建议:除非需要自动解压 tar 文件,否则始终使用 COPY。明确的行为比隐式的魔法更好。
---
@@ -179,7 +160,6 @@ ADD app.tar.gz /app/
#### 从其他构建阶段复制
```docker
-
## 构建阶段
FROM node:20 AS builder
@@ -194,16 +174,13 @@ RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
```
-
#### 使用 --link 优化缓存
```docker
-
## 使用 --link 后,文件以独立层添加,不依赖前序指令
COPY --link --from=builder /app/dist /usr/share/nginx/html
```
-
`--link` 的优势:
- 更高效利用构建缓存
@@ -217,7 +194,6 @@ COPY --link --from=builder /app/dist /usr/share/nginx/html
使用 `.dockerignore` 排除不需要复制的文件:
```text
-
## .dockerignore
node_modules
@@ -227,7 +203,6 @@ node_modules
Dockerfile
.dockerignore
```
-
这可以:
- 减小构建上下文大小
@@ -241,7 +216,6 @@ Dockerfile
#### 1. 利用缓存,先复制依赖文件
```docker
-
## ✅ 好:先复制依赖定义,再安装,最后复制代码
COPY package.json package-lock.json ./
@@ -253,11 +227,9 @@ COPY . .
COPY . .
RUN npm install
```
-
#### 2. 使用 .dockerignore
```docker
-
## 确保 node_modules 不被复制
COPY . .
@@ -266,11 +238,9 @@ COPY . .
...
```
-
#### 3. 明确复制路径
```docker
-
## ✅ 好:明确的路径
COPY src/ /app/src/
@@ -280,7 +250,6 @@ COPY package.json /app/
COPY . .
```
-
---
> **🔥 踩坑实录**
diff --git a/07_dockerfile/7.3_add.md b/07_dockerfile/7.3_add.md
index 7ec065e..ac951de 100644
--- a/07_dockerfile/7.3_add.md
+++ b/07_dockerfile/7.3_add.md
@@ -6,7 +6,6 @@
ADD [选项] <源路径>... <目标路径>
ADD [选项] ["<源路径>", ... "<目标路径>"]
```
-
`ADD` 在 `COPY` 基础上增加了两个功能:
1. 自动解压 tar 压缩包
@@ -33,12 +32,10 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
#### 基本用法:自动解压本地 tar
```docker
-
## 自动解压 tar.gz 到目标目录
ADD app.tar.gz /app/
```
-
ADD 会识别并解压以下格式:
- `.tar`
@@ -54,7 +51,6 @@ ADD 会识别并解压以下格式:
FROM scratch
ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
```
-
#### 解压过程
```bash
@@ -69,7 +65,6 @@ app.tar.gz 包含: /app/ 目录结果:
│ └── main.py │ └── main.py
└── config.json └── config.json
```
-
---
### 7.3.4 URL 下载功能:不推荐
@@ -77,12 +72,10 @@ app.tar.gz 包含: /app/ 目录结果:
#### 基本用法
```docker
-
## 从 URL 下载文件
ADD https://example.com/app.zip /app/app.zip
```
-
#### 为什么不推荐
| 问题 | 说明 |
@@ -95,7 +88,6 @@ ADD https://example.com/app.zip /app/app.zip
#### 推荐替代方案
```docker
-
## ❌ 不推荐:使用 ADD 下载
ADD https://example.com/app.tar.gz /tmp/
@@ -105,7 +97,6 @@ RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz
RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
```
-
优势:
- 一条 RUN 完成下载、解压、清理
@@ -120,7 +111,6 @@ RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
ADD --chown=node:node app.tar.gz /app/
ADD --chown=1000:1000 files/ /app/
```
-
---
### 7.3.6 何时使用 ADD
@@ -128,7 +118,6 @@ ADD --chown=1000:1000 files/ /app/
#### ✅ 适合使用 ADD
```docker
-
## 解压本地 tar 文件
FROM scratch
@@ -138,11 +127,9 @@ ADD rootfs.tar.gz /
ADD dist.tar.gz /app/
```
-
#### ❌ 不适合使用 ADD
```docker
-
## 复制普通文件(用 COPY)
ADD package.json /app/ # ❌
@@ -158,7 +145,6 @@ RUN curl -fsSL ... -o /file # ✅
ADD archive.tar.gz /archives/ # ❌ 会解压
COPY archive.tar.gz /archives/ # ✅ 保持原样
```
-
---
### 7.3.7 缓存行为
@@ -166,17 +152,14 @@ COPY archive.tar.gz /archives/ # ✅ 保持原样
ADD 可能导致构建缓存失效:
```docker
-
## 如果 app.tar.gz 内容变化,此层及后续层都需重建
ADD app.tar.gz /app/
RUN npm install
```
-
**优化建议**:
```docker
-
## 先复制依赖文件
COPY package*.json /app/
@@ -186,7 +169,6 @@ RUN npm install
ADD app.tar.gz /app/
```
-
---
### 7.3.8 最佳实践
@@ -194,25 +176,20 @@ ADD app.tar.gz /app/
#### 1. 默认使用 COPY
```docker
-
## ✅ 大多数场景使用 COPY
COPY . /app/
```
-
#### 2. 仅在需要解压时使用 ADD
```docker
-
## ✅ 自动解压场景
ADD app.tar.gz /app/
```
-
#### 3. 不要用 ADD 下载文件
```docker
-
## ❌ 避免
ADD https://example.com/file.tar.gz /tmp/
@@ -221,16 +198,13 @@ ADD https://example.com/file.tar.gz /tmp/
RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
```
-
#### 4. 解压后清理
```docker
-
## 如果需要控制解压过程
COPY app.tar.gz /tmp/
RUN tar -xzf /tmp/app.tar.gz -C /app && \
rm /tmp/app.tar.gz
```
-
---
diff --git a/07_dockerfile/7.4_cmd.md b/07_dockerfile/7.4_cmd.md
index cf290fa..4430d89 100644
--- a/07_dockerfile/7.4_cmd.md
+++ b/07_dockerfile/7.4_cmd.md
@@ -25,7 +25,6 @@ CMD ["nginx", "-g", "daemon off;"]
CMD ["python", "app.py"]
CMD ["node", "server.js"]
```
-
**优点**:
- 直接执行指定程序,是容器的 PID 1
@@ -38,11 +37,9 @@ CMD ["node", "server.js"]
CMD echo "Hello World"
CMD nginx -g "daemon off;"
```
-
**实际执行**:会被包装为 `sh -c`
```docker
-
## 你写的
CMD echo $HOME
@@ -51,7 +48,6 @@ CMD echo $HOME
CMD ["sh", "-c", "echo $HOME"]
```
-
**优点**:可以使用环境变量、管道等 shell 特性 **缺点**:主进程是 sh,信号无法正确传递给应用
---
@@ -68,7 +64,6 @@ CMD ["sh", "-c", "echo $HOME"]
#### 信号传递问题示例
```docker
-
## ❌ shell 格式:docker stop 会超时
CMD node server.js
@@ -85,7 +80,6 @@ CMD ["node", "server.js"]
...
```
-
---
### 7.4.4 运行时覆盖 CMD
@@ -93,13 +87,11 @@ CMD ["node", "server.js"]
`docker run` 后的命令会覆盖 Dockerfile 中的 CMD:
```bash
-
## ubuntu 默认 CMD 是 /bin/bash
$ docker run -it ubuntu # 进入 bash
$ docker run ubuntu cat /etc/os-release # 覆盖为 cat 命令
```
-
```bash
Dockerfile: docker run 命令:
CMD ["/bin/bash"] + cat /etc/os-release
@@ -108,7 +100,6 @@ CMD ["/bin/bash"] + cat /etc/os-release
↓
执行: cat /etc/os-release
```
-
---
### 7.4.5 经典错误:容器立即退出
@@ -116,12 +107,10 @@ CMD ["/bin/bash"] + cat /etc/os-release
#### 错误示例
```docker
-
## ❌ 容器启动后立即退出
CMD service nginx start
```
-
#### 原因分析
```bash
@@ -137,16 +126,13 @@ CMD service nginx start
↓
6. 容器主进程(sh)退出 → 容器停止
```
-
#### 正确做法
```docker
-
## ✅ 让 nginx 在前台运行
CMD ["nginx", "-g", "daemon off;"]
```
-
---
### 7.4.6 CMD vs ENTRYPOINT
@@ -159,32 +145,26 @@ CMD ["nginx", "-g", "daemon off;"]
#### 单独使用 CMD
```docker
-
## Dockerfile
CMD ["curl", "-s", "http://example.com"]
```
-
```bash
$ docker run myimage # 执行默认命令
$ docker run myimage curl -v ... # 完全覆盖
```
-
#### 搭配 ENTRYPOINT
```docker
-
## Dockerfile
ENTRYPOINT ["curl", "-s"]
CMD ["http://example.com"]
```
-
```bash
$ docker run myimage # curl -s http://example.com
$ docker run myimage http://other.com # curl -s http://other.com(参数覆盖)
```
-
详见 [ENTRYPOINT 入口点](7.5_entrypoint.md)章节。
---
@@ -194,7 +174,6 @@ $ docker run myimage http://other.com # curl -s http://other.com(参数覆盖
#### 1. 优先使用 exec 格式
```docker
-
## ✅ 推荐
CMD ["python", "app.py"]
@@ -203,11 +182,9 @@ CMD ["python", "app.py"]
CMD ["sh", "-c", "echo $PATH && python app.py"]
```
-
#### 2. 确保应用在前台运行
```docker
-
## ✅ 前台运行
CMD ["nginx", "-g", "daemon off;"]
@@ -219,11 +196,9 @@ CMD ["java", "-jar", "app.jar"]
CMD service nginx start
CMD systemctl start nginx
```
-
#### 3. 使用双引号
```docker
-
## ✅ 正确:双引号
CMD ["node", "server.js"]
@@ -232,11 +207,9 @@ CMD ["node", "server.js"]
CMD ['node', 'server.js']
```
-
#### 4. 配合 ENTRYPOINT 使用
```docker
-
## 用于可配置参数的场景
ENTRYPOINT ["python", "app.py"]
@@ -248,7 +221,6 @@ $ docker run myapp --port 9000
...
```
-
---
### 7.4.8 常见问题
@@ -261,11 +233,9 @@ $ docker run myapp --port 9000
CMD ["echo", "first"]
CMD ["echo", "second"] # 只有这个生效
```
-
#### Q:如何在 CMD 中使用环境变量?
```docker
-
## 方法1:使用 shell 格式
CMD echo "Port is $PORT"
@@ -274,13 +244,11 @@ CMD echo "Port is $PORT"
CMD ["sh", "-c", "echo Port is $PORT"]
```
-
#### Q:为什么我的容器不响应 Ctrl+C?
可能是使用了 shell 格式,信号被 sh 吃掉了:
```docker
-
## ❌ 信号无法传递
CMD python app.py
@@ -289,5 +257,4 @@ CMD python app.py
CMD ["python", "app.py"]
```
-
---
diff --git a/07_dockerfile/7.5_entrypoint.md b/07_dockerfile/7.5_entrypoint.md
index 70276a8..d9fa714 100644
--- a/07_dockerfile/7.5_entrypoint.md
+++ b/07_dockerfile/7.5_entrypoint.md
@@ -16,7 +16,6 @@
| **shell 格式** | `ENTRYPOINT 命令 参数` | ⚠️ 不推荐 |
```docker
-
## exec 格式(推荐)
ENTRYPOINT ["nginx", "-g", "daemon off;"]
@@ -25,7 +24,6 @@ ENTRYPOINT ["nginx", "-g", "daemon off;"]
ENTRYPOINT nginx -g "daemon off;"
```
-
---
### 7.5.3 ENTRYPOINT vs CMD
@@ -42,44 +40,35 @@ ENTRYPOINT nginx -g "daemon off;"
#### 行为对比
```docker
-
## 只用 CMD
CMD ["curl", "-s", "http://example.com"]
```
-
```bash
$ docker run myimage # curl -s http://example.com
$ docker run myimage -v # 执行 -v(错误!)
$ docker run myimage curl -v ... # curl -v ...(完全替换)
```
-
```docker
-
## 只用 ENTRYPOINT
ENTRYPOINT ["curl", "-s"]
```
-
```bash
$ docker run myimage # curl -s(缺参数)
$ docker run myimage http://example.com # curl -s http://example.com ✓
```
-
```docker
-
## ENTRYPOINT + CMD 组合(推荐)
ENTRYPOINT ["curl", "-s"]
CMD ["http://example.com"]
```
-
```bash
$ docker run myimage # curl -s http://example.com(默认)
$ docker run myimage http://other.com # curl -s http://other.com ✓
$ docker run myimage -v http://other.com # curl -s -v http://other.com ✓
```
-
---
### 7.5.4 场景一:让镜像像命令一样使用
@@ -95,7 +84,6 @@ FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
CMD ["curl", "-s", "http://myip.ipip.net"]
```
-
```bash
$ docker run myip # ✓ 正常工作
当前 IP:61.148.226.66
@@ -107,7 +95,6 @@ exec: "-i": executable file not found
...
```
-
#### 使用 ENTRYPOINT 解决
```docker
@@ -115,7 +102,6 @@ FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
```
-
```bash
$ docker run myip # ✓ 正常工作
当前 IP:61.148.226.66
@@ -125,7 +111,6 @@ HTTP/1.1 200 OK
...
当前 IP:61.148.226.66
```
-
#### 交互图示
```bash
@@ -138,7 +123,6 @@ curl -s http://myip.ipip.net -i
└─────────────────────────────┘
ENTRYPOINT + docker run 参数
```
-
---
### 7.5.5 场景二:启动前的准备工作
@@ -155,7 +139,6 @@ COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["redis-server"]
```
-
**docker-entrypoint.sh**:
```bash
@@ -177,7 +160,6 @@ fi
exec "$@"
```
-
#### 工作流程
```bash
@@ -191,7 +173,6 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
└─ exec gosu redis redis-server └─ exec bash
(以 redis 用户运行) (以 root 用户运行)
```
-
#### 关键点
1. **exec “$@”**:用传入的参数替换当前进程,确保信号正确传递
@@ -211,9 +192,7 @@ RUN pip install -r requirements.txt
ENTRYPOINT ["python", "app.py"]
CMD ["--host", "0.0.0.0", "--port", "8080"]
```
-
```bash
-
## 使用默认参数
$ docker run myapp
@@ -234,7 +213,6 @@ $ docker run myapp --help
...
```
-
---
### 7.5.7 覆盖 ENTRYPOINT
@@ -242,7 +220,6 @@ $ docker run myapp --help
使用 `--entrypoint` 参数覆盖:
```bash
-
## 正常运行
$ docker run myimage
@@ -255,7 +232,6 @@ $ docker run --entrypoint /bin/sh myimage
$ docker run --entrypoint /bin/cat myimage /etc/os-release
```
-
---
### 7.5.8 ENTRYPOINT 与 CMD 组合表
@@ -277,7 +253,6 @@ $ docker run --entrypoint /bin/cat myimage /etc/os-release
#### 1. 使用 exec 格式
```docker
-
## ✅ 推荐
ENTRYPOINT ["python", "app.py"]
@@ -286,14 +261,12 @@ ENTRYPOINT ["python", "app.py"]
ENTRYPOINT python app.py
```
-
#### 2. 提供有意义的默认参数
```docker
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
```
-
#### 3. 入口脚本使用 exec
```bash
@@ -305,7 +278,6 @@ CMD ["-g", "daemon off;"]
exec "$@"
```
-
#### 4. 处理信号
确保 ENTRYPOINT 脚本能正确传递信号:
@@ -323,5 +295,4 @@ PID=$!
wait $PID
```
-
---
diff --git a/07_dockerfile/7.6_env.md b/07_dockerfile/7.6_env.md
index 9621eb0..be32312 100644
--- a/07_dockerfile/7.6_env.md
+++ b/07_dockerfile/7.6_env.md
@@ -3,7 +3,6 @@
### 7.6.1 基本语法
```docker
-
## 格式一:单个变量
ENV
@@ -12,7 +11,6 @@ ENV
ENV = = ...
```
-
---
### 7.6.2 基本用法
@@ -23,7 +21,6 @@ ENV = = ...
ENV NODE_VERSION 20.10.0
ENV APP_ENV production
```
-
#### 设置多个变量
```docker
@@ -31,7 +28,6 @@ ENV NODE_VERSION=20.10.0 \
APP_ENV=production \
APP_NAME="My Application"
```
-
> 💡 包含空格的值用双引号括起来。
---
@@ -57,24 +53,20 @@ WORKDIR $APP_HOME
COPY . $APP_HOME
```
-
#### 2. 容器运行时使用
```docker
ENV DATABASE_URL=postgres://localhost/mydb
```
-
应用代码中可以读取:
```python
import os
db_url = os.environ.get('DATABASE_URL')
```
-
```javascript
const dbUrl = process.env.DATABASE_URL;
```
-
---
### 7.6.4 支持环境变量的指令
@@ -102,7 +94,6 @@ const dbUrl = process.env.DATABASE_URL;
使用 `-e` 或 `--env` 覆盖 Dockerfile 中定义的环境变量:
```bash
-
## 覆盖单个变量
$ docker run -e APP_ENV=development myimage
@@ -115,18 +106,15 @@ $ docker run -e APP_ENV=development -e DEBUG=true myimage
$ docker run --env-file .env myimage
```
-
#### .env 文件格式
```bash
-
## .env
APP_ENV=development
DEBUG=true
DATABASE_URL=postgres://localhost/mydb
```
-
---
### 7.6.6 ENV vs ARG
@@ -141,7 +129,6 @@ DATABASE_URL=postgres://localhost/mydb
#### 组合使用
```docker
-
## ARG 接收构建时参数
ARG NODE_VERSION=20
@@ -154,14 +141,11 @@ 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 .
```
-
---
### 7.6.7 最佳实践
@@ -169,7 +153,6 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
#### 1. 统一管理版本号
```docker
-
## ✅ 好:版本集中管理
ENV NGINX_VERSION=1.25.0 \
@@ -182,11 +165,9 @@ RUN apt-get install nginx=${NGINX_VERSION}
RUN apt-get install nginx=1.25.0
```
-
#### 2. 不要存储敏感信息
```docker
-
## ❌ 错误:密码写入镜像
ENV DB_PASSWORD=secret123
@@ -197,7 +178,6 @@ ENV DB_PASSWORD=secret123
...
```
-
#### 3. 为应用提供合理默认值
```docker
@@ -205,11 +185,9 @@ ENV APP_ENV=production \
APP_PORT=8080 \
LOG_LEVEL=info
```
-
#### 4. 使用有意义的变量名
```docker
-
## ✅ 好:清晰的命名
ENV REDIS_HOST=localhost \
@@ -220,7 +198,6 @@ ENV REDIS_HOST=localhost \
ENV HOST=localhost \
PORT=6379
```
-
---
### 7.6.8 常见问题
@@ -230,7 +207,6 @@ ENV HOST=localhost \
exec 格式不会自动展开环境变量:
```docker
-
## ❌ 不会展开 $PORT
CMD ["python", "app.py", "--port", "$PORT"]
@@ -239,18 +215,15 @@ CMD ["python", "app.py", "--port", "$PORT"]
CMD ["sh", "-c", "python app.py --port $PORT"]
```
-
#### Q:如何查看容器的环境变量
```bash
$ docker inspect mycontainer --format '{{json .Config.Env}}'
$ docker exec mycontainer env
```
-
#### Q:多行 ENV 还是多个 ENV
```docker
-
## ✅ 推荐:减少层数
ENV VAR1=value1 \
@@ -263,5 +236,4 @@ ENV VAR1=value1
ENV VAR2=value2
ENV VAR3=value3
```
-
---
diff --git a/07_dockerfile/7.7_arg.md b/07_dockerfile/7.7_arg.md
index ca145f6..2d9a615 100644
--- a/07_dockerfile/7.7_arg.md
+++ b/07_dockerfile/7.7_arg.md
@@ -5,7 +5,6 @@
```docker
ARG <参数名>[=<默认值>]
```
-
`ARG` 指令定义构建时的变量,可以在 `docker build` 时通过 `--build-arg` 传入。
---
@@ -26,7 +25,6 @@ ARG <参数名>[=<默认值>]
├─ ENV APP_ENV=prod │ APP_ENV=prod(仍存在)
└─ RUN echo $VERSION │
```
-
> ⚠️ **安全提示**:不要用 ARG 传递密码等敏感信息,`docker history` 可以查看所有 ARG 值。
---
@@ -36,7 +34,6 @@ ARG <参数名>[=<默认值>]
#### 定义和使用
```docker
-
## 定义有默认值的 ARG
ARG NODE_VERSION=20
@@ -46,11 +43,9 @@ ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
RUN echo "Using Node.js $NODE_VERSION"
```
-
#### 构建时覆盖
```bash
-
## 使用默认值
$ docker build -t myapp .
@@ -59,7 +54,6 @@ $ docker build -t myapp .
$ docker build --build-arg NODE_VERSION=18 -t myapp .
```
-
---
### 7.7.4 ARG 的作用域
@@ -67,7 +61,6 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
#### FROM 之前的 ARG
```docker
-
## FROM 之前的 ARG 只能用于 FROM 指令
ARG REGISTRY=docker.io
@@ -79,7 +72,6 @@ FROM ${REGISTRY}/${IMAGE_NAME}:20
RUN echo $REGISTRY # 输出空
```
-
#### FROM 之后重新声明
```docker
@@ -92,7 +84,6 @@ FROM node:${NODE_VERSION}-alpine
ARG NODE_VERSION
RUN echo "Node version: $NODE_VERSION"
```
-
#### 多阶段构建中的 ARG
```docker
@@ -112,7 +103,6 @@ FROM node:20-${BASE_VERSION}
ARG NODE_VERSION=20
RUN echo "Running with Node $NODE_VERSION"
```
-
---
### 7.7.5 常见使用场景
@@ -123,11 +113,9 @@ RUN echo "Running with Node $NODE_VERSION"
ARG ALPINE_VERSION=3.19
FROM alpine:${ALPINE_VERSION}
```
-
```bash
$ docker build --build-arg ALPINE_VERSION=3.18 .
```
-
#### 2. 设置软件版本
```docker
@@ -135,7 +123,6 @@ ARG NGINX_VERSION=1.25.0
RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -xz
```
-
#### 3. 配置构建环境
```docker
@@ -148,7 +135,6 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
npm install --production; \
fi
```
-
#### 4. 配置私有仓库
```docker
@@ -158,14 +144,11 @@ RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \
npm install && \
rm ~/.npmrc
```
-
```bash
-
## 构建时传入 token
$ docker build --build-arg NPM_TOKEN=xxx .
```
-
---
### 7.7.6 将 ARG 传递给 ENV
@@ -183,7 +166,6 @@ ENV APP_VERSION=$VERSION
CMD echo "App version: $APP_VERSION"
```
-
---
### 7.7.7 预定义 ARG
@@ -198,12 +180,10 @@ Docker 提供了一些预定义的 ARG,无需声明即可使用:
| `FTP_PROXY` | FTP 代理 |
```bash
-
## 构建时使用代理
$ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
```
-
---
### 7.7.8 最佳实践
@@ -211,7 +191,6 @@ $ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
#### 1. 为 ARG 提供合理默认值
```docker
-
## ✅ 好:有默认值
ARG NODE_VERSION=20
@@ -220,11 +199,9 @@ ARG NODE_VERSION=20
ARG NODE_VERSION
```
-
#### 2. 不要用 ARG 存储敏感信息
```docker
-
## ❌ 错误:密码会被记录在镜像历史中
ARG DB_PASSWORD
@@ -234,7 +211,6 @@ RUN echo "password=$DB_PASSWORD" > /app/.env
...
```
-
#### 3. 使用 ARG 提高构建灵活性
```docker
@@ -247,5 +223,4 @@ FROM ${BASE_IMAGE}
...
```
-
---
diff --git a/07_dockerfile/7.8_volume.md b/07_dockerfile/7.8_volume.md
index 75b8c74..cbf1e7c 100644
--- a/07_dockerfile/7.8_volume.md
+++ b/07_dockerfile/7.8_volume.md
@@ -6,7 +6,6 @@
VOLUME ["/路径1", "/路径2"]
VOLUME /路径
```
-
`VOLUME` 指令创建挂载点,并标记为外部挂载的卷。
---
@@ -38,7 +37,6 @@ flowchart LR
Volume ~~~ Result2
end
```
-
---
### 7.8.3 基本用法
@@ -49,14 +47,12 @@ flowchart LR
FROM mysql:8.0
VOLUME /var/lib/mysql
```
-
#### 定义多个卷
```docker
FROM myapp
VOLUME ["/data", "/logs", "/config"]
```
-
---
### 7.8.4 VOLUME 的行为
@@ -71,25 +67,20 @@ $ docker volume ls
DRIVER VOLUME NAME
local a1b2c3d4e5f6... # 自动创建的匿名卷
```
-
#### 2. 可被命名卷覆盖
```bash
-
## 使用命名卷替代匿名卷
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
```
-
#### 3. 可被 Bind Mount 覆盖
```bash
-
## 使用宿主机目录替代
$ docker run -v /my/data:/var/lib/mysql mysql:8.0
```
-
---
### 7.8.5 VOLUME 在构建时的特殊行为
@@ -104,7 +95,6 @@ VOLUME /data
RUN echo "hello" > /data/test.txt
```
-
**原因**:在构建过程中,VOLUME 指令会为该目录创建一个临时的匿名卷。后续 RUN 指令对该目录的写入实际发生在这个临时卷中,而非镜像层。当该 RUN 指令结束后,临时卷被丢弃,因此写入的内容不会保存到最终镜像中。注意:这与容器运行时创建的匿名卷是不同的——运行时创建的卷会在容器生命周期内持续存在。
#### 正确做法
@@ -120,7 +110,6 @@ RUN mkdir -p /data && echo "hello" > /data/test.txt
VOLUME /data
```
-
---
### 7.8.6 常见使用场景
@@ -131,27 +120,23 @@ VOLUME /data
FROM postgres:16
VOLUME /var/lib/postgresql/data
```
-
#### 日志目录
```docker
FROM nginx
VOLUME /var/log/nginx
```
-
#### 上传文件目录
```docker
FROM myapp
VOLUME /app/uploads
```
-
---
### 7.8.7 查看 VOLUME 定义
```bash
-
## 查看镜像定义的 VOLUME
$ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
@@ -163,7 +148,6 @@ $ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
```
-
---
### 7.8.8 VOLUME vs docker run -v
@@ -196,7 +180,6 @@ services:
volumes:
postgres_data: # 声明命名卷
```
-
---
### 7.8.10 安全注意事项
@@ -204,7 +187,6 @@ volumes:
#### 匿名卷可能导致数据丢失
```bash
-
## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
$ docker run --rm mysql:8.0
@@ -213,13 +195,11 @@ $ docker run --rm mysql:8.0
...
```
-
**解决**:始终使用命名卷
```bash
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
```
-
---
### 7.8.11 最佳实践
@@ -227,17 +207,14 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
#### 1. 定义必须持久化的路径
```docker
-
## 数据库必须使用卷
FROM postgres:16
VOLUME /var/lib/postgresql/data
```
-
#### 2. 不要在 VOLUME 后修改目录
```docker
-
## ❌ 避免
VOLUME /app/data
@@ -248,11 +225,9 @@ RUN cp init-data.json /app/data/
RUN mkdir -p /app/data && cp init-data.json /app/data/
VOLUME /app/data
```
-
#### 3. 文档中说明 VOLUME 用途
```docker
-
## 持久化用户上传的文件
VOLUME /app/uploads
@@ -261,5 +236,4 @@ VOLUME /app/uploads
VOLUME /var/lib/mysql
```
-
---
diff --git a/07_dockerfile/7.9_expose.md b/07_dockerfile/7.9_expose.md
index 40d5c17..67d8211 100644
--- a/07_dockerfile/7.9_expose.md
+++ b/07_dockerfile/7.9_expose.md
@@ -5,7 +5,6 @@
```docker
EXPOSE <端口> [<端口>/<协议>...]
```
-
`EXPOSE` 声明容器运行时提供服务的端口。这是一个 **文档性质的声明**,告诉使用者容器会监听哪些端口。
---
@@ -13,7 +12,6 @@ EXPOSE <端口> [<端口>/<协议>...]
### 7.9.2 基本用法
```docker
-
## 声明单个端口
EXPOSE 80
@@ -27,7 +25,6 @@ EXPOSE 80 443
EXPOSE 80/tcp
EXPOSE 53/udp
```
-
---
### 7.9.3 EXPOSE 的作用
@@ -37,37 +34,30 @@ EXPOSE 53/udp
告诉镜像使用者,容器将在哪些端口提供服务:
```docker
-
## 使用者一看就知道这是 web 应用
EXPOSE 80 443
```
-
```bash
-
## 查看镜像暴露的端口
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
map[80/tcp:{}]
```
-
#### 2. 配合 -P 使用
使用 `docker run -P` 时,Docker 会自动映射 EXPOSE 的端口到宿主机随机端口:
```docker
-
## Dockerfile
EXPOSE 80
```
-
```bash
$ docker run -P nginx
$ docker port $(docker ps -q)
80/tcp -> 0.0.0.0:32768
```
-
---
### 7.9.4 EXPOSE vs -p
@@ -85,11 +75,9 @@ flowchart TD
Run["docker run -p
实际端口映射
宿主机 ←→ 容器"]
Expose ~~~ Run
```
-
#### 没有 EXPOSE 也能 -p
```docker
-
## 即使没有 EXPOSE,也可以使用 -p
FROM nginx
@@ -98,14 +86,11 @@ FROM nginx
...
```
-
```bash
-
## 仍然可以映射端口
$ docker run -p 8080:80 mynginx
```
-
---
### 7.9.5 常见误解
@@ -113,12 +98,10 @@ $ docker run -p 8080:80 mynginx
#### 误解:EXPOSE 会打开端口
```docker
-
## ❌ 错误理解:这不会让容器可从外部访问
EXPOSE 80
```
-
EXPOSE 不会:
- 自动进行端口映射
@@ -130,20 +113,16 @@ EXPOSE 只是元数据声明。容器是否实际监听该端口,取决于容
#### 正确理解
```docker
-
## Dockerfile
FROM nginx
EXPOSE 80 # 1. 声明:这个容器会在 80 端口提供服务
```
-
```bash
-
## 运行:需要 -p 才能从外部访问
$ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
```
-
---
### 7.9.6 最佳实践
@@ -151,7 +130,6 @@ $ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
#### 1. 总是声明应用使用的端口
```docker
-
## Web 服务
FROM nginx
@@ -167,11 +145,9 @@ EXPOSE 5432
FROM redis
EXPOSE 6379
```
-
#### 2. 使用明确的协议
```docker
-
## 默认是 TCP
EXPOSE 80
@@ -184,11 +160,9 @@ EXPOSE 53/udp
EXPOSE 53/tcp 53/udp
```
-
#### 3. 与应用实际端口保持一致
```docker
-
## ✅ 好:EXPOSE 与应用端口一致
ENV PORT=3000
@@ -200,7 +174,6 @@ CMD ["node", "server.js"]
EXPOSE 80
CMD ["node", "server.js"] # 实际监听 3000
```
-
---
### 7.9.7 使用环境变量
@@ -209,7 +182,6 @@ CMD ["node", "server.js"] # 实际监听 3000
ARG PORT=80
EXPOSE $PORT
```
-
---
### 7.9.8 在 Compose 中
@@ -225,7 +197,6 @@ services:
expose:
- "80" # 仅声明(类似 EXPOSE)
```
-
`expose` 在 Compose 中仅用于容器间通信的文档说明,不进行端口映射。
---
diff --git a/07_dockerfile/README.md b/07_dockerfile/README.md
index 18263a4..2e9562e 100644
--- a/07_dockerfile/README.md
+++ b/07_dockerfile/README.md
@@ -57,11 +57,9 @@ Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像
```bash
docker build [选项] <上下文路径/URL/->
```
-
例如,在 Dockerfile 所在目录执行:
```bash
docker build -t my-image:v1 .
```
-
更多关于 `docker build` 的用法,我们在实战中会结合具体指令进行演示。
diff --git a/08_data/8.1_volume.md b/08_data/8.1_volume.md
index 7608789..14614c1 100644
--- a/08_data/8.1_volume.md
+++ b/08_data/8.1_volume.md
@@ -10,7 +10,6 @@ flowchart LR
Write --> Delete[容器删除]
Delete -->|数据都在容器 writable 层| Lost[DATA LOST! ❌]
```
-
数据卷 (Volume) 解决了这个问题,它的生命周期独立于容器。
---
@@ -42,7 +41,6 @@ graph TD
Lifecycle[生命周期 = 容器生命周期] -.-> Container
Delete[容器删除] -->|导致| DataLost[数据丢失 ❌]
```
-
#### 数据卷:推荐
```mermaid
@@ -58,7 +56,6 @@ graph TD
AppDir == 挂载 ==> Volume
Delete[容器删除] -.->|不会影响| Volume
```
-
---
### 8.1.4 数据卷基本操作
@@ -68,7 +65,6 @@ graph TD
```bash
$ docker volume create my-vol
```
-
#### 列出所有数据卷
```bash
@@ -78,7 +74,6 @@ local my-vol
local postgres_data
local redis_data
```
-
#### 查看数据卷详情
```bash
@@ -95,7 +90,6 @@ $ docker volume inspect my-vol
}
]
```
-
**关键字段**:
- `Mountpoint`:数据卷在宿主机上的实际存储位置
@@ -113,7 +107,6 @@ $ docker run -d \
--mount source=my-vol,target=/usr/share/nginx/html \
nginx
```
-
**参数说明**:
| 参数 | 说明 |
@@ -130,7 +123,6 @@ $ docker run -d \
-v my-vol:/usr/share/nginx/html \
nginx
```
-
**格式**:`-v 数据卷名:容器路径[:选项]`
#### 两种方式对比
@@ -147,7 +139,6 @@ $ docker run -d \
#### 只读挂载
```bash
-
## --mount 方式
$ docker run -d \
@@ -160,7 +151,6 @@ $ docker run -d \
-v my-vol:/data:ro \
nginx
```
-
---
### 8.1.6 使用场景示例
@@ -168,7 +158,6 @@ $ docker run -d \
#### 场景一:数据库持久化
```bash
-
## 创建数据卷
$ docker volume create postgres_data
@@ -193,11 +182,9 @@ $ docker run -d \
-v postgres_data:/var/lib/postgresql/data \
postgres:16
```
-
#### 场景二:多容器共享数据
```bash
-
## 创建共享数据卷
$ docker volume create shared-data
@@ -214,11 +201,9 @@ $ docker run --rm \
-v shared-data:/data \
alpine cat /data/log.txt
```
-
#### 场景三:配置文件持久化
```bash
-
## 将 nginx 配置存储在数据卷中
$ docker run -d \
@@ -227,7 +212,6 @@ $ docker run -d \
-p 80:80 \
nginx
```
-
---
### 8.1.7 数据卷管理
@@ -235,7 +219,6 @@ $ docker run -d \
#### 删除数据卷
```bash
-
## 删除指定数据卷
$ docker volume rm my-vol
@@ -244,11 +227,9 @@ $ docker volume rm my-vol
$ docker rm -v container_name
```
-
#### 清理未使用的数据卷
```bash
-
## 查看未被任何容器使用的数据卷
$ docker volume ls -f dangling=true
@@ -261,7 +242,6 @@ $ docker volume prune
$ docker volume prune -f
```
-
> ⚠️ **注意**:数据卷不会自动垃圾回收。长期运行的系统应定期清理无用数据卷。
---
@@ -271,7 +251,6 @@ $ docker volume prune -f
#### 备份数据卷
```bash
-
## 使用临时容器挂载数据卷,打包备份
$ docker run --rm \
@@ -279,7 +258,6 @@ $ docker run --rm \
-v $(pwd):/backup \
alpine tar czf /backup/my-vol-backup.tar.gz -C /source .
```
-
**原理**:
1. 创建临时容器
@@ -290,7 +268,6 @@ $ docker run --rm \
#### 恢复数据卷
```bash
-
## 创建新数据卷
$ docker volume create my-vol-restored
@@ -302,7 +279,6 @@ $ docker run --rm \
-v $(pwd):/backup:ro \
alpine tar xzf /backup/my-vol-backup.tar.gz -C /target
```
-
#### 备份脚本示例
```bash
@@ -321,7 +297,6 @@ docker run --rm \
echo "Backed up ${VOLUME_NAME} to ${BACKUP_DIR}/${VOLUME_NAME}_${TIMESTAMP}.tar.gz"
```
-
---
### 8.1.9 数据卷 vs 绑定挂载
@@ -337,7 +312,6 @@ Docker 有两种主要的数据持久化方式:
| **备份** | 需要工具 | 直接访问文件 |
```bash
-
## 数据卷
$ docker run -v mydata:/app/data nginx
@@ -346,7 +320,6 @@ $ docker run -v mydata:/app/data nginx
$ docker run -v /host/path:/app/data nginx
```
-
详见[绑定挂载](8.2_bind-mounts.md)章节。
---
@@ -358,11 +331,9 @@ $ docker run -v /host/path:/app/data nginx
```bash
$ docker inspect container_name --format '{{json .Mounts}}' | jq
```
-
#### Q:数据卷的数据在哪里?
```bash
-
## 查看数据卷详情
$ docker volume inspect my-vol
@@ -371,7 +342,6 @@ $ docker volume inspect my-vol
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data"
```
-
> ⚠️ **注意**:不建议直接修改 Mountpoint 中的文件,应通过容器操作。
#### Q:如何在不同机器间迁移数据卷?
diff --git a/08_data/8.2_bind-mounts.md b/08_data/8.2_bind-mounts.md
index 4561042..82c0f46 100644
--- a/08_data/8.2_bind-mounts.md
+++ b/08_data/8.2_bind-mounts.md
@@ -16,7 +16,6 @@ flowchart LR
Dir1 <-->|Bind Mount| Dir2
```
-
目录结构(同一份文件):
```text
/home/user/code/ (或 /usr/share/nginx/html/)
@@ -24,7 +23,6 @@ flowchart LR
├── style.css
└── app.js
```
-
---
### 8.2.2 Bind Mount vs Volume
@@ -60,7 +58,6 @@ $ docker run -d \
--mount type=bind,source=/宿主机路径,target=/容器路径 \
nginx
```
-
#### 使用 -v:简写
```bash
@@ -68,7 +65,6 @@ $ docker run -d \
-v /宿主机路径:/容器路径 \
nginx
```
-
#### 两种语法对比
| 特性 | --mount | -v |
@@ -86,7 +82,6 @@ $ docker run -d \
#### 场景一:开发环境代码同步
```bash
-
## 将本地代码目录挂载到容器
$ docker run -d \
@@ -102,40 +97,33 @@ $ echo "Hello" > src/index.html
...
```
-
#### 场景二:配置文件挂载
```bash
-
## 挂载自定义 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 密钥
```bash
-
## 挂载 SSH 密钥(只读)
$ docker run --rm -it \
--mount type=bind,source=$HOME/.ssh,target=/root/.ssh,readonly \
alpine ssh user@remote
```
-
---
### 8.2.5 只读挂载
@@ -143,7 +131,6 @@ $ docker run --rm -it \
防止容器修改宿主机文件:
```bash
-
## --mount 语法
$ docker run -d \
@@ -156,20 +143,17 @@ $ docker run -d \
-v /config:/app/config:ro \
myapp
```
-
容器内尝试写入会报错:
```bash
$ touch /app/config/new.txt
touch: /app/config/new.txt: Read-only file system
```
-
---
### 8.2.6 挂载单个文件
```bash
-
## 挂载 bash 历史记录
$ docker run --rm -it \
@@ -182,7 +166,6 @@ $ docker run -d \
--mount type=bind,source=/path/to/my.cnf,target=/etc/mysql/my.cnf \
mysql
```
-
> ⚠️ **注意**:挂载单个文件时,如果宿主机上的文件被编辑器替换 (而非原地修改),容器内仍是旧文件的 inode。建议重启容器或挂载目录。
---
@@ -192,7 +175,6 @@ $ docker run -d \
```bash
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
```
-
输出:
```json
@@ -207,7 +189,6 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq
}
]
```
-
| 字段 | 说明 |
|------|------|
| `Type` | 挂载类型 (bind)|
@@ -227,7 +208,6 @@ $ docker run --mount type=bind,source=/not/exist,target=/app nginx
docker: Error response from daemon: invalid mount config for type "bind":
bind source path does not exist: /not/exist
```
-
**解决**:确保源路径存在,或改用 `-v` (会自动创建)
#### Q:权限问题
@@ -235,7 +215,6 @@ bind source path does not exist: /not/exist
容器内用户可能无权访问挂载的文件:
```bash
-
## 方法1:确保宿主机文件权限允许容器用户访问
$ chmod -R 755 /path/to/data
@@ -248,18 +227,15 @@ $ docker run -u root ...
$ docker run -u $(id -u):$(id -g) ...
```
-
#### Q:macOS/Windows 性能问题
在 Docker Desktop 上,Bind Mount 性能较差 (需要跨文件系统同步):
```bash
-
## 使用 :cached 或 :delegated 提高性能(macOS)
$ docker run -v /host/path:/container/path:cached myapp
```
-
| 选项 | 说明 |
|------|------|
| `:cached` | 宿主机权威,容器读取可能延迟 |
@@ -273,31 +249,25 @@ $ docker run -v /host/path:/container/path:cached myapp
#### 1. 开发环境使用 Bind Mount
```bash
-
## 代码热更新
$ docker run -v $(pwd):/app -p 3000:3000 node npm run dev
```
-
#### 2. 生产环境使用 Volume
```bash
-
## 数据持久化
$ docker run -v mysql_data:/var/lib/mysql mysql
```
-
#### 3. 配置文件使用只读挂载
```bash
$ docker run -v /config/nginx.conf:/etc/nginx/nginx.conf:ro nginx
```
-
#### 4. 注意路径安全
```bash
-
## ❌ 危险:挂载根目录或敏感目录
$ docker run -v /:/host ...
@@ -306,5 +276,4 @@ $ docker run -v /:/host ...
$ docker run -v /app/data:/data ...
```
-
---
diff --git a/08_data/8.3_tmpfs.md b/08_data/8.3_tmpfs.md
index 9caefd1..2313ec2 100644
--- a/08_data/8.3_tmpfs.md
+++ b/08_data/8.3_tmpfs.md
@@ -15,13 +15,11 @@
```bash
$ docker run --mount type=tmpfs,destination=/run,tmpfs-size=67108864,tmpfs-mode=1770 nginx
```
-
也可以使用 `--tmpfs` 简写语法:
```bash
$ docker run --tmpfs /run:size=64m nginx
```
-
> **注意**:`--tmpfs` 支持的选项有限,主要为 `size` 和 `mode`。如果需要更精细的控制(如 `noexec`、`nosuid`),推荐使用 `--mount` 语法并通过 `tmpfs-mode` 参数设置权限。
### 8.3.3 注意事项
diff --git a/09_network/9.1_dns.md b/09_network/9.1_dns.md
index 41d3dfb..4ff418c 100644
--- a/09_network/9.1_dns.md
+++ b/09_network/9.1_dns.md
@@ -18,7 +18,6 @@ Docker 容器的 DNS 配置有两种情况:
这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过 “名字” 找到彼此,而不需要知道对方的 IP (因为 IP 可能会变)。
```bash
-
## 1. 创建自定义网络
$ docker network create mynet
@@ -33,7 +32,6 @@ $ 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
```
-
**原理**:
Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器。容器内的 DNS 请求会被转发到这里。如果是容器名,解析为容器 IP;如果是外部域名 (如 google.com),转发给上游 DNS。
@@ -51,7 +49,6 @@ Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器。容器内的
$ docker run -it --dns=114.114.114.114 ubuntu cat /etc/resolv.conf
nameserver 114.114.114.114
```
-
#### 2. --dns-search
指定 DNS 搜索域。例如设置为 `example.com`,则 `ping host` 会尝试解析 `host.example.com`。
@@ -59,7 +56,6 @@ nameserver 114.114.114.114
```bash
$ docker run --dns-search=example.com myapp
```
-
#### 3. --hostname 与 -h
设置容器的主机名。
@@ -67,7 +63,6 @@ $ docker run --dns-search=example.com myapp
```bash
$ docker run -h myweb nginx
```
-
---
### 9.1.4 全局 DNS 配置
@@ -82,7 +77,6 @@ $ docker run -h myweb nginx
]
}
```
-
修改后需要重启 Docker 服务:`systemctl restart docker`。
---
diff --git a/09_network/9.2_network_types.md b/09_network/9.2_network_types.md
index 28e6058..35bdfbd 100644
--- a/09_network/9.2_network_types.md
+++ b/09_network/9.2_network_types.md
@@ -9,7 +9,6 @@ abc123... bridge bridge local
def456... host host local
ghi789... none null local
```
-
### 9.2.1 网络类型对比
各网络类型的特点和适用场景如下:
@@ -42,7 +41,6 @@ Bridge 是 Docker 默认使用的网络模式。Docker 启动时会自动创建
```bash
$ docker run -d --network host nginx
```
-
这种模式下网络性能最高,但容器之间和宿主机之间没有网络隔离。
### 9.2.4 None 网络
@@ -54,7 +52,6 @@ $ docker run -it --network none alpine ip addr
1: lo: ...
inet 127.0.0.1/8 scope host lo
```
-
### 9.2.5 数据流向
容器网络中的数据流向可以分为以下几种情况:
diff --git a/09_network/9.3_custom_network.md b/09_network/9.3_custom_network.md
index febf45d..d778da8 100644
--- a/09_network/9.3_custom_network.md
+++ b/09_network/9.3_custom_network.md
@@ -17,7 +17,6 @@
使用 `docker network create` 命令可以创建自定义网络:
```bash
-
## 创建网络
$ docker network create mynet
@@ -26,13 +25,11 @@ $ docker network create mynet
$ docker network inspect mynet
```
-
### 9.3.3 使用自定义网络
启动容器时通过 `--network` 参数指定连接的网络:
```bash
-
## 启动容器并连接到自定义网络
$ docker run -d --name web --network mynet nginx
@@ -44,7 +41,6 @@ $ 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
```
-
### 9.3.4 容器名 DNS 解析
自定义网络自动提供 DNS 服务。Docker 守护进程在 `127.0.0.11` 运行了一个嵌入式 DNS 服务器,容器内的 DNS 请求会被转发到这里:
@@ -59,13 +55,11 @@ flowchart LR
Web["web
172.18.0.2"] -- "DNS: 'db' → 172.18.0.3" --> DB["db
172.18.0.3"]
end
```
-
### 9.3.5 常用网络命令
以下是 Docker 网络管理中常用的命令:
```bash
-
## 列出网络
$ docker network ls
@@ -94,7 +88,6 @@ $ docker network rm mynet
$ docker network prune
```
-
---
> **🔥 踩坑实录**
diff --git a/09_network/9.4_container_linking.md b/09_network/9.4_container_linking.md
index cc8d5bf..451cf43 100644
--- a/09_network/9.4_container_linking.md
+++ b/09_network/9.4_container_linking.md
@@ -7,7 +7,6 @@
同一自定义网络内的容器可以直接通过容器名通信,这是推荐的容器互联方式:
```bash
-
## 创建网络
$ docker network create app-net
@@ -21,13 +20,11 @@ $ docker run -d --name app --network app-net myapp
...
```
-
### 9.4.2 连接到多个网络
一个容器可以同时连接到多个网络,这对于需要跨网络通信的中间件容器特别有用:
```bash
-
## 启动容器
$ docker run -d --name multi-net-container --network frontend nginx
@@ -40,13 +37,11 @@ $ docker network connect backend multi-net-container
$ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}}'
```
-
### 9.4.3 ⚠️ --link 已废弃
`--link` 是 Docker 早期用于容器互联的方式,**已经被废弃**,不建议在新项目中使用。请使用自定义网络替代:
```bash
-
## 旧方式(不推荐)
$ docker run --link db:database myapp
@@ -57,7 +52,6 @@ $ docker network create mynet
$ docker run --network mynet --name db postgres
$ docker run --network mynet --name app myapp
```
-
使用自定义网络的优势在于:
- 原生支持 DNS 解析
diff --git a/09_network/9.5_port_mapping.md b/09_network/9.5_port_mapping.md
index a0a2be4..f64cef2 100644
--- a/09_network/9.5_port_mapping.md
+++ b/09_network/9.5_port_mapping.md
@@ -18,7 +18,6 @@ flowchart TD
Host --> Proxy["Docker Proxy
端口映射 (8080 -> 80)"]
Proxy --> Container["容器 (Class B: 80)"]
```
-
---
### 9.5.2 端口映射方式
@@ -30,12 +29,10 @@ Docker 提供了多种方式来指定端口映射。
使用 `-p <宿主机端口>:<容器端口>` 格式:
```bash
-
## 将宿主机的 8080 端口映射到容器的 80 端口
$ docker run -d -p 8080:80 nginx
```
-
此时访问 `http://localhost:8080` 即可看到 Nginx 页面。
**多种格式**:
@@ -54,7 +51,6 @@ $ docker run -d -p 8080:80 nginx
```bash
$ docker run -d -P nginx
```
-
查看映射结果:
```bash
@@ -62,7 +58,6 @@ $ docker ps
CONTAINER ID PORTS
abc123456 0.0.0.0:49153->80/tcp
```
-
此时 Nginx 被映射到了宿主机的 49153 端口。
---
@@ -80,7 +75,6 @@ $ docker port mycontainer
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080
```
-
#### docker ps
运行 `docker ps` 可以查看到所有容器的端口映射列表:
@@ -90,7 +84,6 @@ $ docker ps
CONTAINER ID IMAGE PORTS NAMES
abc123456 nginx 0.0.0.0:8080->80/tcp web
```
-
---
### 9.5.4 最佳实践与安全
@@ -104,12 +97,10 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web
如果不希望对外暴露 (例如数据库服务),应绑定到 `127.0.0.1`:
```bash
-
## 仅允许本机访问
$ docker run -d -p 127.0.0.1:3306:3306 mysql
```
-
#### 2. 避免端口冲突
如果宿主机 8080 已经被占用了,容器将无法启动。
@@ -126,7 +117,6 @@ $ docker run -d -p 127.0.0.1:3306:3306 mysql
```bash
$ docker run -d -p 53:53/udp dns-server
```
-
---
### 9.5.5 实现原理
@@ -136,12 +126,10 @@ Docker 使用 `docker-proxy` 进程 (用户态) 或 `iptables` DNAT 规则 (内
当流量到达宿主机端口时,iptables 规则将其目标地址修改为容器 IP 并转发:
```bash
-
## 简化的 iptables 逻辑
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
```
-
这也是为什么你在容器内部看到的访问来源 IP 通常是网关 IP (如 172.17.0.1),而不是真实的外部 Client IP (除非使用 host 网络模式)。
---
diff --git a/09_network/9.6_network_isolation.md b/09_network/9.6_network_isolation.md
index 2eed861..7d86be1 100644
--- a/09_network/9.6_network_isolation.md
+++ b/09_network/9.6_network_isolation.md
@@ -7,7 +7,6 @@ Docker 网络提供了天然的隔离能力,不同网络之间的容器默认
不同网络之间默认隔离,容器只能与同一网络中的容器直接通信:
```bash
-
## 创建两个网络
$ docker network create frontend
@@ -26,7 +25,6 @@ $ docker run -d --name db --network backend postgres
$ docker exec web ping db
ping: db: Name or service not known
```
-
### 9.6.2 安全优势
这种隔离机制带来以下安全优势:
@@ -43,7 +41,6 @@ ping: db: Name or service not known
如果确实需要某个容器跨网络通信,可以将其同时连接到多个网络:
```bash
-
## 创建一个中间件容器,连接到两个网络
$ docker run -d --name api --network frontend myapi
@@ -51,7 +48,6 @@ $ docker network connect backend api
## 现在 api 容器既可以访问 frontend 中的 web,也可以访问 backend 中的 db
```
-
这种方式让你可以精确控制哪些容器可以跨网络通信,遵循最小权限原则。
### 9.6.4 典型网络架构
@@ -79,5 +75,4 @@ graph TD
API --> DB
API --> Cache
```
-
在这种架构中,API 服务器同时连接到 `frontend` 和 `backend` 网络,充当两个网络之间的桥梁。负载均衡器和 Web 服务器无法直接访问数据库,增强了安全性。
diff --git a/09_network/9.7_advanced_networking.md b/09_network/9.7_advanced_networking.md
index c04b67d..f3ef1a5 100644
--- a/09_network/9.7_advanced_networking.md
+++ b/09_network/9.7_advanced_networking.md
@@ -29,13 +29,11 @@ veth 对
↓
容器 B (192.168.0.3,不同宿主机)
```
-
#### 创建和使用 Overlay 网络
**Docker Swarm 模式下的 Overlay 网络:**
```bash
-
# 初始化 Swarm(创建集群)
docker swarm init
@@ -58,11 +56,9 @@ docker service create --name web \
# 验证服务跨节点通信
docker service ps web
```
-
**单机 Overlay 网络模拟(Linux 容器):**
```bash
-
# 创建自定义 overlay 网络
docker network create --driver overlay custom-overlay
@@ -77,11 +73,9 @@ docker exec container1 curl http://container2
# 检查网络配置
docker network inspect custom-overlay
```
-
#### Overlay 网络性能优化
```bash
-
# 调整 MTU(Maximum Transmission Unit)避免分片
# VXLAN 开销 50 字节,物理 MTU 1500,建议设置为 1450
docker network create --driver overlay \
@@ -113,7 +107,6 @@ networks:
driver_opts:
com.docker.network.driver.mtu: 1450
```
-
### 9.7.2 CNI 插件生态概览
容器网络接口(CNI)是容器编排平台(尤其是 Kubernetes)的标准化网络接口。不同的 CNI 插件提供不同的网络能力。
@@ -125,7 +118,6 @@ networks:
Calico 使用 BGP 协议进行路由,支持网络策略和 eBPF 加速。
```yaml
-
# Kubernetes 中安装 Calico
apiVersion: v1
kind: ConfigMap
@@ -154,13 +146,11 @@ data:
]
}
```
-
**Flannel - 简单可靠的 Overlay**
Flannel 提供简单的 overlay 网络实现,适合小到中等规模的集群。
```bash
-
# 安装 Flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
@@ -201,13 +191,11 @@ data:
}
EOF
```
-
**Cilium - eBPF 驱动的先进网络**
Cilium 使用 eBPF 在内核级别实现网络策略和可观测性,性能优异。
```bash
-
# 安装 Cilium
helm repo add cilium https://helm.cilium.io
helm install cilium cilium/cilium \
@@ -222,13 +210,11 @@ helm upgrade cilium cilium/cilium \
--set hubble.enabled=true \
--set hubble.ui.enabled=true
```
-
**Weave - 跨主机网络通信**
Weave 提供简单的跨主机通信,支持加密和多播。
```bash
-
# Docker 中使用 Weave 网络
docker run -d --name weave \
--net=host \
@@ -239,7 +225,6 @@ docker run -d --name weave \
# 连接到 Weave 网络
docker run -d --network weave --name web nginx:latest
```
-
**CNI 插件对比表:**
| 特性 | Calico | Flannel | Cilium | Weave |
@@ -270,13 +255,11 @@ Docker 内嵌 DNS 服务器 (127.0.0.11)
↓
DNS 响应 → 容器缓存 → 应用
```
-
#### 配置容器 DNS
**在运行时指定 DNS:**
```bash
-
# 单个容器
docker run -d \
--dns 8.8.8.8 \
@@ -294,7 +277,6 @@ docker run -d \
# 查看容器 DNS 配置
docker exec cat /etc/resolv.conf
```
-
**Docker Compose DNS 配置:**
```yaml
@@ -325,7 +307,6 @@ networks:
# nameserver 8.8.8.8
# nameserver 1.1.1.1
```
-
**Docker 守护进程级别配置:**
```json
@@ -336,13 +317,11 @@ networks:
"registry-mirrors": ["https://mirror.example.com"]
}
```
-
#### 自定义服务发现
**使用 Docker 内建 DNS 的服务发现:**
```bash
-
# 创建自定义网络
docker network create mynet
@@ -356,7 +335,6 @@ docker run -it --network mynet busybox sh
# ping web # 自动解析到 web 容器 IP
# ping db # 自动解析到 db 容器 IP
```
-
**Compose 服务名自动发现:**
```yaml
@@ -383,11 +361,9 @@ services:
# frontend 容器可以直接访问 http://backend:8080
# backend 容器可以直接访问 postgres://database:5432
```
-
#### DNS 性能优化
```bash
-
# 检查 DNS 延迟
time docker exec nslookup www.example.com
@@ -417,7 +393,6 @@ kubectl patch deployment -n kube-system coredns --patch '{
}
}'
```
-
### 9.7.4 网络策略实践
网络策略定义了容器间的流量控制规则,是微服务架构中的安全基础。
@@ -438,7 +413,6 @@ spec:
- Ingress
# 不指定 ingress 规则,表示拒绝所有入站流量
```
-
**允许特定来源的入站流量:**
```yaml
@@ -461,7 +435,6 @@ spec:
- protocol: TCP
port: 8080
```
-
**允许出站流量到数据库:**
```yaml
@@ -500,7 +473,6 @@ spec:
- protocol: TCP
port: 443
```
-
#### 微服务网络策略示例
```yaml
@@ -625,7 +597,6 @@ spec:
- protocol: TCP
port: 5432
```
-
#### 使用 Calico/Cilium 的高级网络策略
**L7 应用层策略(仅 Cilium 支持):**
@@ -659,7 +630,6 @@ spec:
sourceIPs:
- "10.0.0.0/8"
```
-
### 9.7.5 跨主机容器通信方案对比
#### 方案对比表
@@ -675,7 +645,6 @@ spec:
#### 选择建议
```bash
-
# 1. 开发环境:使用 Bridge 网络
docker network create my-app
docker compose up # 默认使用 bridge
@@ -692,13 +661,11 @@ helm install cilium cilium/cilium --namespace kube-system
# 5. 需要多云/跨域:使用 Weave
```
-
### 9.7.6 网络故障排查
**常见网络问题诊断:**
```bash
-
# 1. 容器无法访问外部网络
docker exec ping 8.8.8.8
docker exec cat /etc/resolv.conf
diff --git a/09_network/README.md b/09_network/README.md
index 4d5299f..22efae0 100644
--- a/09_network/README.md
+++ b/09_network/README.md
@@ -28,7 +28,6 @@ graph TD
Internet((互联网)) <--> eth0
```
-
本章将详细介绍 Docker 网络配置的各个方面。
## 本章内容
diff --git a/10_buildx/10.1_buildkit.md b/10_buildx/10.1_buildkit.md
index 913a43d..85c5c73 100644
--- a/10_buildx/10.1_buildkit.md
+++ b/10_buildx/10.1_buildkit.md
@@ -15,11 +15,9 @@ BuildKit 引入了多项新指令,旨在优化构建缓存和安全性。以
要使用最新的 Dockerfile 语法特性,建议在 Dockerfile 开头添加语法指令:
```docker
-
## syntax=docker/dockerfile:1
```
-
这将使用最新的稳定版语法解析器,确保你可以使用所有最新特性。
#### `RUN --mount=type=cache`
@@ -46,7 +44,6 @@ FROM nginx:alpine
COPY --from=builder /app/dist /app/dist
```
-
使用多阶段构建,构建的镜像中只包含了目标文件夹 `dist`,但仍然存在一些问题,当 `package.json` 文件变动时,`RUN npm i && rm -rf ~/.npm` 这一层会重新执行,变更多次后,生成了大量的中间层镜像。
为解决这个问题,进一步的我们可以设想一个类似 **数据卷** 的功能,在镜像构建时把 `node_modules` 文件夹挂载上去,在构建完成后,这个 `node_modules` 文件夹会自动卸载,实际的镜像中并不包含 `node_modules` 这个文件夹,这样我们就省去了每次获取依赖的时间,大大增加了镜像构建效率,同时也避免了生成了大量的中间层镜像。
@@ -54,7 +51,6 @@ COPY --from=builder /app/dist /app/dist
`BuildKit` 提供了 `RUN --mount=type=cache` 指令,可以实现上边的设想。
```docker
-
## syntax=docker/dockerfile:1
FROM node:alpine as builder
@@ -87,7 +83,6 @@ RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist
```
-
第一个 `RUN` 指令执行后,`id` 为 `my_app_npm_module` 的缓存文件夹挂载到了 `/app/node_modules` 文件夹中。多次执行也不会产生多个中间层镜像。
第二个 `RUN` 指令执行时需要用到 `node_modules` 文件夹,`node_modules` 已经挂载,命令也可以正确执行。
@@ -110,47 +105,39 @@ RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
该指令可以将一个镜像 (或上一构建阶段) 的文件挂载到指定位置。
```docker
-
## 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`
该指令可以将一个 `tmpfs` 文件系统挂载到指定位置。
```docker
-
## syntax=docker/dockerfile:1
RUN --mount=type=tmpfs,target=/temp \
mount | grep /temp
```
-
#### `RUN --mount=type=secret`
该指令可以将一个文件 (例如密钥) 挂载到指定位置。
```docker
-
## syntax=docker/dockerfile:1
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
cat /root/.aws/credentials
```
-
```bash
$ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .
```
-
#### `RUN --mount=type=ssh`
该指令可以挂载 `ssh` 密钥。
```docker
-
## syntax=docker/dockerfile:1
FROM alpine
@@ -158,14 +145,12 @@ RUN apk add --no-cache openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh ssh git@gitlab.com | tee /hello
```
-
```bash
$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ docker build -t test --ssh default=$SSH_AUTH_SOCK .
```
-
### 10.1.2 使用 `docker compose build` 与 BuildKit
Docker Compose 同样支持 BuildKit,这使得多服务应用的构建更加高效。
diff --git a/10_buildx/10.2_buildx.md b/10_buildx/10.2_buildx.md
index 118b2bd..3adc697 100644
--- a/10_buildx/10.2_buildx.md
+++ b/10_buildx/10.2_buildx.md
@@ -11,7 +11,6 @@ $ docker buildx build .
[+] Building 8.4s (23/32)
=> ...
```
-
Buildx 使用 [BuildKit 引擎](10.1_buildkit.md)进行构建,支持许多新的功能,具体参考 [Buildkit](10.1_buildkit.md) 一节。
#### 使用 `bake`
@@ -19,7 +18,6 @@ Buildx 使用 [BuildKit 引擎](10.1_buildkit.md)进行构建,支持许多新
`docker buildx bake` 是一个高级构建命令,支持从 HCL、JSON 或 Compose 文件中定义构建目标,实现复杂的流水线构建。
```bash
-
## 从 Compose 文件构建所有服务
$ docker buildx bake
@@ -28,7 +26,6 @@ $ docker buildx bake
$ docker buildx bake web
```
-
#### 生成 SBOM
Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对于软件供应链安全至关重要。
@@ -36,7 +33,6 @@ Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对
```bash
$ docker buildx build --sbom=true -t myimage .
```
-
该命令会在构建结果中包含 SPDX 或 CycloneDX 格式的 SBOM 数据。
> **⚠️ 注意与失败模式**:
diff --git a/10_buildx/10.3_multi-arch-images.md b/10_buildx/10.3_multi-arch-images.md
index 790b78e..afa17ea 100644
--- a/10_buildx/10.3_multi-arch-images.md
+++ b/10_buildx/10.3_multi-arch-images.md
@@ -39,7 +39,6 @@ $ docker manifest inspect hello-world
]
}
```
-
### 10.3.2 使用 `docker buildx` 构建多架构镜像
`docker buildx` 是构建多架构镜像的最佳实践工具,它屏蔽了底层的复杂性,提供了一键构建多架构镜像的能力。
@@ -54,13 +53,11 @@ $ docker manifest inspect hello-world
$ docker buildx create --name mybuilder --use
$ docker buildx inspect --bootstrap
```
-
#### 构建和推送
使用 `docker buildx build` 命令并指定 `--platform` 参数,可以同时构建支持多种架构的镜像。`--push` 参数会将构建好的镜像和 manifest list 推送到 Docker 仓库。
```dockerfile
-
## Dockerfile
FROM --platform=$TARGETPLATFORM alpine
@@ -69,11 +66,9 @@ RUN uname -a > /os.txt
CMD cat /os.txt
```
-
```bash
$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t your-username/multi-arch-image . --push
```
-
构建完成后,你就可以在不同架构的机器上拉取并运行 `your-username/multi-arch-image` 这个镜像了。
#### 架构相关的构建参数
@@ -101,7 +96,6 @@ COPY bin/dist-${TARGETOS}-${TARGETARCH} /dist
ENTRYPOINT ["/dist"]
```
-
### 10.3.3 使用 `docker manifest`:底层工具
除了 `docker buildx`,我们也可以直接操作 Manifest List 来手动组合不同架构的镜像。
@@ -111,7 +105,6 @@ ENTRYPOINT ["/dist"]
#### 创建 manifest list
```bash
-
## 首先,为每个架构构建并推送镜像
$ docker buildx build --platform linux/amd64 -t your-username/my-app:amd64 . --push
@@ -127,7 +120,6 @@ $ docker manifest create your-username/my-app:latest \
$ docker manifest push your-username/my-app:latest
```
-
#### 检查 manifest list
你可以使用 `docker manifest inspect` 来查看一个 manifest list 的详细信息,如上文所示。
diff --git a/11_compose/11.2_install.md b/11_compose/11.2_install.md
index 006b683..be2685e 100644
--- a/11_compose/11.2_install.md
+++ b/11_compose/11.2_install.md
@@ -25,26 +25,22 @@ $ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
$ mkdir -p $DOCKER_CONFIG/cli-plugins
$ curl -SL https://github.com/docker/compose/releases/download/v5.1.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
```
-
之后,执行
```bash
$ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
```
-
### 11.2.2 测试安装
```bash
$ docker compose version
Docker Compose version v5.1.0
```
-
### 11.2.3 bash 补全命令
```bash
$ curl -L https://raw.githubusercontent.com/docker/compose/v5.1.0/contrib/completion/bash/docker-compose | sudo tee /etc/bash_completion.d/docker-compose > /dev/null
```
-
### 11.2.4 卸载
如果是二进制包方式安装的,删除二进制文件即可。
diff --git a/11_compose/11.3_usage.md b/11_compose/11.3_usage.md
index 1a4e621..f8b330d 100644
--- a/11_compose/11.3_usage.md
+++ b/11_compose/11.3_usage.md
@@ -37,7 +37,6 @@ def hello():
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
```
-
#### Dockerfile
编写 `Dockerfile` 文件,内容为
@@ -49,7 +48,6 @@ WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
```
-
#### compose.yaml
编写 `compose.yaml` 文件,这是 Compose 推荐使用的主模板文件 (也兼容 `docker-compose.yml` 等历史文件名)。
@@ -64,13 +62,11 @@ services:
redis:
image: "redis:alpine"
```
-
#### 运行 compose 项目
```bash
$ docker compose up
```
-
此时访问本地 `5000` 端口,每次刷新页面,计数就会加 1。
@@ -81,13 +77,11 @@ $ docker compose up
```bash
$ docker compose up -d
```
-
#### 停止
```bash
$ docker compose stop
```
-
#### 进入服务
```bash
@@ -96,37 +90,31 @@ $ docker compose exec redis sh
127.0.0.1:6379> get hits
"9"
```
-
#### 查看日志
```bash
$ docker compose logs -f
```
-
#### 构建镜像
```bash
$ docker compose build
```
-
#### 启动服务
```bash
$ docker compose start
```
-
#### 运行一次性命令
```bash
$ docker compose run web python app.py
```
-
#### 验证 Compose 文件
```bash
$ docker compose config
```
-
#### 删除项目
```bash
diff --git a/11_compose/11.4_commands.md b/11_compose/11.4_commands.md
index 25d027d..0734334 100644
--- a/11_compose/11.4_commands.md
+++ b/11_compose/11.4_commands.md
@@ -13,7 +13,6 @@ Docker Compose 提供了丰富的命令来管理项目和容器。本节将详
```bash
docker compose [-f=...] [options] [COMMAND] [ARGS...]
```
-
### 11.4.2 命令选项
* `-f, --file FILE` 指定使用的 Compose 模板文件。默认会自动识别 `compose.yaml` (也兼容 `docker-compose.yml` 等),并且可以多次指定。
@@ -75,7 +74,6 @@ docker compose [-f=...] [options] [COMMAND] [ARGS...]
```bash
$ docker compose kill -s SIGINT
```
-
#### `logs`
格式为 `docker compose logs [options] [SERVICE...]`。
@@ -159,7 +157,6 @@ $ docker compose kill -s SIGINT
```bash
$ docker compose run ubuntu ping docker.com
```
-
将会启动一个 ubuntu 服务容器,并执行 `ping docker.com` 命令。
默认情况下,如果存在关联,则所有关联的服务将会自动被启动,除非这些服务已经在运行中。
@@ -177,7 +174,6 @@ $ docker compose run ubuntu ping docker.com
```bash
$ docker compose run --no-deps web python manage.py shell
```
-
将不会启动 web 容器所关联的其它容器。
选项:
@@ -213,7 +209,6 @@ $ docker compose run --no-deps web python manage.py shell
```bash
$ docker compose scale web=3 db=2
```
-
将启动 3 个容器运行 web 服务,2 个容器运行 db 服务。
> **提示**:部分版本的 Compose 可能不再提供独立的 `scale` 子命令 (或不推荐使用)。此时可使用 `docker compose up` 的 `--scale` 选项达到同样效果:
@@ -316,7 +311,6 @@ services:
- action: rebuild
path: package.json
```
-
选项:
* `--no-up` 不自动启动服务。
diff --git a/11_compose/11.5_compose_file.md b/11_compose/11.5_compose_file.md
index a24f42f..c94940b 100644
--- a/11_compose/11.5_compose_file.md
+++ b/11_compose/11.5_compose_file.md
@@ -13,7 +13,6 @@ services:
volumes:
- "/data"
```
-
注意每个服务都必须通过 `image` 指令指定镜像或 `build` 指令 (需要 Dockerfile) 等来自动构建生成镜像。
如果使用 `build` 指令,在 `Dockerfile` 中设置的选项 (例如:`CMD`、`EXPOSE`、`VOLUME`、`ENV` 等) 将会自动被获取,无需在 Compose 文件中重复设置。
@@ -29,7 +28,6 @@ services:
webapp:
build: ./dir
```
-
你也可以使用 `context` 指令指定 `Dockerfile` 所在文件夹的路径。
使用 `dockerfile` 指令指定 `Dockerfile` 文件名。
@@ -45,7 +43,6 @@ services:
args:
buildno: 1
```
-
使用 `cache_from` 指定构建镜像的缓存
```yaml
@@ -55,7 +52,6 @@ build:
- alpine:latest
- corp/web_app:3.14
```
-
### 11.5.2 `cap_add, cap_drop`
指定容器的内核能力 (capacity) 分配。
@@ -66,14 +62,12 @@ build:
cap_add:
- ALL
```
-
去掉 NET_ADMIN 能力可以指定为:
```yaml
cap_drop:
- NET_ADMIN
```
-
### 11.5.3 `command`
覆盖容器启动后默认执行的命令。
@@ -81,7 +75,6 @@ cap_drop:
```yaml
command: echo "hello world"
```
-
### 11.5.4 `configs`
`configs` 来自 Compose Specification。它在 Swarm 中是原生对象;在本地 `docker compose` 模式下通常以文件挂载的形式实现,具体能力取决于 Compose 版本与运行平台。
@@ -95,7 +88,6 @@ command: echo "hello world"
```yaml
cgroup_parent: cgroups_1
```
-
### 11.5.6 `container_name`
指定容器名称。默认将会使用 `项目名称_服务名称_序号` 这样的格式。
@@ -103,7 +95,6 @@ cgroup_parent: cgroups_1
```yaml
container_name: docker-web-container
```
-
> 注意:指定容器名称后,该服务将无法进行扩展 (scale),因为 Docker 不允许多个容器具有相同的名称。
### 11.5.7 `deploy`
@@ -118,7 +109,6 @@ container_name: docker-web-container
devices:
- "/dev/ttyUSB1:/dev/ttyUSB0"
```
-
### 11.5.9 `depends_on`
解决容器的依赖、启动先后的问题。以下例子中会先启动 `redis` `db` 再启动 `web`
@@ -137,7 +127,6 @@ services:
db:
image: postgres
```
-
> 注意:`web` 服务不会等待 `redis` `db` “完全启动” 之后才启动。
### 11.5.10 `dns`
@@ -151,7 +140,6 @@ dns:
- 8.8.8.8
- 114.114.114.114
```
-
### 11.5.11 `dns_search`
配置 `DNS` 搜索域。可以是一个值,也可以是一个列表。
@@ -163,7 +151,6 @@ dns_search:
- domain1.example.com
- domain2.example.com
```
-
### 11.5.12 `tmpfs`
挂载一个 tmpfs 文件系统到容器。
@@ -174,7 +161,6 @@ tmpfs:
- /run
- /tmp
```
-
### 11.5.13 `env_file`
从文件中获取环境变量,可以为单独的文件路径或列表。
@@ -191,16 +177,13 @@ env_file:
- ./apps/web.env
- /opt/secrets.env
```
-
环境变量文件中每一行必须符合格式,支持 `#` 开头的注释行。
```bash
-
## common.env: Set development environment
PROG_ENV=development
```
-
### 11.5.14 `environment`
设置环境变量。你可以使用数组或字典两种格式。
@@ -216,13 +199,11 @@ environment:
- RACK_ENV=development
- SESSION_SECRET
```
-
如果变量名称或者值中用到 `true|false,yes|no` 等表达[布尔](https://yaml.org/type/bool.html)含义的词汇,最好放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义。这些特定词汇,包括
```bash
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
```
-
### 11.5.15 `expose`
暴露端口,但不映射到宿主机,只被连接的服务访问。
@@ -234,7 +215,6 @@ expose:
- "3000"
- "8000"
```
-
### 11.5.16 `external_links`
> 注意:不建议使用该指令。
@@ -247,7 +227,6 @@ external_links:
- project_db_1:mysql
- project_db_1:postgresql
```
-
### 11.5.17 `extra_hosts`
类似 Docker 中的 `--add-host` 参数,指定额外的 host 名称映射信息。
@@ -257,14 +236,12 @@ extra_hosts:
- "googledns:8.8.8.8"
- "dockerhub:52.1.157.61"
```
-
会在启动后的服务容器中 `/etc/hosts` 文件中添加如下两条条目。
```bash
8.8.8.8 googledns
52.1.157.61 dockerhub
```
-
### 11.5.18 `healthcheck`
通过命令检查容器是否健康运行。
@@ -276,7 +253,6 @@ healthcheck:
timeout: 10s
retries: 3
```
-
### 11.5.19 `image`
指定为镜像名称或镜像 ID。如果镜像在本地不存在,`Compose` 将会尝试拉取这个镜像。
@@ -286,7 +262,6 @@ image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
```
-
### 11.5.20 `labels`
为容器添加 Docker 元数据 (metadata) 信息。例如可以为容器添加辅助说明信息。
@@ -297,7 +272,6 @@ labels:
com.startupteam.department: "devops department"
com.startupteam.release: "rc3 for v1.0"
```
-
### 11.5.21 `links`
> 注意:不推荐使用该指令。容器之间应通过 Docker 网络 (networks) 进行互联。
@@ -312,7 +286,6 @@ logging:
options:
syslog-address: "tcp://192.168.0.42:123"
```
-
目前支持三种日志驱动类型。
```yaml
@@ -320,7 +293,6 @@ driver: "json-file"
driver: "syslog"
driver: "none"
```
-
`options` 配置日志驱动的相关参数。
```yaml
@@ -328,7 +300,6 @@ options:
max-size: "200k"
max-file: "10"
```
-
### 11.5.23 `network_mode`
设置网络模式。使用和 `docker run` 的 `--network` 参数一样的值。
@@ -340,13 +311,11 @@ network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
```
-
### 11.5.24 `networks`
配置容器连接的网络。
```yaml
-
services:
some-service:
@@ -358,7 +327,6 @@ networks:
some-network:
other-network:
```
-
### 11.5.25 `pid`
跟主机系统共享进程命名空间。打开该选项的容器之间,以及容器和宿主机系统之间可以通过进程 ID 来相互访问和操作。
@@ -366,7 +334,6 @@ networks:
```yaml
pid: "host"
```
-
### 11.5.26 `ports`
暴露端口信息。
@@ -380,7 +347,6 @@ ports:
- "49100:22"
- "127.0.0.1:8001:8001"
```
-
*注意:当使用 `HOST:CONTAINER` 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 `YAML` 会自动解析 `xx:yy` 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。*
### 11.5.27 `secrets`
@@ -388,7 +354,6 @@ ports:
存储敏感数据,例如 `mysql` 服务密码。
```yaml
-
services:
mysql:
@@ -405,7 +370,6 @@ secrets:
my_other_secret:
external: true
```
-
### 11.5.28 `security_opt`
指定容器模板标签 (label) 机制的默认属性 (用户、角色、类型、级别等)。例如配置标签的用户名和角色名。
@@ -415,7 +379,6 @@ security_opt:
- label:user:USER
- label:role:ROLE
```
-
### 11.5.29 `stop_signal`
设置另一个信号来停止容器。在默认情况下使用的是 SIGTERM 停止容器。
@@ -423,7 +386,6 @@ security_opt:
```yaml
stop_signal: SIGUSR1
```
-
### 11.5.30 `sysctls`
配置容器内核参数。
@@ -437,7 +399,6 @@ sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
```
-
### 11.5.31 `ulimits`
指定容器的 ulimits 限制值。
@@ -451,7 +412,6 @@ sysctls:
soft: 20000
hard: 40000
```
-
### 11.5.32 `volumes`
数据卷所挂载路径设置。可以设置为宿主机路径 (`HOST:CONTAINER`) 或者数据卷名称 (`VOLUME:CONTAINER`),并且可以设置访问模式 (`HOST:CONTAINER:ro`)。
@@ -464,7 +424,6 @@ volumes:
- cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
```
-
如果路径为数据卷名称,必须在文件中配置数据卷。
```yaml
@@ -477,7 +436,6 @@ services:
volumes:
mysql_data:
```
-
### 11.5.33 其它指令
此外,还有包括 `domainname, entrypoint, hostname, ipc, mac_address, privileged, read_only, shm_size, restart, stdin_open, tty, user, working_dir` 等指令,基本跟 `docker run` 中对应参数的功能一致。
@@ -487,19 +445,16 @@ volumes:
```yaml
entrypoint: /code/entrypoint.sh
```
-
指定容器中运行应用的用户名。
```yaml
user: nginx
```
-
指定容器中工作目录。
```yaml
working_dir: /code
```
-
指定容器中搜索域名、主机名、mac 地址等。
```yaml
@@ -507,37 +462,31 @@ domainname: your_website.com
hostname: test
mac_address: 08-00-27-00-0C-0A
```
-
允许容器中运行一些特权命令。
```yaml
privileged: true
```
-
指定容器退出后的重启策略为始终重启。该命令对保持服务始终运行十分有效,在生产环境中推荐配置为 `always` 或者 `unless-stopped`。
```yaml
restart: always
```
-
以只读模式挂载容器的 root 文件系统,意味着不能对容器内容进行修改。
```yaml
read_only: true
```
-
打开标准输入,可以接受外部输入。
```yaml
stdin_open: true
```
-
模拟一个伪终端。
```yaml
tty: true
```
-
### 11.5.34 读取变量
Compose 模板文件支持动态读取主机的系统环境变量和当前目录下的 `.env` 文件中的变量。
@@ -545,13 +494,11 @@ Compose 模板文件支持动态读取主机的系统环境变量和当前目录
例如,下面的 Compose 文件将从运行它的环境中读取变量 `${MONGO_VERSION}` 的值,并写入执行的指令中。
```yaml
-
services:
db:
image: "mongo:${MONGO_VERSION}"
```
-
如果执行 `MONGO_VERSION=3.2 docker compose up` 则会启动一个 `mongo:3.2` 镜像的容器;如果执行 `MONGO_VERSION=2.8 docker compose up` 则会启动一个 `mongo:2.8` 镜像的容器。
若当前目录存在 `.env` 文件,执行 `docker compose` 命令时将从该文件中读取变量。
@@ -559,10 +506,8 @@ db:
在当前目录新建 `.env` 文件并写入以下内容。
```bash
-
## 支持 # 号注释
MONGO_VERSION=3.6
```
-
执行 `docker compose up` 则会启动一个 `mongo:3.6` 镜像的容器。
diff --git a/11_compose/11.6_django.md b/11_compose/11.6_django.md
index a868e05..2f3e281 100644
--- a/11_compose/11.6_django.md
+++ b/11_compose/11.6_django.md
@@ -30,7 +30,6 @@ flowchart TD
Browser["localhost:8000
(浏览器访问)"]
Port8000 --> Browser
```
-
图 11-1:Django + PostgreSQL 的 Compose 架构
**关键点**:
@@ -47,7 +46,6 @@ flowchart TD
```bash
$ mkdir django-docker && cd django-docker
```
-
我们需要创建三个文件:`Dockerfile`、`requirements.txt` 和 `compose.yaml`。
### 11.6.3 步骤 1:创建 Dockerfile
@@ -75,7 +73,6 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY . /code/
```
-
**逐行解释**:
| 指令 | 作用 | 为什么这样写 |
@@ -95,7 +92,6 @@ Django>=5.0,<6.0
psycopg[binary]>=3.1,<4.0
gunicorn>=21.0,<22.0
```
-
**依赖说明**:
| 包名 | 作用 |
@@ -140,7 +136,6 @@ services:
volumes:
postgres_data:
```
-
**配置详解**:
#### db 服务
@@ -160,7 +155,6 @@ db:
test: ["CMD-SHELL", "pg_isready -U django_user -d django_db"]
interval: 5s
```
-
> ⚠️ **笔者提醒**:`volumes` 配置很重要!没有它,每次容器重启数据都会丢失。笔者见过不少新手因为忘记这一步,导致开发数据全部丢失。
#### web 服务
@@ -179,7 +173,6 @@ web:
db:
condition: service_healthy # 等待数据库健康后再启动
```
-
**关键配置说明**:
| 配置项 | 作用 | 笔者建议 |
@@ -195,7 +188,6 @@ web:
```bash
$ docker compose run --rm web django-admin startproject mysite .
```
-
**命令解释**:
- `docker compose run`:运行一次性命令
@@ -218,7 +210,6 @@ django-docker/
├── asgi.py
└── wsgi.py
```
-
> 💡 **Linux 用户注意**:如果遇到权限问题,执行 `sudo chown -R $USER:$USER .`
### 11.6.7 步骤 5:配置数据库连接
@@ -243,7 +234,6 @@ DATABASES = {
ALLOWED_HOSTS = ['*']
```
-
**为什么 HOST 是 `db` 而不是 `localhost`?**
在 Docker Compose 中,各服务通过服务名相互访问。Docker 内置的 DNS 会将 `db` 解析为 db 服务容器的 IP 地址。这是 Docker Compose 的核心功能之一。
@@ -253,7 +243,6 @@ ALLOWED_HOSTS = ['*']
```bash
$ docker compose up
```
-
你会看到:
1. 首先构建 web 镜像 (第一次运行)
@@ -266,7 +255,6 @@ db-1 | LOG: database system is ready to accept connections
web-1 | Watching for file changes with StatReloader
web-1 | Starting development server at http://0.0.0.0:8000/
```
-
打开浏览器访问 `http://localhost:8000`,可以看到 Django 欢迎页面!
### 11.6.9 常用开发命令
@@ -274,7 +262,6 @@ web-1 | Starting development server at http://0.0.0.0:8000/
在另一个终端窗口执行:
```bash
-
## 执行数据库迁移
$ docker compose exec web python manage.py migrate
@@ -291,7 +278,6 @@ $ docker compose exec web python manage.py shell
$ docker compose exec db psql -U django_user -d django_db
```
-
> 💡 笔者建议使用 `exec` 而不是 `run`。`exec` 在已运行的容器中执行命令,`run` 会创建新容器。
### 11.6.10 常见问题排查
@@ -307,13 +293,11 @@ $ docker compose exec db psql -U django_user -d django_db
| 网络未创建 | 运行 `docker compose down` 后重新 `up` |
```bash
-
## 调试:检查数据库是否正常运行
$ docker compose ps
$ docker compose logs db
```
-
#### Q2:代码修改没有生效
**可能原因**:
@@ -325,12 +309,10 @@ $ docker compose logs db
#### Q3:权限问题
```bash
-
## 如果容器内创建的文件 root 用户所有
$ sudo chown -R $USER:$USER .
```
-
### 11.6.11 开发 vs 生产:关键差异
笔者特别提醒,本节的配置是 **开发环境** 配置。生产环境需要以下调整:
@@ -344,7 +326,6 @@ $ sudo chown -R $USER:$USER .
| **ALLOWED_HOSTS**| `['*']` | 具体域名 |**生产环境 Compose 文件示例**:
```yaml
-
## compose.prod.yaml
services:
@@ -359,7 +340,6 @@ services:
# ...
```
-
### 11.6.12 延伸阅读
- [Compose 模板文件详解](11.5_compose_file.md):深入理解 Compose 文件的所有配置项
diff --git a/11_compose/11.7_rails.md b/11_compose/11.7_rails.md
index 478e483..208b536 100644
--- a/11_compose/11.7_rails.md
+++ b/11_compose/11.7_rails.md
@@ -30,7 +30,6 @@ flowchart TD
Browser["localhost:3000"]
Port3000 --> Browser
```
-
图 11-2:Rails + PostgreSQL 的 Compose 架构
### 11.7.2 准备工作
@@ -40,7 +39,6 @@ flowchart TD
```bash
$ mkdir rails-docker && cd rails-docker
```
-
需要创建三个文件:`Dockerfile`、`Gemfile` 和 `compose.yaml`。
### 11.7.3 步骤 1:创建 Dockerfile
@@ -68,7 +66,6 @@ RUN bundle install
COPY . /myapp
```
-
**配置说明**:
| 指令 | 作用 |
@@ -86,13 +83,11 @@ COPY . /myapp
source 'https://rubygems.org'
gem 'rails', '~> 7.1'
```
-
创建空的 `Gemfile.lock`:
```bash
$ touch Gemfile.lock
```
-
### 11.7.5 步骤 3:创建 compose.yaml
配置如下:
@@ -121,7 +116,6 @@ services:
volumes:
postgres_data:
```
-
**配置详解**:
| 配置项 | 说明 |
@@ -138,7 +132,6 @@ volumes:
```bash
$ docker compose run --rm web rails new . --force --database=postgresql --skip-bundle
```
-
**命令解释**:
- `--rm`:执行后删除临时容器
@@ -155,7 +148,6 @@ Gemfile.lock README.md app config.ru log
compose.yaml bin db public
```
-
> ⚠️ **Linux 用户**:如遇权限问题,执行 `sudo chown -R $USER:$USER .`
### 11.7.7 步骤 5:重新构建镜像
@@ -165,7 +157,6 @@ compose.yaml bin db public
```bash
$ docker compose build
```
-
### 11.7.8 步骤 6:配置数据库连接
修改 `config/database.yml`:
@@ -187,7 +178,6 @@ test:
production:
<<: *default
```
-
> 💡 使用 `DATABASE_URL` 环境变量配置数据库,符合 12-factor 应用原则,便于在不同环境间切换。
### 11.7.9 步骤 7:启动应用
@@ -195,7 +185,6 @@ production:
```bash
$ docker compose up
```
-
输出示例:
```bash
@@ -207,7 +196,6 @@ web-1 | => Run `bin/rails server --help` for more startup options
web-1 | Puma starting in single mode...
web-1 | * Listening on http://0.0.0.0:3000
```
-
### 11.7.10 步骤 8:创建数据库
在另一个终端执行:
@@ -217,13 +205,11 @@ $ docker compose exec web rails db:create
Created database 'myapp_development'
Created database 'myapp_test'
```
-
访问 http://localhost:3000 查看 Rails 欢迎页面。
### 11.7.11 常用开发命令
```bash
-
## 数据库迁移
$ docker compose exec web rails db:migrate
@@ -244,7 +230,6 @@ $ docker compose exec web rails generate scaffold Post title:string body:text
$ docker compose exec web bash
```
-
### 11.7.12 常见问题
#### Q:数据库连接失败
@@ -255,7 +240,6 @@ $ docker compose exec web bash
$ docker compose ps
$ docker compose logs db
```
-
#### Q:server.pid 文件导致启动失败
错误信息:`A server is already running`
@@ -265,7 +249,6 @@ $ docker compose logs db
```bash
$ docker compose exec web rm -f tmp/pids/server.pid
```
-
#### Q:Gem 安装失败
可能需要更新 bundler 或清理缓存:
@@ -273,7 +256,6 @@ $ docker compose exec web rm -f tmp/pids/server.pid
```bash
$ docker compose run --rm web bundle update
```
-
### 11.7.13 开发 vs 生产
| 配置项 | 开发环境 | 生产环境 |
diff --git a/11_compose/11.8_wordpress.md b/11_compose/11.8_wordpress.md
index c933fe1..79d1672 100644
--- a/11_compose/11.8_wordpress.md
+++ b/11_compose/11.8_wordpress.md
@@ -13,7 +13,6 @@ wordpress/
└── nginx/ # 可选:反向代理配置
└── nginx.conf
```
-
---
### 11.8.2 编写 `compose.yaml`
@@ -74,7 +73,6 @@ volumes:
networks:
wp_net:
```
-
---
### 11.8.3 配置文件详解
@@ -87,7 +85,6 @@ networks:
DB_ROOT_PASSWORD=somestrongrootpassword
DB_PASSWORD=somestronguserpassword
```
-
Compose 会自动读取此同级目录下的文件。
#### 2. 数据持久化
@@ -108,7 +105,6 @@ upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 600
```
-
---
### 11.8.4 启动与运行
@@ -118,7 +114,6 @@ max_execution_time = 600
```bash
$ docker compose up -d
```
-
2. 访问安装界面:
打开浏览器访问 `http://localhost:8000`
@@ -127,7 +122,6 @@ $ docker compose up -d
```bash
$ docker compose logs -f
```
-
---
### 11.8.5 生产环境最佳实践
@@ -137,12 +131,10 @@ $ docker compose logs -f
不要只依赖 Volume。建议定期备份数据库:
```bash
-
## 导出 SQL
$ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup.sql
```
-
或者添加一个自动备份容器:
```yaml
@@ -162,7 +154,6 @@ $ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup
networks:
- wp_net
```
-
#### 2. 使用 Nginx 反向代理
在生产环境中,不要直接暴露 WordPress 端口,而是通过 Nginx 进行反向代理并配置 SSL。
@@ -178,7 +169,6 @@ WordPress 支持 Redis 缓存以提高性能。
networks:
- wp_net
```
-
在 WordPress 容器环境变量中添加:
```yaml
WORDPRESS_REDIS_HOST: redis
@@ -204,7 +194,6 @@ WordPress 支持 Redis 缓存以提高性能。
```bash
$ docker compose restart wordpress
```
-
---
### 11.8.7 延伸阅读
diff --git a/12_implementation/12.1_arch.md b/12_implementation/12.1_arch.md
index 83f830b..e31ceb4 100644
--- a/12_implementation/12.1_arch.md
+++ b/12_implementation/12.1_arch.md
@@ -13,7 +13,6 @@ graph LR
D -->|管理| C2["Containers\n容器"]
D -->|管理| C3["Images\n镜像"]
```
-
---
### 12.1.2 组件详解
@@ -84,7 +83,6 @@ flowchart TD
R -->|7. 进程退出| E
S -->|8. 监控 IO 和退出| P
```
-
1. **CLI** 发送请求给 **Dockerd**
2. **Dockerd** 解析请求,调用 **Containerd**
3. **Containerd** 准备镜像,转换为 OCI Bundle
@@ -119,7 +117,6 @@ flowchart TD
CLI -- "(Socket 映射)" --> Engine
end
```
-
- 使用轻量级虚拟机 (Apple Virtualization / WSL 2) 运行 Linux 内核
- 文件挂载 (Bind Mount) 需要跨越 VM 边界 (这也是文件 I/O 慢的原因)
- 网络端口需要从宿主机转发到 VM
diff --git a/12_implementation/12.2_namespace.md b/12_implementation/12.2_namespace.md
index 2c10e69..9a82663 100644
--- a/12_implementation/12.2_namespace.md
+++ b/12_implementation/12.2_namespace.md
@@ -25,7 +25,6 @@ flowchart LR
H4 -. "(实际是宿主机的 1234)" .- C1
```
-
### 12.2.2 Namespace 的类型
Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部:
@@ -53,7 +52,6 @@ PID Namespace 负责进程 ID 的隔离,使得容器内的进程彼此不可
#### PID 隔离效果
```bash
-
## 宿主机上查看进程
$ ps aux | grep nginx
@@ -67,7 +65,6 @@ PID USER COMMAND
1 root nginx: master process ← 在容器内是 PID 1
2 root nginx: worker process
```
-
#### PID 关键点
- 容器内的 PID 1 进程特殊重要——它是容器的主进程,退出则容器停止
@@ -102,7 +99,6 @@ flowchart LR
H2 <--> C2
```
-
#### NET 关键点
- 每个容器有独立的网卡、IP、路由表、iptables 规则
@@ -133,7 +129,6 @@ MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的
│ └── merged/ ────┼─── 这个目录成为容器的 /
└── ... └── ...
```
-
#### 与 chroot 的区别
| 特性 | chroot | MNT Namespace |
@@ -155,7 +150,6 @@ UTS Namespace 主要用于隔离主机名和域名。
#### UTS 隔离效果
```bash
-
## 宿主机
$ hostname
@@ -166,7 +160,6 @@ my-server
$ docker run --hostname mycontainer ubuntu hostname
mycontainer
```
-
UTS = “UNIX Time-sharing System”,是历史遗留的名称。
---
@@ -219,7 +212,6 @@ flowchart LR
C1 -- 映射 --> H1
C2 -- 映射 --> H2
```
-
#### 安全意义
容器内的 root 用户可以映射为宿主机上的普通用户,即使容器被突破,攻击者在宿主机上也只有普通权限。
@@ -235,7 +227,6 @@ flowchart LR
#### 实验 1:UTS Namespace
```bash
-
## 创建新的 UTS namespace 并启动 shell
$ sudo unshare --uts /bin/bash
@@ -252,11 +243,9 @@ $ exit
$ hostname
my-server
```
-
#### 实验 2:PID Namespace
```bash
-
## 创建新的 PID 和 MNT namespace
$ sudo unshare --pid --mount --fork /bin/bash
@@ -272,11 +261,9 @@ 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
```bash
-
## 创建新的网络 namespace
$ sudo unshare --net /bin/bash
@@ -287,7 +274,6 @@ $ 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
```
-
---
### 12.2.10 Namespace 的局限性
diff --git a/12_implementation/12.3_cgroups.md b/12_implementation/12.3_cgroups.md
index 8617c3c..25e8663 100644
--- a/12_implementation/12.3_cgroups.md
+++ b/12_implementation/12.3_cgroups.md
@@ -28,7 +28,6 @@ flowchart LR
end
end
```
-
---
### 12.3.2 cgroups 的历史
@@ -62,7 +61,6 @@ Docker 提供了丰富的参数来配置容器的资源限制,主要包括内
#### 内存限制
```bash
-
## 限制容器最多使用 512MB 内存
$ docker run -m 512m myapp
@@ -75,7 +73,6 @@ $ docker run -m 512m --memory-swap 1g myapp
$ docker run --memory-reservation 256m myapp
```
-
| 参数 | 说明 |
|------|------|
| `-m` / `--memory` | 硬限制 (超过会 OOM Kill)|
@@ -86,7 +83,6 @@ $ docker run --memory-reservation 256m myapp
#### CPU 限制
```bash
-
## 限制使用 1.5 个 CPU 核心
$ docker run --cpus=1.5 myapp
@@ -99,7 +95,6 @@ $ docker run --cpuset-cpus="0,1" myapp
$ docker run --cpu-shares=512 myapp
```
-
| 参数 | 说明 |
|------|------|
| `--cpus` | 限制 CPU 核心数 (如 1.5)|
@@ -110,7 +105,6 @@ $ docker run --cpu-shares=512 myapp
#### 磁盘 I/O 限制
```bash
-
## 限制设备写入速度为 10MB/s
$ docker run --device-write-bps /dev/sda:10mb myapp
@@ -123,22 +117,18 @@ $ docker run --device-read-bps /dev/sda:10mb myapp
$ docker run --device-write-iops /dev/sda:100 myapp
```
-
#### 进程数限制
```bash
-
## 限制最多 100 个进程
$ docker run --pids-limit=100 myapp
```
-
---
### 12.3.5 查看容器资源使用
```bash
-
## 实时监控所有容器的资源使用
$ docker stats
@@ -154,7 +144,6 @@ $ docker stats mycontainer
$ docker inspect mycontainer --format '{{json .HostConfig}}' | jq
```
-
---
### 12.3.6 资源限制的效果
@@ -162,7 +151,6 @@ $ docker inspect mycontainer --format '{{json .HostConfig}}' | jq
#### 内存超限
```bash
-
## 启动限制 100MB 内存的容器
$ docker run -m 100m stress --vm 1 --vm-bytes 200M
@@ -177,11 +165,9 @@ abc123 Exited (137) 5 seconds ago hopeful_darwin
...
```
-
#### CPU 限制验证
```bash
-
## 不限制 CPU
$ docker run --rm stress --cpu 4
@@ -196,7 +182,6 @@ $ docker run --rm --cpus=1 stress --cpu 4
...
```
-
---
### 12.3.7 cgroups v1 vs v2
@@ -218,13 +203,11 @@ Docker 19.03+ 默认优先使用 cgroups v2(如果系统支持),提供更
"cgroup-driver": "systemd"
}
```
-
常见的 `cgroup-driver` 值包括 `systemd` (推荐) 和 `cgroupfs`。重启 Docker 守护进程后生效。
#### 检查系统使用的版本
```bash
-
## 查看 cgroup 版本
$ mount | grep cgroup
@@ -238,7 +221,6 @@ $ cat /proc/filesystems | grep cgroup
nodev cgroup
nodev cgroup2
```
-
---
### 12.3.8 在 Compose 中设置限制
@@ -258,7 +240,6 @@ services:
cpus: '0.25'
memory: 256M
```
-
---
### 12.3.9 最佳实践
@@ -268,22 +249,18 @@ services:
#### 1. 始终设置内存限制
```bash
-
## 防止 OOM 影响宿主机
$ docker run -m 1g myapp
```
-
#### 2. 为关键应用设置 CPU 保证
```bash
$ docker run --cpus=2 --cpu-shares=2048 critical-app
```
-
#### 3. 监控资源使用
```bash
-
## 配合 Prometheus + cAdvisor 监控
$ docker run -d --name cadvisor \
@@ -293,5 +270,4 @@ $ docker run -d --name cadvisor \
-v /var/lib/docker:/var/lib/docker:ro \
ghcr.io/google/cadvisor
```
-
---
diff --git a/12_implementation/12.4_ufs.md b/12_implementation/12.4_ufs.md
index 77daa04..40d2a7e 100644
--- a/12_implementation/12.4_ufs.md
+++ b/12_implementation/12.4_ufs.md
@@ -21,7 +21,6 @@ flowchart TD
ContainerFS --> UnionFS
UnionFS --> ContainerLayer --> ImageLayer3 --> ImageLayer2 --> ImageLayer1
```
-
---
### 12.4.2 为什么 Docker 使用联合文件系统
@@ -35,7 +34,6 @@ flowchart TD
Nginx["nginx:alpine"] --> Alpine["alpine:3.19 (共享基础层)"]
MyApp["myapp:latest"] --> Alpine
```
-
多个镜像共享相同的底层,节省磁盘空间。
#### 2. 快速构建
@@ -48,7 +46,6 @@ COPY package.json ./ # 层2:依赖定义
RUN npm install # 层3:安装依赖
COPY . . # 层4:应用代码
```
-
代码变化时,只需重建层 4,层 1-3 使用缓存。
#### 3. 容器启动快
@@ -80,7 +77,6 @@ flowchart LR
B_C --- B_I
A_C --- A_I
```
-
**流程**:
1. 从只读层读取文件
@@ -112,7 +108,6 @@ Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, device
#### 查看当前存储驱动与后端
```bash
-
## 查看默认存储驱动 (Storage Driver)
$ docker info | grep "Storage Driver"
Storage Driver: overlay2
@@ -121,7 +116,6 @@ Storage Driver: overlay2
$ docker info | grep "containerd image store"
containerd image store: true
```
-
---
### 12.4.5 overlay2 工作原理
@@ -142,7 +136,6 @@ flowchart TD
OverlayFS --> Lower2
OverlayFS --> Lower1
```
-
- **lowerdir**:只读的镜像层 (可以有多个)
- **upperdir**:可写的容器层
- **workdir**:OverlayFS 的工作目录
@@ -162,7 +155,6 @@ flowchart TD
### 12.4.6 查看镜像层
```bash
-
## 查看镜像的层信息
$ docker history nginx:alpine
@@ -184,7 +176,6 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
"WorkDir": "/var/lib/docker/overlay2/.../work"
}
```
-
---
### 12.4.7 最佳实践
@@ -194,7 +185,6 @@ $ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
#### 1. 减少镜像层数
```docker
-
## ❌ 每条命令创建一层
RUN apt-get update
@@ -207,7 +197,6 @@ RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
```
-
#### 2. 避免在容器中写入大量数据
容器层的写入性能低于直接写入。大量数据应使用:
diff --git a/13_kubernetes_concepts/13.2_concepts.md b/13_kubernetes_concepts/13.2_concepts.md
index b7fb4c1..771e33f 100644
--- a/13_kubernetes_concepts/13.2_concepts.md
+++ b/13_kubernetes_concepts/13.2_concepts.md
@@ -48,7 +48,6 @@ control-plane Ready control-plane 10d v1.35.1
worker-1 Ready 10d v1.35.1
worker-2 Ready 10d v1.35.1
```
-
每个节点的详细信息以如下结构保存:
```yaml
@@ -66,7 +65,6 @@ status:
- type: Ready
status: "True"
```
-
#### 节点控制器
在 Kubernetes 控制平面中,节点控制器 (Node Controller) 负责管理节点的生命周期,主要包含:
@@ -77,14 +75,12 @@ status:
节点控制器会持续监控节点的健康状态。当节点变为不可达时,控制器会等待一个超时期限,然后将该节点上的 Pod 标记为失败,并触发重新调度。可以使用 `kubectl` 来管理节点,例如标记节点为不可调度或排空节点上的工作负载:
```bash
-
## 标记节点为不可调度
$ kubectl cordon worker-1
## 排空节点上的 Pod
$ kubectl drain worker-1 --ignore-daemonsets
```
-
### 13.2.2 容器组
在 Kubernetes 中,使用的最小调度单位是容器组 (Pod),它是创建、调度、管理的最小单位。一个 Pod 包含一个或多个紧密协作的容器,它们共享网络命名空间和存储卷。
@@ -172,7 +168,6 @@ spec:
ports:
- containerPort: 80
```
-
Deployment 的核心能力包括:
* **副本管理**:确保始终有指定数量的 Pod 在运行
@@ -198,7 +193,6 @@ spec:
targetPort: 80
type: ClusterIP
```
-
常见的 Service 类型:
| 类型 | 说明 |
@@ -225,14 +219,12 @@ spec:
标签 (Label) 是附加到 Kubernetes 对象上的键值对,用于组织和选择对象子集。标签是 Kubernetes 中实现松耦合的关键机制。
```bash
-
## 为 Pod 添加标签
$ kubectl label pod my-pod env=production
## 通过标签选择器查询
$ kubectl get pods -l env=production
```
-
Service、Deployment 等资源都通过标签选择器 (`selector`) 来关联目标 Pod。
### 13.2.7 API 访问控制
@@ -252,7 +244,6 @@ Kubernetes Dashboard 是一个基于 Web 的用户界面,用于部署容器化
`kubectl` 是 Kubernetes 的命令行工具,用于与集群进行交互。常用命令如下:
```bash
-
## 查看集群中的资源
$ kubectl get pods,deployments,services,nodes
@@ -268,5 +259,4 @@ $ kubectl exec -it my-pod -- /bin/sh
## 查看资源详情
$ kubectl describe pod my-pod
```
-
更多 kubectl 操作详见[kubectl 命令行](../14_kubernetes_setup/14.8_kubectl.md)章节。
diff --git a/13_kubernetes_concepts/13.4_advanced.md b/13_kubernetes_concepts/13.4_advanced.md
index 9b6d967..8a7b46f 100644
--- a/13_kubernetes_concepts/13.4_advanced.md
+++ b/13_kubernetes_concepts/13.4_advanced.md
@@ -52,7 +52,6 @@ spec:
type: Utilization
averageUtilization: 50
```
-
### 13.4.5 ConfigMap 与 Secret
* **ConfigMap**:存储非机密的配置数据 (配置文件、环境变量)。
diff --git a/13_kubernetes_concepts/13.5_practice.md b/13_kubernetes_concepts/13.5_practice.md
index ce49155..aae23d5 100644
--- a/13_kubernetes_concepts/13.5_practice.md
+++ b/13_kubernetes_concepts/13.5_practice.md
@@ -35,13 +35,11 @@ spec:
ports:
- containerPort: 80
```
-
应用配置:
```bash
kubectl apply -f nginx-deployment.yaml
```
-
### 13.5.3 步骤 2:创建 Service
创建一个名为 `nginx-service.yaml` 的文件:
@@ -60,19 +58,16 @@ spec:
targetPort: 80
type: NodePort # 使用 NodePort 方便本地测试
```
-
应用配置:
```bash
kubectl apply -f nginx-service.yaml
```
-
查看分配的端口:
```bash
kubectl get svc nginx-service
```
-
如果输出端口是 `80:30080/TCP`,你可以通过 `http://:30080` 访问 Nginx。
### 13.5.4 步骤 3:模拟滚动更新
@@ -82,13 +77,11 @@ kubectl get svc nginx-service
```bash
kubectl apply -f nginx-deployment.yaml
```
-
观察更新过程:
```bash
kubectl rollout status deployment/nginx-deployment
```
-
### 13.5.5 步骤 4:清理资源
练习结束后,记得清理资源:
diff --git a/14_kubernetes_setup/14.1_kubeadm.md b/14_kubernetes_setup/14.1_kubeadm.md
index 96f0472..7872a82 100644
--- a/14_kubernetes_setup/14.1_kubeadm.md
+++ b/14_kubernetes_setup/14.1_kubeadm.md
@@ -9,7 +9,6 @@
参考[安装 Docker](../03_install/README.md) 一节添加 apt/yum 源,之后执行如下命令。
```bash
-
## debian 系
$ sudo apt install containerd.io
@@ -18,7 +17,6 @@ $ sudo apt install containerd.io
$ sudo yum install containerd.io
```
-
### 14.1.2 配置 containerd
新建 `/etc/systemd/system/cri-containerd.service` 文件
@@ -57,7 +55,6 @@ OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
```
-
新建 `/etc/cri-containerd/config.toml` containerd 配置文件
```toml
@@ -233,7 +230,6 @@ oom_score = 0
base_image_size = ""
async_remove = false
```
-
### 14.1.3 安装 **kubelet**、**kubeadm**、**kubectl**、**cri-tools**、**kubernetes-cni**
需要在每台机器上安装以下的软件包:
@@ -257,7 +253,6 @@ $ sudo apt-get install -y kubelet kubeadm kubectl cri-tools kubernetes-cni
$ sudo apt-mark hold kubelet kubeadm kubectl
```
-
#### CentOS/Fedora
```bash
@@ -275,7 +270,6 @@ EOF
$ sudo yum install -y kubelet kubeadm kubectl cri-tools kubernetes-cni
```
-
### 14.1.4 修改内核的运行参数
#### 加载内核模块
@@ -289,7 +283,6 @@ EOF
$ sudo modprobe overlay
$ sudo modprobe br_netfilter
```
-
#### 禁用 swap:必须
kubelet 默认要求禁用 swap,否则可能导致初始化失败或节点无法加入集群。
@@ -299,7 +292,6 @@ $ sudo swapoff -a
## 如需永久禁用,可在 /etc/fstab 中注释 swap 对应行
```
-
```bash
$ cat < 执行可能出现错误,例如缺少依赖包,根据提示安装即可。
@@ -386,7 +373,6 @@ Then you can join any number of worker nodes by running the following on each as
kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
```
-
#### node 工作节点
在 **另一主机** 重复 **部署** 小节以前的步骤,安装配置好 kubelet。根据提示,加入到集群。
@@ -401,7 +387,6 @@ $ kubeadm join 192.168.199.100:6443 \
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe \
--cri-socket /run/cri-containerd/cri-containerd.sock
```
-
### 14.1.7 查看服务
所有服务启动后,通过 `crictl` 查看本地实际运行的容器。这些服务大概分为三类:主节点服务、工作节点服务和其它服务。
@@ -409,7 +394,6 @@ $ kubeadm join 192.168.199.100:6443 \
```bash
CONTAINER_RUNTIME_ENDPOINT=/run/cri-containerd/cri-containerd.sock crictl ps -a
```
-
#### 主节点服务
* `apiserver` 是整个系统的对外接口,提供 RESTful 方式供客户端和其它组件调用;
@@ -450,11 +434,9 @@ $ kubectl get node -o yaml | grep CIDR
podCIDR: 10.244.0.0/16
podCIDRs:
```
-
```bash
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.1/Documentation/kube-flannel.yml
```
-
### 14.1.10 master 节点默认不能运行 pod
如果用 `kubeadm` 部署一个单节点集群,默认情况下无法使用,请执行以下命令解除限制
@@ -472,7 +454,6 @@ $ kubectl taint nodes --all node-role.kubernetes.io/master-
...
```
-
### 14.1.11 参考文档
* [官方文档](https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)
diff --git a/14_kubernetes_setup/14.2_kubeadm-docker.md b/14_kubernetes_setup/14.2_kubeadm-docker.md
index 26bfc9e..d7d987c 100644
--- a/14_kubernetes_setup/14.2_kubeadm-docker.md
+++ b/14_kubernetes_setup/14.2_kubeadm-docker.md
@@ -21,7 +21,6 @@
#### Ubuntu/Debian
```bash
-
## 安装 cri-dockerd
$ cd /tmp
@@ -45,11 +44,9 @@ $ sudo systemctl start cri-docker
$ sudo /usr/local/bin/cri-dockerd --version
```
-
#### CentOS/Fedora
```bash
-
## 安装 cri-dockerd
$ cd /tmp
@@ -69,7 +66,6 @@ $ sudo systemctl daemon-reload
$ sudo systemctl enable cri-docker
$ sudo systemctl start cri-docker
```
-
### 14.2.3 安装 **kubelet**、**kubeadm**、**kubectl**
需要在每台机器上安装以下的软件包:
@@ -93,7 +89,6 @@ $ sudo apt-get install -y kubelet kubeadm kubectl
$ sudo apt-mark hold kubelet kubeadm kubectl
```
-
#### CentOS/Fedora
```bash
@@ -111,7 +106,6 @@ EOF
$ sudo yum install -y kubelet kubeadm kubectl
```
-
### 14.2.4 修改内核的运行参数
#### 加载内核模块
@@ -125,7 +119,6 @@ EOF
$ sudo modprobe overlay
$ sudo modprobe br_netfilter
```
-
#### 禁用 swap:必须
kubelet 默认要求禁用 swap,否则可能导致初始化失败或节点无法加入集群。
@@ -135,7 +128,6 @@ $ sudo swapoff -a
## 如需永久禁用,可在 /etc/fstab 中注释 swap 对应行
```
-
```bash
$ cat <
@@ -86,7 +81,6 @@ docker tag my-app:latest ccr.ccs.tencentyun.com/namespace/my-app:latest
# 推送镜像到腾讯云
docker push ccr.ccs.tencentyun.com/namespace/my-app:latest
```
-
### 腾讯云 Docker 镜像加速器配置
为了加快镜像拉取速度,腾讯云提供了镜像加速服务。配置方法如下:
@@ -96,12 +90,10 @@ docker push ccr.ccs.tencentyun.com/namespace/my-app:latest
编辑 `/etc/docker/daemon.json` 文件(如果不存在则创建):
```bash
-
# 创建或编辑配置文件
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json
```
-
添加以下内容:
```json
@@ -112,22 +104,18 @@ sudo nano /etc/docker/daemon.json
"insecure-registries": []
}
```
-
重启 Docker 服务:
```bash
sudo systemctl daemon-reload
sudo systemctl restart docker
```
-
验证配置:
```bash
-
# 查看镜像源是否生效
docker info | grep -A 5 "Registry Mirrors"
```
-
#### Windows/Mac 配置
对于 Docker Desktop,在设置界面中:
@@ -157,7 +145,6 @@ docker info | grep -A 5 "Registry Mirrors"
#### 完整推送/拉取示例
```bash
-
# 登录到腾讯云 TCR(使用 API 密钥)
docker login ccr.ccs.tencentyun.com \
--username <腾讯云账号ID> \
@@ -180,7 +167,6 @@ docker push ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
FROM ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
RUN echo "使用腾讯云镜像作为基础镜像"
```
-
#### TKE 集群中使用 TCR 镜像
配置镜像拉取凭证后,在 Deployment 中直接引用 TCR 镜像:
diff --git a/16_cloud/16.3_alicloud.md b/16_cloud/16.3_alicloud.md
index e926572..8b84ca9 100644
--- a/16_cloud/16.3_alicloud.md
+++ b/16_cloud/16.3_alicloud.md
@@ -33,12 +33,10 @@
- 完成创建,下载 kubeconfig 文件
```bash
-
# 配置本地 kubectl
export KUBECONFIG=/path/to/kubeconfig.yaml
kubectl get nodes
```
-
#### 2. 部署容器应用
通过 Deployment 部署应用示例:
@@ -68,7 +66,6 @@ spec:
memory: "512Mi"
cpu: "500m"
```
-
部署应用:
```bash
@@ -76,7 +73,6 @@ kubectl apply -f deployment.yaml
kubectl get pods -o wide
kubectl logs
```
-
#### 3. 暴露服务
创建 Service 暴露应用:
@@ -94,14 +90,12 @@ spec:
selector:
app: web
```
-
应用:
```bash
kubectl apply -f service.yaml
kubectl get svc web-service
```
-
### 阿里云 Docker 镜像加速器配置
为了加快从阿里云镜像源拉取官方镜像的速度,可以配置镜像加速器。阿里云为容器服务 ACK 用户提供了免费的镜像加速服务。
@@ -118,7 +112,6 @@ kubectl get svc web-service
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json
```
-
添加或修改以下内容(替换为你的加速器地址):
```json
@@ -128,20 +121,17 @@ sudo nano /etc/docker/daemon.json
]
}
```
-
重新加载并重启 Docker:
```bash
sudo systemctl daemon-reload
sudo systemctl restart docker
```
-
验证配置生效:
```bash
docker info | grep -A 5 "Registry Mirrors"
```
-
#### Windows/Mac 配置
在 Docker Desktop 的 Settings 中:
@@ -152,12 +142,10 @@ docker info | grep -A 5 "Registry Mirrors"
#### 测试加速效果
```bash
-
# 从加速器拉取镜像(速度应该明显提升)
docker pull nginx:latest
time docker pull alpine:latest
```
-
### 阿里云容器镜像服务:ACR
阿里云容器镜像服务 (ACR, Container Registry) 是企业级的容器镜像存储和分发平台:
@@ -172,7 +160,6 @@ time docker pull alpine:latest
#### 完整推送/拉取示例
```bash
-
# 登录阿里云镜像仓库(使用 Docker 登录)
# 使用阿里云账户 ID 和 RAM 访问密钥或密码
docker login registry.cn-hangzhou.aliyuncs.com \
@@ -196,7 +183,6 @@ FROM registry.cn-hangzhou.aliyuncs.com/myapp/my-app:v1.0
COPY . /app
RUN echo "已成功使用阿里云镜像"
```
-
#### ACK 集群中使用 ACR 镜像
在 ACK 集群中,需要先配置镜像拉取凭证(Secret),然后在 Deployment 中引用:
@@ -247,13 +233,11 @@ spec:
- web
topologyKey: kubernetes.io/hostname
```
-
#### 创建镜像拉取凭证
在 ACK 集群中创建 Secret,用于拉取私有镜像:
```bash
-
# 创建镜像拉取 Secret
kubectl create secret docker-registry acr-secret \
--docker-server=registry.cn-hangzhou.aliyuncs.com \
@@ -265,7 +249,6 @@ kubectl create secret docker-registry acr-secret \
kubectl get secret acr-secret
kubectl describe secret acr-secret
```
-
#### ACR 优势
- 在 ACK 集群中与镜像仓库无缝集成,简化身份认证
diff --git a/17_ecosystem/17.2_coreos_install.md b/17_ecosystem/17.2_coreos_install.md
index e361cf1..d554d1c 100644
--- a/17_ecosystem/17.2_coreos_install.md
+++ b/17_ecosystem/17.2_coreos_install.md
@@ -9,7 +9,6 @@
FCC 是 Fedora CoreOS Configuration (Fedora CoreOS 配置) 的简称。
```yaml
-
## example.fcc
variant: fcos
@@ -20,7 +19,6 @@ passwd:
ssh_authorized_keys:
- ssh-rsa AAAA...
```
-
将 `ssh-rsa AAAA...` 替换为自己的 SSH 公钥 (位于 `~/.ssh/id_rsa.pub`)。
### 17.2.3 转换 FCC 为 Ignition
@@ -28,7 +26,6 @@ passwd:
```bash
$ docker run -i --rm quay.io/coreos/fcct:v0.5.0 --pretty --strict < example.fcc > example.ign
```
-
### 17.2.4 挂载 ISO 启动虚拟机并安装
> 虚拟机需要分配 3GB 以上内存,否则会无法启动。
@@ -38,7 +35,6 @@ $ docker run -i --rm quay.io/coreos/fcct:v0.5.0 --pretty --strict < example.fcc
```bash
$ sudo coreos-installer install /dev/sda --ignition-file example.ign
```
-
安装之后重新启动即可使用。
### 17.2.5 使用
diff --git a/17_ecosystem/17.3_podman.md b/17_ecosystem/17.3_podman.md
index bc2c815..bfaef79 100644
--- a/17_ecosystem/17.3_podman.md
+++ b/17_ecosystem/17.3_podman.md
@@ -22,7 +22,6 @@ Podman 支持多种操作系统,安装过程也相对简单。
```bash
$ sudo yum -y install podman
```
-
#### macOS
macOS 上需要安装 Podman Desktop 或通过 Homebrew 安装:
@@ -32,7 +31,6 @@ $ brew install podman
$ podman machine init
$ podman machine start
```
-
### 17.3.3 基本使用
`podman` 的命令行几乎与 `docker` 完全兼容,大多数情况下,你只需将 `docker` 替换为 `podman` 即可。
@@ -40,30 +38,25 @@ $ podman machine start
#### 运行容器
```bash
-
## $ docker run -d -p 80:80 nginx:alpine
$ podman run -d -p 80:80 nginx:alpine
```
-
#### 列出容器
```bash
$ podman ps
```
-
#### 构建镜像
```bash
$ podman build -t myimage .
```
-
### 17.3.4 Pods 的概念
与 Docker 不同,Podman 支持“Pod”的概念 (类似于 Kubernetes 的 Pod),允许你在同一个网络命名空间中运行多个容器。
```bash
-
## 创建一个 Pod
$ podman pod create --name mypod -p 8080:80
@@ -72,7 +65,6 @@ $ podman pod create --name mypod -p 8080:80
$ podman run -d --pod mypod --name webbing nginx
```
-
### 17.3.5 迁移到 Podman
如果你习惯使用 `docker` 命令,可以简单地设置别名:
@@ -80,13 +72,11 @@ $ podman run -d --pod mypod --name webbing nginx
```bash
$ alias docker=podman
```
-
#### Systemd 集成
Podman 可以生成 systemd 单元文件,让容器像普通系统服务一样管理。
```bash
-
## 创建容器
$ podman run -d --name myweb -p 8080:80 nginx
@@ -99,7 +89,6 @@ $ podman generate systemd --name myweb --files --new
$ systemctl --user enable --now container-myweb.service
```
-
#### Podman Compose
虽然 Podman 兼容 Docker Compose,但在某些场景下你可能需要明确使用 `podman-compose`。
diff --git a/17_ecosystem/17.4_buildah.md b/17_ecosystem/17.4_buildah.md
index 93f047d..c32fd1a 100644
--- a/17_ecosystem/17.4_buildah.md
+++ b/17_ecosystem/17.4_buildah.md
@@ -24,14 +24,12 @@ Buildah 由 Red Hat 主导开发,通常和 Podman、Skopeo 一起使用,被
```bash
$ sudo dnf install -y buildah
```
-
以 Ubuntu/Debian 为例(需引入官方源后):
```bash
$ sudo apt-get update
$ sudo apt-get -y install buildah
```
-
### 基础用法示例
#### 1. 从现有的 Dockerfile 构建镜像
@@ -41,7 +39,6 @@ Buildah 最常见的用法就是像 Docker 一样根据 `Dockerfile` 来构建
```bash
$ buildah bud -t my-app:latest .
```
-
可以看到在这点上,它与 `docker build` 的体验完全一致。
#### 2. 交互式从空镜像开始构建
@@ -49,7 +46,6 @@ $ buildah bud -t my-app:latest .
除了使用 Dockerfile,Buildah 最强大的功能来自于它的交互式和脚本化构建机制。我们可以从一个极简的镜像(或基础镜像)开始构建:
```bash
-
# 获取一个基础镜像
$ container=$(buildah from alpine:latest)
@@ -71,7 +67,6 @@ $ buildah commit $container my-hello-image:latest
$ buildah unmount $container
$ buildah rm $container
```
-
这种模式在自动化流水线中极为有用,因为我们可以将上述过程编写成标准的 bash 脚本,无需为了构建镜像而撰写只在其独立语法中运行的 Dockerfile 指令。
#### 3. 查看和推送镜像
@@ -79,12 +74,10 @@ $ buildah rm $container
通过 `buildah images` 可以查看当前环境中的镜像。推送镜像到外部 Registry 也十分安全方便:
```bash
-
# 查看本地构建的镜像
$ buildah images
# 推送镜像到 Docker Hub(注意需要先登录)
$ buildah push my-hello-image:latest docker://docker.io/username/my-hello-image:latest
```
-
结合其无需特权和灵活脚本的优点,Buildah 正变得越来越受到构建和分发 OCI 镜像的用户喜爱。
diff --git a/17_ecosystem/17.5_skopeo.md b/17_ecosystem/17.5_skopeo.md
index f6b0b3b..dd3c6be 100644
--- a/17_ecosystem/17.5_skopeo.md
+++ b/17_ecosystem/17.5_skopeo.md
@@ -24,20 +24,17 @@ Skopeo 最大的特点是其可以在“不将镜像拉取到本地”的情况
```bash
$ sudo dnf install -y skopeo
```
-
在 Ubuntu/Debian 中:
```bash
$ sudo apt-get update
$ sudo apt-get -y install skopeo
```
-
如果是 macOS 环境,可以通过 Homebrew 安装:
```bash
$ brew install skopeo
```
-
### 基础用法示例
#### 1. 远程检查镜像
@@ -47,7 +44,6 @@ $ brew install skopeo
```bash
$ skopeo inspect docker://docker.io/library/alpine:latest
```
-
这个命令会返回一段 JSON 格式的数据,其中包含了诸如镜像摘要(Digest)、创建时间、架构(Architecture)、标签(Tags)等丰富信息。在自动化的工具和系统审查环境中,这是一个不可或缺的利器。
#### 2. 同步与复制镜像
@@ -59,13 +55,11 @@ $ skopeo inspect docker://docker.io/library/alpine:latest
```bash
$ skopeo copy docker://docker.io/library/alpine:latest docker://registry.example.com/library/alpine:latest
```
-
又或者,你可以将远程镜像拉取到本地,只为了检查其拆解后的格式,比如将镜像解压到本地某个目录下以 OCI 规范存放:
```bash
$ skopeo copy docker://docker.io/library/alpine:latest oci:alpine-oci
```
-
如果我们要将本地的某个目录下的打包好的镜像再次推向 Registry 或转换为其它存储类型也是完全支持的,诸如:
- `docker://` 远端 Registry
- `docker-archive:` / `docker-daemon:` Docker 对应的归档文件或本地守护进程
diff --git a/17_ecosystem/17.6_containerd.md b/17_ecosystem/17.6_containerd.md
index c5f406a..01abe07 100644
--- a/17_ecosystem/17.6_containerd.md
+++ b/17_ecosystem/17.6_containerd.md
@@ -56,7 +56,6 @@ Kubernetes 作为一个容器编排系统,为了屏蔽底层不同容器运行
安装完 containerd 和 nerdctl 后,你可以体验到几乎与 Docker 完全一致的命令行:
```bash
-
# 启动一个 nginx 容器
$ nerdctl run -d -p 8080:80 --name my-nginx nginx:alpine
@@ -66,5 +65,4 @@ $ nerdctl ps
# 查看本地镜像
$ nerdctl images
```
-
对于那些希望在生产服务器上剥离 Docker 庞大体积,但又想要保留类似 Docker 方便的命令行体验的用户,`containerd` + `nerdctl` 是一个极佳的组合。
diff --git a/18_security/18.1_kernel_ns.md b/18_security/18.1_kernel_ns.md
index 4efd910..4048b40 100644
--- a/18_security/18.1_kernel_ns.md
+++ b/18_security/18.1_kernel_ns.md
@@ -43,7 +43,6 @@ Docker 守护进程在启动容器时,会在后台为容器创建一套独立
"userns-remap": "default"
}
```
-
使用 `default` 值时,Docker 会自动在宿主机上创建一个名为 `dockremap` 的用户和用户组。
2. **验证子 UID 和子 GID 分配**
@@ -61,13 +60,11 @@ dockremap:165536:65536
```bash
$ sudo systemctl restart docker
```
-
#### 验证映射效果
我们可以运行一个简单的容器并执行 `sleep` 命令,同时在宿主机上观察进程的所有者:
```bash
-
## 在容器内以 root 身份运行
$ docker run -d --name userns_test alpine sleep 3600
@@ -75,7 +72,6 @@ $ docker run -d --name userns_test alpine sleep 3600
$ ps aux | grep sleep
165536 12345 0.0 0.0 1568 4 ? Ss 14:20 0:00 sleep 3600
```
-
你会发现,尽管在容器内该进程是由 root 启动的,但在宿主机上,它的属主是 `165536`(一个完全没有特权的用户)。
> [!TIP]
diff --git a/18_security/18.2_control_group.md b/18_security/18.2_control_group.md
index 17eda8a..19452df 100644
--- a/18_security/18.2_control_group.md
+++ b/18_security/18.2_control_group.md
@@ -38,7 +38,6 @@ $ docker run -d \
--memory-swap="512m" \
nginx:alpine
```
-
如果该容器内的应用尝试分配超过 512MB 的内存,该进程将会被内核的 OOM Killer 杀掉,但绝不会波及到宿主机的其他部分。
#### 2. CPU 限制
@@ -60,7 +59,6 @@ $ docker run -d \
busybox \
md5sum /dev/urandom
```
-
即使上面的命令是一个死循环的哈希计算进程,容器也永远无法吃满双核 CPU 系统的全部算力。
#### 3. 进程数限制
@@ -80,7 +78,6 @@ $ docker run -d \
--pids-limit=100 \
python:alpine python app.py
```
-
当容器内的进程总数达到 100 时,任何尝试派生新进程的操作都会失败并返回 `Resource temporarily unavailable`,从而挫败相关的攻击行为。
### 18.2.3 最佳实践建议
@@ -98,5 +95,4 @@ resources:
memory: "512Mi"
cpu: "500m"
```
-
通过 Cgroups 的资源边界控制,你可以从根本上切断一条导致整个系统雪崩的脆弱链路。这也进一步使得 Docker 以及容器技术成为了现代高可用服务的基础设施首选。
diff --git a/18_security/18.3_daemon_sec.md b/18_security/18.3_daemon_sec.md
index 980de5c..5539244 100644
--- a/18_security/18.3_daemon_sec.md
+++ b/18_security/18.3_daemon_sec.md
@@ -33,7 +33,6 @@ dockerd \
--tlskey=server-key.pem \
-H=0.0.0.0:2376
```
-
3. 客户端想要连接时,也必须出示客户端证书。
> [!TIP]
@@ -62,23 +61,19 @@ Rootless 模式允许在完全局限于非 `root` 用户的环境中运行 Docke
```bash
$ sudo apt-get install uidmap
```
-
2. 切换到一个没有任何 `sudo` 权限的普通用户(假设用户名为 `testuser`):
```bash
$ su - testuser
```
-
3. 运行 Docker 官方提供的 Rootless 安装脚本:
```bash
$ curl -fsSL https://get.docker.com/rootless | sh
```
-
4. 配置环境变量指向新创建的私有 socket:
```bash
$ export DOCKER_HOST=unix:///run/user/1000/docker.sock
$ docker version
```
-
安装并暴露相应的配置后,该用户的环境将能独立启动属于他自己的 Docker Daemon。即使由于某些未知 0-Day 漏洞使得攻击者突破了容器,他们也只会受限于 `testuser` 这个非特权用户所在的有限系统环境内。
### 18.3.4 结语
diff --git a/18_security/18.4_kernel_capability.md b/18_security/18.4_kernel_capability.md
index 52f76ae..2551703 100644
--- a/18_security/18.4_kernel_capability.md
+++ b/18_security/18.4_kernel_capability.md
@@ -36,7 +36,6 @@ $ docker run -d \
--cap-add NET_BIND_SERVICE \
nginx:alpine
```
-
这里的 `--cap-drop ALL` 是实现“特权最小化”的最强杀手锏。此时,即便某黑客利用 0-Day 手段拿到了 Web 服务的容器 root Shell,当他试图改变任何不属于他自己的进程配置或者所有权时,系统都会报错拒绝访问。
#### 实战场景二:需要捕获网络数据包的网络实验
@@ -52,7 +51,6 @@ $ docker run -it --rm \
--cap-add NET_RAW \
tshark-image /bin/bash
```
-
我们只授予了所需的网络管理控制(NET_ADMIN)和侦听底层套接字的权限(NET_RAW),而免去了赋予整个容器终极杀器 `--privileged` 参数。
> [!WARNING]
diff --git a/18_security/18.5_other_feature.md b/18_security/18.5_other_feature.md
index 03d7b02..4c1f08f 100644
--- a/18_security/18.5_other_feature.md
+++ b/18_security/18.5_other_feature.md
@@ -26,7 +26,6 @@ Docker 默认启用了 Seccomp 并利用预置的 [默认配置文件](https://g
]
}
```
-
在启动时告诉 Docker 载入这套过滤配置:
```bash
@@ -54,7 +53,6 @@ $ docker run --rm -it \
--security-opt apparmor=custom-nginx-profile \
nginx
```
-
### 18.5.3 容器镜像漏洞静态扫描
现代防护的防御已经不仅仅在运行阶段,而向“左”延伸至了构建与分发时期控制。很多安全隐患并不是用户代码中的直接逻辑异常,而是打包环境或者引入库的基础 `APT` 安装层面潜伏了开源界众所周知的历史漏洞。
@@ -64,7 +62,6 @@ $ docker run --rm -it \
[Trivy](https://github.com/aquasecurity/trivy) 是由 Aqua Security 发行的一款针对容器技术的快速镜像漏洞扫描利器。在分发应用前通过它的扫描可以规避绝大多数风险。
```bash
-
## 如果使用本地命令行扫描容器镜像
$ trivy image alpine:3.10
@@ -81,7 +78,6 @@ Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
| busybox | CVE-2022-28391 | HIGH | 1.30.1-r3 | 1.30.1-r4 | busybox: out-of-bounds read in... |
...
```
-
只要确保所有上传给私有或公共仓库分发服务的产物先被引入至 CI/CD 流水线,如果出现 `HIGH` 及 `CRITICAL` 严重的报错记录强行阻拦部署,这本身便是构建环节极其有力的自动化安全大门保障。除 Trivy 外,最新的 Docker 版本也已内置支持官方扫描利刃 **Docker Scout**。
### 18.5.4 容器核心层基石结语
diff --git a/18_security/18.6_image_security.md b/18_security/18.6_image_security.md
index 2e58d5b..c63c0ae 100644
--- a/18_security/18.6_image_security.md
+++ b/18_security/18.6_image_security.md
@@ -18,7 +18,6 @@ Trivy 是由 Aqua Security 开发的开源漏洞扫描器,以其轻量级、
**安装与基本使用:**
```bash
-
# 安装 Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
@@ -34,17 +33,14 @@ trivy fs /path/to/project
# 扫描 Git 仓库
trivy repo https://github.com/aquasecurity/trivy
```
-
**在 CI/CD 中集成:**
```bash
-
# 设置严重程度过滤
trivy image --severity HIGH,CRITICAL \
--exit-code 1 \
myregistry.com/myapp:v1.0.0
```
-
#### Grype - 支持多种软件包的扫描器
Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。
@@ -58,7 +54,6 @@ Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。
**安装与使用:**
```bash
-
# 安装 Grype
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
@@ -72,7 +67,6 @@ grype sbom:sbom.json
# 扫描特定目录
grype dir:/path/to/app
```
-
#### Snyk - 完整的安全平台
Snyk 提供了商业级的安全扫描服务,特别适合企业环境。
@@ -86,7 +80,6 @@ Snyk 提供了商业级的安全扫描服务,特别适合企业环境。
**基本使用:**
```bash
-
# 安装 Snyk CLI
npm install -g snyk
@@ -99,7 +92,6 @@ snyk container test docker-archive://image.tar
# 监控仓库
snyk monitor --docker
```
-
**工具对比表:**
| 特性 | Trivy | Grype | Snyk |
@@ -124,11 +116,9 @@ Syft 是 Anchore 推出的专业 SBOM 生成工具。
```bash
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
```
-
**生成 SBOM:**
```bash
-
# 从镜像生成 SBOM(多种格式)
syft docker:nginx:latest -o json > sbom.json
syft docker:nginx:latest -o spdx > sbom.spdx
@@ -140,7 +130,6 @@ syft dir:/path/to/app -o json > sbom.json
# 从 OCI 镜像档案生成
syft oci-archive:image.tar -o json > sbom.json
```
-
#### CycloneDX 与 SPDX 格式
两种主流的 SBOM 格式:
@@ -164,7 +153,6 @@ syft oci-archive:image.tar -o json > sbom.json
```
-
**SPDX 格式示例:**
```json
@@ -185,7 +173,6 @@ syft oci-archive:image.tar -o json > sbom.json
]
}
```
-
#### SBOM 的应用场景
**漏洞关联:**
@@ -193,11 +180,9 @@ syft oci-archive:image.tar -o json > sbom.json
当新的 CVE 被发现时,可快速查询受影响的应用:
```bash
-
# 使用 Grype 针对 SBOM 进行漏洞扫描
grype sbom:sbom.json --add-cpes-if-none
```
-
**合规性报告:**
将 SBOM 保存为构建产物,用于审计和合规性检查。
@@ -221,7 +206,6 @@ wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-am
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
```
-
**生成密钥对(传统方式):**
```bash
@@ -229,21 +213,17 @@ cosign generate-key-pair
# 生成 cosign.key 和 cosign.pub
```
-
**签名镜像:**
```bash
-
# 使用私钥签名(推送到仓库前)
cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
# 系统会提示输入私钥密码
```
-
**验证签名:**
```bash
-
# 使用公钥验证
cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
@@ -258,11 +238,9 @@ cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
# "optional": {...}
# }
```
-
**Keyless 签名(推荐用于 CI/CD):**
```bash
-
# 在 GitHub Actions 等 CI 中无需存储密钥
cosign sign --yes myregistry.com/myapp:v1.0.0
@@ -271,7 +249,6 @@ cosign verify myregistry.com/myapp:v1.0.0 \
--certificate-identity https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
```
-
#### Docker Content Trust 与 Notary
Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的签名解决方案。
@@ -279,7 +256,6 @@ Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的签
**启用 DCT:**
```bash
-
# 在环境中启用 DCT
export DOCKER_CONTENT_TRUST=1
@@ -291,24 +267,20 @@ docker push myregistry.com/myapp:v1.0.0
# 禁用 DCT(仅用于特定操作)
docker push --disable-content-trust myregistry.com/myapp:v1.0.0
```
-
**签名密钥管理:**
```bash
-
# 首次推送时会提示创建 Delegation Key
# 密钥存储在 ~/.docker/trust/private/root_keys/ 和 ~/.docker/trust/private/tuf_keys/
# 查看签名信息
docker inspect --format='{{.RepoDigests}}' myregistry.com/myapp:v1.0.0
```
-
### 18.6.4 供应链安全最佳实践
#### 1. 基础镜像安全
```dockerfile
-
# ❌ 不推荐:使用 latest 标签
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl
@@ -317,7 +289,6 @@ RUN apt-get update && apt-get install -y curl
FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e6e0e14...(完整 64 位哈希)
RUN apt-get update && apt-get install -y curl=7.68.0-1ubuntu1
```
-
#### 2. 构建时扫描
在 Dockerfile 中集成安全扫描:
@@ -337,11 +308,9 @@ RUN go build -o app .
FROM alpine:3.17@sha256:abcd1234...(请替换为实际完整的 64 位摘要哈希)
COPY --from=builder /app/app /app
```
-
#### 3. 运行时镜像扫描策略
```bash
-
# 镜像构建完成后立即扫描
trivy image --severity HIGH,CRITICAL \
--exit-code 1 \
@@ -351,13 +320,11 @@ trivy image --severity HIGH,CRITICAL \
# 定期扫描已部署的镜像
trivy image --scanners vuln,misconfig registry:5000/myapp:latest
```
-
#### 4. 镜像仓库安全配置
**Harbor(私有镜像仓库)的安全扫描:**
```yaml
-
# harbor.yml 配置示例
trivy:
enabled: true
@@ -368,7 +335,6 @@ trivy:
scan_on_push: true # 推送时自动扫描
scan_all: true # 扫描仓库中的所有镜像
```
-
#### 5. 政策执行
在 Kubernetes 环境中使用 Admission Webhook 强制镜像签名和扫描:
@@ -393,7 +359,6 @@ webhooks:
admissionReviewVersions: ["v1"]
sideEffects: None
```
-
### 18.6.5 CI/CD 中集成安全扫描
#### GitHub Actions 工作流示例
@@ -480,7 +445,6 @@ jobs:
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
```
-
#### GitLab CI 工作流示例
```yaml
@@ -545,7 +509,6 @@ push:
only:
- main
```
-
### 18.6.6 常见问题与最佳实践
**Q: 扫描报告中有过时的 CVE,如何处理?**
diff --git a/18_security/README.md b/18_security/README.md
index e014fdf..813261d 100644
--- a/18_security/README.md
+++ b/18_security/README.md
@@ -23,7 +23,6 @@ flowchart LR
Proc --> Mech
end
```
-
## 本章内容
本章涵盖 Docker 安全的多个层面,从内核隔离机制到运行时防护和供应链安全。
diff --git a/19_observability/19.1_prometheus.md b/19_observability/19.1_prometheus.md
index 2d94452..644be04 100644
--- a/19_observability/19.1_prometheus.md
+++ b/19_observability/19.1_prometheus.md
@@ -48,7 +48,6 @@ scrape_configs:
rule_files:
- /etc/prometheus/rules.yml
```
-
#### 2. 编写 Docker Compose 文件
创建 `compose.yaml` (或 `docker-compose.yml`):
@@ -106,13 +105,11 @@ networks:
volumes:
prometheus_data:
```
-
#### 3. 启动服务
```bash
$ docker compose up -d
```
-
启动后,访问以下地址:
* Prometheus: `http://localhost:9090`
@@ -208,7 +205,6 @@ groups:
summary: "磁盘可用空间不足"
description: "Instance={{ $labels.instance }}, Mountpoint={{ $labels.mountpoint }}"
```
-
说明:这里的规则是“可用空间低于 10%”的阈值告警,并非“未来 24 小时写满”的预测。生产环境建议针对特定文件系统与挂载点做更精确的过滤。
##### 2. 配置 Prometheus 加载规则并接入 Alertmanager
@@ -224,7 +220,6 @@ alerting:
- static_configs:
- targets: ["alertmanager:9093"]
```
-
并在 Compose 中挂载规则文件。
##### 3. 部署 Alertmanager
@@ -240,7 +235,6 @@ receivers:
webhook_configs:
- url: http://example.com/webhook
```
-
再在 `compose.yaml` 增加服务:
```yaml
@@ -253,7 +247,6 @@ receivers:
networks:
- monitoring
```
-
生产环境中,建议将告警发送到可追踪的渠道 (如 IM 机器人、事件平台、工单系统),并在告警中附带 Dashboard 链接与排障入口,避免告警成为噪声。
#### 建议的文件清单
diff --git a/19_observability/19.2_elk.md b/19_observability/19.2_elk.md
index 5ed9114..767549e 100644
--- a/19_observability/19.2_elk.md
+++ b/19_observability/19.2_elk.md
@@ -71,7 +71,6 @@ volumes:
networks:
logging:
```
-
#### 2. 配置 Fluentd
创建 `fluentd/conf/fluent.conf`:
@@ -102,7 +101,6 @@ networks:
```
-
#### 3. 配置应用容器使用 fluentd 驱动
启动一个测试容器,指定日志驱动为 `fluentd`:
@@ -115,7 +113,6 @@ docker run -d \
--name nginx-test \
nginx
```
-
**注意**:确保 `fluentd` 容器已经启动并监听在 `localhost:24224`。在生产环境中,如果你是在不同机器上,需要将 `localhost` 替换为运行 fluentd 的主机 IP。
#### 4. 在 Kibana 中查看日志
diff --git a/19_observability/19.3_performance_optimization.md b/19_observability/19.3_performance_optimization.md
index e8657a2..35792e5 100644
--- a/19_observability/19.3_performance_optimization.md
+++ b/19_observability/19.3_performance_optimization.md
@@ -48,7 +48,6 @@
**基本使用:**
```bash
-
# 实时监控所有运行中的容器
docker stats
@@ -72,7 +71,6 @@ docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" --no-s
# 导出为 JSON 格式用于日志记录
docker stats --format json --no-stream > stats.json
```
-
**在脚本中使用:**
```bash
@@ -86,16 +84,13 @@ while true; do
sleep 10
done
```
-
**性能指标解读:**
```bash
-
# CPU % 超过 80%:需要增加 CPU 限制或优化应用
# MEM % 接近 100%:容器即将 OOM,需要增加内存或排查内存泄漏
# 如果 NET I/O 中 dropped 为非零:网络拥塞或丢包
```
-
### 19.3.3 cAdvisor 容器监控系统
cAdvisor 是 Google 开发的容器监控工具,提供比 `docker stats` 更详细的性能数据。
@@ -125,7 +120,6 @@ networks:
monitoring:
driver: bridge
```
-
启动后访问 `http://localhost:8080` 查看:
- 容器性能统计
- 系统资源使用情况
@@ -134,7 +128,6 @@ networks:
**从 cAdvisor 提取指标:**
```bash
-
# 获取所有容器的 JSON 格式性能数据
curl http://localhost:8080/api/v1.3/machine | jq .
@@ -144,11 +137,9 @@ curl http://localhost:8080/api/v1.3/docker | jq '.docker | keys' | head -5
# 获取容器统计信息
curl http://localhost:8080/api/v1.3/docker/abc123/ | jq '.stats[-1]'
```
-
**与 Prometheus 集成:**
```yaml
-
# prometheus.yml 配置
global:
scrape_interval: 15s
@@ -159,7 +150,6 @@ scrape_configs:
- targets: ['localhost:8080']
metrics_path: '/metrics'
```
-
### 19.3.4 Prometheus 容器监控配置
使用 Prometheus 和 node-exporter 进行长期的容器性能监控。
@@ -234,7 +224,6 @@ networks:
monitoring:
driver: bridge
```
-
**Prometheus 配置文件(prometheus.yml):**
```yaml
@@ -259,11 +248,9 @@ scrape_configs:
static_configs:
- targets: ['localhost:9323']
```
-
**常用的 Prometheus 查询(PromQL):**
```text
-
# 容器 CPU 使用百分比
rate(container_cpu_usage_seconds_total[5m]) * 100
@@ -288,13 +275,11 @@ container_memory_cache_bytes / container_memory_usage_bytes
# 按镜像统计容器数
count(container_memory_usage_bytes) by (image)
```
-
### 19.3.5 容器 OOM 排查与内存限制调优
#### OOM 问题诊断
```bash
-
# 检查容器是否因 OOM 被杀死
docker inspect | grep OOMKilled
@@ -308,7 +293,6 @@ docker logs 2>&1 | grep -i "out of memory\|oom"
dmesg | grep -i "oom\|kill"
journalctl -u docker -n 100 | grep -i "oom"
```
-
#### 内存泄漏检测
使用专项工具分析应用内存使用:
@@ -316,7 +300,6 @@ journalctl -u docker -n 100 | grep -i "oom"
**Python 应用内存泄漏检测:**
```python
-
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
@@ -326,9 +309,7 @@ RUN pip install -r requirements.txt memory_profiler tracemalloc
COPY app.py .
CMD ["python", "-m", "memory_profiler", "app.py"]
```
-
```python
-
# app.py - 内存泄漏示例
from memory_profiler import profile
import tracemalloc
@@ -351,11 +332,9 @@ current, peak = tracemalloc.get_traced_memory()
print(f"Current: {current / 1024 / 1024:.2f} MB")
print(f"Peak: {peak / 1024 / 1024:.2f} MB")
```
-
**Java 应用内存分析:**
```bash
-
# 在容器中启用 JVM 远程调试
docker run -e JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC" \
-p 5005:5005 \
@@ -368,11 +347,9 @@ jstat -gc 1000 # 每秒采样一次
# S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU
# 6144 6144 0 6144 39424 12288 149504 84320 50552 47689 6464 5989
```
-
#### 内存限制最佳实践
```bash
-
# 为容器设置内存限制
docker run -m 512m --memory-swap 1g myapp:latest
@@ -392,11 +369,9 @@ services:
reservations:
memory: 256M
```
-
**内存超额提交(Memory Overcommit):**
```bash
-
# 在 Docker Compose 中区分限制和预留
# limits:绝不能超过的最大值
# reservations:Compose 排期时的参考值
@@ -410,7 +385,6 @@ services:
memory: 2G
memory_reservation: 1G # 预留 1GB,允许突发到 2GB
```
-
### 19.3.6 镜像体积优化与多阶段构建
#### 镜像体积分析工具
@@ -418,7 +392,6 @@ services:
**使用 dive 分析镜像层:**
```bash
-
# 安装 dive
wget https://github.com/wagoodman/dive/releases/download/v0.11.0/dive_0.11.0_linux_amd64.deb
sudo apt install ./dive_0.11.0_linux_amd64.deb
@@ -428,11 +401,9 @@ dive myapp:latest
# 输出详细的分层信息,显示每一层的大小和内容
```
-
**使用 Dockerfile 分析工具:**
```bash
-
# 安装 hadolint
curl https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 -L -o hadolint
chmod +x hadolint
@@ -440,13 +411,11 @@ chmod +x hadolint
# 检查 Dockerfile 最佳实践
./hadolint Dockerfile
```
-
#### 多阶段构建最佳实践
**Go 应用的最小化镜像构建:**
```dockerfile
-
# Stage 1: 构建阶段
FROM golang:1.20-alpine AS builder
@@ -479,11 +448,9 @@ ENTRYPOINT ["/app"]
# 最终镜像大小通常 < 15MB(相比 golang:1.20-alpine 的 ~1GB)
```
-
**Node.js 应用的多阶段构建:**
```dockerfile
-
# Stage 1: 依赖安装
FROM node:18-alpine AS dependencies
@@ -526,11 +493,9 @@ CMD ["node", "dist/index.js"]
# 不优化:~500MB
# 多阶段构建后:~120MB(减少 76%)
```
-
**Python 应用的多阶段构建:**
```dockerfile
-
# Stage 1: 构建阶段
FROM python:3.11-slim AS builder
@@ -563,11 +528,9 @@ EXPOSE 5000
CMD ["python", "app.py"]
```
-
#### 镜像体积优化检查清单
```bash
-
# 检查清单
□ 使用精简基础镜像(Alpine、Distroless)
□ 清理包管理器缓存(apt-get clean、rm -rf /var/cache/*)
@@ -595,7 +558,6 @@ RUN apt-get update && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
```
-
### 19.3.7 常见性能问题及解决方案
**问题 1: 容器频繁被 OOM 杀死**
@@ -603,7 +565,6 @@ RUN apt-get update && \
症状:容器进程被无故杀死,exit code 137
解决方案:
```bash
-
# 增加内存限制
docker update -m 1g
@@ -616,13 +577,11 @@ docker stats
# 启用内存交换(作为最后手段)
docker run -m 512m --memory-swap 1g myapp:latest
```
-
**问题 2: CPU 被限流(CPU Throttling)**
症状:应用性能突然下降,但 CPU 使用率不高
诊断:
```bash
-
# 查看 CPU 限流统计
docker exec cat /sys/fs/cgroup/cpu/cpu.stat
@@ -630,12 +589,10 @@ docker exec cat /sys/fs/cgroup/cpu/cpu.stat
# 解决方案:增加 CPU 限制
docker update --cpus 2
```
-
**问题 3: 网络丢包或延迟高**
诊断:
```bash
-
# 进入容器检查网络状态
docker exec ip -s link show
diff --git a/20_cases_os/20.1_busybox.md b/20_cases_os/20.1_busybox.md
index 631e01d..60ab74b 100644
--- a/20_cases_os/20.1_busybox.md
+++ b/20_cases_os/20.1_busybox.md
@@ -23,7 +23,6 @@ Digest: sha256:c6b45a95f932202dbb27c31333c4789f45184a744060f6e569cc9d2bf1b9ad6f
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
```
-
下载后,可以看到 `busybox` 镜像只有 **2.433 MB**:
```bash
@@ -31,7 +30,6 @@ $ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
busybox latest e72ac664f4f0 6 weeks ago 2.433 MB
```
-
### 20.1.3 运行 busybox
启动一个 `busybox` 容器,并在容器中执行 `grep` 命令。
@@ -68,7 +66,6 @@ Search for PATTERN in FILEs (or stdin)
-e PTRN Pattern to match
-f FILE Read pattern from file
```
-
查看容器内的挂载信息。
```bash
@@ -107,7 +104,6 @@ tmpfs on /proc/timer_list type tmpfs (rw,nosuid,size=65536k,mode=755)
tmpfs on /proc/sched_debug type tmpfs (rw,nosuid,size=65536k,mode=755)
tmpfs on /sys/firmware type tmpfs (ro,relatime)
```
-
`busybox` 镜像虽然小巧,但包括了大量常见的 `Linux` 命令,读者可以用它快速熟悉 `Linux` 命令。
### 20.1.4 相关资源
diff --git a/20_cases_os/20.2_alpine.md b/20_cases_os/20.2_alpine.md
index 62fb072..e47a13e 100644
--- a/20_cases_os/20.2_alpine.md
+++ b/20_cases_os/20.2_alpine.md
@@ -25,7 +25,6 @@ debian latest 4d6ce913b130 84.98 MB
ubuntu latest b39b81afc8ca 188.3 MB
centos latest 8efe422e6104 210 MB
```
-
### 20.2.2 获取并使用官方镜像
由于镜像很小,下载时间往往很短,读者可以直接使用 `docker run` 指令直接运行一个 `Alpine` 容器,并指定运行的 Linux 指令,例如:
@@ -34,7 +33,6 @@ centos latest 8efe422e6104 210 MB
$ docker run alpine echo '123'
123
```
-
### 20.2.3 迁移至 Alpine 基础镜像
目前,大部分 Docker 官方镜像都已经支持 `Alpine` 作为基础镜像,可以很容易进行迁移。
@@ -50,21 +48,18 @@ $ docker run alpine echo '123'
```bash
$ apk add --no-cache
```
-
`Alpine` 中软件安装包的名字可能会与其他发行版有所不同,可以在 `https://pkgs.alpinelinux.org/packages` 网站搜索并确定安装包名称。如果需要的安装包不在主索引内,但是在测试或社区索引中。那么可以按照以下方法使用这些安装包。
```bash
$ echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
$ apk --update add --no-cache
```
-
由于在国内访问 `apk` 仓库较缓慢,建议在使用 `apk` 之前先替换仓库地址为国内镜像。
```docker
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \
&& apk add --no-cache
```
-
### 20.2.4 相关资源
* `Alpine` 官网:https://www.alpinelinux.org/
diff --git a/20_cases_os/20.3_debian.md b/20_cases_os/20.3_debian.md
index 85b3807..1fdc569 100644
--- a/20_cases_os/20.3_debian.md
+++ b/20_cases_os/20.3_debian.md
@@ -27,7 +27,6 @@ $ docker run -it debian bash
root@668e178d8d69:/# cat /etc/issue
Debian GNU/Linux 8
```
-
`Debian` 镜像很适合作为基础镜像,构建自定义镜像。
### 20.3.2 Ubuntu 系统简介
@@ -62,7 +61,6 @@ HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
```
-
当试图直接使用 `apt-get` 安装一个软件的时候,会提示 `E: Unable to locate package`。
```bash
@@ -72,7 +70,6 @@ Building dependency tree... Done
Reading state information... Done
E: Unable to locate package curl
```
-
这并非系统不支持 `apt-get` 命令。Docker 镜像在制作时为了精简清除了 `apt` 仓库信息,因此需要先执行 `apt-get update` 命令来更新仓库信息。更新信息后即可成功通过 `apt-get` 命令来安装软件。
```bash
@@ -83,7 +80,6 @@ Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Fetched 25.8 MB in 8s (3215 kB/s)
Reading package lists... Done
```
-
首先,安装 `curl` 工具。
```bash
@@ -98,7 +94,6 @@ The following additional packages will be installed:
root@7d93de07bf76:/# curl
curl: try 'curl --help' or 'curl --manual' for more information
```
-
接下来,再安装 `apache` 服务。
```bash
@@ -110,7 +105,6 @@ The following additional packages will be installed:
apache2-bin apache2-data apache2-utils file libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap libexpat1 libgdbm-compat4 libgdbm5 libicu60 liblua5.2-0 libmagic-mgc libmagic1 libperl5.26 libxml2 mime-support netbase perl perl-modules-5.26 ssl-cert xz-utils
...
```
-
启动这个 `apache` 服务,然后使用 `curl` 来测试本地访问。
```bash
@@ -132,7 +126,6 @@ root@7d93de07bf76:/# curl 127.0.0.1