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

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

View File

@@ -4,9 +4,11 @@
### 一般性的指南和建议
本节涵盖了相关内容与详细描述主要探讨以下几个方面
#### 容器应该是短暂的
通过 `Dockerfile` 构建的镜像所启动的容器应该尽可能短暂生命周期短短暂意味着可以停止和销毁容器并且创建一个新容器并部署好所需的设置和配置工作量应该是极小的
通过 `Dockerfile` 构建的镜像所启动的容器应该尽可能短暂 (生命周期短)短暂 意味着可以停止和销毁容器并且创建一个新容器并部署好所需的设置和配置工作量应该是极小的
#### 使用 `.dockerignore` 文件
@@ -14,7 +16,7 @@
#### 使用多阶段构建
Docker 17.05 以上版本中你可以使用 [多阶段构建](../07_dockerfile/7.17_multistage_builds.md) 来减少所构建镜像的大小
Docker 17.05 以上版本中你可以使用[多阶段构建](../07_dockerfile/7.17_multistage_builds.md)来减少所构建镜像的大小
#### 避免安装不必要的包
@@ -22,17 +24,17 @@
#### 一个容器只运行一个进程
应该保证在一个容器中只运行一个进程将多个应用解耦到不同容器中保证了容器的横向扩展和复用例如 web 应用应该包含三个容器web应用数据库缓存
应该保证在一个容器中只运行一个进程将多个应用解耦到不同容器中保证了容器的横向扩展和复用例如 web 应用应该包含三个容器web 应用数据库缓存
如果容器互相依赖你可以使用 [Docker 自定义网络](../08_data_network/network/README.md) 来把这些容器连接起来
如果容器互相依赖你可以使用 [Docker 自定义网络](../08_data_network/network/README.md)来把这些容器连接起来
#### 镜像层数尽可能少
你需要在 `Dockerfile` 可读性也包括长期的可维护性和减少层数之间做一个平衡
你需要在 `Dockerfile` 可读性 (也包括长期的可维护性) 和减少层数之间做一个平衡
#### 将多行参数排序
将多行参数按字母顺序排序比如要安装多个包时这可以帮助你避免重复包含同一个包更新包列表时也更容易也便于 `PRs` 阅读和审查建议在反斜杠符号 `\` 之前添加一个空格以增加可读性
将多行参数按字母顺序排序 (比如要安装多个包时)这可以帮助你避免重复包含同一个包更新包列表时也更容易也便于 `PRs` 阅读和审查建议在反斜杠符号 `\` 之前添加一个空格以增加可读性
下面是来自 `buildpack-deps` 镜像的例子
@@ -51,7 +53,7 @@ RUN apt-get update && apt-get install -y \
但是如果你想在构建的过程中使用缓存你得明白什么时候会什么时候不会找到匹配的镜像遵循的基本规则如下
* 从一个基础镜像开始`FROM` 指令指定下一条指令将和该基础镜像的所有子镜像进行匹配检查这些子镜像被创建时使用的指令是否和被检查的指令完全一样如果不是则缓存失效
* 从一个基础镜像开始 (`FROM` 指令指定)下一条指令将和该基础镜像的所有子镜像进行匹配检查这些子镜像被创建时使用的指令是否和被检查的指令完全一样如果不是则缓存失效
* 在大多数情况下只需要简单地对比 `Dockerfile` 中的指令和子镜像然而有些指令需要更多的检查和解释
* 对于 `ADD` `COPY` 指令镜像中对应文件的内容也会被检查每个文件都会计算出一个校验和文件的最后修改时间和最后访问时间不会纳入校验在缓存的查找过程中会将这些校验和和已存在镜像中的文件校验和进行对比如果文件有任何改变比如内容和元数据则缓存失效
* 除了 `ADD` `COPY` 指令缓存匹配过程不会查看临时容器中的文件来决定缓存是否匹配例如当执行完 `RUN apt-get -y update` 指令后容器中一些文件被更新 Docker 不会检查这些文件这种情况下只有指令字符串本身被用来匹配缓存
@@ -64,7 +66,7 @@ RUN apt-get update && apt-get install -y \
#### FROM
尽可能使用当前官方仓库作为你构建镜像的基础推荐使用 [Alpine](https://hub.docker.com/_/alpine/) 镜像,因为它被严格控制并保持最小尺寸目前小于 5 MB,但它仍然是一个完整的发行版。
尽可能使用当前官方仓库作为你构建镜像的基础推荐使用 [Alpine](https://hub.docker.com/_/alpine/) 镜像,因为它被严格控制并保持最小尺寸 (目前小于 5 MB),但它仍然是一个完整的发行版。
#### LABEL
@@ -102,11 +104,15 @@ LABEL vendor=ACME\ Incorporated \
为了保持 `Dockerfile` 文件的可读性可理解性以及可维护性建议将长的或复杂的 `RUN` 指令用反斜杠 `\` 分割成多行
##### 概述
总体概述了以下内容
##### apt-get
`RUN` 指令最常见的用法是安装包用的 `apt-get`因为 `RUN apt-get` 指令会安装包所以有几个问题需要注意
不要使用 `RUN apt-get upgrade` `dist-upgrade`因为许多基础镜像中的必须包不会在一个非特权容器中升级如果基础镜像中的某个包过时了你应该联系它的维护者如果你确定某个特定的包比如 `foo`需要升级使用 `apt-get install -y foo` 就行该指令会自动升级 `foo`
不要使用 `RUN apt-get upgrade` `dist-upgrade`因为许多基础镜像中的 必须 包不会在一个非特权容器中升级如果基础镜像中的某个包过时了你应该联系它的维护者如果你确定某个特定的包比如 `foo`需要升级使用 `apt-get install -y foo` 就行该指令会自动升级 `foo`
永远将 `RUN apt-get update` `apt-get install` 组合成一条 `RUN` 声明例如
@@ -174,9 +180,9 @@ RUN apt-get update && apt-get install -y \
#### CMD
`CMD` 指令用于执行目标镜像中包含的软件可以包含参数`CMD` 大多数情况下都应该以 `CMD ["executable", "param1", "param2"...]` 的形式使用因此如果创建镜像的目的是为了部署某个服务(比如 `Apache`)你可能会执行类似于 `CMD ["apache2", "-DFOREGROUND"]` 形式的命令我们建议任何服务镜像都使用这种形式的命令
`CMD` 指令用于执行目标镜像中包含的软件可以包含参数`CMD` 大多数情况下都应该以 `CMD ["executable", "param1", "param2"...]` 的形式使用因此如果创建镜像的目的是为了部署某个服务 (比如 `Apache`)你可能会执行类似于 `CMD ["apache2", "-DFOREGROUND"]` 形式的命令我们建议任何服务镜像都使用这种形式的命令
多数情况下`CMD` 都需要一个交互式的 `shell` (bash, Python, perl )例如 `CMD ["perl", "-de0"]`或者 `CMD ["PHP", "-a"]`使用这种形式意味着当你执行类似 `docker run -it python` 你会进入一个准备好的 `shell` `CMD` 应该在极少的情况下才能以 `CMD ["param", "param"]` 的形式与 `ENTRYPOINT` 协同使用除非你和你的镜像使用者都对 `ENTRYPOINT` 的工作方式十分熟悉
多数情况下`CMD` 都需要一个交互式的 `shell` (bashPythonperl )例如 `CMD ["perl", "-de0"]`或者 `CMD ["PHP", "-a"]`使用这种形式意味着当你执行类似 `docker run -it python` 你会进入一个准备好的 `shell` `CMD` 应该在极少的情况下才能以 `CMD ["param", "param"]` 的形式与 `ENTRYPOINT` 协同使用除非你和你的镜像使用者都对 `ENTRYPOINT` 的工作方式十分熟悉
#### EXPOSE
@@ -206,7 +212,7 @@ ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
#### ADD COPY
虽然 `ADD` `COPY` 功能类似但一般优先使用 `COPY`因为它比 `ADD` 更透明`COPY` 只支持简单将本地文件拷贝到容器中 `ADD` 有一些并不明显的功能比如本地 tar 提取和远程 URL 支持因此`ADD` 的最佳用例是将本地 tar 文件自动提取到镜像中例如 `ADD rootfs.tar.xz`
虽然 `ADD` `COPY` 功能类似但一般优先使用 `COPY`因为它比 `ADD` 更透明`COPY` 只支持简单将本地文件拷贝到容器中 `ADD` 有一些并不明显的功能 (比如本地 tar 提取和远程 URL 支持)因此`ADD` 的最佳用例是将本地 tar 文件自动提取到镜像中例如 `ADD rootfs.tar.xz`
如果你的 `Dockerfile` 有多个步骤需要使用上下文中不同的文件单独 `COPY` 每个文件而不是一次性的 `COPY` 所有文件这将保证每个步骤的构建缓存只在特定的文件变化时失效例如
@@ -245,9 +251,9 @@ RUN mkdir -p /usr/src/things \
#### ENTRYPOINT
`ENTRYPOINT` 的最佳用处是设置镜像的主命令允许将镜像当成命令本身来运行 `CMD` 提供默认选项
`ENTRYPOINT` 的最佳用处是设置镜像的主命令允许将镜像当成命令本身来运行 ( `CMD` 提供默认选项)
例如下面的示例镜像提供了命令行工具 `s3cmd`:
例如下面的示例镜像提供了命令行工具 `s3cmd`
```docker
ENTRYPOINT ["s3cmd"]
@@ -330,7 +336,7 @@ $ docker run --rm -it postgres bash
>注意在镜像中用户和用户组每次被分配的 UID/GID 都是不确定的下次重新构建镜像时被分配到的 UID/GID 可能会不一样如果要依赖确定的 UID/GID你应该显式的指定一个 UID/GID
你应该避免使用 `sudo`因为它不可预期的 TTY 和信号转发行为可能造成的问题比它能解决的问题还多如果你真的需要和 `sudo` 类似的功能例如 root 权限初始化某个守护进程以非 root 权限执行它你可以使用 [gosu](https://github.com/tianon/gosu)。
你应该避免使用 `sudo`因为它不可预期的 TTY 和信号转发行为可能造成的问题比它能解决的问题还多如果你真的需要和 `sudo` 类似的功能 (例如 root 权限初始化某个守护进程以非 root 权限执行它)你可以使用 [gosu](https://github.com/tianon/gosu)。
最后为了减少层数和复杂度避免频繁地使用 `USER` 来回切换用户