使用 BuildKit 和 DinD 构建 Docker 镜像的解决方案

88次阅读
没有评论

问题描述

在使用 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 镜像。请根据你的具体情况选择适合的方法。如果有进一步的问题或需求,欢迎继续提问!

正文完