Docker 执行器

  • Tier: 基础版, 专业版, 旗舰版
  • Offering: JihuLab.com, 私有化部署

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

您可以使用 Docker 执行器 来:

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

Docker 执行器 使用 Docker Engine 在一个独立且隔离的容器中运行每个作业。为了连接到 Docker Engine,executor 使用:

先决条件:

  • 安装 Docker。

Docker 执行器 工作流程#

Docker 执行器 使用基于 Alpine Linux 的 Docker 镜像,该镜像包含运行准备、预作业和后作业步骤的工具。要查看特殊 Docker 镜像的定义,请参阅 极狐GitLab Runner 仓库

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

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

支持的配置#

Docker 执行器 支持以下配置。

有关 Windows 配置的已知问题和附加要求,请参阅 使用 Windows 容器

Runner 安装在:Executor 是:容器运行在:
Windowsdocker-windowsWindows
WindowsdockerLinux
LinuxdockerLinux

这些配置 支持:

Runner 安装在:Executor 是:容器运行在:
Linuxdocker-windowsLinux
LinuxdockerWindows
Linuxdocker-windowsWindows
WindowsdockerWindows
Windowsdocker-windowsLinux

极狐GitLab Runner 使用 Docker Engine API v1.25 与 Docker Engine 进行通信。这意味着在 Linux 服务器上 Docker 的最低支持版本是 1.13.0。在 Windows Server 上,需要更新 才能识别 Windows Server 版本。

使用 Docker 执行器#

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

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

toml
1concurrent = 4 2 3[[runners]] 4name = "myRunner" 5url = "https://gitlab.com/ci" 6token = "......" 7executor = "docker" 8[runners.docker] 9 tls_verify = true 10 image = "my.registry.tld:5000/alpine:latest" 11 privileged = false 12 disable_entrypoint_overwrite = false 13 oom_kill_disable = false 14 disable_cache = false 15 volumes = [ 16 "/cache", 17 ] 18 shm_size = 0 19 allowed_pull_policies = ["always", "if-not-present"] 20 allowed_images = ["my.registry.tld:5000/*:*"] 21 allowed_services = ["my.registry.tld:5000/*:*"] 22 [runners.docker.volume_driver_ops] 23 "size" = "50G"

配置镜像和服务#

先决条件:

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

要配置 Docker 执行器,您需要在 .gitlab-ci.ymlconfig.toml 中定义 Docker 镜像和服务。

使用以下关键字:

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

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

定义 runner 用于所有作业的镜像以及构建时使用的服务列表。

示例:

yaml
1image: ruby:2.7 2 3services: 4 - postgres:9.3 5 6before_script: 7 - bundle install 8 9test: 10 script: 11 - bundle exec rake spec

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

yaml
1before_script: 2 - bundle install 3 4test:2.6: 5 image: ruby:2.6 6 services: 7 - postgres:9.3 8 script: 9 - bundle exec rake spec 10 11test:2.7: 12 image: ruby:2.7 13 services: 14 - postgres:9.4 15 script: 16 - 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 中定义的镜像。

示例:

toml
1[runners.docker] 2 image = "ruby:2.7" 3 4[[runners.docker.services]] 5 name = "mysql:latest" 6 alias = "db" 7 8[[runners.docker.services]] 9 name = "redis:latest" 10 alias = "cache"

此示例使用表数组语法。

从私有注册表定义镜像#

先决条件:

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

示例:

yaml
image: my.registry.tld:5000/namespace/image:tag

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

网络配置#

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

要配置网络,您可以:

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

为每个作业创建一个网络#

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

启用此网络模式后,runner 为每个作业创建并使用一个用户定义的 Docker 桥接网络。Docker 环境变量不会在容器之间共享。

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

不要设置 network_mode

示例:

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

或者:

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

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

此功能仅在 Docker 守护进程配置为启用 IPv6 时有效。要启用 IPv6 支持,请在 Docker 配置中将 enable_ipv6 设置为 true

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:无网络。不推荐。

示例:

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

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

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

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

覆盖创建网络的 MTU#

对于某些环境,如 OpenStack 中的虚拟机,可能需要自定义 MTU。Docker 守护进程不尊重 docker.json 中的 MTU。您可以在 config.toml 中将 network_mtu 设置为任何有效值,以便 Docker 守护进程可以为新创建的网络使用正确的 MTU。您还必须启用 FF_NETWORK_PER_BUILD 以使覆盖生效。

以下配置将每个作业创建的网络的 MTU 设置为 1402。请确保根据您的具体环境要求调整该值。

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 network_mtu = 1402 6 [runners.feature_flags] 7 FF_NETWORK_PER_BUILD = true

限制 Docker 镜像和服务#

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

例如,仅允许来自您私人 Docker 注册表的镜像:

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 allowed_images = ["my.registry.tld:5000/*:*"] 7 allowed_services = ["my.registry.tld:5000/*:*"]

限制为来自您私人 Docker 注册表的镜像列表:

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 allowed_images = ["my.registry.tld:5000/ruby:*", "my.registry.tld:5000/node:*"] 7 allowed_services = ["postgres:9.4", "postgres:latest"]

排除特定镜像,如 Kali:

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 allowed_images = ["**", "!*/kali*"]

访问服务主机名#

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

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

yaml
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 选项,您可以为每个路径指定多个路径,每个路径都有自己的选项。

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

toml
1[runners.docker] 2 # 对于主容器 3 [runners.docker.tmpfs] 4 "/var/lib/mysql" = "rw,noexec" 5 6 # 对于服务 7 [runners.docker.services_tmpfs] 8 "/var/lib/mysql" = "rw,noexec"

在服务中构建目录#

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

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

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

History
    • 在极狐GitLab 16.0 中引入了多个端口检查。

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

  • 在极狐GitLab 15.11 及更早版本中,仅检查第一个公开端口。
  • 在极狐GitLab 16.0 及更高版本中,检查前 20 个公开端口。

可以使用 HEALTHCHECK_TCP_PORT 服务变量在特定端口上执行健康检查:

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

要查看如何实现此功能,请使用健康检查 Go 命令。

指定 Docker 驱动操作#

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

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

使用主机设备#

History
    • 在极狐GitLab 17.10 中引入。

您可以将极狐GitLab Runner 主机上的硬件设备暴露给运行作业的容器。要做到这一点,请配置 runner 的 devicesservices_devices 选项。

  • 要将设备暴露给 buildhelper 容器,请使用 devices 选项。
  • 要将设备暴露给服务容器,请使用 services_devices 选项。要限制服务容器对特定镜像的设备访问,请使用确切的镜像名称或全局模式。这一操作可以防止直接访问主机系统设备。

构建容器示例#

在此示例中,config.toml 部分将 /dev/bus/usb 暴露给构建容器。此配置允许流水线访问连接到主机机器的 USB 设备,例如通过 Android 调试桥 (adb) 控制的 Android 智能手机。

由于构建作业容器可以直接访问主机 USB 设备,同时执行的流水线在访问相同硬件时可能会发生冲突。要防止这些冲突,请使用 resource_group

toml
1[[runners]] 2 name = "hardware-runner" 3 url = "https://gitlab.com" 4 token = "__REDACTED__" 5 executor = "docker" 6 [runners.docker] 7 # 所有作业容器都可以访问主机设备 8 devices = ["/dev/bus/usb"]

私有注册表示例#

此示例显示如何将 /dev/kvm/dev/dri 设备暴露给来自私有 Docker 注册表的容器镜像。这些设备通常用于硬件加速的虚拟化和渲染。为了降低提供用户直接访问硬件资源的风险,将设备访问限制为 myregistry:5000/emulator/* 命名空间中的受信任镜像:

toml
[runners.docker] [runners.docker.services_devices] # 仅来自内部注册表的镜像可访问主机设备 "myregistry:5000/emulator/*" = ["/dev/kvm", "/dev/dri"]

镜像名称 **/* 可能会将设备暴露给任何镜像。

配置容器构建和缓存的目录#

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

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

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

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

清除 Docker 缓存#

History
    • 在极狐GitLab Runner 13.9 中引入,清理所有创建的 runner 资源。

使用 clear-docker-cache 删除由 runner 创建的未使用的容器和卷。

要获取选项列表,请使用 help 选项运行脚本:

shell
clear-docker-cache help

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

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

  • 定期使用 cron 运行 clear-docker-cache(例如,每周一次)。
  • 在缓存中保持一些最近的容器以提高性能,同时回收磁盘空间。

FILTER_FLAG 环境变量控制哪些对象被修剪。

清除 Docker 构建镜像#

clear-docker-cache 脚本不删除 Docker 镜像,因为它们不是由极狐GitLab Runner 标记的。

要清除 Docker 构建镜像:

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

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

持久存储#

当 Docker 执行器 运行容器时,它提供持久存储。所有在 volumes = 中定义的目录在构建之间是持久的。

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

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

构建的持久存储#

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

  • <short-token> 是 Runner 的 token 的简短版本(前 8 个字母)。
  • <concurrent-id> 是一个唯一编号,用于标识项目上下文中的特定 runner 的本地作业 ID。

IPC 模式#

Docker 执行器 支持与其他位置共享容器的 IPC 命名空间。这映射到 docker run --ipc 标志。

特权模式#

Docker 执行器 支持几种选项,可以对构建容器进行精细调整。其中一个选项是 特权 模式。

使用特权模式的 Docker-in-Docker#

配置的 privileged 标志传递给构建容器和所有服务。通过此标志,您可以使用 Docker-in-Docker 方法。

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

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

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

yaml
1image: docker:git 2services: 3- docker:dind 4 5build: 6 script: 7 - docker build -t my-image . 8 - docker push my-image

以特权模式运行的容器具有安全风险。当您的容器以特权模式运行时,您禁用容器安全机制,并将您的主机暴露于权限提升。以特权模式运行容器可能导致容器突破。

您可能需要使用 TLS 配置 Docker in Docker,或禁用 TLS,以避免出现类似以下的错误:

plaintext
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

    toml
    [[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 无根容器:

    yaml
    1image: docker:git 2services: 3- docker:dind-rootless 4 5build: 6 script: 7 - docker build -t my-image . 8 - docker push my-image

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

由于它们以非 root 身份运行,因此使用特权模式镜像如 Docker-in-Docker 无根或 BuildKit 无根的安全性几乎是安全的。

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

配置 Docker ENTRYPOINT#

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

为了确保作业能够运行,其 Docker 镜像必须:

  • 提供 shbashgrep
  • 定义一个 ENTRYPOINT,当传递 sh/bash 作为参数时启动一个 shell

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

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

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

yaml
# 等效于 # docker run --entrypoint "" <image> sh -c "echo 'It works!'" image: name: my-image entrypoint: [""]

有关更多信息,请参阅 覆盖镜像的 Entrypoint 和 Docker 中 CMDENTRYPOINT 的交互方式。

作业脚本作为 ENTRYPOINT#

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

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

  1. 创建一个新的 Dockerfile:

    dockerfile
    FROM docker:dind ADD / /entrypoint.sh ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
  2. 创建一个 bash 脚本(entrypoint.sh),用作 ENTRYPOINT

    shell
    1#!/bin/sh 2 3dind docker daemon 4 --host=unix:///var/run/docker.sock \ 5 --host=tcp://0.0.0.0:2375 \ 6 --storage-driver=vf & 7 8docker build -t "$BUILD_IMAGE" . 9docker push "$BUILD_IMAGE"
  3. 将镜像推送到 Docker 注册表。

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

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

    yaml
    1variables: 2 BUILD_IMAGE: my.image 3build: 4 image: my/docker-build:image 5 script: 6 - Dummy Script

使用 Podman 运行 Docker 命令#

History
    • 在极狐GitLab 15.3 中引入。

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

先决条件:

  • Podman v4.2.0 或更高版本。
  • 要使用 Podman 作为 executor 运行 服务,启用 FF_NETWORK_PER_BUILD 功能标志。Docker 容器链接是遗留的,并且不受 Podman 支持。对于创建网络别名的服务,您必须安装 podman-plugins 包。
  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 套接字:

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

    shell
    systemctl status --user podman.socket
  7. 复制 Podman API 被访问的 Listen 键中的套接字字符串。

  8. 确保 Podman 套接字在极狐GitLab Runner 用户注销后仍然可用:

    shell
    sudo loginctl enable-linger gitlab-runner
  9. 编辑极狐GitLab Runner config.toml 文件,并将套接字值添加到 [runners.docker] 部分中的主机条目。例如:

    toml
    1[[runners]] 2 name = "podman-test-runner-2022-06-07" 3 url = "https://gitlab.com" 4 token = "x-XxXXXXX-xxXxXxxxxx" 5 executor = "docker" 6 [runners.docker] 7 host = "unix:///run/user/1012/podman/podman.sock" 8 tls_verify = false 9 image = "quay.io/podman/stable" 10 privileged = true

使用 Podman 从 Dockerfile 构建容器镜像#

以下示例使用 Podman 从 Dockerfile 构建容器镜像并将镜像推送到极狐GitLab 容器注册表。

Runner config.toml 中的默认容器镜像设置为 quay.io/podman/stable,以便 CI 作业使用该镜像执行包含的命令。

yaml
1variables: 2 IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 3 4before_script: 5 - podman login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY 6 7oci-container-build: 8 stage: build 9 script: 10 - podman build -t $IMAGE_TAG . 11 - podman push $IMAGE_TAG 12 when: manual

使用 Buildah 从 Dockerfile 构建容器镜像#

以下示例演示如何使用 Buildah 从 Dockerfile 构建容器镜像并将镜像推送到极狐GitLab 容器注册表。

yaml
1image: quay.io/buildah/stable 2 3variables: 4 IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG 5 6before_script: 7 - buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY 8 9oci-container-build: 10 stage: build 11 script: 12 - buildah bud -t $IMAGE_TAG . 13 - buildah push $IMAGE_TAG 14 when: manual

指定运行作业的用户#

默认情况下,runner 以容器中的 root 用户身份运行作业。要指定一个不同的非 root 用户运行作业,请在 Docker 镜像的 Dockerfile 中使用 USER 指令。

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

当您使用该 Docker 镜像执行作业时,它将以指定用户身份运行:

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

配置 runner 如何拉取镜像#

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

使用以下值作为 pull_policy

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

设置 always 拉取策略#

always 选项默认启用,总是在创建容器之前启动拉取。此选项确保镜像是最新的,并防止您使用过时的镜像,即使存在本地镜像。

使用此拉取策略如果:

  • runner 必须始终拉取最新的镜像。
  • runner 是公开可用的,并配置为 自动缩放 或作为极狐GitLab 实例中的实例 runner。

不要使用 此策略如果 runner 必须使用本地存储的镜像。

config.toml 中设置 always 作为 pull_policy

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 pull_policy = "always"

设置 if-not-present 拉取策略#

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

使用 if-not-present 策略可以:

  • 使用本地镜像,但如果不存在本地镜像,也可以拉取镜像。
  • 减少 runner 分析镜像层差异的时间,特别是对于重量级且不经常更新的镜像。在这种情况下,您必须定期从本地 Docker Engine 存储中手动删除镜像以强制更新镜像。

不要使用 此策略:

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

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

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 pull_policy = "if-not-present"

设置 never 拉取策略#

前提条件:

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

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

使用 never 拉取策略:

  • 控制 runner 用户使用的镜像。
  • 对于专用于只能使用特定镜像且无法在任何注册表中公开获取的项目的私有 runner。

不要使用 never 拉取策略用于自动扩展的 Docker 执行器。never 拉取策略仅在使用预定义的云实例镜像的情况下可用。

config.toml 中设置 never 策略:

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 pull_policy = "never"

设置多个拉取策略#

History
    • 在极狐GitLab Runner 13.8 中引入。

您可以列出多个拉取策略,以便在拉取失败时执行。runner 按列出的顺序处理拉取策略,直到拉取成功或列表耗尽。例如,如果 runner 使用 always 拉取策略并且注册表不可用,您可以添加 if-not-present 作为第二个拉取策略。此配置允许 runner 使用本地缓存的 Docker 镜像。

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

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

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 pull_policy = ["always", "if-not-present"]

允许 Docker 拉取策略#

History
    • 在极狐GitLab 15.1 中引入。

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

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

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

toml
1[[runners]] 2 (...) 3 executor = "docker" 4 [runners.docker] 5 (...) 6 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 foundrunner 无法找到镜像。当设置 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 使用了本地镜像而不是拉取镜像。当在仅极狐GitLab Runner 1.8 及更早版本中设置 always 拉取策略时显示。
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 policyrunner 未能拉取镜像,并尝试使用下一个列出的拉取策略拉取镜像。当设置了多个拉取策略时显示。

重试失败的拉取#

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

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

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

此设置类似于.gitlab-ci.yml 文件中使用的 retry 指令,但仅在 Docker 拉取初始失败时生效。

使用 Windows 容器#

History
    • 在极狐GitLab Runner 11.11 中引入。

要在 Docker 执行器中使用 Windows 容器,请注意以下有关限制、支持的 Windows 版本和配置 Windows Docker 执行器的信息。

Nanoserver 支持#

History
    • 在极狐GitLab Runner 13.6 中引入。

随着在 Windows 助手镜像中引入了 PowerShell Core 的支持,现在可以利用助手镜像的 nanoserver 变体。

Windows 上 Docker 执行器的已知问题#

以下是使用 Windows 容器与 Docker 执行器的一些限制:

  • 不支持 Docker-in-Docker,因为 Docker 本身不支持。

  • 不支持交互式 Web 终端。

  • 不支持主机设备挂载。

  • 当挂载卷目录时,它必须存在,否则 Docker 将无法启动容器,详见#3754

  • docker-windows 执行器只能在运行 Windows 的极狐GitLab Runner 上运行。

  • Windows 上的 Linux 容器不受支持,因为它们仍在实验阶段。

  • 由于 Docker 的限制,如果目标路径驱动器号不是 c:,则不支持路径:

    这意味着诸如 f:\\cache_dir 之类的值不受支持,但 f: 是支持的。然而,如果目标路径在 c: 驱动器上,路径也受到支持(例如 c:\\cache_dir)。

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

支持的 Windows 版本#

极狐GitLab Runner 仅支持以下 Windows 版本,这些版本遵循我们的Windows 支持生命周期

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

针对未来的 Windows Server 版本,我们有一个未来版本支持策略

您只能运行与 Docker 守护进程正在运行的相同操作系统版本的容器。例如,可以使用以下 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 使用 Docker 来检测运行的 Windows Server 版本。因此,运行极狐GitLab Runner 的 Windows Server 必须运行 Docker 的最新版本。

一个已知不能与极狐GitLab Runner 一起工作的 Docker 版本是 Docker 17.06。Docker 无法识别 Windows Server 版本,导致出现以下错误:

plaintext
unsupported Windows Version: Windows Server Datacenter

阅读更多关于此问题的故障排除信息

配置 Windows Docker 执行器#

当 runner 使用 c:\\cache 作为源目录注册时,在传递 --docker-volumesDOCKER_VOLUMES 环境变量时存在一个已知问题。

下面是一个运行 Windows 的 Docker 执行器的配置示例。

toml
1[[runners]] 2 name = "windows-docker-2019" 3 url = "https://gitlab.com/" 4 token = "xxxxxxx" 5 executor = "docker-windows" 6 [runners.docker] 7 image = "mcr.microsoft.com/windows/servercore:1809_amd64" 8 volumes = ["c:\\cache"]

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

服务#

在极狐GitLab Runner 12.9 及更高版本中,您可以通过为每个作业启用网络来使用服务

原生步骤运行器集成#

History
    • 在极狐GitLab 17.6.0 中通过功能标志 FF_USE_NATIVE_STEPS 引入,默认情况下禁用。更新于极狐GitLab 17.9.0。极狐GitLab Runner 将 step-runner 二进制文件注入到构建容器中,并相应调整 $PATH 环境变量。此增强功能使得可以将任何镜像用作构建镜像。

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

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

yaml
1step job: 2 stage: test 3 variables: 4 FF_USE_NATIVE_STEPS: true 5 image: 6 name: alpine:latest 7 run: 8 - name: step1 9 script: pwd 10 - name: step2 11 script: env 12 - name: step3 13 script: ls -Rlah ../

已知问题#

  • 在极狐GitLab 17.9 及更高版本中,构建镜像必须安装 ca-certificates 软件包,否则 step-runner 将无法拉取作业中定义的步骤。例如,基于 Debian 的 Linux 发行版默认不安装 ca-certificates

  • 在极狐GitLab 17.9 之前的版本中,构建镜像必须在 $PATH 中包含 step-runner 二进制文件。为此,您可以:

    • 创建您自己的自定义构建镜像,并在其中包含 step-runner 二进制文件。
    • 如果 registry.gitlab.com/gitlab-org/step-runner:v0 镜像包含您需要运行作业的依赖项,则可以使用该镜像。
  • 运行一个运行 Docker 容器的步骤必须遵循与传统 scripts 相同的配置参数和约束。例如,您必须使用Docker-in-Docker

  • 此执行模式尚不支持运行 Github Actions