Docker 执行器

极狐GitLab Runner 使用 Docker 执行器在 Docker 镜像上运行作业。

您可以使用 Docker 执行器来:

  • 为每个作业保持相同的构建环境。
  • 使用相同的镜像在本地测试命令,而无需在 CI 服务器中运行作业。

Docker 执行器使用 Docker Engine 在单独和隔离的容器中运行每个作业。要连接到 Docker 引擎,执行器使用:

前提条件:

Docker 执行器工作流

Docker 执行器使用基于 Alpine Linux 的特殊 Docker 镜像,该镜像包含运行准备、作业前和作业后步骤的工具。

Docker 执行器将作业分为几个步骤:

  1. 准备:创建并启动服务
  2. 作业前:克隆、恢复缓存,并从前面的阶段下载产物。 在特殊的 Docker 镜像上运行。
  3. 作业中:在您为 Runner 配置的 Docker 镜像中运行您的构建。
  4. 作业后:创建缓存,上传产物到极狐GitLab。运行在特殊的 Docker 镜像上。

支持的配置

Docker 执行器支持以下配置。

对于已知的 Windows 问题和其他要求,请使用 Windows 容器

Runner 安装在 执行器 容器运行
Windows docker-windows Windows
Windows docker Linux
Linux docker Linux

支持以下配置:

Runner 安装在 执行器 容器运行
Linux docker-windows Linux
Linux docker Windows
Linux docker-windows Windows
Windows docker Windows
Windows docker-windows Linux
note 极狐GitLab Runner 使用 Docker Engine API v1.25 与 Docker Engine 通信。也就是说在 Linux 服务器上,Docker 的最低支持版本1.13.0Windows 服务器上需要更高版本以识别 Windows 服务器版本。

使用 Docker 执行器

要使用 Docker 执行器,请在 config.toml 中将 Docker 定义为执行器。

以下示例显示了定义为执行器的 Docker 和示例配置。有关这些值的更多信息,请参阅高级配置

concurrent = 4

[[runners]]
name = "myRunner"
url = "https://gitlab.com/ci"
token = "......"
executor = "docker"
[runners.docker]
  tls_verify = true
  image = "my.registry.tld:5000/alpine:latest"
  privileged = false
  disable_entrypoint_overwrite = false
  oom_kill_disable = false
  disable_cache = false
  volumes = [
    "/cache",
  ]
  shm_size = 0
  allowed_pull_policies = ["always", "if-not-present"]
  allowed_images = ["my.registry.tld:5000/*:*"]
  allowed_services = ["my.registry.tld:5000/*:*"]
  [runners.docker.volume_driver_ops]
    "size" = "50G"

配置镜像和 Services

先决条件:

  • 运行作业的镜像必须在其操作系统 PATH 中有一个 working shell。支持的 shell 为:
    • 对于 Linux:
      • sh
      • bash
      • PowerShell Core (pwsh)。引入于 13.9。
    • 对于 Windows
      • PowerShell (powershell)
      • PowerShell Core (pwsh)。引入于 13.6。

要配置 Docker 执行器,您可以在 .gitlab-ci.ymlconfig. toml 中定义 Docker 镜像和 services。

使用以下关键字:

  • image:Runner 用来运行作业的 Docker 镜像的名称。
    • 输入来自本地 Docker Engine 的镜像,或 Docker Hub 中的任何镜像。 有关详细信息,请参阅 Docker 文档
    • 要定义镜像版本,请使用冒号 (:) 添加标签。如果您不指定标签,Docker 使用 latest 作为版本。
  • services:创建另一个容器并链接到 image 的其他镜像。有关 services 类型的更多信息,请参阅 Services

定义 .gitlab-ci.yml 中的镜像和服务

定义 Runner 用于所有作业的镜像和在构建期间使用的服务列表。

示例:

image: ruby:2.7

services:
  - postgres:9.3

before_script:
  - bundle install

test:
  script:
  - bundle exec rake spec

要为每个作业定义不同的镜像和服务:

before_script:
  - bundle install

test:2.6:
  image: ruby:2.6
  services:
  - postgres:9.3
  script:
  - bundle exec rake spec

test:2.7:
  image: ruby:2.7
  services:
  - postgres:9.4
  script:
  - bundle exec rake spec

如果您没有在 .gitlab-ci.yml 中定义 image,Runner 将使用 config.toml 中定义的 image

定义 config.toml 中的镜像和服务

要向 Runner 运行的所有作业添加镜像和服务,请更新 config.toml 中的 [runners.docker]。 如果您没有在 .gitlab-ci.yml 中定义 image,Runner 将使用 config.toml 中定义的镜像。

示例:

[runners.docker]
  image = "ruby:2.7"

[[runners.docker.services]]
  name = "mysql:latest"
  alias = "db"

[[runners.docker.services]]
  name = "redis:latest"
  alias = "cache"

这个示例使用表格阵列语法

定义私有镜像库中的镜像

先决条件:

要从私有镜像库定义镜像,请在 .gitlab-ci.yml 中提供镜像库名称和镜像。

示例:

image: my.registry.tld:5000/namepace/image:tag

在此示例中,极狐GitLab Runner 在镜像库 my.registry.tld:5000 中搜索镜像 namespace/image:tag

网络配置

您必须配置网络以将服务连接到 CI/CD 作业。

要配置网络,您可以:

  • 推荐。配置 Runner 为每个作业创建网络。
  • 定义容器链接。容器链接是 Docker 的遗留功能。

为每个作业创建网络

您可以配置 Runner 为每个作业创建一个网络。

当您启用此网络模式时,Runner 会为每个作业创建并使用一个用户定义的 Docker 桥接网络。 Docker 环境变量不在容器之间共享。更多关于用户定义的桥接网络信息,请参见 Docker 文档

要使用此网络模式,请在功能标志中启用 FF_NETWORK_PER_BUILD 或在 config.toml 中启用环境变量。

不要设置 network_mode

示例:

[[runners]]
  (...)
  executor = "docker"
  environment = ["FF_NETWORK_PER_BUILD = 1"]

或:

[[runners]]
  (...)
  executor = "docker"
  [runners.feature_flags]
    FF_NETWORK_PER_BUILD = true

要设置默认的 Docker 地址池,请在 dockerd 中使用 default-address-pool。 如果已在网络中使用了 CIDR 范围,Docker 网络可能与主机上的其他网络冲突,包括其他 Docker 网络。

此功能仅在 Docker daemon 配置为启用 IPv6 时有效。 要启用 IPv6 支持,请在 Docker 配置中将 enable_ipv6 设置为 true。 有关详细信息,请参阅 Docker 文档

Runner 使用 build 别名来解析作业容器。

Runner 如何为每个作业创建网络

作业开始时,Runner:

  1. 创建桥接网络,类似于 Docker 命令 docker network create <network>
  2. 将服务和容器连接到桥接网络。
  3. 在作业结束时删除网络。

运行作业的容器和运行服务的容器解析彼此的主机名和别名。 这个功能由 Docker 提供

使用容器链接配置网络

您可以配置使用 Docker 遗留容器链接和默认 Docker bridge 的网络模式将作业容器与服务进行连接。 如果未启用 FF_NETWORK_PER_BUILD,这种网络模式是默认的。

要配置网络,请在 config.toml 文件中指定网络模式

  • bridge:使用桥接网络。默认。
  • host:在容器内使用主机的网络栈。
  • none:没有网络。不建议。

示例:

[[runners]]
  (...)
  executor = "docker"
[runners.docker]
  network_mode = "bridge"

如果您使用任何其他 network_mode 值,这些被视为构建容器连接的现存 Docker 网络的名称。

在名称解析期间,Docker 会使用服务容器主机名和别名更新目录中的 /etc/hosts 文件。 然而,服务容器不能解析容器名称。 要解析容器名称,您必须为每个作业创建一个网络。

链接的容器共享它们的环境变量。

覆盖创建网络的 MTU

在有些环境下,诸如 OpenStack 的虚拟机,自定义 MTU 是有必要的。Docker 守护进程在 docker.json 文件中并不包含 MTUS。您可以在您的 config.toml 文件中将 network_mtu 设为任意有效值,以便 Docker 守护进程可以使用正确的 MTU 创建新的网络。您还必须启用 FF_NETWORK_PER_BUILD 以使覆盖生效。

以下配置将每个作业的创建网络的 MTU 设置为 1402。您需要确保将此值调整到符合您的实际环境所需。

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    network_mtu = 1402
    [runners.feature_flags]
      FF_NETWORK_PER_BUILD = true

限制 Docker 镜像和服务

要限制 Docker 镜像和服务,请在 allowed_imagesallowed_services 参数中指定通配符模式。

例如,仅允许您的私有 Docker 镜像库的镜像:

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    allowed_images = ["my.registry.tld:5000/*:*"]
    allowed_services = ["my.registry.tld:5000/*:*"]

要限制您的私有 Docker 镜像库的镜像列表:

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    allowed_images = ["my.registry.tld:5000/ruby:*", "my.registry.tld:5000/node:*"]
    allowed_services = ["postgres:9.4", "postgres:latest"]

访问服务主机名

要访问服务主机名,请将服务添加到 .gitlab-ci.yml 中的 services 中。

例如,要使用 Wordpress 实例来测试 API 与您的应用程序的集成,请使用 tutum/wordpress 作为服务镜像:

services:
  - tutum/wordpress:latest

当作业运行时,tutum/wordpress 服务启动。您可以从主机名为 tutum__wordpresstutum-wordpress 的构建容器进行访问。

除了指定的服务别名之外,Runner 还将服务镜像的名称作为别名分配给服务容器。您可以使用这些别名中的任何一个。

Runner 使用以下规则根据镜像名称创建别名:

  • 删除 : 之后的所有内容。
  • 对于第一个别名,将斜杠 (/) 替换为双下划线 (__)。
  • 对于第二个别名,将斜杠 (/) 替换为单破折号 (-)。

如果您使用私有服务镜像,则 Runner 会剥离任何指定的端口并应用规则。 服务 registry.gitlab-wp.com:4999/tutum/wordpress 会生成主机名 registry.gitlab-wp.com__tutum__wordpressregistry.gitlab-wp.com-tutum-wordpress

配置服务

要更改数据库名称或设置账户名称,您可以为服务定义环境变量。

当 Runner 传递变量时:

  • 变量传递给所有容器。Runner 无法将变量传递给特定容器。
  • 安全变量被传递到构建容器。

有关配置变量的更多信息,请参阅相应的 Docker Hub 页面中提供的镜像文档。

在 RAM 中挂载目录

您可以使用 tmpfs 选项在 RAM 中挂载目录。如果有很多 I/O 相关的工作,例如数据库,测试所需的时间会缩短。

如果您在 Runner 配置中使用 tmpfsservices_tmpfs 选项, 您可以指定多个路径,每个路径都有自己的选项。有关详细信息,请参阅 Docker 文档

例如,要在 RAM 中挂载官方 MySQL 容器的数据目录,配置 config.toml

[runners.docker]
# For the main container
[runners.docker.tmpfs]
"/var/lib/mysql" = "rw,noexec"

# For services
[runners.docker.services_tmpfs]
"/var/lib/mysql" = "rw,noexec"

在服务中构建目录

极狐GitLab Runner 将 /builds 目录挂载到所有共享服务。

有关使用不同服务的更多信息,请参阅:

极狐GitLab Runner 如何执行服务健康检查

引入多个端口检查于极狐GitLab 16.0。

服务启动后,极狐GitLab Runner 等待服务响应。Docker 执行器尝试打开服务容器中暴露的服务端口的 TCP 连接。

  • 在 15.11 及更早版本中,仅检查第一个暴露的端口。
  • 在 16.0 及更高版本中,检查前 20 个暴露的端口。

HEALTHCHECK_TCP_PORT 服务变量可用于对特定端口进行健康检查:

job:
  services:
    - name: mongo
      variables:
        HEALTHCHECK_TCP_PORT: "27017"

要查看实现方式,请使用健康检查 Go 命令

指定 Docker driver 操作

当您为构建创建卷时,指定提供给 Docker 卷驱动程序的参数。 例如,除了所有其他特定于驱动程序的选项之外,您还可以使用这些参数来限制每个构建运行的空间。 以下示例显示了 config.toml,其中每个构建可以使用的限制设置为 50GB。

[runners.docker]
  [runners.docker.volume_driver_ops]
      "size" = "50G"

为容器构建和缓存配置目录

要定义数据在容器中的存储位置,请配置 config.toml[[runners]] 部分中的 /builds/cache 目录。

如果修改 /cache 存储路径,要将路径标记为永久,您必须在 config.toml 中的 [runners.docker] 部分下的 volumes = ["/my/cache/"] 中进行定义。

默认情况下,Docker 执行器将构建和缓存存储在以下目录中:

  • /builds/<namespace>/<project-name> 中构建
  • 在容器内的 /cache 中缓存。

清理 Docker 缓存

引入于极狐GitLab Runner 13.9。

使用 clear-docker-cache 移除 Runner 创建的未使用的容器和卷。

对于选项列表,使用 help 选项运行脚本:

clear-docker-cache help

默认选项是 prune-volumes,它会删除所有未使用的容器(悬挂和未引用的)和卷。

要有效地管理缓存存储,您应该:

  • 定期运行带有 cronclear-docker-cache(例如,每周一次)。
  • 回收磁盘空间时,维护缓存中最近的容器以提高性能。

清理 Docker 构建镜像

clear-docker-cache 脚本不会移除 Docker 镜像,因为极狐GitLab Runner 没对其打标签。

要清理 Docker 构建镜像:

  1. 确认可以回收哪些磁盘空间:

     clear-docker-cache space
    
     Show docker disk usage
     ----------------------
    
     TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
     Images          14        9         1.306GB   545.8MB (41%)
     Containers      19        18        115kB     0B (0%)
     Local Volumes   0         0         0B        0B
     Build Cache     0         0         0B        0B
    
  2. 要删除所有未使用的容器、网络、镜像(悬挂和未引用)和未打标签的卷,请运行 docker system prune

持久化存储

Docker 执行器在运行容器时提供持久化存储。 所有 volumes = 下定义的目录在构建间都是持久的。

volumes 指令支持以下存储类型:

  1. 对于动态存储,使用 <path><path> 在项目的同一个并发作业的后续运行中是持久的。 数据附属于自定义缓存卷:runner-<short-token>-project-<id>-concurrent-<concurrency-id>-cache-<md5-of-path>
  2. 对于主机绑定存储,使用 <host-path>:<path>[:<mode>]<path> 在主机系统上绑定到 <host-path>。可选的 <mode> 指定存储是只读或读写(默认)。

构建的持久化存储

如果您使 /builds 目录成为主机绑定存储,您的构建存储在: /builds/<short-token>/<concurrent-id>/<namespace>/<project-name>,其中:

  • <short-token> 是 Runner 的令牌(前 8 个字母)的缩写版本。
  • <concurrent-id> 是一个独特的数字,识别在项目的上下文中的特定 Runner 的本地作业 ID。

IPC 模式

Docker 执行器支持与其他位置共享容器的 IPC 命名空间。 这会映射到 docker run --ipc 标志。 更多内容,请参见 Docker 文档中的 IPC 设置

特权模式

Docker 执行器支持很多允许构建容器的微调的选项。 其中一个选项是privileged 模式

通过特权模式使用 Docker-in-Docker

配置的 privileged 标记被传递到构建容器和所有 服务,因此允许容易地使用 Docker-in-Docker 方法。

首先,配置您的 Runner (config.toml) 在 privileged 模式下运行:

[[runners]]
  executor = "docker"
  [runners.docker]
    privileged = true

然后,让您的构建脚本 (.gitlab-ci.yml) 使用 Docker-in-Docker 容器:

image: docker:git
services:
- docker:dind

build:
  script:
  - docker build -t my-image .
  - docker push my-image
caution 在特权模式下运行的容器存在安全风险。 当您的容器在特权模式下运行时,您将禁用容器安全机制并使您的主机面临特权升级。 在特权模式下运行容器可能会导致容器崩溃。有关更多信息,请参阅有关运行时权限和 Linux 功能的 Docker 文档。

您可能需要为 Docker in Docker 配置 TLS 或禁用 TLS 以避免发生如下错误:

Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?

在受限特权模式下使用无根 Docker-in-Docker

在此版本中,仅允许 Docker-in-Docker 无根镜像作为服务在特权模式下运行。

services_privilegedallowed_privileged_services 配置参数限制允许在特权模式下运行的容器。

要在受限特权模式下使用无根 Docker-in-Docker:

  1. config.toml 中,配置 Runner 使用 services_privilegedallowed_privileged_services

    [[runners]]
      executor = "docker"
      [runners.docker]
        services_privileged = true
        allowed_privileged_services = [docker.io/library/docker:*-dind-rootless, docker.io/library/docker:dind-rootless, docker:*-dind-rootless, docker:*-dind-rootless]
    
  2. .gitlab-ci.yml 中,编辑构建脚本以使用 Docker-in-Docker 无根容器:

    image: docker:git
    services:
    - docker:dind-rootless
    
    build:
      script:
      - docker build -t my-image .
      - docker push my-image
    

只有您在 allowed_privileged_services 中列出的 Docker-in-Docker 无根镜像才允许在特权模式下运行。 用于作业和服务的所有其他容器都以非特权模式运行。

因为它们以非 root 身份运行,所以与 Docker-in-Docker rootless 或 Buildkit rootless 等特权模式镜像一起使用几乎是安全的。

有关安全问题的更多信息,请参阅 Docker 执行器的安全风险

配置 Docker 入口点(ENTRYPOINT)

默认情况下,Docker 执行器不会覆盖 Docker 镜像的 ENTRYPOINT 并将 shbash 作为 COMMAND 进行传递以启动运行作业脚本的容器。

为确保作业可以运行,其 Docker 镜像必须:

  • 提供 shbash
  • 定义一个 ENTRYPOINT,在将 sh/bash 作为参数进行传递时启动 shell。

Docker 执行器使用与以下命令等效的命令运行作业的容器:

docker run <image> sh -c "echo 'It works!'" # or bash

如果您的 Docker 镜像不支持此机制,您可以在项目配置中覆盖镜像的入口点,如下所示:

# Equivalent of
# docker run --entrypoint "" <image> sh -c "echo 'It works!'"
image:
  name: my-image
  entrypoint: [""]

有关详细信息,请参阅覆盖镜像的入口点CMD 和 ENTRYPOINT 如何在 Docker 中交互

作业脚本作为 ENTRYPOINT

您可以使用 ENTRYPOINT 创建一个在自定义环境或安全模式下运行构建脚本的 Docker 镜像。

例如,您可以创建一个使用 ENTRYPOINT 但不执行构建脚本的 Docker 镜像。 相反,Docker 镜像执行一组预定义的命令,从您的目录构建 Docker 镜像。您以特权模式运行构建容器,并且确保 Runner 构建环境的安全。

  1. 创建新的 Dockerfile:

    FROM docker:dind
    ADD / /entrypoint.sh
    ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
    
  2. 创建被用作 ENTRYPOINT 的 Bash 脚本 (entrypoint.sh):

    #!/bin/sh
    
    dind docker daemon
        --host=unix:///var/run/docker.sock \
        --host=tcp://0.0.0.0:2375 \
        --storage-driver=vf &
    
    docker build -t "$BUILD_IMAGE" .
    docker push "$BUILD_IMAGE"
    
  3. 将镜像推送到 Docker 镜像库。

  4. privileged 模式运行 Docker 执行器。在 config.toml 中定义:

    [[runners]]
      executor = "docker"
      [runners.docker]
        privileged = true
    
  5. 在您的项目中,使用以下 .gitlab-ci.yml

    variables:
      BUILD_IMAGE: my.image
    build:
      image: my/docker-build:image
      script:
      - Dummy Script
    

使用 Podman 运行 Docker 命令

引入于极狐GitLab 15.3。

如果您在 Linux 上安装了就GitLab Runner,您的作业可以使用 Podman 代替 Docker 作为 Docker 执行器中的容器运行时。

先决条件:

  1. 在您的 Linux 主机上,安装极狐GitLab Runner。如果您使用系统的包管理器安装了极狐GitLab Runner,它会自动创建一个 gitlab-runner 用户。
  2. 以运行极狐GitLab Runner 的用户身份登录。您必须以不绕过 pam_systemd 的方式处理。 您可以以正确的用户身份使用 SSH,因为这样您可以以该用户身份运行 systemctl
  3. 确保您的系统满足 Rootless Podman 设置的先决条件。 具体来说,确保您的用户/etc/subuid/etc/subgid 拥有正确的条目
  4. 在 Linux 主机上,安装 Podman
  5. 启用并启动 Podman 套接字:

    systemctl --user --now enable podman.socket
    
  6. 验证 Podman 套接字正在监听:

    systemctl status --user podman.socket
    
  7. 复制 Listen 密钥中的套接字字符串,通过该密钥可以访问 Podman 的 API。
  8. 确保在极狐GitLab Runner 用户登出后,Podman 套接字仍然可用:

    sudo loginctl enable-linger gitlab-runner
    
  9. 编辑极狐GitLab Runner config.toml 文件并向 [[runners.docker]] 部分中的服务器条目添加套接字值。

    例如:

    [[runners]]
      name = "podman-test-runner-2022-06-07"
      url = "https://jihulab.com"
      token = "x-XxXXXXX-xxXxXxxxxx"
      executor = "docker"
      [runners.docker]
        host = "unix:///run/user/1012/podman/podman.sock"
        tls_verify = false
        image = "quay.io/podman/stable"
        privileged = true
    

使用 Podman 从 Dockerfile 构建容器镜像

下面的示例描述如何使用 Podman 构建容器镜像并将镜像推送到极狐GitLab 容器镜像库。Runner config.toml 中的默认容器镜像设置为 quay.io/podman/stable,所以 CI 作业将默认使用该镜像来执行包含的命令。

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG

before_script:
  - podman login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY

oci-container-build:
  stage: build
  script:
    - podman build -t $IMAGE_TAG .
    - podman push $IMAGE_TAG
  when: manual

使用 Buildah 从 Dockerfile 构建容器镜像

下面的示例描述如何使用 Buildah 构建容器镜像并将镜像推送到极狐GitLab 容器镜像库。

image: quay.io/buildah/stable

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG

before_script:
  - buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY

oci-container-build:
  stage: build
  script:
    - buildah bud -t $IMAGE_TAG .
    - buildah push $IMAGE_TAG
  when: manual

指定运行作业的用户

默认情况下,Runner 在容器内以 root 用户的身份运行作业。为了指定不同的、非根用户运行作业,使用 Docker 镜像的 Docker 文件中的 USER 指令。

FROM amazonlinux
RUN ["yum", "install", "-y", "nginx"]
RUN ["useradd", "www"]
USER "www"
CMD ["/bin/bash"]

当您使用 Docker 镜像执行作业,它作为特定用户运行:

build:
  image: my/docker-build:image
  script:
  - whoami   # www

配置 Runner 如何拉取镜像

config.toml 中配置拉取策略以定义 Runner 如何从镜像库拉取 Docker 镜像。您可以设置单个策略、策略列表允许特定的拉取策略

pull_policy 使用以下值:

  • always:即使本地镜像存在也拉取镜像。默认。
  • if-not-present:仅在本地版本不存在时拉取镜像。
  • never: 从不拉取镜像,只使用本地镜像。
[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    pull_policy = "always" # available: always, if-not-present, never

设置always 拉取策略

默认情况下打开的 always 选项总是在创建容器之前启动拉取。 此选项确保镜像是最新的,并且即使存在本地镜像,也可以防止您使用过期的镜像。

在以下情况下使用此拉取策略:

  • Runner 必须始终拉取最新的镜像。
  • Runner 公开可用,并配置为弹性伸缩或作为您的极狐GitLab 实例中的共享 Runner。

如果 Runner 必须使用本地存储的镜像,请勿使用此政策。

config.toml 中将 always 设置为 pull policy

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    pull_policy = "always"

设置 if-not-present 拉取策略

当您将拉取策略设置为 if-not-present 时,Runner 首先检查是否存在本地镜像。 如果没有本地镜像,Runner 会从镜像库拉取镜像。

使用 if-not-present 策略:

  • 使用本地镜像,但如果本地镜像不存在,也会拉取镜像。
  • 减少 Runner 分析频繁和很少更新镜像的镜像层差异的时间。 在这种情况下,您必须定期从本地 Docker Engine 存储中手动删除镜像以强制更新镜像。

不要使用此政策:

  • 对于共享 Runner,使用 Runner 的不同用户可能可以访问私有镜像。 有关安全问题的详细信息,请参阅使用带有 if-not-present 拉取策略的私有 Docker 镜像
  • 如果作业经常更新并且必须在最新的镜像版本中运行。 这可能会导致网络负载减少,会超过频繁删除本地镜像的价值。

在 config.toml 中设置 if-not-present 策略:

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    pull_policy = "if-not-present"

设置 never 拉取策略

先决条件:

  • 本地镜像必须包含已安装的 Docker 引擎和已用镜像的本地副本。

当您将拉取策略设置为 never 时,镜像拉取将被禁用。用户只能使用在运行 Runner 的 Docker 主机上手动拉取的镜像。

使用 never 拉取策略:

  • 控制 Runner 用户使用的镜像。
  • 对于专用于只能使用在任何镜像库中不公开可用的特定镜像的项目的私有 Runner。

不要弹性伸缩的 Docker 执行器使用 never 拉取策略。 never 拉取策略仅在使用所选云提供商的预定义的云实例镜像时可用。

config.toml 中设置 never 策略:

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    pull_policy = "if-not-present"

设置多个拉取策略

引入于极狐GitLab Runner 13.8。

如果拉取失败,您可以列出要执行的多个拉取策略。Runner 按照列出的顺序处理拉取策略,直到拉取尝试成功或列表耗尽。 例如,如果一个 Runner 使用 always 拉取策略并且镜像库不可用,您可以将 if-not-present 添加为使用本地缓存的 Docker 镜像的第二个拉取策略。

有关此拉取策略的安全影响,请参阅使用带有 if-not-present 拉取策略的私有 Docker 镜像

要设置多个拉取策略,请将其作为列表添加到 config.toml 中:

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    pull_policy = ["always", "if-not-present"]

允许 Docker 拉取策略

引入于极狐GitLab 15.1。

.gitlab-ci.yml 文件中,您可以指定拉取策略。该策略决定了 CI/CD 作业如何获取镜像。

要限制可以在 .gitlab-ci.yml 文件中使用的拉取策略,请使用 allowed_pull_policies

例如,要仅允许 alwaysif-not-present 拉取策略,请将其添加到 config.toml 中:

[[runners]]
  (...)
  executor = "docker"
  [runners.docker]
    (...)
    allowed_pull_policies = ["always", "if-not-present"]
  • 如果不指定 allowed_pull_policies,则默认为 pull_policy 关键字中的值。
  • 如果不指定 pull_policy,则默认为 always
  • 现有的 pull_policy 关键字不得包含未在 allowed_pull_policies 中指定的拉取策略。如果包含,则作业返回错误。

镜像拉取错误信息

错误信息 描述
Pulling docker image registry.tld/my/image:latest ... ERROR: Build failed: Error: image registry.tld/my/image:latest not found Runner 无法找到镜像。当设置了 always 拉取策略时显示。
Pulling docker image local_image:latest ... ERROR: Build failed: Error: image local_image:latest not found 该镜像是本地构建的,不存在于任何公共或默认的 Docker 镜像库中。设置 always 拉取策略时显示。
Pulling docker image registry.tld/my/image:latest ... WARNING: Cannot pull the latest version of image registry.tld/my/image:latest : Error: image registry.tld/my/image:latest not found WARNING: Locally found image will be used instead. Runner 使用了本地镜像,没有拉取镜像。只有设置 always 拉取策略且版本为 1.8 及更早版本时显示。
Pulling docker image local_image:latest ... ERROR: Build failed: Error: image local_image:latest not found 无法本地找到镜像。设置 never 拉取策略时显示。
WARNING: Failed to pull image with policy "always": Error response from daemon: received unexpected HTTP status: 502 Bad Gateway (docker.go:143:0s) Attempt #2: Trying "if-not-present" pull policy Using locally found image version due to "if-not-present" pull policy Runner 拉取镜像失败,尝试使用下一个列出的拉取策略拉取镜像。设置多个拉取策略时显示。

重试失败的拉取

要将 Runner 配置为重试失败的镜像拉取,请多次在 config.toml 中指定相同的策略。

例如,此配置会重试拉取一次:

[runners.docker]
  pull_policy = ["always", "always"]

此设置类似于项目的 .gitlab-ci.yml 文件中的 retry 指令,但只有当 Docker 拉取最初失败时才会生效。

Docker vs Docker-SSH(Docker+Machine vs Docker-SSH+Machine)(已移除)

此功能移除于极狐GitLab 16.0。

使用 Windows 容器

引入于极狐GitLab Runner 11.11。

如果您想通过 Docker 执行器使用 Windows 容器,您需要注意以下有关限制、支持的 Windows 版本和配置 Windows Docker 执行器的内容。

Nanoserver 支持

引入于极狐GitLab Runner 13.6。

基于 Windows Helper 镜像中引入的对 PowerShell Core 的支持,现在可以为 Helper 镜像使用 nanoserver 变量。

Windows 上 Docker 执行器的限制

以下是通过 Docker 执行器使用 Windows 容器的限制:

  • 不支持 Docker-in-Docker,因为 Docker 本身就不支持
  • 不支持交互式网页终端。
  • 不支持主机设备加载。
  • docker-windows 执行器只有在极狐GitLab Runner 运行在 Windows 上时可以运行。
  • 不支持 Windows 上的 Linux 容器, 因为仍处于实验阶段。
  • 由于 Docker 限制,如果目的路径驱动字母不是 c:,路径不支持于:

    这表明不支持 f:\\cache_dir 这样的值,但是支持 f:。 然而,支持 c: 驱动上的目的路径(例如 c:\\cache_dir)。

    要配置 Docker daemon 保存镜像和容器的位置,请更新 Docker daemon 的 daemon.json 文件中的 data-root 参数。

    有关详细信息,请参考使用配置文件配置 Docker

支持的 Windows 版本

极狐GitLab Runner 支持以下 Windows 版本,它们遵循支持 Windows 生命周期

  • Windows Server 2022 LTSC (21H2)
  • Windows Server 2019 LTSC (1809)

对于未来的 Windows 服务器版本,我们拥有未来版本支持政策

您只可以基于与运行 Docker Daemon 相同的 OS 版本运行容器。 例如,可以使用以下 Windows Server Core 镜像:

  • mcr.microsoft.com/windows/servercore:ltsc2022
  • mcr.microsoft.com/windows/servercore:ltsc2022-amd64
  • mcr.microsoft.com/windows/servercore:1809
  • mcr.microsoft.com/windows/servercore:1809-amd64
  • mcr.microsoft.com/windows/servercore:ltsc2019

支持的 Docker 版本

运行极狐GitLab Runner 的 Windows 服务器必须运行近期版本的 Docker, 因为 Runner 使用 Docker 探测运行的 Windows 服务器的版本。

不与极狐GitLab Runner 一起工作的 Docker 的一个已知版本是 Docker 17.06, 因为 Docker 没有识别出 Windows 服务器的版本,导致以下错误:

unsupported Windows Version: Windows Server Datacenter

更多故障排除的内容

配置 Windows Docker 执行器

以下是配置简单 Docker 执行器运行 Windows 的例子。

[[runners]]
  name = "windows-docker-2019"
  url = "https://jihulab.com/"
  token = "xxxxxxx"
  executor = "docker-windows"
  [runners.docker]
    image = "mcr.microsoft.com/windows/servercore:1809_amd64"
    volumes = ["c:\\cache"]

其他 Docker 执行器的配置选项,请参见高级配置部分。

Services

在极狐GitLab Runner 12.9 及更高版本中,您可以为每个作业开启网络从而使用 Services

原生 Step Runner 的集成

  • 自极狐GitLab 17.6.0 引入,并使用功能开关 FF_USE_NATIVE_STEPS,该开关默认禁用。

Docker 执行器支持通过使用 step-runner 提供的 gRPC API 来原生运行 CI/CD 步骤

如要开启此执行模式,您必须使用 run 关键字指定 CI/CD 作业,而不是使用传统的 script 关键字。此外,您必须启用 FF_USE_NATIVE_STEPS 功能开关。您可以在作业或流水线级别启用此功能开关。

step job:
  stage: test
  variables:
    FF_USE_NATIVE_STEPS: true
  image:
    name: registry.gitlab.com/gitlab-org/step-runner:v0
  run:
    - name: step1
      script: pwd
    - name: step2
      script: env
    - name: step3
      script: ls -Rlah --ignore .git ../

已知问题

  • 构建镜像必须在 $PATH 包含 step-runner 二进制文件。要实现这一点,您可以:
    • 创建您自己的自定义构建镜像并在其中包含 step-runner 二进制文件。
    • 使用 registry.gitlab.com/gitlab-org/step-runner:v0 镜像,如果它包含运行作业所需的依赖项。

      这是一个临时的解决方法。在将来,runner 会将 step-runner 二进制文件注入任何构建镜像中。

  • 运行一个步骤,该步骤运行 Docker 容器必须符合传统 scripts 的相同配置参数和约束。例如,您必须使用 Docker-in-Docker
  • 此执行模式目前还不不支持 Github Actions