我如何在使用 docker:dind 构建 docker 图像时在 gitlab ci 中缓存
How do i cache in gitlab ci while building docker images with docker:dind
我有一个 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 ...
这样的命令,即使您切换了图像工作用于 docker:latest
。这有点违反直觉,但能够 运行 这些命令的唯一方法是使用 docker-in-docker 服务。
但是,您并非不走运。我建议您将 before_script
阶段中的步骤移动到您自己的扩展 amazon/aws-cli
的 docker 图像。只要您可以访问 docker hub,Gitlab 包含的注册表(如果使用 gitlab.com 它是可用的,否则管理员必须 enable/configure 它),Amazon 的注册表(我认为是 ECR?),或私人 运行 注册表,您可以创建自己的自定义图像并在 Gitlab CI 管道中使用它们。
这是一个例子Docker文件:
FROM amazon/aws-cli
RUN amazon-linux-extras install docker
这就是扩展现有 amazon/aws-cli
映像并将 before_script
安装移动到 Docker 所需的全部内容。文件完成后,运行
docker build /path/to/dockerfile-directory -t my_tag:latest
之后,您需要登录到您的注册表,docker login my.registry.example.com
,然后上传图像 docker push my_tag:latest
。如果您不使用 Gitlab 的注册表或 public docker 集线器,则需要配置您的作业或 运行ners(其中之一)以便他们可以使用您的注册表进行身份验证。你可以在这里阅读:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#define-an-image-from-a-private-container-registry
接下来您只需在您的管道中使用它:
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
您可以做的另一件事来节省流水线时间(如果它适用),就是在您的 Docker 文件发生更改时仅 运行 这一步。这样,如果它没有但其他工作依赖它,他们可以重复使用最后创建的图像。您可以使用 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
将作业的默认值设置为从不 运行,但 rules
部分检查 Docker 是否有更改文件(如果需要,接受多个文件)。如果有更改,作业将始终为 运行.
您可以在此处查看有关 rules
关键字的详细信息:https://docs.gitlab.com/ee/ci/yaml/#rules
您可以在此处查看有关 Gitlab CI 的自定义 docker 图像的详细信息:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html
我尝试过的一件事是在 docker 构建中使用缓存层。
您可以从注册表中提取现有图像,然后使用 --cache-from
参数进行构建。
这份工作 shell 会是这样的:
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-ciofficial document中也提到了这个方法
我有一个 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 ...
这样的命令,即使您切换了图像工作用于 docker:latest
。这有点违反直觉,但能够 运行 这些命令的唯一方法是使用 docker-in-docker 服务。
但是,您并非不走运。我建议您将 before_script
阶段中的步骤移动到您自己的扩展 amazon/aws-cli
的 docker 图像。只要您可以访问 docker hub,Gitlab 包含的注册表(如果使用 gitlab.com 它是可用的,否则管理员必须 enable/configure 它),Amazon 的注册表(我认为是 ECR?),或私人 运行 注册表,您可以创建自己的自定义图像并在 Gitlab CI 管道中使用它们。
这是一个例子Docker文件:
FROM amazon/aws-cli
RUN amazon-linux-extras install docker
这就是扩展现有 amazon/aws-cli
映像并将 before_script
安装移动到 Docker 所需的全部内容。文件完成后,运行
docker build /path/to/dockerfile-directory -t my_tag:latest
之后,您需要登录到您的注册表,docker login my.registry.example.com
,然后上传图像 docker push my_tag:latest
。如果您不使用 Gitlab 的注册表或 public docker 集线器,则需要配置您的作业或 运行ners(其中之一)以便他们可以使用您的注册表进行身份验证。你可以在这里阅读:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#define-an-image-from-a-private-container-registry
接下来您只需在您的管道中使用它:
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
您可以做的另一件事来节省流水线时间(如果它适用),就是在您的 Docker 文件发生更改时仅 运行 这一步。这样,如果它没有但其他工作依赖它,他们可以重复使用最后创建的图像。您可以使用 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
将作业的默认值设置为从不 运行,但 rules
部分检查 Docker 是否有更改文件(如果需要,接受多个文件)。如果有更改,作业将始终为 运行.
您可以在此处查看有关 rules
关键字的详细信息:https://docs.gitlab.com/ee/ci/yaml/#rules
您可以在此处查看有关 Gitlab CI 的自定义 docker 图像的详细信息:https://docs.gitlab.com/ee/ci/docker/using_docker_images.html
我尝试过的一件事是在 docker 构建中使用缓存层。
您可以从注册表中提取现有图像,然后使用 --cache-from
参数进行构建。
这份工作 shell 会是这样的:
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-ciofficial document中也提到了这个方法