在Docker容器中运行你的CI/CD作业
- Tier: Free, Premium, Ultimate
- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
你可以在专用CI/CD构建服务器或本地机器上托管的Docker容器中运行CI/CD作业。
要在Docker容器中运行CI/CD作业,你需要:
- 注册一个Runner并配置它使用 Docker执行器。
- 在
.gitlab-ci.yml文件中指定你要运行CI/CD作业的容器镜像。 - 可选。在容器中运行其他服务(如MySQL)。通过在你的
.gitlab-ci.yml文件中指定 services 来实现。
注册使用Docker执行器的Runner
要使用带有Docker的GitLab Runner,你需要 注册一个Runner,该Runner使用Docker执行器。
此示例展示了如何设置临时模板以提供服务:
cat > /tmp/test-config.template.toml << EOF
[[runners]]
[runners.docker]
[[runners.docker.services]]
name = "postgres:latest"
[[runners.docker.services]]
name = "mysql:latest"
EOF然后使用此模板注册Runner:
sudo gitlab-runner register \
--url "https://gitlab.example.com/" \
--token "$RUNNER_TOKEN" \
--description "docker-ruby:2.6" \
--executor "docker" \
--template-config /tmp/test-config.template.toml \
--docker-image ruby:3.3已注册的Runner使用 ruby:2.6 Docker镜像并运行两个服务:postgres:latest 和 mysql:latest,这两个服务在构建过程中均可访问。
什么是镜像
image 关键字是Docker执行器用于运行CI/CD作业的Docker镜像的名称。
默认情况下,执行器从 Docker Hub 拉取镜像。但是,你可以在 gitlab-runner/config.toml 文件中配置注册表位置。例如,你可以设置 Docker拉取策略 以使用本地镜像。
有关镜像和Docker Hub的更多信息,请参见 Docker概述。
镜像要求
任何用于运行CI/CD作业的镜像都必须安装以下应用程序:
sh或bashgrep
在 .gitlab-ci.yml 文件中定义 image
你可以定义一个用于所有作业的镜像,以及要在运行时使用的服务列表:
default:
image: ruby:2.6
services:
- postgres:11.7
before_script:
- bundle install
test:
script:
- bundle exec rake spec镜像名称必须采用以下格式之一:
image: <镜像名称>(等同于使用带latest标签的<镜像名称>)image: <镜像名称>:<标签>image: <镜像名称>@<摘要>
扩展Docker配置选项
你可以对 image 或 services 条目使用字符串或映射:
- 字符串必须包含完整的镜像名称(包括注册表,如果你想从非Docker Hub的注册表中下载镜像)。
- 映射必须至少包含
name选项,该选项与字符串设置中使用的镜像名称相同。
例如,以下两种定义方式是等效的:
-
image和services的字符串形式:image: "registry.example.com/my/image:latest" services: - postgresql:14.3 - redis:latest -
image和services的映射形式。image:name是必需的:image: name: "registry.example.com/my/image:latest" services: - name: postgresql:14.3 - name: redis:latest
脚本执行的位置
当CI作业在Docker容器中运行时,before_script、script 和 after_script 命令会在 /builds/<项目路径>/ 目录下运行。你的镜像可能定义了不同的默认 WORKDIR。若要移动到你的 WORKDIR,请将 WORKDIR 保存为环境变量,以便在作业运行期间在容器中引用它。
覆盖镜像的入口点
在解释可用的入口点覆盖方法前,先描述下 Runner 是如何启动的。它使用 Docker 镜像来运行 CI/CD 作业中的容器:
- Runner 使用定义好的入口点启动一个 Docker 容器。这个入口点的默认值来自
Dockerfile,可能会被.gitlab-ci.yml文件覆盖。 - Runner 附加到正在运行的容器上。
- Runner 准备一个脚本(由
before_script、script和after_script组合而成)。 - Runner 将脚本发送到容器的 shell
stdin并接收输出。
若要覆盖 Docker 镜像的 entrypoint,可在 .gitlab-ci.yml 文件中:
- 对于 Docker 17.06 及更高版本,将
entrypoint设为空值。 - 对于 Docker 17.03 及更早版本,将
entrypoint设为/bin/sh -c、/bin/bash -c或镜像中可用的等效 shell。
image:entrypoint 的语法类似于 Dockerfile ENTRYPOINT。
假设你有一个包含 SQL 数据库的 super/sql:experimental 镜像。你想把它用作作业的基础镜像,因为你希望用这个数据库二进制文件执行一些测试。再假设该镜像已配置 /usr/bin/super-sql run 作为入口点。当容器未添加额外选项启动时,它会运行数据库进程。Runner 期望镜像没有入口点,或者入口点已准备好启动 shell 命令。
借助扩展的 Docker 配置选项,无需:
- 基于
super/sql:experimental创建自己的镜像。 - 将
ENTRYPOINT设为 shell。 - 在 CI 作业中使用新镜像。
你现在可以直接在 .gitlab-ci.yml 文件中定义 entrypoint。
对于 Docker 17.06 及更高版本:
image:
name: super/sql:experimental
entrypoint: [""]对于 Docker 17.03 及更早版本:
image:
name: super/sql:experimental
entrypoint: ["/bin/sh", "-c"]在 config.toml 中定义镜像和服务
在 config.toml 文件中,你可以定义:
- 在
[runners.docker]部分,用于运行 CI/CD 作业的容器镜像。 - 在
[[runners.docker.services]]部分,服务 容器。
[runners.docker]
image = "ruby:latest"
services = ["mysql:latest", "postgres:latest"]以这种方式定义的镜像和服务会被添加到该 Runner 运行的所有作业中。
从私有容器注册表中访问镜像
要访问私有容器注册表,GitLab Runner 进程可以使用:
- 静态定义的凭证。特定注册表的 username 和 password。
- 凭证存储。更多信息请参见 相关 Docker 文档。
- 凭证助手。更多信息请参见 相关 Docker 文档。
当你使用同一 GitLab 实例上的 GitLab 容器注册表 时,GitLab 会为此注册表提供默认凭证。使用这些凭证时,会使用 CI_JOB_TOKEN 进行身份验证。要使用 job token,启动作业的用户必须拥有托管私有镜像的项目中至少 Developer 角色。托管私有镜像的项目也必须允许其他项目通过 job token 进行身份验证,此访问默认是禁用的。更多详情,请参阅 CI/CD job token。
要确定应使用哪个选项,Runner 进程按以下顺序读取配置:
- 一个
DOCKER_AUTH_CONFIGCI/CD 变量。 - 在 Runner 的
config.toml文件中设置的DOCKER_AUTH_CONFIG环境变量。 - 用户运行进程的
$HOME/.docker目录下的config.json文件。如果提供了--user标志以非特权用户运行子进程,则使用主 Runner 进程用户的 home 目录。
要求和限制
- 凭证存储 和 凭证助手 要求二进制文件添加到 GitLab Runner 的
$PATH中,且需有权限执行此操作。因此,这些功能在实例 Runner 或任何用户无法访问 Runner 安装环境的 Runner 上不可用。
使用静态定义的凭证
你可采用两种方式访问私有仓库。两者均需设置 CI/CD 变量 DOCKER_AUTH_CONFIG 并提供相应认证信息。
- 每个作业:若要为一个作业配置访问私有仓库,可将
DOCKER_AUTH_CONFIG作为 CI/CD 变量 添加。 - 每个 Runner:若要配置一个 Runner 使其所有作业均可访问私有仓库,可在 Runner 配置中将
DOCKER_AUTH_CONFIG作为环境变量添加。
参见以下各节示例。
确定 DOCKER_AUTH_CONFIG 数据
举个例子,假设你要使用 registry.example.com:5000/private/image:latest 镜像。该镜像为私有镜像,要求你登录私有容器仓库。
再假设登录凭据如下:
| 键 | 值 |
|---|---|
| registry | registry.example.com:5000 |
| username | my_username |
| password | my_password |
使用以下任一方法确定 DOCKER_AUTH_CONFIG 的值:
-
在本地机器执行
docker login:docker login registry.example.com:5000 --username my_username --password my_password然后复制
~/.docker/config.json的内容。若无需从电脑访问该仓库,可执行
docker logout:docker logout registry.example.com:5000 -
部分环境下,Docker 客户端可能使用系统密钥库存储
docker login结果。此时无法读取~/.docker/config.json,需准备${username}:${password}的 base64 编码版本并手动创建 Docker 配置 JSON。打开终端执行以下命令:# 使用 printf(而非 echo)可防止密码中的换行符被编码。 printf "my_username:my_password" | openssl base64 -A # 示例输出供复制 bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=若用户名含特殊字符(如
@),需用反斜杠(\)转义以避免认证问题。创建 Docker JSON 配置内容如下:
{ "auths": { "registry.example.com:5000": { "auth": "(来自上述的 Base64 内容)" } } }
配置作业
若要为单个作业配置对 registry.example.com:5000 的访问,按以下步骤操作:
-
创建 CI/CD 变量
DOCKER_AUTH_CONFIG,值为 Docker 配置文件内容:{ "auths": { "registry.example.com:5000": { "auth": "bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=" } } } -
现在,你可在
.gitlab-ci.yml文件的image或services中使用registry.example.com:5000下的任意私有镜像:image: registry.example.com:5000/namespace/image:tag前例中,GitLab Runner 会查找
registry.example.com:5000上的镜像namespace/image:tag。
你可按需为多个仓库添加配置,向 "auths" 哈希中添加更多仓库(如前所述)。
Runner 在所有场景下均需完整 hostname:port 组合才能匹配 DOCKER_AUTH_CONFIG。例如,若 .gitlab-ci.yml 文件指定 registry.example.com:5000/namespace/image:tag,则 DOCKER_AUTH_CONFIG 也必须指定 registry.example.com:5000。仅指定 registry.example.com 无效。
配置 Runner
如果你的很多流水线都访问同一个注册表,你应该在 Runner 级别设置注册表访问权限。这让流水线作者只需在合适的 Runner 上运行作业就能访问私有注册表,还能简化注册表变更和凭证轮换流程。
这意味着该 Runner 上的任何作业都能以相同权限访问注册表,即使跨项目也是如此。若需控制对注册表的访问,你必须确保能控制对该 Runner 的访问。
要给 Runner 添加 DOCKER_AUTH_CONFIG:
-
按如下方式修改 Runner 的
config.toml文件:[[runners]] environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]DOCKER_AUTH_CONFIG数据中包含的双引号必须用反斜杠转义,避免被解析为 TOML。environment是一个列表。你的 Runner 可能有现有条目,应将其添加到列表中而非替换。
-
重启 Runner 服务。
使用凭证存储
要配置凭证存储:
-
要使用凭证存储,你需要一个外部辅助程序来与特定密钥链或外部存储交互。确保辅助程序在 GitLab Runner 的
$PATH中可用。 -
让 GitLab Runner 使用它。可通过以下任一方式实现:
-
创建一个 CI/CD 变量
DOCKER_AUTH_CONFIG,值为 Docker 配置文件的内容:{ "credsStore": "osxkeychain" } -
或者,若你运行自托管 Runner,将上述 JSON 添加到
${GITLAB_RUNNER_HOME}/.docker/config.json。GitLab Runner 会读取此配置文件,并为特定仓库使用所需的辅助程序。
-
credsStore 用于访问所有注册表。若你同时使用私有注册表的镜像和 Docker Hub 的公开镜像,从 Docker Hub 拉取会失败——Docker 守护进程会尝试对所有注册表使用相同凭证。
使用凭证助手
举个例子,假设你想使用 <aws_account_id>.dkr.ecr.<region>.amazonaws.com/private/image:latest 镜像。这个镜像属于私有库,需要你登录私有容器注册表才能访问。
要配置对 <aws_account_id>.dkr.ecr.<region>.amazonaws.com 的访问,按以下步骤操作:
-
确保
docker-credential-ecr-login在 GitLab Runner 的$PATH中可用。 -
完成任意一种 AWS 凭证设置。确保 GitLab Runner 能访问这些凭证。
-
让 GitLab Runner 使用它。可通过以下任一方式实现:
-
创建一个 CI/CD 变量
DOCKER_AUTH_CONFIG,值为 Docker 配置文件的内容:{ "credHelpers": { "<aws_account_id>.dkr.ecr.<region>.amazonaws.com": "ecr-login" } }此配置让 Docker 对特定注册表使用凭证助手。
相反,你也可以配置 Docker 对所有 Amazon Elastic Container Registry (ECR) 注册表使用凭证助手:
{ "credsStore": "ecr-login" }若使用
{"credsStore": "ecr-login"},需在 AWS 共享配置文件(~/.aws/config)中明确设置区域。当 ECR 凭证助手检索授权令牌时,必须指定该区域。 -
或者,若你运行自托管 Runner,将上述 JSON 添加到
${GITLAB_RUNNER_HOME}/.docker/config.json。GitLab Runner 会读取此配置文件,并为特定仓库使用所需的辅助程序。
-
-
现在,你可在
.gitlab-ci.yml文件的image和/或services中使用<aws_account_id>.dkr.ecr.<region>.amazonaws.com下的任意私有镜像:image: <aws_account_id>.dkr.ecr.<region>.amazonaws.com/private/image:latest在此示例中,GitLab Runner 会查找
<aws_account_id>.dkr.ecr.<region>.amazonaws.com下的private/image:latest镜像。
你可按需为任意多个注册表添加配置,只需向 "credHelpers" 哈希中添加更多注册表即可。
使用校验和保障镜像安全
在 .gitlab-ci.yml 文件的作业定义中使用镜像校验和来验证镜像的完整性。镜像完整性验证失败会阻止你使用被修改的容器。
使用镜像校验和时,必须在末尾附加校验和:
image: ruby:2.6.8@sha256:d1dbaf9665fe8b2175198e49438092fdbcf4d8934200942b94425301b17853c7要获取镜像校验和,请在镜像的 “TAG” 标签页中查看 “DIGEST” 列。
例如,查看 Ruby 镜像。
校验和是一个随机字符串,类似 6155f0235e95。
你也可以通过命令 docker images --digests 获取系统中任何镜像的校验和:
❯ docker images --digests
REPOSITORY TAG DIGEST (...)
gitlab/gitlab-ee latest sha256:723aa6edd8f122d50cae490b1743a616d54d4a910db892314d68470cc39dfb24 (...)
gitlab/gitlab-runner latest sha256:4a18a80f5be5df44cb7575f6b89d1fdda343297c6fd666c015c0e778b276e726 (...)创建自定义 GitLab Runner Docker 镜像
你可以创建一个自定义 GitLab Runner Docker 镜像来打包 AWS CLI 和 Amazon ECR Credential Helper。此设置便于与 AWS 服务进行安全且高效的交互,尤其适用于容器化应用。例如,使用此设置管理、部署和更新 Amazon ECR 上的 Docker 镜像。此设置有助于避免耗时、易出错的手动配置和凭证管理。
-
创建包含以下内容的
Dockerfile:# 控制软件包版本 ARG GITLAB_RUNNER_VERSION=v17.3.0 ARG AWS_CLI_VERSION=2.17.36 # AWS CLI 和 Amazon ECR 凭证助手 FROM amazonlinux as aws-tools RUN set -e \ && yum update -y \ && yum install -y --allowerasing git make gcc curl unzip \ && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" --output "awscliv2.zip" \ && unzip awscliv2.zip && ./aws/install -i /usr/local/bin \ && yum clean all # 下载并安装 ECR 凭证助手 RUN curl --location --output /usr/local/bin/docker-credential-ecr-login "https://github.com/awslabs/amazon-ecr-credential-helper/releases/latest/download/docker-credential-ecr-login-linux-amd64" RUN chmod +x /usr/local/bin/docker-credential-ecr-login # 配置 ECR 凭证助手 RUN mkdir -p /root/.docker RUN echo '{ "credsStore": "ecr-login" }' > /root/.docker/config.json # 基于 GitLab Runner 的最终镜像 FROM gitlab/gitlab-runner:${GITLAB_RUNNER_VERSION} # 安装必要软件包 RUN apt-get update \ && apt-get install -y --no-install-recommends jq procps curl unzip groff libgcrypt20 tar gzip less openssh-client \ && apt-get clean && rm -rf /var/lib/apt/lists/* # 复制 AWS CLI 和 Amazon ECR 凭证助手的二进制文件 COPY --from=aws-tools /usr/local/bin/ /usr/local/bin/ # 复制 ECR 凭证助手配置 COPY --from=aws-tools /root/.docker/config.json /root/.docker/config.json -
要在
.gitlab-ci.yml中构建自定义 GitLab Runner Docker 镜像,请包含以下示例:variables: DOCKER_DRIVER: overlay2 IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME GITLAB_RUNNER_VERSION: v17.3.0 AWS_CLI_VERSION: 2.17.36 stages: - build build-image: stage: build script: - echo "登录 GitLab 容器注册表..." - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - echo "构建 Docker 镜像..." - docker build --build-arg GITLAB_RUNNER_VERSION=${GITLAB_RUNNER_VERSION} --build-arg AWS_CLI_VERSION=${AWS_CLI_VERSION} -t ${IMAGE_NAME} . - echo "推送 Docker 镜像至 GitLab 容器注册表..." - docker push ${IMAGE_NAME} rules: - changes: - Dockerfile