Gitlab docker executor - 在 before_script 之后缓存图像
Posted
技术标签:
【中文标题】Gitlab docker executor - 在 before_script 之后缓存图像【英文标题】:Gitlab docker executor - cache image after before_script 【发布时间】:2016-04-21 14:50:58 【问题描述】:在gitlab-ci
中,.gitlab-ci.yml
文件中有一个选项可以在任何实际脚本运行之前执行命令,称为before_script
。 .gitlab-ci.yml
示例说明了在此处安装辅助程序。但是,我注意到的是,在使用 docker 执行程序时,这些更改不会缓存在 Docker 中。我天真地假设在运行这些命令后,docker 会缓存图像,所以在下一次运行或测试时,docker 只会加载在before_script
之后生成的缓存图像。这将大大加快构建速度。
例如,我的.gitlab-ci.yml
看起来有点像:
image: ubuntu
before_script:
- apt-get update -qq && apt-get install -yqq make ...
build:
script:
- cd project && make
一个可能的解决方案是转到运行器机器并创建一个 docker 映像,该映像可以构建我的软件而无需任何其他安装,然后在 yaml 文件的image
部分中引用它。这样做的缺点是,每当我想添加依赖项时,我都需要登录到运行器机器并在构建成功之前更新映像。如果我只需将依赖项添加到 apt-get install
的末尾并让 docker / gitlab-ci 处理适当的缓存,那就更好了。
.gitlab-ci.yml
中还有一个cache
命令,我尝试将其设置为untracked: true
,我认为它会缓存不是我项目副产品的所有内容,但它似乎没有任何内容效果。
有什么方法可以得到我想要的行为吗?
【问题讨论】:
我希望有像“image:dockerfile”或“image:build”这样的选项,可以内联或作为文件参考,类似于 docker-compose 允许自定义图像的方式。有了 runner 的这种支持,如果我们唯一需要的是可重现的构建环境,我们甚至可以忘记 docker-in-docker。 【参考方案1】:您可以首先添加一个阶段来构建图像。如果图像没有任何变化,这个阶段会很短,不到 1 秒。
您可以在以下阶段使用该图像,加快整个过程。
这是.gitlab-ci.yml
的示例:
stages:
- build_test_image
- test
build_test:
stage: build_test_image
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:test -f dockerfiles/test/Dockerfile .
- docker push $CI_REGISTRY_IMAGE:test
tags:
- docker_build
test_syntax:
image: $CI_REGISTRY_IMAGE:test
stage: test
script:
- pip install flake8
- flake8 --ignore=E501,E265 app/
查看标签docker_build
。该标签用于强制在具有该标签的运行器上执行阶段。该运行程序的执行程序是shell
,它仅用于构建 Docker 映像。所以,runner 所在的主机应该已经安装了 Docker Engine。我发现这个解决方案比 docker in docker 和 another solutions 更适合我的需求。
另外,我使用的是私有注册表,这就是我使用$CI_REGISTRY*
变量的原因,但您可以使用 DockerHub 而无需指定注册表。不过,问题在于在 DockerHub 上进行身份验证。
【讨论】:
此功能是否有任何文档? 如果我已将自己的运行器添加到托管的 GitLab 实例中,我应该向其添加docker_build
标签还是 GitLab 在内部隐式处理它?
您应该明确添加它,标签docker_build
这只是我选择的一个方便的名称,但可以是任何名称。它没有记录,这只是一种方法,我想通了。
我正在编辑答案以澄清标签的用法。
感谢您的回复。实际上有很多反对shell executor的声音,我已经手动完成了图像缓存,如这篇文章:gitlab.com/gitlab-org/gitlab-ce/issues/17861#note_21746810【参考方案2】:
我处理这个问题的方式是,我在 Docker Hub 上为我们的每个项目都有自定义图像,并从 .gitlab-ci.yml
引用它们。如果我需要新的依赖项,我会编辑用于创建初始映像的 Dockerfile,重新构建映像,并使用特定标记对其进行标记并推送到 Docker Hub。
cat "RUN apt-get install gcc" >> Dockerfile
ID=$(docker build)
docker tag $ID ACCOUNT/gitlab_ci_image:gcc
docker push ACCOUNT/gitlab_ci_image
然后我更新 .gitlab-ci.yml
文件以指向该图像的特定版本。
image: ACCOUNT/gitlab_ci_image:gcc
build:
script:
- cd project && make
这允许我根据我尝试测试的提交来拥有不同的依赖项(因为该提交中的gitlab-ci.yml
文件告诉运行者使用哪个)。它还避免了每次在特定运行器上运行测试时都需要安装依赖项,因为运行器将重复使用相同的图像,只要它不改变。
另一个好处是,使用 Docker Hub 上托管的图像,如果运行器需要一个本地没有的特定标签,它会自动获取正确的标签,这样你就可以拥有 10 个运行器并且只维护一个图像,这种维护可以在您自己的工作站或任何机器上完成。
我个人认为这比尝试缓存跑步者图像中的任何内容要好得多。当您创建新分支以在较新版本的依赖项上测试代码时尤其如此。如果你有缓存,你的稳定分支和开发分支会有不同的测试环境问题。同样在我看来,测试应该在尽可能干净的环境中运行,而这种设置可以实现这一点。
【讨论】:
我已经想到了这一点,并且有一些好处,但似乎将before_script
的每一行作为 RUN 命令运行然后让 docker 进行缓存并不难在那个级别。
是的,我认为这绝对是可能的,但我对它背后的基本原理的最佳猜测将接近我的答案的结尾,因为如果你在不同的提交中有不同的 before_script
指令,事情可能会得到一个有点乱。除了安装软件包之外,before_script
还可以用来做各种事情。如果你好奇,你可以随时在他们的 github 页面上发帖。他们真的很擅长回应。不过,我发布的内容对我们的团队很有帮助。
我将暂时使用您描述的内容。
但它是私人码头中心还是公共码头?以上是关于Gitlab docker executor - 在 before_script 之后缓存图像的主要内容,如果未能解决你的问题,请参考以下文章
Gitlab CI/CD 之 Gitlab Runner Docker Executor 缓存问题
如何使用 docker executor 在同一个 gitlab 运行器上禁用并发作业?
Gitlab docker executor - 在 before_script 之后缓存图像
GitLab Runner Docker Executor 中的缓存层 - 长时间 DinD 容器