十、镜像缓存与多级构建
00 分钟
2024-6-27
2024-7-22
type
status
date
slug
summary
tags
category
icon
password
文章状态

镜像 Cache 机制

Docker Daemon 通过 Dockerfile 构建镜像时,当发现即将新构建出的镜像与已有的某镜像重复时,可以选择放弃构建新的镜像,而是选用已有的镜像作为构建结果,也就是采取本地已经 cache 的镜像作为结果。
注意事项:
注意事项:
  1. ADD 命令与 COPY 命令
    1. Dockerfile 中的 ADD 和 COPY 命令会检查指定文件的内容变化。Docker 通过计算文件的唯一 hash 值来判断文件内容是否改变(MD5sum)。如果 hash 值未变,则认为文件内容未变,可以继续使用缓存;否则,缓存将失效。
  1. RUN 命令存在外部依赖
    1. 当 RUN 命令涉及外部依赖(如 RUN apt-get update),由于软件源的更新,缓存可能会导致不满足用户需求的情况。用户可以使用 --no-cache 参数来确保获取最新的外部依赖,例如:
  1. 优化 Dockerfile 以利用缓存
    1. 为了更好地利用 Docker 的缓存机制,建议将静态的安装和配置命令尽可能放在 Dockerfile 的前部。这样可以确保这些静态内容在变化较少的情况下,后续的构建步骤能够更有效地利用缓存。

传统构建流程

步骤一:先编译、打包(镜像一)
步骤二:将打包好的应用复制到镜像中(镜像二)

多阶段构建

multi-stage
旧版本的 docker 是不支持 multi-stage 的,只有 17.05 以及之后的版本才开始支持
旧版本的 docker 是不支持 multi-stage 的,只有 17.05 以及之后的版本才开始支持

🤔
虽然 Alpine 镜像已经很小了,但是它依旧包含了许多不必要的组件。那么有没有可能让我们的镜像里不包含包管理工具、SHELL、冗余的二进制文件,只包含最小的可运行系统,以及我们的语言 Runtime,或者核心的 glibc 依赖呢?

distroless

Google 内部精简镜像
官方目前已经提供了多数场景下所需要的镜像,比如:
  • 适合静态编译语言运行的镜像:C, C++, Go, Rust
  • 适合动态语言使用的镜像:Java, Python, Node

Dockerfile 最佳实践 BP

Dockerfile 的最佳实践是为了确保构建的 Docker 镜像更小、更高效、更安全、更易于维护。
目标
目标
  • 易管理
  • 少漏洞
  • 镜像小
  • 层级少
  • 利用缓存
  1. 置于独立目录 & 使用 .dockerignore 文件
    1. 使用 Dockerfile 构建镜像时最好是将其放置在一个新建的空目录下。然后将构建镜像所需要的文件添加到该目录中。为了提高构建镜像的效率,可在目录下新建一个 .dockerignore 文件来指定要忽略的文件和目录
  1. 使用多阶段构建
    1. 可使用多阶段构建减少所构建镜像的大小以及层数
  1. 避免安装不必要的包
    1. 为了降低复杂性减少依赖减小文件大小节约构建时间,应避免安装任何不必要的包
  1. 一个容器只运行一个进程
    1. 理想情况应保证在一个容器中只运行一个进程。将多个应用解耦到不同容器中,保证了容器的横向扩展和复用。如果无法避免同一镜像运行多进程,应选择合理的初始化进程(init process)。
  1. 镜像层数尽可能少
    1. 需在 Dockerfile 可读性(也包括长期的可维护性)和减少层数之间做一个平衡。
      • 只有 RUNCOPYADD 指令会创建新层,其他指令创建临时层,不会增加镜像大小。
      • 使用连接符 && 将多条 RUN 命令连接成一条指令集,以减少层数
  1. RUN 指令
    1. 为了保持 Dockerfile 文件的可读性可理解性,以及可维护性建议将长的或复杂的 RUN 指令用反斜杠 \ 分割成多行。
  1. 将多行参数排序
    1. 多行参数按字母顺序排序。可以减少可能出现的重复参数(比如安装多个包时的软件包名)。也便于阅读和审查,提高可读性。
  1. 使用构建缓存
    1. 在镜像的构建过程中,Docker 会遍历 Dockerfile 中的指令,然后顺序执行。执行前 Docker 都会在缓存中查找。故编写 Dockerfile 时,应将变更频率低的编译指令优先构建,放在镜像底层,有效利用 build cache 。
  1. 选择最优的基础镜像
    1. 尽可能使用官方仓库作为构建镜像的基础。 选择可以满足业务需求最优的 base image,以确保镜像大小和功能的最优平衡。推荐使用较小的 Alpine 镜像以及 distroless 的镜像。
  1. 独立复制文件
    1. 复制文件时,每个文件应独立复制,这确保某个文件变更时,只影响该文件对应的缓存。
通过遵循这些最佳实践,可以确保 Dockerfile 编写得更加高效和易于维护,达到上述目标。
 
上一篇
十一、容器的优雅退出
下一篇
九、 docker compose