自定义执行器

引入于极狐GitLab Runner 12.1。

极狐GitLab Runner 为其不原生支持的环境提供自定义执行器。例如,LXD 或 Libvirt。

您可以通过配置极狐GitLab Runner 使用可执行文件,用以部署、运行和清理您的环境,进而创建执行器。

您为自定义执行器配置的脚本叫做 Drivers。 例如,您可以创建 LXD 驱动Libvirt 驱动

限制

以下是当前使用自定义执行器的一些限制:

配置

以下是一些您可以选择的配置密钥。其中有一些是可选的。

以下是使用所有可用配置密钥配置自定义执行器的例子:

[[runners]]
  name = "custom"
  url = "https://jihulab.com"
  token = "TOKEN"
  executor = "custom"
  builds_dir = "/builds"
  cache_dir = "/cache"
  [runners.custom]
    config_exec = "/path/to/config.sh"
    config_args = [ "SomeArg" ]
    config_exec_timeout = 200

    prepare_exec = "/path/to/script.sh"
    prepare_args = [ "SomeArg" ]
    prepare_exec_timeout = 200

    run_exec = "/path/to/binary"
    run_args = [ "SomeArg" ]

    cleanup_exec = "/path/to/executable"
    cleanup_args = [ "SomeArg" ]
    cleanup_exec_timeout = 200

    graceful_kill_timeout = 200
    force_kill_timeout = 200

对于字段定义和是否是必填字段,请参见 [runners.custom] 部分 配置。

此外,[[runners]] 中的 builds_dircache_dir 都是必填的。

运行作业的必备软件

用户必须设置环境,包括 PATH 中必须出现的以下内容:

阶段

自定义执行器为您提供阶段,用以配置作业详情、准备和清理环境以及在其中运行作业脚本。每个阶段都负责特定的事情,而且要注意不同的事情。

自定义执行器会在内置极狐GitLab Runner 执行器执行它们的时候执行每个阶段。

对于每个被执行的步骤,特定的环境变量都会展示给可执行文件,进而获得运行的特定作业的信息。所有的阶段都会拥有以下可用的环境变量:

  • 标准 CI/CD 环境变量,包括 预定义变量
  • 自定义执行器 Runner 主机系统提供的所有环境变量。
  • 所有服务及其可用设置。 以 JSON 格式展示为 CUSTOM_ENV_CI_JOB_SERVICES

CI/CD 环境变量和预定义变量都以 CUSTOM_ENV_ 作为前缀,防止系统环境变量冲突。 例如,CI_BUILDS_DIR 会展示为 CUSTOM_ENV_CI_BUILDS_DIR

阶段按照以下顺序运行:

  1. config_exec
  2. prepare_exec
  3. run_exec
  4. cleanup_exec

服务

引入于极狐GitLab Runner 13.6。

服务展示为 JSON 阵列 CUSTOM_ENV_CI_JOB_SERVICES

示例:

custom:
  script:
    - echo $CUSTOM_ENV_CI_JOB_SERVICES
  services:
    - redis:latest
    - name: my-postgres:9.4
      alias: pg
      entrypoint: ["path", "to", "entrypoint"]
      command: ["path", "to", "cmd"]

以上示例会使用以下值设置 CUSTOM_ENV_CI_JOB_SERVICES 环境变量:

[{"name":"redis:latest","alias":"","entrypoint":null,"command":null},{"name":"my-postgres:9.4","alias":"pg","entrypoint":["path","to","entrypoint"],"command":["path","to","cmd"]}]

配置

配置阶段由 config_exec 执行。

有时您或许想在执行时间内进行设置。 例如,根据项目 ID 设置构建目录。 config_exec 从 STDOUT 读取并使用特定密钥期望得到有效 JSON 字符串。

示例:

#!/usr/bin/env bash

cat << EOS
{
  "builds_dir": "/builds/${CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID}/${CUSTOM_ENV_CI_PROJECT_PATH_SLUG}",
  "cache_dir": "/cache/${CUSTOM_ENV_CI_CONCURRENT_PROJECT_ID}/${CUSTOM_ENV_CI_PROJECT_PATH_SLUG}",
  "builds_dir_is_shared": true,
  "hostname": "custom-hostname",
  "driver": {
    "name": "test driver",
    "version": "v0.0.1"
  },
  "job_env" : {
    "CUSTOM_ENVIRONMENT": "example"
  }
}
EOS

任何 JSON 字符串中的额外密钥会被忽略。如果它不是有效的 JSON 字符串,阶段会失败且会重试两次。

参数 类型 必填 允许空值 描述
builds_dir 字符串 创建作业的工作目录的基础目录。
cache_dir 字符串 存储本地缓存的基础目录。
builds_dir_is_shared 布尔 定义是否在并发作业中共享环境。
hostname 字符串 关联 Runner 存储的作业的”元数据”的主机名。如果未指定,则不设置主机名。
driver.name 字符串 用户定义的驱动名称。与 Using custom executor... 行一起打印。如果未指定,则不会打印有关驱动的信息。
driver.version 字符串 用户定义的驱动版本。与 Using custom executor... 行一起打印。如果未指定,只会打印名称信息。
job_env 对象 通过环境变量,对作业的所有后续阶段都可用的所有名值对。

可扩展文件的 STDERR 会打印到作业日志中。

如果用户想设置极狐GitLab Runner 在结束进程前等待返回 JSON 字符串的截止时间, 他们可以设置 config_exec_timeout

如果定义了 config_exec_args,这些会被按照顺序添加到 config_exec 中定义的可执行文件中。 例如,我们拥有以下 config.toml 内容:

...
[runners.custom]
  ...
  config_exec = "/path/to/config"
  config_args = [ "Arg1", "Arg2" ]
  ...

极狐GitLab Runner 会将其执行为 /path/to/config Arg1 Arg2

job_env 使用

job_env 配置的主要目的是将变量传递到自定义执行器驱动调用的上下文以用于作业执行的后续阶段。

比如我们有一个示例驱动程序,连接作业执行环境需要准备一些证书并且此操作非常昂贵。 假设我们需要连接本地证书提供者以获取临时的 SSH 用户名和密码,自定义执行器接下来可以使用该用户名和密码来连接作业执行环境。

使用自定义执行器执行流程,其中每个作业执行阶段: prepare、多个 run 调用 和 cleanup 都单独执行驱动程序,每个阶段的上下文都是独立的。对于我们的证书解析示例来说,每次都需要连接到证书提供者。

如果此操作代价高昂,我们可能希望为整个作业执行执行一次,然后为所有作业执行阶段重新使用证书。 这就是 job_env 可以提供帮助的地方。使用 job_env,您可以与提供者在 config_exec 调用期间连接一次,然后将收到的证书与 job_env 一起进行传递。驱动程序不会每次都连接证书提供者,可能只是读取变量并使用存在的证书。

需要理解的很重要的一点是变量不会自动用于作业本身。 完全取决于自定义执行器驱动程序是如何实现的,而且在许多情况下它根本不存在。

如果您正在考虑 job_env 设置,那么您可以将一组变量传递给特定 Runner 执行的每个作业,然后查看 [[runners]]environment 设置

如果变量是动态的,并且预计它们的值会在不同作业之间发生变化,您应该确保您的驱动程序以将 job_env 传递的变量添加到作业执行调用的方式进行实现。

准备

准备阶段由 prepare_exec 执行。

在这点上,极狐GitLab Runner 了解作业的所有信息(它运行的位置和方式)。唯一遗留的问题是设置环境,用以运行作业。极狐GitLab Runner 会执行 prepare_exec 中定义的可执行文件。

它负责设置环境(例如,创建虚拟机或容器、服务或其他事情)。完成这些后,我们期待环境可以运行作业了。

这个阶段在一次作业执行中仅被执行一次。

如果用户想设置极狐GitLab Runner 在结束进程前等待准备环境的截止时间,他们可以设置 prepare_exec_timeout

从可执行文件返回的 STDOUTSTDERR 将会打印到作业日志中。

如果定义了 prepare_exec_args, 这些会被按照顺序添加到 prepare_exec 中定义的可执行文件中。 例如,我们拥有以下 config.toml 内容:

...
[runners.custom]
  ...
  prepare_exec = "/path/to/bin"
  prepare_args = [ "Arg1", "Arg2" ]
  ...

极狐GitLab Runner 会将其执行为 /path/to/bin Arg1 Arg2

运行

运行阶段由 run_exec 执行。

从可执行文件返回的 STDOUTSTDERR 将会打印到作业日志中。

不像其他阶段,run_exec 阶段会被执行很多次,因为它被分成很多子阶段,按顺序排列为:

  1. prepare_script
  2. get_sources
  3. restore_cache
  4. download_artifacts
  5. step_*
  6. build_script
  7. step_*
  8. after_script
  9. archive_cachearchive_cache_on_failure
  10. upload_artifacts_on_successupload_artifacts_on_failure
  11. cleanup_file_variables
note 在极狐GitLab Runner 14.0 及更高版本中,build_script 将会被 step_script 代替。

以上提及的每个阶段,都可以用以下内容执行 run_exec 可执行文件:

  • 常见环境变量。
  • 两个参数:
    • 极狐GitLab Runner 为运行自定义执行器所创建的脚本的路径。
    • 阶段名称。

例如:

/path/to/run_exec.sh /path/to/tmp/script1 prepare_executor
/path/to/run_exec.sh /path/to/tmp/script1 prepare_script
/path/to/run_exec.sh /path/to/tmp/script1 get_sources

如果您定义了 run_args,他们会是第一组传送到 run_exec 可执行文件的参数。极狐GitLab Runner 添加其他。 例如,假设我们拥有以下 config.toml

...
[runners.custom]
  ...
  run_exec = "/path/to/run_exec.sh"
  run_args = [ "Arg1", "Arg2" ]
  ...

极狐GitLab Runner 会使用以下参数执行可执行文件:

/path/to/run_exec.sh Arg1 Arg2 /path/to/tmp/script1 prepare_executor
/path/to/run_exec.sh Arg1 Arg2 /path/to/tmp/script1 prepare_script
/path/to/run_exec.sh Arg1 Arg2 /path/to/tmp/script1 get_sources

这个可扩展文件负责执行第一个参数中指定的脚本。 包含任何极狐GitLab Runner 执行器正常运行、克隆、下载产物、运行用户脚本和所有以下描述的其他步骤的所有脚本。 脚本可以是以下 Shell:

  • Bash
  • PowerShell 桌面
  • PowerShell 核心
  • Batch(废弃)

我们使用 [[runners]]shell 配置的 Shell 生成脚本。 如果没有提供,将使用 OS 平台的默认值。

下表主要介绍每个脚本做什么及其主要目的。

脚本名称 脚本内容
prepare_script 运行作业的机器的简单调试信息。
get_sources 准备 Git 配置,克隆/获取目录。我们建议您不要修改,因为您会获得极狐GitLab 提供的 Git 策略的所有好处。
restore_cache 如果定义,则提取缓存。前提是 gitlab-runner 二进制文件在 $PATH 中可用。
download_artifacts 如果定义,则下载产物。前提是 gitlab-runner 二进制文件在 $PATH 中可用。
step_* 由极狐GitLab 生成,是一组执行脚本,或许不会被发送到自定义执行器中。或许有多个步骤,例如 step_releasestep_accessibility。它可以是 .gitlab-ci.yml 文件中的功能。
build_script before_scriptscript的结合。在极狐GitLab Runner 14.0 及更高版本中,build_script 会被 step_script 代替。
after_script 这是从作业中定义的 after_script。即使前面步骤失败了,也会一直调用。
archive_cache 如果定义,则创建所有缓存的归档。只有当 build_script 成功时执行。
archive_cache_on_failure 如果定义,则创建所有缓存的归档。只有当 build_script 失败时执行。
upload_artifacts_on_success 上传定义的产物。只有当 build_script 成功时执行。
upload_artifacts_on_failure 上传定义的产物。只有当 build_script 失败时执行。
cleanup_file_variables 从磁盘删除所有基于文件的变量。

清理

清理阶段由 cleanup_exec 执行。

即使上述有一些阶段失败了,还是会执行这个最终阶段。 这个阶段的主要目的是清理可能设置的环境。 例如,关闭虚拟机或删除容器。

cleanup_exec 的结果不影响作业状态。 例如,即使发生了以下状态,作业也会被标记为成功。

  • prepare_execrun_exec 成功。
  • cleanup_exec 失败。

如果用户想设置极狐GitLab Runner 在结束进程前清理环境的截止时间,他们可以设置 cleanup_exec_timeout

可执行文件的 STDOUT 会以调试级别打印到极狐GitLab Runner 日志。 STDERR 会以警告级别打印到日志。

如果定义了 cleanup_exec_args, 这些会被按照顺序添加到 cleanup_exec 中定义的可执行文件中。 例如,我们拥有以下 config.toml 内容:

...
[runners.custom]
  ...
  cleanup_exec = "/path/to/bin"
  cleanup_args = [ "Arg1", "Arg2" ]
  ...

极狐GitLab Runner 会将其执行为 /path/to/bin Arg1 Arg2

终止和结束可执行文件

极狐GitLab Runner 会试图在以下情况中优雅终止可执行文件:

  • 满足 config_exec_timeoutprepare_exec_timeoutcleanup_exec_timeout
  • 作业超时
  • 作业被取消。

超时的时候,SIGTERM 会被发送到可执行文件,并且 exec_terminate_timeout 的倒计时会开始。可执行文件应该监听这个信号,确保其清理了资源。如果 exec_terminate_timeout 进行了传递且进程仍在运行,会发送 SIGKILL 结束进程,而且 exec_force_kill_timeout 会开始。如果 exec_force_kill_timeout 完成后,进程仍在运行, 极狐GitLab Runner 会废弃进程, 且不再会试图关闭/结束进程。如果在 config_execprepare_execrun_exec 过程中,两个超时时间都达到了,构建会被标记为失败。

错误处理

有两种不同类型的错误,极狐GitLab Runner 会用不同的方法处理。 只有当 config_execprepare_execrun_execcleanup_exec 中的可执行文件退出并显示这些代码时,才能处理这些错误。 如果用户退出并显示非零退出码,它应该成为以下错误码。

如果用户脚本退出并显示这些代码,它会成为可执行的退出码。

构建失败

极狐GitLab Runner 提供 BUILD_FAILURE_EXIT_CODE 环境变量,它应该被可执行文件用作退出码,通知极狐GitLab Runner 用户作业失败。 如果可执行文件退出并显示 BUILD_FAILURE_EXIT_CODE 码,构建会在极狐GitLab CI 中被标记为失败。

如果用户在 .gitlab-ci.yml 文件中定义的脚本退出并显示非零码,run_exec 应该退出并显示 BUILD_FAILURE_EXIT_CODE 值。

note 我们强烈建议您使用 BUILD_FAILURE_EXIT_CODE 而不是硬编码值退出。 因为它在任何发布中都可以变化,使得您的二进制/脚本成为未来证据。

系统失败

您可以通过退出进程并显示 SYSTEM_FAILURE_EXIT_CODE 中定义的错误码向极狐GitLab Runner 发送系统失败。 如果返回了错误码,在特定阶段上,极狐GitLab Runner 会重试这个阶段;如果重试也失败了,这个作业会被标记为失败。

下表介绍重试的阶段和重试次数。

阶段名称 重试次数 重试间隔时间
prepare_exec 3 3 秒
get_sources GET_SOURCES_ATTEMPTS 变量的值 (默认为 1)。 0 秒
restore_cache RESTORE_CACHE_ATTEMPTS 变量的值 (默认为 1)。 0 秒
download_artifacts ARTIFACT_DOWNLOAD_ATTEMPTS 变量的值 (默认为 1)。 0 秒
note 我们强烈建议您使用 SYSTEM_FAILURE_EXIT_CODE 而不是硬编码值退出。 因为它在任何发布中都可以变化,使得您的二进制/脚本成为未来证据。

作业响应

您可以改变作业级别的 CUSTOM_ENV_ 变量,因为他们遵守记录的 CI/CD 变量优先级别。 尽管这个功能很有必要,但当受信任的作业上下文必填时, 会自动提供完整的 JSON 作业响应。 Runner 生成一个 JOB_RESPONSE_FILE 环境变量中引用的临时文件。 这个文件在每个阶段都存在,且在清理时会自动移除。

$ cat ${JOB_RESPONSE_FILE}
{"id": 123456, "token": "jobT0ken",...}