为什么在 Docker 中使用完全相同的构建命令每次都会产生不同的哈希值?

hal*_*fer 4 docker alpine-linux

我正在 CircleCI 上构建一个简单的 CI 流程。它 Dockerises 一个 WordPress 实例,确定远程注册表是否有结果镜像的副本,如果没有,以特殊格式标记镜像并推送它。

但是,我在实践中发现图像总是不同的,并且我已经将问题直接追溯到 Dockerfile 的顶部,我在那里调用了 Alpine 的apk命令。完整的命令是:

RUN apk --update add git openssh-client
Run Code Online (Sandbox Code Playgroud)

我已经完成了两个相隔大约 20 分钟的构建,并且这个命令在每种情况下都在做一些不同的事情。我开始使用 Alpine 3.6 中的固定哈希。

这是倒数第二个版本的前几行:

Step 1/42 : FROM alpine@sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106 AS build
sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106: Pulling from library/alpine

Digest: sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106
Status: Downloaded newer image for alpine@sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106
 ---> 77144d8c6bdc
Step 2/42 : RUN apk --update add git openssh-client
 ---> Running in 4dee205378ad
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz
(1/8) Installing ca-certificates (20161130-r2)
(2/8) Installing libssh2 (1.8.0-r1)
(3/8) Installing libcurl (7.59.0-r0)
(4/8) Installing expat (2.2.0-r1)
(5/8) Installing pcre (8.41-r0)
(6/8) Installing git (2.13.5-r0)
(7/8) Installing openssh-keygen (7.5_p1-r2)
(8/8) Installing openssh-client (7.5_p1-r2)
Executing busybox-1.26.2-r9.trigger
Executing ca-certificates-20161130-r2.trigger
OK: 28 MiB in 19 packages
 ---> 1c11addc5a9f
Removing intermediate container 4dee205378ad
Step 3/42 : WORKDIR /root
 ---> 0ec3661faedc
Removing intermediate container 3f0f8610abbc
Run Code Online (Sandbox Code Playgroud)

这是最新版本:

Step 1/42 : FROM alpine@sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106 AS build
sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106: Pulling from library/alpine

Digest: sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106
Status: Downloaded newer image for alpine@sha256:3d44fa76c2c83ed9296e4508b436ff583397cac0f4bad85c2b4ecc193ddb5106
 ---> 77144d8c6bdc
Step 2/42 : RUN apk --update add git openssh-client
 ---> Running in 8ad903516136
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz
(1/8) Installing ca-certificates (20161130-r2)
(2/8) Installing libssh2 (1.8.0-r1)
(3/8) Installing libcurl (7.59.0-r0)
(4/8) Installing expat (2.2.0-r1)
(5/8) Installing pcre (8.41-r0)
(6/8) Installing git (2.13.5-r0)
(7/8) Installing openssh-keygen (7.5_p1-r2)
(8/8) Installing openssh-client (7.5_p1-r2)
Executing busybox-1.26.2-r9.trigger
Executing ca-certificates-20161130-r2.trigger
OK: 28 MiB in 19 packages
 ---> 4192a8ae6ba6
Removing intermediate container 8ad903516136
Step 3/42 : WORKDIR /root
 ---> 9f2a57c9923b
Removing intermediate container 050a150cf83f
Run Code Online (Sandbox Code Playgroud)

为了方便读者,这里有一个图形差异:

Docker 层哈希的差异

我的观点是,这种短期内的更改发生了太多次,以至于无法对旧版本的 Alpine(这是 3.6,最新的是 3.7)进行实际的操作系统更新。我认为它可能是在更新中写入数据或时间戳,这对于包管理器来说似乎是一件明智的事情。

但是,我希望在几分钟内创建的两个构建具有相同的哈希值,除非有实际的操作系统更新。有人会确认幕后可能发生的事情,或者解释我可以做些什么来检查实际变化吗?例如,是否有一种合理的方式可以区分 Docker 层?

如果所做的更改apk永远无法完全重现,那么在我的注册表中创建固定基础映像、安装我需要的软件并在其上构建的最佳解决方案是什么?我必须设置一些东西来定期重建它(例如每隔几周)以获得安全更新,但如果它让我获得稳定的构建层,这是可以接受的。

更新

我已将apk调用移至单独的构建,现在我发现sed命令正在更改哈希。

这是第一次运行:

Step 15/39 : FROM registry.gitlab.com/username/jonblog-machine:latest
 ---> 5f854fc73292
Step 16/39 : RUN sed -i -r 's/memory_limit = \d+M/memory_limit = 30M/g' /etc/php7/php.ini
 ---> Running in d7205d0216f6
 ---> b64f045b6f51
Run Code Online (Sandbox Code Playgroud)

第二次运行:

Step 15/39 : FROM registry.gitlab.com/username/jonblog-machine:latest
 ---> 5f854fc73292
Step 16/39 : RUN sed -i -r 's/memory_limit = \d+M/memory_limit = 30M/g' /etc/php7/php.ini
 ---> Running in 152d628094ff
 ---> a397210c512b
Run Code Online (Sandbox Code Playgroud)

这令人困惑:我从5f854fc73292两者开始,但第 16 步每次都会产生一个新的哈希值。(它从构建 15 开始,因为这是一个多阶段构建)。

我该怎么做才能看到为什么我得到不同的哈希值?

BMi*_*tch 6

层哈希包括文件上的 mtime 时间戳,sed命令将更改该时间戳。您可以在此处查看 docker 密切关注的 OCI 图像规范:

https://github.com/opencontainers/image-spec/blob/master/layer.md#file-attributes