如何在构建时调试docker-compose缓存未命中

6

我正在执行相同的docker-compose build命令,但我发现它缺少缓存。

Building service1
Step 1/31 : FROM node:10 as build-stage
 ---> a7366e5a78b2
Step 2/31 : WORKDIR /app
 ---> Using cache
 ---> 8a744e522376
Step 3/31 : COPY package.json yarn.lock ./
 ---> Using cache
 ---> 66c9bb64a364
Step 4/31 : RUN yarn install --production
 ---> Running in 707365c332e7
yarn install v1.21.1
..
..
..

您可以看到缓存未命中,但我不明白原因是什么。

最好的调试方法是查找更改并尝试弄清原因。

编辑:问题不是要调试我的具体问题。而是如何一般性地调试这种问题。我应该如何知道为什么docker-compose认为事情已经改变了(虽然我几乎确定没有任何改变),哪些文件/命令/结果不同?


你是什么意思? - user972014
1
@user972014 我已经编辑了我的答案,以回答你在编辑中指定的更一般的问题。 - VonC
1个回答

3
一般来说,我应该如何调试这种问题?我怎么知道为什么docker-compose认为事情已经改变了(尽管我非常确定没有任何改变),哪些文件/命令/结果是不同的。通常可以按照此处所示的步骤进行操作:

我有点失望,似乎找不到任何方法使Docker构建更详细

但是当涉及到docker-compose时,它取决于您使用的版本和选项。
moby/moby issue 30081 (由Sebastiaan van Stijn (thaJeztah)解释)
当前版本的docker-composedocker build在许多(或所有)情况下都不会共享构建缓存,或者至少不会产生相同的摘要。
原因是使用docker-compose发送构建上下文时,它将使用稍微不同的压缩方式(docker-compose用Python编写,而docker cli用Go编写)。
由于它们是不同的实现(和语言),可能会有其他差异。

(这也在docker/compose issue 883中讨论过)

下一个版本的docker compose将具有一项(目前是选择性的)功能,使其使用实际的docker cli执行构建(通过设置COMPOSE_DOCKER_CLI_BUILD=1环境变量)。这是在docker/compose#6865中实现的(1.25.0-rc3+,2019年10月)。使用该功能时,docker compose也可以使用BuildKit来构建镜像(设置DOCKER_BUILDKIT=1环境变量)。如果可能的话,我强烈建议您使用buildkit进行构建。当使用BuildKit(需要Docker 18.09或更高版本,并且此时不支持构建Windows容器)时,您将看到构建速度大大提高,并且在重复构建中将构建上下文发送到守护程序所需的时间也会缩短(buildkit使用交互式会话仅发送构建期间需要的文件,而不是上传整个构建上下文)。

因此,首先仔细检查您的docker-compose是否使用了BuildKit,如果问题(缓存未被重用)仍然存在,则:

COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose build

Sebastiaan在问题4012中添加了以下内容:

BuildKit仍然是自选的(因为目前还没有Windows支持),但其质量已经达到生产级别,可以作为构建Linux映像的默认选项。

最后,我意识到对于Azure流水线,您(可能)无法控制安装的Docker和Docker Compose的版本,但对于您的本地机器,请确保升级到最新的19.03补丁版本;例如,Docker 19.03.3及以上版本在BuildKit缓存机制方面有各种改进和修复(请参见,例如,docker#373)。


注意,在您的特定情况下,即使这不是您问题的主要问题,了解以下内容是否有帮助会很有趣:

yarnpkg/yarn/issue 749建议:

您不应该挂载Yarn缓存目录。相反,您应该确保充分利用Docker的镜像层缓存。

这些是我使用的命令:

COPY package.json yarn.lock ./
RUN yarn --pure-lockfile

然后尝试执行yarn install命令,查看是否docker仍然不使用它的缓存。

RUN yarn install --frozen-lockfile --production && yarn cache clean 

不要忘记执行 yarn cache clean 以防止 yarn 缓存进入 docker 层。
如果问题仍然存在,请直接切换到 buildkit(进行测试),使用 buildctl build --progress=plain 查看更详细的输出,并调试缓存情况。
通常,多阶段方法,如下所示,是有用的:
FROM node:alpine
WORKDIR /usr/src/app
COPY . /usr/src/app/

# We don't need to do this cache clean, I guess it wastes time / saves space: https://github.com/yarnpkg/rfcs/pull/53
RUN set -ex; \
  yarn install --frozen-lockfile --production; \
  yarn cache clean; \
  yarn run build

FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=0 /usr/src/app/build/ /usr/share/nginx/html

正如nairum评论中所指出的:

我刚发现,当我使用多阶段Dockerfile和Docker Compose时,必须使用cache_from才能使缓存起作用。

根据文档:

cache_from defines a list of sources the Image builder SHOULD use for cache resolution.

Cache location syntax MUST follow the global format [NAME|type=TYPE[,KEY=VALUE]].
Simple NAME is actually a shortcut notation for type=registry,ref=NAME.

build:
 context: .
 cache_from:
   - alpine:latest
   - type=local,src=path/to/cache
   - type=gha

我使用 COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1,但是 Docker Compose 不使用缓存(Docker 版本 20.10.23)。我仍然想知道如何在使用 Docker Compose 构建镜像时与仅使用 Docker 时一样使用缓存。 - Nairum
@Nairum感谢您的反馈。也许自从我最初的回答以来有些变化,正如在PR 6865中所讨论的那样。 - VonC
抱歉,我的错。我刚刚发现在使用Docker Compose的多阶段Dockerfile时,需要使用cache_from才能使缓存正常工作。 - Nairum
1
@Nairum 谢谢您的跟进。我已经编辑了答案,并包含了您的评论以增加可见性,同时引用了 cache_from 文档。 - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接