Using Docker images

Using Docker images

GitLab CI / CD 与一起可以使用Docker Engine测试和构建任何应用程序.

Docker 是一个开源项目,它允许您使用预定义的映像在单个 Linux 实例中运行的独立”容器”中运行应用程序. 具有丰富的预构建映像数据库,可用于测试和构建您的应用程序.

与 GitLab CI / CD 一起使用时,Docker 使用.gitlab-ci.yml设置的预定义映像在单独的隔离容器中运行每个作业.

这使得拥有可以在您的工作站上运行的简单且可复制的构建环境更加容易. 额外的好处是您可以测试稍后将在您的 Shell 中探索的所有命令,而不必在专用的 CI 服务器上对其进行测试.

要将 GitLab Runner 与 Docker 一起使用,您需要以使用docker executor.

An example can be seen below. First we set up a temporary template to supply the services:

然后,我们使用刚刚创建的模板注册跑步者:

  1. sudo gitlab-runner register \
  2. --url "https://gitlab.example.com/" \
  3. --registration-token "PROJECT_REGISTRATION_TOKEN" \
  4. --description "docker-ruby:2.6" \
  5. --executor "docker" \
  6. --template-config /tmp/test-config.template.toml \
  7. --docker-image ruby:2.6

注册的运行器将使用ruby:2.6 Docker 映像,并将运行两个服务postgres:latestmysql:latest ,在构建过程中均可访问这两个服务.

What is an image

image关键字是 Docker 执行程序将运行以执行 CI 任务的 Docker 映像的名称.

默认情况下,执行程序仅从提取图像,但是可以通过设置Docker 提取策略以允许使用本地映像在gitlab-runner/config.toml进行配置.

有关映像和 Docker Hub 的更多信息,请阅读文档.

What is a service

services关键字仅定义在您的工作期间运行的另一个 Docker 映像,并链接到image关键字定义的 Docker 映像. 这样,您就可以在构建期间访问服务映像.

服务映像可以运行任何应用程序,但是最常见的用例是运行数据库容器,例如mysql . 与每次安装项目时都安装mysql相比,使用现有映像并将其作为附加容器运行更容易,更快捷.

您不仅限于仅具有数据库服务. 您可以将所需的服务添加到.gitlab-ci.yml或手动修改config.toml . 在或您的私有 Container Registry 中找到的任何映像都可以用作服务.

服务继承与 CI 容器本身相同的 DNS 服务器,搜索域和其他主机.

您可以在CI 服务示例的相关文档中看到一些广泛使用的 .

为了更好地了解容器链接的工作方式,请阅读将容器链接在一起 .

总而言之,如果将mysql作为服务添加到应用程序,则该映像将用于创建链接到作业容器的容器.

The service container for MySQL will be accessible under the hostname mysql. So, in order to access your database service you have to connect to the host named mysql instead of a socket or localhost. Read more in .

How the health check of services works

服务旨在提供可通过网络访问的附加功能. 它可能是一个数据库,例如 MySQL 或 Redis,甚至是docker:stable-dind ,它允许您在 Docker 中使用 Docker. CI / CD 作业继续进行并可以通过网络进行访问几乎是任何事情.

为确保此方法有效,跑步者:

  1. 检查默认情况下哪些端口从容器中暴露出来.
  2. 启动一个特殊的容器,等待这些端口可访问.

当检查的第二阶段失败时(由于服务中没有打开的端口,或者由于在超时之前服务未正确启动且端口没有响应),它会显示警告: *** WARNING: Service XYZ probably didn't start properly .

在大多数情况下,它将影响作业,但是在某些情况下,即使打印了该警告,作业仍将成功. 例如:

  • 发出警告后不久,该服务已启动,并且该作业从一开始就没有使用链接的服务. 在那种情况下,当作业需要访问服务时,它可能已经在那里等待连接.
  • 服务容器不提供任何网络服务,但是它正在使用作业的目录(所有服务都将作业目录作为卷挂载在/builds ). 在这种情况下,服务将完成其工作,并且由于该工作未尝试与其连接,因此它不会失败.

What services are not for

如前所述,此功能旨在提供网络可访问的服务. 数据库是此类服务的最简单示例.

注意:服务功能并非旨在且不会将已定义的services映像中的任何软件添加到作业的容器中.

例如,如果您在作业中定义了以下services ,则脚本无法使用phpnodego命令,因此该作业将失败:

  1. job:
  2. services:
  3. - php:7
  4. - node:latest
  5. - golang:1.10
  6. image: alpine:3.7
  7. script:
  8. - php -v
  9. - node -v
  10. - go version

如果你需要有phpnodego供你的脚本,你应该:

  • 选择一个包含所有必需工具的现有 Docker 映像.
  • 创建您自己的 Docker 映像,它将包含所有必需的工具,并在您的工作中使用它.

Accessing the services

假设您需要一个 Wordpress 实例来测试与应用程序的某些 API 集成.

然后,您可以在.gitlab-ci.yml使用例如图像:

  1. services:
  2. - tutum/wordpress:latest

如果未指定服务别名 ,则在运行作业时,将启动tutum/wordpress ,您将可以从构建容器中使用以下两个主机名访问它:

  • tutum-wordpress
  • tutum__wordpress

注意:带下划线的主机名是 RFC 无效的,可能会导致第三方应用程序出现问题.

服务主机名的默认别名是根据以下规则从其映像名称创建的:

  • 冒号后一切( : )被剥离.
  • 将斜杠( / )替换为双下划线( __ ),并创建主别名.
  • 斜杠( / )替换为单破折号( - ),并创建了辅助别名(需要 GitLab Runner v1.1.0 或更高版本).

要覆盖默认行为,可以 .

您可以简单地定义将用于所有作业的映像以及要在构建期间使用的服务列表:

  1. default:
  2. services:
  3. - postgres:11.7
  4. before_script:
  5. - bundle install
  6. test:
  7. script:
  8. - bundle exec rake spec

图像名称必须采用以下格式之一:

  • image: <image-name> (同使用<image-name>latest标签)
  • image: <image-name>:<tag>
  • image: <image-name>@<digest>

还可以为每个作业定义不同的图像和服务:

  1. default:
  2. before_script:
  3. - bundle install
  4. test:2.6:
  5. image: ruby:2.6
  6. services:
  7. - postgres:11.7
  8. script:
  9. - bundle exec rake spec
  10. test:2.7:
  11. image: ruby:2.7
  12. services:
  13. - postgres:12.2
  14. script:
  15. - bundle exec rake spec

或者,您可以传递一些扩展imageservices

  1. default:
  2. image:
  3. name: ruby:2.6
  4. entrypoint: ["/bin/bash"]
  5. services:
  6. - name: my-postgres:11.7
  7. alias: db-postgres
  8. entrypoint: ["/usr/local/bin/db-postgres"]
  9. command: ["start"]
  10. before_script:
  11. test:
  12. script:
  13. - bundle exec rake spec

Passing environment variables to services

您还可以传递自定义环境以直接在.gitlab-ci.yml文件中微调 Docker imagesservices . 有关更多信息,请参见自定义环境变量.

  1. # The following variables will automatically be passed down to the Postgres container
  2. # as well as the Ruby container and available within each.
  3. variables:
  4. HTTPS_PROXY: "https://10.1.1.1:8090"
  5. HTTP_PROXY: "https://10.1.1.1:8090"
  6. POSTGRES_DB: "my_custom_db"
  7. POSTGRES_USER: "postgres"
  8. POSTGRES_PASSWORD: "example"
  9. PGDATA: "/var/lib/postgresql/data"
  10. POSTGRES_INITDB_ARGS: "--encoding=UTF8 --data-checksums"
  11. services:
  12. - name: postgres:11.7
  13. alias: db
  14. entrypoint: ["docker-entrypoint.sh"]
  15. command: ["postgres"]
  16. image:
  17. name: ruby:2.6
  18. entrypoint: ["/bin/bash"]
  19. before_script:
  20. - bundle install
  21. test:
  22. script:
  23. - bundle exec rake spec

Extended Docker configuration options

在 GitLab 和 GitLab Runner 9.4 中引入.

配置imageservices条目时,可以使用字符串或地图作为选项:

  • 使用字符串作为选项时,它必须是要使用的映像的全名(如果要从 Docker Hub 以外的注册表中下载映像,则应包括注册表部分)
  • 使用地图作为选项时,它必须至少包含name选项,该名称与用于字符串设置的图像名称相同

例如,以下两个定义相等:

  1. 使用字符串作为imageservices的选项:

    1. image: "registry.example.com/my/image:latest"
    2. services:
    3. - postgresql:9.4
    4. - redis:latest
    1. image:
    2. name: "registry.example.com/my/image:latest"
    3. services:
    4. - name: postgresql:9.4
    5. - name: redis:latest

Available settings for image

在 GitLab 和 GitLab Runner 9.4 中引入.

在 GitLab 和 GitLab Runner 9.4 中引入.

注意: GitLab Runner 12.8 了对 Kubernetes 执行器的别名支持,并且仅对 Kubernetes 1.7 或更高版本可用.

Starting multiple services from the same image

在 GitLab 和 GitLab Runner 9.4 中引入. 阅读有关更多信息.

在使用新的扩展 Docker 配置选项之前,以下配置将无法正常工作:

  1. services:
  2. - mysql:latest

The Runner would start two containers using the mysql:latest image, but both of them would be added to the job’s container with the mysql alias based on the default hostname naming. This would end with one of the services not being accessible.

在新的扩展 Docker 配置选项之后,以上示例将如下所示:

Runner 仍将使用mysql:latest映像启动两个容器,但是现在每个容器也可以使用.gitlab-ci.yml文件中配置的别名进行访问.

Setting a command for the service

在 GitLab 和 GitLab Runner 9.4 中引入. 阅读有关扩展配置选项的更多信息.

假设您有一个super/sql:latest映像,其中包含一些 SQL 数据库,并且想将其用作您的工作服务. 我们还假设该映像在启动容器时不会启动数据库进程,并且用户需要手动使用/usr/bin/super-sql run作为命令来启动数据库.

在使用新的扩展 Docker 配置选项之前,您需要基于super/sql:latest映像创建自己的映像,添加默认命令,然后在作业的配置中使用它,例如:

  1. # my-super-sql:latest image's Dockerfile
  2. FROM super/sql:latest
  3. CMD ["/usr/bin/super-sql", "run"]
  1. # .gitlab-ci.yml
  2. services:
  3. - my-super-sql:latest

在新的扩展 Docker 配置选项之后,您现在可以简单地在.gitlab-ci.yml设置command ,例如:

  1. # .gitlab-ci.yml
  2. services:
  3. - name: super/sql:latest
  4. command: ["/usr/bin/super-sql", "run"]

如您所见, command的语法类似于 .

Overriding the entrypoint of an image

在 GitLab 和 GitLab Runner 9.4 中引入. 阅读有关更多信息.

在显示可用的入口点覆盖方法之前,让我们简要介绍一下 Runner 如何启动以及如何将 Docker 映像用于 CI 作业中使用的容器:

  1. Runner 使用定义的入口点启动 Docker 容器( Dockerfile中的默认值,该文件可能会在.gitlab-ci.yml覆盖)
  2. 跑步者将自己附加到正在运行的容器上.
  3. 跑步者准备一个脚本( before_script , 和after_script的组合).
  4. 运行程序将脚本发送到容器的外壳 STDIN 并接收输出.

要覆盖 Docker 映像的入口点,建议的解决方案是在.gitlab-ci.yml定义一个空entrypoint .gitlab-ci.yml ,以便 Runner 不会启动无用的 shell 层. 但是,这不适用于所有 Docker 版本,因此您应检查 Runner 使用的是哪个版本. 特别:

  • 如果使用 Docker 17.06 或更高版本,则entrypoint可以设置为空值.
  • 如果使用 Docker 17.03 或更早版本,则entrypoint可以设置为/bin/sh -c/bin/bash -c或映像中可用的等效 shell.

image:entrypoint的语法类似于 .

假设您有一个super/sql:experimental映像,其中包含一些 SQL 数据库,并且您想将其用作工作的基础映像,因为您想使用此数据库二进制文件执行一些测试. 我们还假设此映像是使用/usr/bin/super-sql run作为入口点配置的. 这意味着在启动没有其他选项的容器时,它将运行数据库的进程,而 Runner 希望映像没有入口点,或者入口点已准备好启动 Shell 命令.

使用扩展的 Docker 配置选项,而不是基于super/sql:experimental创建自己的映像,将ENTRYPOINT设置为 shell,然后在 CI 作业中使用新映像,您现在只需在.gitlab-ci.yml定义一个entrypoint .gitlab-ci.yml .

对于 Docker 17.06+:

  1. image:
  2. name: super/sql:experimental
  3. entrypoint: [""]

对于 Docker = <17.03:

  1. name: super/sql:experimental
  2. entrypoint: ["/bin/sh", "-c"]

查找[runners.docker]部分:

  1. [runners.docker]
  2. image = "ruby:latest"
  3. services = ["mysql:latest", "postgres:latest"]

以这种方式定义的图像和服务将添加到该运行程序运行的所有作业中.

Define an image from a private Container Registry

要访问私有容器注册表,GitLab Runner 进程可以使用:

  • . 也就是说,特定注册表的用户名和密码.
  • 凭证存储 . 有关更多信息,请参阅 .
  • 凭证助手 . 有关更多信息,请参阅 .

为了定义应该使用哪个,GitLab Runner 进程按以下顺序读取配置:

  • DOCKER_AUTH_CONFIG变量提供为:
    • .gitlab-ci.yml 变量 .
    • 项目的变量存储在项目的“设置”>” CI / CD”页面上.
  • Runner 的config.toml中提供了DOCKER_AUTH_CONFIG变量作为环境变量.
  • config.json文件放置在运行 GitLab Runner 进程的用户的$HOME/.docker目录中. 如果提供了--user标志以非特权用户身份运行 GitLab Runner 子进程,则将使用 GitLab Runner 主进程用户的主目录.

注意: GitLab Runner 仅从 config.toml读取此配置,并且如果它是作为环境变量提供的,则忽略它. 这是因为 GitLab Runner 使用config.toml配置,并且不会在运行时内插任何环境变量.

Requirements and limitations

  • 此功能需要 GitLab Runner 1.8或更高版本.
  • 对于> = 0.6,<1.8 的 GitLab Runner 版本部分支持使用私有注册表,这要求在运行者的主机上手动配置凭据. 如果要使用私人注册表,建议将 Runner 至少升级到1.8版.
  • 在 GitLab Runner 13.1 和更高版本中适用于Kubernetes 执行器 .

您可以采用两种方法来访问私有注册表. 两者都需要使用适当的身份验证信息设置环境变量DOCKER_AUTH_CONFIG .

  1. 每个作业:要配置一个作业以访问专用注册表,请添加DOCKER_AUTH_CONFIG作为作业变量.
  2. 每个运行者:要配置 Runner 以便其所有作业都可以访问私有注册表,请在 Runner 的配置中将DOCKER_AUTH_CONFIG添加到环境中.

请参阅下面的示例.

Determining your DOCKER_AUTH_CONFIG data

例如,假设您要使用registry.example.com:5000/private/image:latest映像,该映像是私有映像,需要您登录到私有容器注册表.

我们还假设这些是登录凭据:

有两种方法可以确定DOCKER_AUTH_CONFIG的值:

  • 第一种方法-在本地计算机上进行docker login

    1. docker login registry.example.com:5000 --username my_username --password my_password

    然后复制~/.docker/config.json .

    如果您不需要从计算机访问注册表,则可以执行docker logout

    1. docker logout registry.example.com:5000
  • 第二种方式-在某些设置中,Docker 客户端可能会使用可用的系统密钥存储区来存储docker login的结果. 在这种情况下,无法读取~/.docker/config.json ,因此您将需要准备所需的${username}:${password} base64 编码版本,并手动创建 Docker 配置 JSON. 打开一个终端并执行以下命令:

    1. # Note the use of "-n" - it prevents encoding a newline in the password.
    2. echo -n "my_username:my_password" | base64
    3. # Example output to copy
    4. bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=

    创建 Docker JSON 配置内容,如下所示:

    1. { "auths": { "registry.example.com:5000": { "auth": "(Base64 content from above)" } } }

Configuring a job

要配置具有对registry.example.com:5000访问权限的单个作业,请按照下列步骤操作:

  1. 创建一个 DOCKER_AUTH_CONFIG ,并将 Docker 配置文件的内容作为值:

  2. 现在,您可以使用.gitlab-ci.yml文件中image和/或services中定义的registry.example.com:5000任何私有图像:

    1. image: registry.example.com:5000/namespace/image:tag

    在上面的例子,GitLab 转轮会看registry.example.com:5000用于图像namespace/image:tag .

您可以根据需要添加任意数量的注册表配置,如上所述,将更多注册表添加到"auths"哈希中.

注意: Runner 到处都需要完整的hostname:port组合,以使其与DOCKER_AUTH_CONFIG相匹配. 例如,如果registry.example.com:5000/namespace/image:tag中指定.gitlab-ci.yml ,则DOCKER_AUTH_CONFIG还必须指定registry.example.com:5000 . 仅指定registry.example.com将不起作用.

Configuring a Runner

当然,这意味着该运行程序上的任何作业都可以使用相同的特权访问注册表,即使在整个项目中也是如此. 如果需要控制对注册表的访问,则需要确保控制对运行器的访问.

要将DOCKER_AUTH_CONFIG添加到运行器:

  1. 修改 Runner 的config.toml文件,如下所示:

    1. [[runners]]
    2. environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]
  2. 重新启动 Runner 服务.

注意: DOCKER_AUTH_CONFIG数据中包含的双引号必须使用反斜杠转义. 这样可以防止将它们解释为 TOML.注意: environment选项是一个列表. 因此,您的跑步者可能已有条目,您应该将其添加到列表中,而不是替换它.

Using Credentials Store

要配置凭据存储,请按照下列步骤操作:

  1. 要使用凭据存储,您需要一个外部帮助程序来与特定的钥匙串或外部存储进行交互. 确保 GitLab Runner $PATH有可用的帮助程序.

  2. 使 GitLab Runner 使用它. 有两种方法可以完成此操作. 要么:

    • 创建一个变量 DOCKER_AUTH_CONFIG ,并将 Docker 配置文件的内容作为值:

      1. { "credsStore": "osxkeychain" }
    • 或者,如果您正在运行自我管理的${GITLAB_RUNNER_HOME}/.docker/config.json ,请将上面的 JSON 添加到${GITLAB_RUNNER_HOME}/.docker/config.json . GitLab Runner 将读取此配置文件,并将使用此特定存储库所需的帮助程序.

注意: credsStore用于访问所有注册表. 如果要同时使用私有注册表中的映像和 DockerHub 中的公共映像,则从 DockerHub 提取将失败,因为 Docker 守护程序将尝试对所有注册表使用相同的凭据.

Using Credential Helpers

作为示例,假设您要使用aws_account_id.dkr.ecr.region.amazonaws.com/private/image:latest映像,该映像是私有的,需要您登录到私有容器注册表.

要配置aws_account_id.dkr.ecr.region.amazonaws.com访问aws_account_id.dkr.ecr.region.amazonaws.com ,请按照以下步骤操作:

  1. 确保docker-credential-ecr-login在 GitLab Runner 的$PATH可用.

  2. 具有以下任何AWS 凭证设置 . 确保 GitLab Runner 可以访问凭据.

  3. 使 GitLab Runner 使用它. 有两种方法可以完成此操作. 要么:

    • 创建一个 DOCKER_AUTH_CONFIG ,并将 Docker 配置文件的内容作为值:

      1. { "credHelpers": { "aws_account_id.dkr.ecr.region.amazonaws.com": "ecr-login" } }

      这会将 Docker 配置为对特定注册表使用凭据帮助器.

      or

      1. { "credsStore": "ecr-login" }

      这会将 Docker 配置为对所有 Amazon ECR 注册表使用凭证帮助器.

    • 或者,如果您正在运行自我管理的${GITLAB_RUNNER_HOME}/.docker/config.json ,请将上面的 JSON 添加到${GITLAB_RUNNER_HOME}/.docker/config.json . GitLab Runner 将读取此配置文件,并将使用此特定存储库所需的帮助程序.

  4. 现在,您可以使用.gitlab-ci.yml文件中image和/或services中定义的aws_account_id.dkr.ecr.region.amazonaws.com任何私有图像:

    1. 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"数量的注册表配置,如上所述,将更多注册表添加到"credHelpers"哈希中.

Configuring services

许多服务接受环境变量,这些变量使您可以根据环境轻松更改数据库名称或设置帐户名称.

GitLab Runner 0.5.0 及更高版本将所有 YAML 定义的变量传递到创建的服务容器.

For all possible configuration variables check the documentation of each image provided in their corresponding Docker hub page.

注意:所有变量都将传递到所有服务容器. 它并非旨在区分哪个变量应该放在哪里.

PostgreSQL service example

请参阅有关将PostgreSQL 用作服务的特定文档.

请参阅有关将的特定文档.

以下是 Docker 在作业期间执行的步骤的高级概述.

  1. 创建任何服务容器: mysqlpostgresqlmongodbredis .
  2. 创建缓存容器以存储config.toml和构建映像的Dockerfile中定义的所有卷(如上例中的ruby:2.6 ).
  3. 创建构建容器并将任何服务容器链接到构建容器.
  4. 启动构建容器并将作业脚本发送到该容器.
  5. 运行作业脚本.
  6. 检出代码: /builds/group-name/project-name/ .
  7. 运行.gitlab-ci.yml定义的任何步骤.
  8. 检查构建脚本的退出状态.
  9. 删除构建容器和所有创建的服务容器.

How to debug a job locally

注意:以下命令在没有 root 特权的情况下运行. 您应该能够使用常规用户帐户运行 Docker.

首先从创建一个名为build_script的文件build_script

  1. cat <<EOF > build_script
  2. git clone https://gitlab.com/gitlab-org/gitlab-runner.git /builds/gitlab-org/gitlab-runner
  3. cd /builds/gitlab-org/gitlab-runner
  4. make EOF

在这里,我们以包含 Makefile 的 GitLab Runner 存储库为例,因此运行make将执行 Makefile 中定义的命令. 您的里程可能会有所不同,所以不是make你可以运行它是特定于项目的命令.

然后创建一些服务容器:

  1. docker run -d --name service-mysql mysql:latest
  2. docker run -d --name service-postgres postgres:latest

这将创建两个服务容器,分别名为service-mysqlservice-postgres ,它们分别使用最新的 MySQL 和 PostgreSQL 映像. 它们都将在后台( -d )运行.

最后,通过执行我们之前创建的build_script文件来创建构建容器:

  1. docker run --name build -i --link=service-mysql:mysql --link=service-postgres:postgres ruby:2.6 /bin/bash < build_script

上面的命令将创建一个名为build的容器,该容器是从ruby:2.6镜像派生的,并且有两个链接到它的服务. 使用 STDIN 将build_script通过管道传输到 bash 解释器,然后 bash 解释器将在build容器中执行build_script .

完成测试后,不再需要这些容器时,可以使用以下方法删除它们:

  1. docker rm -f -v build service-mysql service-postgres

这将强制( -f )删除build容器,两个服务容器以及随容器创建而创建的所有卷( -v ).