我如何在使用 docker:dind 构建 docker 图像时缓存在 gitlab ci 中

问题描述

我有一个像这样的 gitlab-ci.yml

build and push docker image:
  stage: publish  
  variables:
    DOCKER_REGISTRY: amazon-registry
    AWS_DEFAULT_REGION: ap-south-1
    APP_NAME: sample-app
    DOCKER_HOST: tcp://docker:2375
  image: 
    name: amazon/aws-cli
    entrypoint: [""]
  services:
    - docker:dind 
  before_script:
    - amazon-linux-extras install docker
  script:
    - docker build -t $DOCKER_REGISTRY/$APP_NAME:master .
    - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
    - docker push $DOCKER_REGISTRY/$APP_NAME:master

这一步需要 19=8 分钟才能完成,因为 docker 镜像步骤没有被缓存。我希望能够缓存 before_script amazon-linux-extras install docker 以及我正在构建的 docker 映像。我们在自己的 gitlab runners 上运行。我已经搜索了答案,但找到了 4 年前的解决方案。有没有办法解决这个问题?另外,不使用 docker:dind 会有帮助吗?

解决方法

不幸的是,Gitlab CI 缓存不能那样工作。例如,如果您有一个安装 npm 依赖项的作业,您可以缓存生成的 node_modules 目录,这样 npm install 不需要再次运行,但它不会帮助安装系统包。

关于 docker:dind 服务,如果没有该服务,您将无法运行 docker build...docker push ... 之类的命令,即使您将作业使用的图像切换为 {{1 }}。这有点违反直觉,但能够运行这些命令的唯一方法是使用 docker-in-docker 服务。

但是,您并非不走运。我建议您将 docker:latest 阶段中的步骤移至您自己的扩展 before_script 的 docker 映像。只要您可以访问 docker hub、Gitlab 包含的注册表(如果使用 gitlab.com 它可用,否则管理员必须启用/配置它)、亚马逊的注册表(我认为是 ECR?)或私人运行的注册表,您就可以创建您自己的自定义图像并在 Gitlab CI 管道中使用它们。

这是一个 Dockerfile 示例:

amazon/aws-cli

这就是扩展现有 FROM amazon/aws-cli RUN amazon-linux-extras install docker 映像并将 amazon/aws-cli 安装移动到 Docker 所需的全部内容。文件完成后,运行

before_script

之后,您需要登录到您的注册表 docker build /path/to/dockerfile-directory -t my_tag:latest ,并推送图像 docker login my.registry.example.com。如果您没有使用 Gitlab 的注册表或公共 docker 集线器,则需要配置您的作业或运行程序(两者之一),以便他们可以通过您的注册表进行身份验证。你可以在这里阅读:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#define-an-image-from-a-private-container-registry

接下来你只需要在你的管道中使用它:

docker push my_tag:latest

为了节省管道时间(如果适用),您可以做的另一件事是仅在 Dockerfile 更改时运行此步骤。这样,如果它没有但其他作业依赖它,他们就可以重用最后创建的图像。您可以将 build and push docker image: stage: publish variables: DOCKER_REGISTRY: amazon-registry AWS_DEFAULT_REGION: ap-south-1 APP_NAME: sample-app DOCKER_HOST: tcp://docker:2375 image: name: my_tag:latest entrypoint: [""] services: - docker:dind script: - docker build -t $DOCKER_REGISTRY/$APP_NAME:master . - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY - docker push $DOCKER_REGISTRY/$APP_NAME:master 关键字与 rules 一起使用:

changes

根级 build and push docker image: stage: publish variables: DOCKER_REGISTRY: amazon-registry AWS_DEFAULT_REGION: ap-south-1 APP_NAME: sample-app DOCKER_HOST: tcp://docker:2375 image: name: my_tag:latest entrypoint: [""] services: - docker:dind when: never rules: - changes: - Dockerfile when: always script: - docker build -t $DOCKER_REGISTRY/$APP_NAME:master . - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY - docker push $DOCKER_REGISTRY/$APP_NAME:master 将作业的默认设置设置为从不运行,但 when: never 部分会检查 Dockerfile 是否有更改(如果需要,可以接受多个文件)。如果有更改,作业将始终运行。

您可以在此处查看有关 rules 关键字的详细信息:https://docs.gitlab.com/ee/ci/yaml/#rules

您可以在此处查看有关 Gitlab CI 的自定义 docker 映像的详细信息:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html

,

我尝试过的一件事是在 docker build 中使用缓存层。
您可以从注册表中提取现有映像,然后使用 --cache 参数进行构建。

作业外壳将是这样的:

  variables:
    IMAGE_TAG: $DOCKER_REGISTRY/$APP_NAME:master
  script:
    - aws ecr get-login-password | docker login --username AWS --password-stdin $DOCKER_REGISTRY
    - docker pull $IMAGE_TAG || true
    - docker build --cache-from $IMAGE_TAG -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

这个方法在 gitlab-ci official document 中也有提到。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...