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 容器

docker环境下使用gitlab,gitlab-runner 为 NetCore 持续集成

【Gitlab ci】 缓存