Docker 执行器

极狐GitLab Runner 可以使用 Docker 在用户提供的镜像上运行作业。这可能会使用 Docker 执行器。

当和极狐GitLab CI 一起使用时,Docker 执行器连接到 Docker 引擎 并且使用预定义的镜像在独立的容器中运行构建,这个镜像.gitlab-ci.yml 中设置并且和 config.toml一致。

这样您可以拥有在工作站上可以运行的简单且可复制的构建环境。 另一个好处是您可以测试所有通过您的 Shell 执行的命令,不用在专有 CI 服务器上进行测试。

支持以下配置:

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 服务器版本。

使用 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)。

支持的 Windows 版本

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

  • Windows 服务器 21H1/LTSC2022
  • Windows 服务器 20H2
  • Windows 服务器 2004
  • Windows 服务器 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:20H2
  • mcr.microsoft.com/windows/servercore:20H2-amd64
  • mcr.microsoft.com/windows/servercore:2004
  • mcr.microsoft.com/windows/servercore:2004-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

工作流

Docker 执行器将作业分成以下几个步骤:

  1. 准备:创建和启动服务
  2. 作业前:克隆、还原缓存并从之前的阶段下载产物。 它运行在特殊的 Docker 镜像中。
  3. 作业:用户构建。它运行在用户提供的 Docker 镜像上。
  4. 作业后:创建缓存、向极狐GitLab 上传产物。它运行在 特殊的 Docker 镜像上。

特殊的 Docker 镜像基于 Alpine Linux 并包含所有运行准备、作业前和作业后的步骤所需的工具, 例如 Git 和支持缓存和产物的极狐GitLab Runner 二进制。您可以在官方极狐GitLab Runner 仓库找到这个特殊镜像的定义。

image 关键字

image 关键词是本地 Docker 引擎(用 docker images 列出所有镜像)中的 Docker 镜像的名称, 或是 Docker Hub 中的任意镜像的名称。 有关镜像和 Docker Hub 的更多信息,请参见 Docker 基本原理

简而言之,image 指的是 Docker 镜像,用于创建您的构建运行的容器。

如果您不指定命名空间,Docker 会指定 library,它包括所有官方镜像。这是 .gitlab-ci.ymlconfig.toml 中多次省略 library 部分的原因。 例如,您可以将镜像定义为 image: ruby:2.7,它是 image: library/ruby:2.7 的简写。

每个 Docker 镜像都有标签,表明镜像版本。它在镜像名称中以冒号(:)作为标志。例如,对于 Ruby,您可以在 https://hub.docker.com/_/ruby/ 中查看支持的标签。 如果您未指定标签(例如 image: ruby),会使用 latest

您选择的通过 image 指令运行构建的镜像必须在它的 PATH OS 中有工作的 Shell。支持 shbashpwsh Shell。 对于 Linux 和 Windows PowerShell,极狐GitLab Runner 无法使用底层的 OS 系统调用执行命令(例如 exec)。

services 关键字

services 关键字定义了另一个在您的构建中运行并与 image 关键词定义的 Docker 镜像相关联的 Docker 镜像。 这允许您在构建时间中访问服务镜像。

服务镜像可以运行任何应用,但是最常见的用例是运行数据库容器, 例如,mysql。与每次构建项目都安装 mysql 相比,使用现存的镜像,并且将其作为额外容器运行更加容易和快捷。

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

如有必要,您可以为每个服务分配别名

网络

将服务连接到 CI/CD 作业,网络很重要。网络也可以在用户定义的网络中运行作业。 您可以使用遗留容器链接或者为每个作业创建网络。 我们推荐您为每个作业创建网络。

遗留容器链接

默认网络模式通过默认的 Docker bridge 模式使用遗留容器链接, 通过服务关联作业容器。

用户可以使用这个模式配置怎样通过以下值使用 network_mode 配置参数为容器设置网络栈:

  • 标准 Docker 网络模式
    • bridge:使用网桥网络(默认)。
    • host:在容器内使用主机网络栈。
    • none:无网络(不推荐)。
  • 其他的 network_mode 值作为现存的构建容器应该连接的 Docker 网络的名称。

为了让名称解析生效,Docker 控制容器中的 /etc/hosts 文件, 使其包含服务容器主机名和别名。 然而,服务容器能够解析容器名称。如果您想解析容器名称,请为每个作业创建网络。

链接容器共享环境变量。

为作业创建网络

引入于极狐GitLab Runner 12.9。

这个网络模式为每个作业创建并使用新的用户定义的 Docker 网桥网络。Docker 文档中详细介绍了用户定义的网桥网络

不像其他网络模式中使用的遗留容器链接, Docker 环境变量会在容器中分享。

如果 CIDR 已经被使用,Docker 网络或许会在主机上和其他网络冲突,包括其他 Docker 网络。 可以使用 dockerd 中的 default-address-pool 配置默认的 Docker 地址池。

如果您想开启这个模式,您必须开启 FF_NETWORK_PER_BUILD 功能标记

作业启动时会创建网桥网络(类似于 docker network create <network>)。 创建时,服务容器和构建作业容器会连接到这个网络。

运行作业和运行服务的容器都可以解析对方的主机名和别名。这个功能由 Docker 提供

作业容器也通过 build 别名进行解析,因为主机名由极狐GitLab 分配。

网络会在作业结束时移除。

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

您可以定义所有作业使用的镜像和构建中您想使用的服务列表。

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

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

查看 [runners.docker] 部分:

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

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

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

以上示例使用表格阵列语法

这种方法定义的镜像和服务会被添加到那个 Runner 运行的所有构建中。 所以即使您没有在 .gitlab-ci.yml 中定义 image,也会使用 config.toml 中定义的那一个。

定义私有 Docker 镜像库中的镜像

从极狐GitLab Runner 0.6.0 开始,您可以定义同样需要鉴权的私有镜像库中的镜像。

您只需要知道 .gitlab-ci.yml 中的镜像定义。

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

在以上例子中,极狐GitLab Runner 会查看 namespace/image:tag 镜像的 my.registry.tld:5000

如果仓库是私有的,您需要对镜像库中的极狐GitLab Runner 进行鉴权。 详情请参见使用私有 Docker 镜像

限制 Docker 镜像和服务

您可以限制运行您的作业的 Docker 镜像。 为此,您需要指定通配符模式。例如,仅允许您的私有 Docker 镜像库中的镜像:

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

或者,仅限于这个镜像库中的特定镜像列表:

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

限制 Docker 拉取策略

引入于极狐GitLab 15.1。

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

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

例如,只允许 alwaysif-not-present 拉取策略:

[[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 中指定的拉取策略。如果包含,作业会返回错误。

访问服务

加入您需要 Wordpress 实例以测试应用的 API 集成。

您可以使用例如 tutum/wordpress 作为 .gitlab-ci.yml 中的服务镜像。

services:
- tutum/wordpress:latest

当运行构建时,会先启动 tutum/wordpress,然后您能够以主机名 tutum__wordpresstutum-wordpress 从您的构建容器访问它。

极狐GitLab Runner 为您可以交替使用的服务创建两个别名主机名。 别名遵循以下规则从镜像名中获取:

  1. 去掉 : 后面的内容。
  2. 对于第一个别名,用双下划线(__)代替斜杠(/)。
  3. 对于第二个别名,用单连接号(-)代替斜杠(/)。

使用私有服务镜像会剥离任何给定的端口,并应用上文中描述的规则。registry.gitlab-wp.com:4999/tutum/wordpress 服务会生成主机名 registry.gitlab-wp.com__tutum__wordpressregistry.gitlab-wp.com-tutum-wordpress

配置服务

很多服务接受允许您很容易地改变数据库名字或基于环境设置账户名称的环境变量。

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

对于所有可能的配置变量,检查对应 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"

在服务中构建目录

因为在 1.5 版本中,极狐GitLab Runner 向所有共享服务挂载 /builds 目录。

PostgreSQL 服务示例

参见使用 PostgreSQL 作为一种服务文档。

MySQL 服务示例

参见使用 MySQL 作为一种服务文档。

服务健康检查

服务开启后,极狐GitLab Runner 会等待服务响应。 当前,Docker 执行器试图开启与服务容器中第一个展示的服务的 TCP 连接。

您可以查看 Go 命令,了解它如何执行。

构建和缓存存储

Docker 执行器默认存储所有 /builds/<namespace>/<project-name> 中的构建和 /cache(容器内)中的所有缓存。 您可以通过定义 config.toml[[runners]] 部分下的 builds_dircache_dir 选项,覆盖 /builds/cache 目录。 这可以修改数据在容器中存储的位置。

如果您修改 /cache 存储路径,您也需要通过在 config.toml[runners.docker] 部分下的 volumes = ["/my/cache/"] 里定义它,确保将这个目录标记为永久目录。

清理 Docker 缓存

引入于极狐GitLab Runner 13.9。

极狐GitLab Runner 提供 clear-docker-cache 脚本以移除旧的没有必要占用磁盘空间的容器和卷。

定期运行 clear-docker-cache (例如,每个星期使用一次 cron), 确保在以下内容间获得平衡:

  • 为保证性能,维护缓存中最近的一些容器
  • 回收磁盘空间

clear-docker-cache 可以移除极狐GitLab Runner 创建的旧的或未使用的容器和卷。对于选项列表,使用 help 选项运行脚本:

clear-docker-cache help

默认选项是 prune-volumes,脚本会移除所有未使用的容器(虚悬和未引用的)和卷。

清理旧的构建镜像

clear-docker-cache 脚本不会移除 Docker 镜像,因为它们没有被极狐GitLab Runner 打标签。然而,您可以确认可以通过使用下面描述的 space 选项来运行脚本而回收的空间:

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

一旦您确认了可回收的空间,运行 docker system prune 命令,这个命令会移除所有未使用的容器、镜像(虚悬和未引用的)以及没有被极狐GitLab Runner 打标签的卷(可选)。

持久化存储

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 上识别本地作业。

特权模式

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

入口点

Docker 执行器不会覆盖 Docker 镜像的 ENTRYPOINT

也就是说,如果您的镜像定义了 ENTRYPOINT 而且不允许使用 CMD 运行脚本,镜像不会通过 Docker 执行器工作。

通过使用 ENTRYPOINT,可以创建能够在自定义环境或者安全模式中运行构建脚本的特殊 Docker 镜像。

您可能会想到创建使用不执行构建脚本但执行预定义的一组命令的 ENTRYPOINT 的 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 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

拉取策略如何工作

当您在使用 dockerdocker+machine 执行器时,您可以按照配置文档 Docker 部分中所描述的,在 Runner config.toml 文件中使用 pull_policy 参数。

这个参数描述了拉取 Docker 镜像( imageservices 关键字)时 Runner 如何工作。 您可以将其设置为单个值,或者拉取策略列表,直到成功拉取镜像。

如果您没有为 pull_policy 参数设置任何的值,Runner 会使用 always 拉取策略作为默认值。

下面我们一起来看这些政策如何工作。

使用 never 拉取策略

never 拉取策略完全禁用镜像拉取。如果您将 Runner 的 pull_policy 参数设置为 never,用户仅能够使用在 Runner 运行的 Docker 主机上手动拉取的镜像。

如果无法在本地找到镜像,Runner 构建会失败,错误消息类似于:

Pulling docker image local_image:latest ...
ERROR: Build failed: Error: image local_image:latest not found

何时使用 never 拉取策略

如果您想要或需要完全控制 Runner 的用户所使用的镜像,您应该使用 never 拉取策略。 对于专门处理使用特定镜像(不是在任何镜像库都公开可用)的项目的私有 Runner 来说,这是一个好选择。

何时不使用 never 拉取策略

使用大多数弹性伸缩 Docker 执行器用例,never 拉取策略不会正常工作。 因为弹性伸缩的工作方式,never 拉取策略可能会只有当为选择的云提供商使用预定义的云实例镜像时才可用。镜像需要包含安装的 Docker 引擎和使用的镜像的本地副本。

使用 if-not-present 拉取策略

当使用 if-not-present 拉取策略时,Runner 会首先检查本地是否存在镜像。如果存在,则会使用镜像的本地版本。 否则,Runner 会试图拉取镜像。

何时使用 if-not-present 拉取策略

如果您想使用从远端镜像库拉取的镜像,却又想在使用 heavy 和很少更新的镜像时缩短分析镜像层差异的时间,if-not-present 拉取策略是个好选择。 这种情况下,您需要偶尔手动从本地 Docker 引擎存储移除镜像,以强制更新镜像。

如果您需要使用仅在本地构建和可用的镜像,但是也需要允许从远端镜像库拉取镜像,它也是个好选择。

何时不使用 if-not-present 拉取策略

如果您的构建使用经常更新并且需要在最新的版本中使用的镜像,则不应该使用 if-not-present 拉取策略。 这种情况下,这个政策创建的网络负载降低或许比频繁删除镜像的本地副本更没有必要。

如果不同的本来不应该能够访问各自使用的私有镜像的用户可以使用您的 Runner,则不应该使用这个拉取策略。 特别是不要对共享 Runner 使用这个拉取策略。

如果您想了解当和私有镜像一起使用,if-not-present 拉取策略创建安全问题的原因, 请阅读安全考虑文档

使用 always 拉取策略

always 拉取策略会确保镜像一直被拉取。 当使用 always,即使本地副本可用,Runner 会试着拉取镜像。 底层镜像提供者的缓存语义 使这个政策生效。 因为所有镜像层都是缓存的,所以拉取操作很快速。

如果没有找到镜像,构建会失败,失败信息类似于:

Pulling docker image registry.tld/my/image:latest ...
ERROR: Build failed: Error: image registry.tld/my/image:latest not found

当在早于 v1.8 版本的极狐GitLab Runner 中使用 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.

何时使用 always 拉取策略

如果您的 Runner 公开可用且在您的极狐GitLab 实例中配置为共享 Runner,则应该使用 always 拉取策略。 当通过私有镜像使用 Runner 时,它是唯一一个安全的拉取策略。

当您想强制用户一直使用最新的镜像时,这也是一个好选择。

同样,这对于 Runner 的弹性伸缩配置来说也是最好的解决方案。

何时不使用 always 拉取策略

如果您需要使用本地存储的镜像,则 always 拉取策略一定不会生效。 这种情况下,Runner 会跳过镜像的本地副本并试图从远端镜像库拉取它。 如果镜像是本地构建的,并且在任何公共镜像库中都不存在(特别是在默认 Docker 镜像库中) 构建会失败,并显示以下内容:

Pulling docker image local_image:latest ...
ERROR: Build failed: Error: image local_image:latest not found

使用多个拉取策略

引入于极狐GitLab Runner 13.8。

pull_policy 参数允许您指定拉取策略列表。 列表中的政策会按照从左到右的顺序被尝试,直到成功,否则列表会耗尽。

当 Docker 镜像库不可用,并且您需要增加作业弹性时,这个功能很有用。 如果您使用 always 政策并且镜像库不可用,即使期望的镜像在本地缓存,作业也会失败。

为克服这个行为,您可以添加失败时执行的额外回退拉取策略。 通过添加 if-not-present 的第二个拉取策略值,Runner 找到任何本地缓存的 Docker 镜像层:

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

任何获取 Docker 镜像的失败都会让 Runner 尝试以下拉取策略:示例包括仓库的 HTTP 403 ForbiddenHTTP 500 Internal Server Error 回应。

请注意,使用 if-not-present 拉取策略部分中的 When not to use this pull policy? 子部分中提到的安全限制仍然适用。 所以您应该了解安全限制并阅读安全考虑文档

Using Docker executor with image alpine:latest ...
Pulling docker image alpine:latest ...
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

Docker vs Docker-SSH(和 Docker+Machine vs Docker-SSH+Machine)

caution从极狐GitLab Runner 10.0 开启,Docker-SSH 和 Docker-SSH+machine 执行器都被废弃,并会在后面的发布中移除。

我们为特殊类型的 Docker 执行器提供支持,即 Docker-SSH(和弹性伸缩版本:Docker-SSH+Machine)。Docker-SSH 使用和 Docker 执行器一样的逻辑,但是它没有直接执行脚本,而是使用 SSH 客户端连接构建容器。

然后 Docker-SSH 连接在容器内部使用内部 IP 运行的 SSH 服务器。

这个执行器不再会被维护,并会在未来移除。