问题描述
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 中也有提到。