Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion 03_install/3.1_ubuntu.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,12 @@ $ 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` 用户组。
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。

> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
>
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。

建立 `docker` 组:

Expand Down
7 changes: 6 additions & 1 deletion 03_install/3.2_debian.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,12 @@ $ 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` 用户组。
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。

> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
>
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。

建立 `docker` 组:

Expand Down
7 changes: 6 additions & 1 deletion 03_install/3.3_fedora.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,12 @@ $ 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` 用户组。
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。

> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
>
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。

建立 `docker` 组:

Expand Down
7 changes: 6 additions & 1 deletion 03_install/3.4_centos.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,12 @@ $ 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` 用户组。
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。

> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
>
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。

建立 `docker` 组:

Expand Down
7 changes: 6 additions & 1 deletion 03_install/3.5_raspberry-pi.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,12 @@ $ 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` 用户组。
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。

> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
>
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。

建立 `docker` 组:

Expand Down
9 changes: 4 additions & 5 deletions 06_repository/6.1_dockerhub.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,13 @@ $ docker push username/myapp:v1
在 Account Settings -> Security 中启用 2FA,保护账号安全。启用后,CLI 登录需要使用 **Access Token** 而非密码。

#### 2. 使用 Access Token
> **⚠️ 警告**:绝不要在脚本或 CI/CD 系统中,直接使用 `-p` 参数传递密码或 Token (类似 `docker login -p xxx`)!这会导致凭证直接暴露在系统的命令历史、进程列表和终端输出中。

不要在脚本或 CI/CD 中直接使用登录密码。

1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token。
2. 使用 Token 作为密码登录:
1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token (PAT)。
2. 将 Token 通过标准输入 (stdin) 安全传递给 Docker:

```bash
$ docker login -u username -p dckr_pat_xxxxxxx
$ echo "dckr_pat_xxxxxxx" | docker login --username username --password-stdin
```

#### 3. 关注镜像漏洞
Expand Down
4 changes: 3 additions & 1 deletion 08_data/8.1_volume.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,11 @@ $ docker run -d \
| 特性 | --mount | -v |
|------|---------|-----|
| 语法 | 键值对,更清晰 | 冒号分隔,更简洁 |
| 自动创建卷 | source 不存在会报错 | 自动创建 |
| 自动创建卷 | source 不存在会自动创建 | 自动创建 |
| 推荐程度 | ✅ 推荐 (更明确)| 常用 (更简洁)|

> **提示**:很多人误以为 `--mount` 遇到目标不存在时总是报错。实际上,那仅适用于**绑定挂载 (Bind Mount)**。对于**数据卷 (Volume)**,只要 `source` 指定的卷名称不存在,Docker 都会默默将其创建出来。

#### 只读挂载

```bash
Expand Down
4 changes: 3 additions & 1 deletion 08_data/8.2_bind-mounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ $ docker run -d \
| 特性 | --mount | -v |
|------|---------|-----|
| 语法 | 键值对,更清晰 | 冒号分隔,更简洁 |
| 路径不存在时 | 报错 | 自动创建目录 |
| 路径不存在时 | 直接报错 (Fail Fast) | 静默自动创建**目录** |
| 推荐程度 | ✅ 推荐 | 常用 |

> **⚠️ 陷阱**:如果不小心挂载了一个不存在的宿主机路径,使用 `-v` 会在宿主机上静默创建一个**空目录**(即使你本来想挂载的是一个文件),这常常会导致权限错误或应用无法正常读取。这也正是为什么 Docker 官方更推荐使用 `--mount` 的原因:它会遵循“Fail Fast”原则直接报错,避免弄巧成拙。

---

### 8.2.4 使用场景
Expand Down
10 changes: 5 additions & 5 deletions 09_network/9.1_dns.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Docker 1.10.0 以后,内建了一个 DNS 服务器,使得容器可以直接

但是使用 Docker DNS 有个前提条件,就是它只能在 **自定义网络** 中使用。也就是说,如果使用的是默认的 `bridge` 网络,是无法使用 DNS 的,所以我们就需要自定义网络。

### 9.2.1 容器的 DNS 机制
### 9.1.1 容器的 DNS 机制

Docker 容器的 DNS 配置有两种情况:

Expand All @@ -13,7 +13,7 @@ Docker 容器的 DNS 配置有两种情况:

---

### 9.2.2 嵌入式 DNS
### 9.1.2 嵌入式 DNS

这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过 “名字” 找到彼此,而不需要知道对方的 IP (因为 IP 可能会变)。

Expand All @@ -38,7 +38,7 @@ Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器。容器内的

---

### 9.2.3 配置 DNS 参数
### 9.1.3 配置 DNS 参数

如果你需要手动配置容器的 DNS (例如使用内网 DNS 服务器),可以在 `docker run` 中使用以下参数:

Expand Down Expand Up @@ -69,7 +69,7 @@ $ docker run -h myweb nginx

---

### 9.2.4 全局 DNS 配置
### 9.1.4 全局 DNS 配置

如果希望所有容器都使用特定的 DNS 服务器 (而不是继承宿主机),可以修改 `/etc/docker/daemon.json`:

Expand All @@ -86,7 +86,7 @@ $ docker run -h myweb nginx

---

### 9.2.5 常见问题
### 9.1.5 常见问题

以下是使用容器 DNS 时常见的问题及解决方法:

Expand Down
9 changes: 9 additions & 0 deletions 10_buildx/10.2_buildx.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ $ docker buildx build --sbom=true -t myimage .

该命令会在构建结果中包含 SPDX 或 CycloneDX 格式的 SBOM 数据。

> **⚠️ 注意与失败模式**:
> 要使 SBOM (或其它 attestation 元数据) 成功附着并可见,对底层的存储格式有前置要求:默认的 classic image store 不支持 manifest list/index 这种存放 attestation 的结构。
>
> 如果只简单运行上述命令,你可能会面临**“命令成功执行,但本地镜像中看不到 SBOM”**的体会落差。
>
> **正确的解决路径有两条**:
> 1. 在 Docker 守护进程中启用 `containerd image store` 特性(现代 Docker Desktop 默认推荐)。
> 2. 或者使用 `docker-container` driver 的构建器,并直接**加上 `--push` 参数**将产物推送到远端支持 OCI 的镜像仓库,仓库会正确保存这些元数据。

### 10.2.2 官方文档

* https://docs.docker.com/engine/reference/commandline/buildx/
4 changes: 4 additions & 0 deletions 11_compose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

`Docker Compose` 是 Docker 官方编排 (Orchestration) 项目之一,负责快速的部署分布式应用。

> ⚠️ **重要提示:Compose V1 已停止支持**
>
> 早期基于 Python 编写的 Compose V1(命令为 `docker-compose`)已于 2023 年中正式停止支持。现已全面升级为基于 Go 编写的 Compose V2,作为 Docker CLI 的官方插件提供(命令为 `docker compose`,中间为空格)。本书强烈推荐且后续章节均以 V2 为核心标准进行讲解。

本章将介绍 `Compose` 项目情况以及安装和使用。

* [简介](11.1_introduction.md)
Expand Down
8 changes: 6 additions & 2 deletions 14_kubernetes_setup/14.2_kubeadm-docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

`kubeadm` 提供了 `kubeadm init` 以及 `kubeadm join` 这两个命令,作为快速创建 `Kubernetes` 集群的最佳实践。

> ⚠️ **重要说明**:自 Kubernetes 1.24 起,内置 `dockershim` 已被移除,Kubernetes 默认不再直接使用 Docker Engine 作为容器运行时 (CRI)。因此,**更推荐参考** 同目录下的《[使用 kubeadm 部署 Kubernetes (CRI 使用 containerd)](14.1_kubeadm.md)》。
> ⚠️ **强烈提示:Docker 与 Kubernetes 环境的时代分界**
>
> 本文档主要用于历史环境/学习目的:如果你确实需要在较新版本中继续使用 Docker Engine,通常需要额外部署 `cri-dockerd` 并在 `kubeadm init/join` 中指定 `--cri-socket`。
> 自 Kubernetes v1.24 起,内置的 `dockershim` 组件已被正式移除。这意味着 **Kubernetes 不再将 Docker Engine 作为默认内置的容器运行时**。虽然 Docker 仍然是你本地构建、管理镜像的绝佳工具,但它已不再是 kubelet 的默认运行时选项。
>
> 因此,**强烈推荐** 读者直接参考同目录下的《[使用 kubeadm 部署 Kubernetes (CRI 使用 containerd)](14.1_kubeadm.md)》作为主要的部署路线。
>
> 本文档保留,主要用于历史环境维护或特殊需求场景:如果你必须在较新的 Kubernetes 集群中继续使用 Docker Engine 作为底层运行时,你必须理解 CRI 层机制,额外部署并配置第三方兼容层 `cri-dockerd`,同时在部署时手动补充 `--cri-socket` 等参数约束。

### 14.2.1 安装 Docker

Expand Down
11 changes: 8 additions & 3 deletions 21_case_devops/21.1_devops_workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ build_image:
services:
- docker:20.10.16-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD \
$CI_REGISTRY
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Expand All @@ -81,4 +80,10 @@ deploy_staging:

1. **不可变基础设施**:一旦镜像构建完成,在各个环境(Dev、Staging、Prod)中都应该使用同一个镜像 tag(通常是 commit hash),而不是重新构建。
2. **配置分离**:使用 ConfigMap 和 Secret 管理环境特定的配置,不要打包进镜像。
3. **GitOps**:考虑引入 ArgoCD,将部署配置也作为代码存储在 Git 中,实现 Git 驱动的部署同步。
3. **应对 Docker Hub 限额 (Rate Limits)**:
- Docker Hub 对匿名拉取实施了严格的限制 (6小时内约100次)。若在 CI/CD 中频繁构建,极易触发 `toomanyrequests` 错误。
- **最佳策略**:
- 在流水线开头始终执行安全的身份认证 (使用 PAT,而非密码)。
- 将常用的基础镜像缓存到自建的 Harbor/Nexus,使用 Pull-Through Cache。
- 开启 Docker 构建引擎 (BuildKit) 的 inline 或 registry 缓存功能,以降低全量拉取频率。
4. **GitOps**:考虑引入 ArgoCD,将部署配置也作为代码存储在 Git 中,实现 Git 驱动的部署同步。
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![图](https://img.shields.io/github/stars/yeasy/docker_practice.svg?style=social&label=Stars)](https://github.com/yeasy/docker_practice) [![图](https://img.shields.io/github/release/yeasy/docker_practice/all.svg)](https://github.com/yeasy/docker_practice/releases) [![图](https://img.shields.io/badge/Based-Docker%20Engine%20v29.x-blue.svg)](https://docs.docker.com/engine/release-notes/) [![图](https://img.shields.io/badge/Docker%20%E6%8A%80%E6%9C%AF%E5%85%A5%E9%97%A8%E4%B8%8E%E5%AE%9E%E6%88%98-jd.com-red.svg)][1]

**v1.6.0**
**v1.6.1**

[Docker](https://www.docker.com) 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!

Expand Down
1 change: 1 addition & 0 deletions appendix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
* [**如何调试 Docker**](debug.md):介绍 Docker 调试技巧和工具。
* [**资源链接**](resources.md):推荐更多 Docker 相关的学习资源。
* [**术语词表**](glossary.md):统一全书中英文术语、缩写与命令写法。
* [**示例规范与写作公约**](example_guidelines.md):全书修改与贡献必须遵守的安全、格式及内容基线要求。
41 changes: 41 additions & 0 deletions appendix/example_guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 附录八:本书示例规范与写作公约

为了保证本书在漫长的技术迭代中保持高质量、高安全性以及良好的可读性,我们确立了以下项目写作规范。所有的修改与贡献都必须遵循这些原则。

## 1. 安全与凭据处理

任何示例文档中都**严禁出现将凭据以明文形式直接传递给命令参数**的做法。

* **错误示例**:`docker login -u myuser -p mysecretpassword` (这会导致密码泄露到历史记录及进程列表中)
* **正确示例(交互式)**:推荐读者直接使用 `docker login` (优先使用官方 Device Code Flow)。
* **正确示例(自动化)**:使用标准输入流传递 Token:`echo $PAT | docker login -u myuser --password-stdin`

## 2. 失败模式与前置条件说明

许多现代 Docker 功能 (如 Buildx, SBOM, Kubernetes CRI 集成) 均需要特定的后端存储或者组件支持。在介绍这些进阶命令时,必须:

* **明确声明前置条件**:例如,“此功能需要开启 containerd image store” 或 “需要额外配置 `--push`”。
* **描述失败现象**:明确告诉读者,“如果你不这么配置,命令仍会提示成功,但产物将不可见/被丢弃”。

## 3. 统一使用 "docker compose" 命令

早期 Python 编写的 `docker-compose` (V1) 已停止支持。

* **全书统一标准**:所有的编排命令必须书写为 `docker compose` (带空格的 V2 CLI 插件版)。
* 不得在新的文档和案例中提及或使用旧版格式,除非是为了特意说明 V1 到 V2 的迁移。

## 4. 可复现性目标 (以可重建为目标)

本书中的所有实战和案例 (尤其 OS 与 DevOps 章节) 应尽量给出“最小可复现实验环境”。

* 提供明确的基础镜像版本要求 (不要盲目依赖 `latest`)。
* 明确宿主机的生命周期窗口(例如明确注出 Ubuntu 20.04 的支持结束时间)。

## 5. Markdown 格式纪律

我们使用自动化的格式检查工具 (`check_project_rules.py`) 进行 Lint。以下是必须遵守的排版底线:

* **加粗与空格**:加粗符号内不得有空格(`**错误 黑体**` ❌, `**正确黑体**` ✅)。
* **标题间距**:标题后必须跟恰好一个空行。
* **中文标点**:正文叙述部分的引号必须使用中文弯引号 `“”`,不得使用英文直引号 `""`(除了代码块或 Mermaid 图表中)。
* **层级与桥接**:禁止跳跃级别使用标题 (如 H2 后直接接 H4);且带有子标题的章节,在进入第一个子标题前,必须要有引导/过渡段落介绍该节内容。