【问题标题】:Docker downloads newer image for supposedly-cached digestDocker 为所谓的缓存摘要下载更新的图像
【发布时间】:2020-05-03 09:19:20
【问题描述】:

我的Dockerfile 迈出了第一步:

FROM python:3.6.10@sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11

这个目标是to "lock" or "pin" the version of the image

有一段时间,docker build 正确使用了缓存版本:

Step 1/2 : FROM python:3.6.10@sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11
 ---> 114ae8bdb954

但过了一段时间,它决定“下载更新的图像”:

Step 1/2 : FROM python:3.6.10@sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11
sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11: Pulling from library/python
7e2b2a5af8f6: Pulling fs layer
09b6f03ffac4: Pulling fs layer
dc3f0c679f0f: Pulling fs layer
fd4b47407fc3: Pulling fs layer
bb7b28578995: Pulling fs layer
6ebea4a9a306: Pulling fs layer
22a2327cd1ca: Pulling fs layer
bfbf91c84bbe: Pulling fs layer
f6b29b259c5c: Pulling fs layer
09b6f03ffac4: Verifying Checksum
09b6f03ffac4: Download complete
dc3f0c679f0f: Download complete
7e2b2a5af8f6: Verifying Checksum
7e2b2a5af8f6: Download complete
6ebea4a9a306: Verifying Checksum
6ebea4a9a306: Download complete
fd4b47407fc3: Verifying Checksum
fd4b47407fc3: Download complete
bfbf91c84bbe: Verifying Checksum
bfbf91c84bbe: Download complete
f6b29b259c5c: Verifying Checksum
f6b29b259c5c: Download complete
22a2327cd1ca: Verifying Checksum
22a2327cd1ca: Download complete
bb7b28578995: Verifying Checksum
bb7b28578995: Download complete
7e2b2a5af8f6: Pull complete
09b6f03ffac4: Pull complete
dc3f0c679f0f: Pull complete
fd4b47407fc3: Pull complete
bb7b28578995: Pull complete
6ebea4a9a306: Pull complete
22a2327cd1ca: Pull complete
bfbf91c84bbe: Pull complete
f6b29b259c5c: Pull complete
Digest: sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11
Status: Downloaded newer image for python@sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11
 ---> 114ae8bdb954

即使这一步的最终哈希是相同的:

 ---> 114ae8bdb954

据我了解,摘要 (sha256:...) 是不可变的。
那么它们到底是可变的吗?
还是缓存版本被某种方式删除了?
发生了什么,我该如何解决?

【问题讨论】:

  • 每次运行都这样做吗?
  • @nitishagar 经过仔细检查,似乎每天的第一次运行不使用缓存,但其余的运行。如果缓存每天都清零,不然怎么配置?
  • 你在哪个系统上运行这个? (Win、Mac、Linux)
  • @nitishagar 在docker:1.11 容器上。
  • @nitishagar 纠正并非所有其他人都使用缓存。我以为我找到了一种模式,但它的行为是不确定的。

标签: docker dockerfile docker-registry


【解决方案1】:

鉴于并非每次运行都会发生这种情况,而且如果您在本地进行测试也可能不会发生,那么问题似乎与您的 Dockerfile 或 FROM 行无关。 Docker 不会自动清理缓存,因此您需要调查哪些外部进程正在删除缓存。由于您使用 kubernetes 插件在 Jenkins 中运行构建,因此问题似乎来自该插件在超时后清理构建代理。从文档中可以看到various settings to tune this builder:

  • podRetention 控制保留从属 pod 的行为。可以是 'never()'、'onFailure()'、'always()' 或 'default()' - 如果为空将 默认在activeDeadlineSeconds 过去后删除 pod。
  • activeDeadlineSeconds 如果 podRetention 设置为 'never()' 或 'onFailure()',则在此截止日期过后删除 pod。
  • idleMinutes 允许 Pod 保持活动状态以供重复使用,直到自上一步执行后经过配置的分钟数 在上面执行。

解决临时构建代理的一种方法是在docker build 命令中使用--cache-from 选项。使用经典构建(vs buildkit),您需要首先在本地拉取这个镜像。该图像将来自以前的构建,您可以将多个图像用于缓存,这对于多阶段构建特别有用,因为您需要为每个阶段提取缓存。此标志告诉 docker 信任从注册表中提取的映像,因为通常只信任本地构建的映像(有人可能会注入恶意映像,该映像声称已在流行映像中运行了步骤,但在该层的 tar 中包含恶意软件) .

【讨论】:

  • 感谢您提供如此详尽的回答!当我尝试使用--cache-from 时,我发现我的图像docker:1.11 太旧了以至于它不支持它。升级到docker:1.13,最先引入了这个功能,即使没有flag,似乎也做到了。 (首先我尝试了 flag,然后没有,它仍然在不同的分支上工作)干杯!
  • 如果已经在节点上构建了镜像,则不需要--cache-from,因为 docker 信任它构建的镜像。一旦构建器被 Jenkins 修剪,您需要拉取图像并在下一个构建器实例中使用标志以避免缓存未命中。我只是将它包含在每个构建的管道中,因为拉取你已经拥有的图像非常快。
  • 我还建议尽可能使用最新的稳定 docker 映像,自 1.13 以来的 3 年多来发生了很多变化以改进构建,包括多阶段构建,并且 buildkit 支持也可用于较新的版本。
【解决方案2】:

有两种摘要:注册表中的图像清单摘要和本地图像的JSON配置摘要,其中还包含图像内容的摘要。

第一个摘要:python:3.6.10@sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11 是 Docker Hub 中清单的摘要作为参考。

摘要是不可变的。

如果两个不同的东西产生相同的摘要值 - 那么哈希函数(在这种情况下使用 sha256)将被破坏并且不能再使用。见collision.

在您的情况下,由于某种原因,它不再找到缓存的图像。 它再次下载了相同的图像。

最后生成的摘要 (---> 114ae8bdb954) 是该图像的结果配置摘要 (Image ID)。

您可以确认下载了正确的清单:

docker inspect 114ae8bdb954 

包括:

"RepoDigests": [
            "python@sha256:6cd232ed00e729b4d4d3aa57c1764dddfab70f616042b7f36536e2c3d70c4c11"
        ],

由于两种情况下的图像 id 相同,我认为没有什么需要修复的。但是,如果它总是发生,那么缓存就会出现一些问题。

关于缓存的编辑:如果这是在 docker-in-docker 场景中完成的 - 如果在父 Docker 中构建阶段之前发生某些变化,它将始终重新构建此映像。

更多图片ID信息:https://windsock.io/explaining-docker-image-ids/

【讨论】:

  • 感谢您的回答。您声称这种情况总是会重建映像,但接受的解决方案解释了如何避免这种情况。
【解决方案3】:

注意:有一个固定“来源”的 RFC:moby/buildkit issue 2794,来自 Akihiro Suda(NTT 公司的软件工程师)。
它会介绍:

Dockerfile.sum 相当于 go.sums/go/Dockerfile/

内容是 BuildInfo 的子集:

{
   "sources": [
     {
       "type": "docker-image",
       "ref": "docker.io/library/alpine:latest",
       "pin": "sha256:4edbd2beb5f78b1014028f4fbb99f3237d9561100b6881aabbf5acce2c4f9454"
     },
     {
       "type": "http",
       "ref": "https://raw.githubusercontent.com/moby/buildkit/v0.10.1/README.md",
       "pin": "sha256:6e4b94fc270e708e1068be28bd3551dc6917a4fc5a61293d51bb36e6b75c4b53"
     }
   ]
}

When `Dockerfile.sum` exists in the context, the Dockerfile builder does:

- Pinning the digest of docker-image sources (`FROM ...`)
- Pinning the digest of http sources (`ADD https://...`)
- Recording the consumed entries to the build info structure (`["containerimage.buildinfo"].consumedPin`)

In the future, Dockerfile should also support `ADD git://...` and pinning its commit hash.

这是一种向最终用户提供/展示buildinfo 功能的方式,参与Build reproducibility

【讨论】:

    猜你喜欢
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 2015-04-02
    • 2022-01-08
    相关资源
    最近更新 更多