问题描述
在使用 GitLab 的流水线来描述部署过程,其中包括构建 Docker 镜像的步骤。为此,用户使用 Docker-in-Docker (DinD) 来构建这些镜像(即在 DinD 容器内下载 Docker-in-Docker 镜像并执行所有的 Docker 相关操作)。用户还设置了使用 Docker BuildKit 功能,其中一个特性是 --cache-from
选项(可以减少构建时间)。然而,似乎这个选项在 DinD 中无法正常工作(至少对用户而言是这样)。
以下是用户的流水线配置:
stages:
- build
- purge
- deploy
variables:
DOCKER_HOST: tcp://localhost:2375
DOCKER_TLS_CERTDIR: ""
DOCKER_BUILDKIT: 1
LATEST: ${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}:${CI_COMMIT_REF_SLUG}
IMAGE_COMMIT_TAG: ${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}:${CI_COMMIT_SHORT_SHA}
services:
- docker:dind
build:
stage: build
image: docker:stable
script:
- docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY}
- docker build --cache-from ${LATEST} -t ${LATEST} -t ${IMAGE_COMMIT_TAG} .
- docker push ${IMAGE_COMMIT_TAG}
- docker push ${LATEST}
构建日志显示 BuildKit 已启用,但没有提到 ‘CACHE’ 的使用情况。而且,构建阶段的时间明显更长。用户希望获得解决方案或建议。
解决方案
请注意以下操作可能涉及到版本差异,根据具体情况酌情选择,并在操作前备份重要数据。
方案1
使用 BuildKit 和 DinD 时,如果要在外部注册表(registry)中缓存图层(layers),需要额外的步骤,具体取决于你如何希望缓存图层。一个简单的选项是在构建时包含一个 build arg 来启用内联缓存。可以如下修改构建命令:
docker build --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from ${LATEST} -t ${LATEST} -t ${IMAGE_COMMIT_TAG} .
请注意,内联缓存仅对已在图像中推送的目标阶段进行缓存,因此在多阶段构建中的其他阶段需要单独构建和缓存,或者在没有缓存的情况下重新构建,这两者都不是理想的解决方法。
方案2
你还可以将缓存存储到本地文件中,或者将缓存推送到不同的注册表镜像,而不是与你推送的镜像一起内联。不幸的是,标准的 docker build
命令无法访问所有的 BuildKit 标志来启用此功能。相反,你可以直接安装 BuildKit 或者使用 buildx,后者是一个用于管理 BuildKit 的 CLI 插件。你可以单独安装 buildx,但在当前的版本中,它可以通过启用实验性 CLI 选项来使用。你需要使用以下命令来创建一个基于容器的构建器,以包括所有的 BuildKit 选项:
docker buildx create --use --driver docker-container --name local ${DOCKER_HOST:-unix:///var/run/docker.sock}
然后,你应该可以运行类似于以下命令:
docker buildx build --cache-from ${IMG_CACHE} --cache-to ${IMG_CACHE} -t ${LATEST} -t ${IMAGE_COMMIT_TAG} .
有关 BuildKit 缓存的更多文档,请参阅:https://github.com/moby/buildkit#export-cache
有关 buildx 的更多详细信息,请参阅:https://github.com/docker/buildx
方案3
用户提到了 ‘Makisu’,这是另一个构建 Docker 镜像的工具,用户表示在使用 ‘Makisu’ 进行镜像构建时,效果很好。用户可以在以下链接找到 ‘Makisu’ 的详细信息:https://github.com/uber/makisu。用户还提供了一个使用 ‘Makisu’ 的例子,可以参考此链接:https://findwork.dev/blog/6-ways-speed-your-ci/
以上解决方案可以帮助你在使用 BuildKit 和 DinD 时更有效地构建 Docker 镜像。请根据你的具体情况选择适合的方法。如果有进一步的问题或需求,欢迎继续提问!