Skip to content

编写 Dockerfile 的通用最佳实践

原文:https://docs.docker.com/develop/develop-images/guidelines/

使用多阶段构建

多阶段构建让您可以通过创建干净的分离来减小最终镜像的大小,确保结果输出只包含运行应用所需的文件。 将您的 Dockerfile 指令分成不同阶段,确保最终输出只包含需要的文件。

使用多个阶段还可以让您通过并行执行构建步骤来更高效地构建。

有关更多信息,请参阅多阶段构建

使用 .dockerignore 排除文件

使用 .dockerignore 文件排除与构建不相关的文件,而无需重组您的源代码仓库。此文件支持类似 .gitignore 文件的排除模式。有关创建一个的信息,请参阅 Dockerignore 文件

创建短暂容器

您的 Dockerfile 定义的镜像应该生成尽可能短暂的容器。短暂意味着容器可以被停止和销毁,然后重新构建并替换,配置和设置达到绝对最小。

参考 The Twelve-factor App 方法论下的 Processes 来了解以这种无状态方式运行容器的动机。

不要安装不必要的包

避免安装额外或不必要的包,就因为它们可能很好用。例如,您不需要在数据库镜像中包含文本编辑器。

避免安装额外或不必要的包可以减少您的镜像的复杂性,减少依赖,减少文件大小,并缩短构建时间。

解耦应用

每个容器应只关心一个问题。将应用分解到多个容器中可以更容易地横向扩展和重用容器。例如,一个 Web 应用堆栈可能由三个独立的容器组成,每个容器都有自己独特的镜像,以解耦的方式管理 Web 应用、数据库和内存中的缓存。

限制每个容器只运行一个进程是一个好的经验法则,但这不是一个硬性规则。例如,容器可以以 init 进程启动,有些程序可能自行生成额外的进程。例如,Celery 可以生成多个工作进程,Apache 可以为每个请求创建一个进程。

尽量保持容器的清洁和模块化。如果容器相互依赖,您可以使用 Docker 容器网络 来确保这些容器能够通信。

对多行参数进行排序

尽可能按字母顺序排序多行参数以简化维护。这有助于避免包的重复并使列表更易于更新。这也使 PR 更易于阅读和审查。在反斜杠 (\) 前添加一个空格也有帮助。

这里是一个来自 buildpack-deps 镜像 的示例:

dockerfile
RUN apt-get update && apt-get install -y \
  bzr \
  cvs \
  git \
  mercurial \
  subversion \
  && rm -rf /var/lib/apt/lists/*

利用构建缓存

构建镜像时,Docker 会逐步执行 Dockerfile 中的指令,按指定的顺序执行

每一条。对于每条指令,Docker 检查是否可以重用构建缓存中的指令。

了解构建缓存的工作原理以及缓存失效如何发生,对确保更快的构建至关重要。有关 Docker 构建缓存及如何优化构建的更多信息,请参阅 Docker 构建缓存

固定基础镜像版本

镜像标签是可变的,意味着发布者可以更新标签指向新的镜像。这很有用,因为它允许发布者更新标签指向镜像的新版本。作为镜像消费者,这意味着当您重新构建镜像时会自动获得新版本。

例如,如果您在 Dockerfile 中指定 FROM alpine:3.193.19 解析为 3.19 的最新补丁版本。

dockerfile
# syntax=docker/dockerfile:1
FROM alpine:3.19

某个时间点,3.19 标签可能指向镜像的 3.19.1 版本。如果您 3 个月后重新构建镜像,同一个标签可能指向不同的版本,例如 3.19.4。这种发布工作流是最佳实践,大多数发布者都使用这种标签策略,但这并不是强制的。

这样做的缺点是您不能保证每次构建都获得相同的结果。这可能导致破坏性更改,并意味着您也没有使用的确切镜像版本的审核轨迹。

为了完全保障您的供应链完整性,您可以将镜像版本固定到特定的摘要。通过固定镜像到摘要,您可以保证始终使用相同的镜像版本,即使发布者替换了标签也是如此。例如,以下 Dockerfile 将 Alpine 镜像固定到与之前相同的标签 3.19,但这次使用摘要引用。

dockerfile
# syntax=docker/dockerfile:1
FROM alpine:3.19@sha256:13b7e62e8df80264dbb747995705a986aa530415763a6c58f84a3ca8af9a5bcd

使用此 Dockerfile,即使发布者更新了 3.19 标签,您的构建仍会使用固定的镜像版本:13b7e62e8df80264dbb747995705a986aa530415763a6c58f84a3ca8af9a5bcd

虽然这可以帮助您避免意外的变化,但手动查找并包含基础镜像版本的镜像摘要每次您想更新时也更加繁琐。而且,您放弃了自动化的安全修复,这可能是您想要获得的。

Docker Scout 有一个内置的过时的基础镜像政策,该政策检查您是否使用的基础镜像版本确实是最新的。这个政策还检查您的 Dockerfile 中固定的摘要是否与正确的版本对应。如果发布者更新了您固定的镜像,政策评估会返回不合规状态,表明您应该更新您的镜像。

Docker Scout 还支持自动修正工作流以保持您的基础镜像更新。当有新的镜像摘要可用时,Docker Scout 可以自动在您的仓库上提出拉取请求,以更新您的 Dockerfiles 使用最新版本。这比使用自动更改版本的标签更好,因为您可以控制并且有一个更改发生时的审核轨迹。

有关使用 Docker Scout 自动更新您的基础镜像的更多信息,请参阅修正