Kubernetes 执行器

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

使用 Kubernetes 执行器来使用 Kubernetes 集群进行构建。执行器调用 Kubernetes 集群 API,并为每个极狐GitLab CI 作业创建一个 pod。

Kubernetes 执行器将构建分为多个步骤:

  1. 准备:针对 Kubernetes 集群创建 Pod。这将创建构建和服务所需的容器。
  2. 预构建:克隆、恢复缓存,并下载来自先前阶段的产物。此步骤在 Pod 的特殊容器上运行。
  3. 构建:用户构建。
  4. 后构建:创建缓存,将产物上传至极狐GitLab。此步骤也使用 Pod 的特殊容器。

Runner 如何创建 Kubernetes pods#

下图显示了极狐GitLab实例与托管在 Kubernetes 集群上的 runner 之间的交互。runner 调用 Kubernetes API 以在集群上创建 pods。

Pod 由以下容器组成,每个 service.gitlab-ci.ymlconfig.toml 文件中定义:

  • 定义为 build 的构建容器。
  • 定义为 helper 的辅助容器。
  • 定义为 svc-X 的服务容器,其中 X[0-9]+

服务和容器在同一个 Kubernetes pod 中运行,并共享相同的 localhost 地址。适用以下限制:

  • 在 GitLab Runner 12.8 和 Kubernetes 1.7 及更高版本中,可以通过其 DNS 名称访问服务。如果您使用旧版本,必须使用 localhost
  • 不能使用同一端口的多个服务。例如,不能同时有两个 mysql 服务。
Rendering chart...

图中的交互适用于任何 Kubernetes 集群。例如,托管在主要公共云提供商上的交钥匙解决方案,或私有化部署的 Kubernetes 安装。

连接到 Kubernetes API#

使用以下选项连接到 Kubernetes API。提供的用户帐户必须有权在指定的命名空间中创建、列出和附加到 Pods。

选项描述
host可选 Kubernetes API 服务器主机 URL(如果未指定则尝试自动发现)。
cert_file可选 Kubernetes API 服务器用户认证证书。
key_file可选 Kubernetes API 服务器用户认证私钥。
ca_file可选 Kubernetes API 服务器 ca 证书。

如果您在 Kubernetes 集群中运行极狐GitLab Runner,可以省略这些字段,以便极狐GitLab Runner 自动发现 Kubernetes API。

如果您在集群外部运行极狐GitLab Runner,这些设置确保极狐GitLab Runner 可以访问集群上的 Kubernetes API。

为 Kubernetes API 调用设置承载令牌#

要设置用于创建 pods 的 API 调用的承载令牌,请使用 KUBERNETES_BEARER_TOKEN 变量。这允许项目所有者使用项目密钥变量指定承载令牌。

指定承载令牌时,必须设置 Host 配置设置。

yaml
variables: KUBERNETES_BEARER_TOKEN: thebearertokenfromanothernamespace

配置 runner API 权限#

要为核心 API 组配置权限,请更新极狐GitLab Runner Helm 图表的 values.yml 文件。

您可以选择:

  • rbac.create 设置为 true
  • values.yml 文件中指定具有以下权限的服务帐户 serviceAccount.name: <service_account_name>
资源动词(可选功能/配置标志)
eventslist, watch (FF_PRINT_POD_EVENTS=true)
namespacescreate (kubernetes.NamespacePerJob=true), delete (kubernetes.NamespacePerJob=true)
podscreate, delete, get, list (使用 Informers), watch (使用 Informers, FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/attachcreate (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), delete (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), get (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false), patch (FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
pods/execcreate, delete, get, patch
pods/logget (FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false, FF_WAIT_FOR_POD_TO_BE_REACHABLE=true), list (FF_KUBERNETES_HONOR_ENTRYPOINT=true, FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false)
secretscreate, delete, get, update
serviceaccountsget
servicescreate, get

您可以使用以下 YAML 角色定义来创建具有所需权限的角色。

yaml
1apiVersion: rbac.authorization.k8s.io/v1 2kind: Role 3metadata: 4 name: gitlab-runner 5 namespace: default 6rules: 7- apiGroups: [""] 8 resources: ["events"] 9 verbs: 10 - "list" 11 - "watch" # Required when `FF_PRINT_POD_EVENTS=true` 12- apiGroups: [""] 13 resources: ["namespaces"] 14 verbs: 15 - "create" # Required when `kubernetes.NamespacePerJob=true` 16 - "delete" # Required when `kubernetes.NamespacePerJob=true` 17- apiGroups: [""] 18 resources: ["pods"] 19 verbs: 20 - "create" 21 - "delete" 22 - "get" 23 - "list" # Required when using Informers (https://gitlab.cn/docs/runner/executors/kubernetes/#informers) 24 - "watch" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`, using Informers (https://gitlab.cn/docs/runner/executors/kubernetes/#informers) 25- apiGroups: [""] 26 resources: ["pods/attach"] 27 verbs: 28 - "create" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false` 29 - "delete" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false` 30 - "get" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false` 31 - "patch" # Required when `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false` 32- apiGroups: [""] 33 resources: ["pods/exec"] 34 verbs: 35 - "create" 36 - "delete" 37 - "get" 38 - "patch" 39- apiGroups: [""] 40 resources: ["pods/log"] 41 verbs: 42 - "get" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false`, `FF_WAIT_FOR_POD_TO_BE_REACHABLE=true` 43 - "list" # Required when `FF_KUBERNETES_HONOR_ENTRYPOINT=true`, `FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY=false` 44- apiGroups: [""] 45 resources: ["secrets"] 46 verbs: 47 - "create" 48 - "delete" 49 - "get" 50 - "update" 51- apiGroups: [""] 52 resources: ["serviceaccounts"] 53 verbs: 54 - "get" 55- apiGroups: [""] 56 resources: ["services"] 57 verbs: 58 - "create" 59 - "get"

Informers#

在 GitLab Runner 17.9.0 及更高版本中,Kubernetes informer 跟踪构建 pod 的更改。这有助于执行器更快地检测更改。

Informer 需要 podslistwatch 权限。当执行器开始构建时,它会检查 Kubernetes API 的权限。 如果授予了所有权限,执行器将使用 informer。 如果缺少任何权限,极狐GitLab Runner 会记录警告。构建继续并使用以前的机制来跟踪构建 pod 的状态和更改。

配置设置#

config.toml 文件中使用以下设置来配置 Kubernetes 执行器。

CPU 请求和限制#

设置描述
cpu_limit分配给构建容器的 CPU。
cpu_limit_overwrite_max_allowed构建容器的最大 CPU 分配量。为空时,禁用 CPU 限制覆盖功能。
cpu_request构建容器请求的 CPU。
cpu_request_overwrite_max_allowed构建容器的最大 CPU 请求量。为空时,禁用 CPU 请求覆盖功能。
helper_cpu_limit分配给构建辅助容器的 CPU。
helper_cpu_limit_overwrite_max_allowed辅助容器的最大 CPU 分配量。为空时,禁用 CPU 限制覆盖功能。
helper_cpu_request构建辅助容器请求的 CPU。
helper_cpu_request_overwrite_max_allowed辅助容器的最大 CPU 请求量。为空时,禁用 CPU 请求覆盖功能。
service_cpu_limit分配给构建服务容器的 CPU。
service_cpu_limit_overwrite_max_allowed服务容器的最大 CPU 分配量。为空时,禁用 CPU 限制覆盖功能。
service_cpu_request构建服务容器请求的 CPU。
service_cpu_request_overwrite_max_allowed服务容器的最大 CPU 请求量。为空时,禁用 CPU 请求覆盖功能。

内存请求和限制#

设置描述
memory_limit分配给构建容器的内存量。
memory_limit_overwrite_max_allowed构建容器的最大内存分配量。为空时,禁用内存限制覆盖功能。
memory_request构建容器请求的内存量。
memory_request_overwrite_max_allowed构建容器的最大内存请求量。为空时,禁用内存请求覆盖功能。
helper_memory_limit分配给构建辅助容器的内存量。
helper_memory_limit_overwrite_max_allowed辅助容器的最大内存分配量。为空时,禁用内存限制覆盖功能。
helper_memory_request构建辅助容器请求的内存量。
helper_memory_request_overwrite_max_allowed辅助容器的最大内存请求量。为空时,禁用内存请求覆盖功能。
service_memory_limit分配给构建服务容器的内存量。
service_memory_limit_overwrite_max_allowed服务容器的最大内存分配量。为空时,禁用内存限制覆盖功能。
service_memory_request构建服务容器请求的内存量。
service_memory_request_overwrite_max_allowed服务容器的最大内存请求量。为空时,禁用内存请求覆盖功能。

存储请求和限制#

设置描述
ephemeral_storage_limit构建容器的临时存储限制。
ephemeral_storage_limit_overwrite_max_allowed构建容器的最大临时存储限制。为空时,禁用临时存储限制覆盖功能。
ephemeral_storage_request构建容器的临时存储请求。
ephemeral_storage_request_overwrite_max_allowed构建容器的最大临时存储请求。为空时,禁用临时存储请求覆盖功能。
helper_ephemeral_storage_limit辅助容器的临时存储限制。
helper_ephemeral_storage_limit_overwrite_max_allowed辅助容器的最大临时存储限制。为空时,禁用临时存储限制覆盖功能。
helper_ephemeral_storage_request辅助容器的临时存储请求。
helper_ephemeral_storage_request_overwrite_max_allowed辅助容器的最大临时存储请求。为空时,禁用临时存储请求覆盖功能。
service_ephemeral_storage_limit服务容器的临时存储限制。
service_ephemeral_storage_limit_overwrite_max_allowed服务容器的最大临时存储限制。为空时,禁用临时存储限制覆盖功能。
service_ephemeral_storage_request服务容器的临时存储请求。
service_ephemeral_storage_request_overwrite_max_allowed服务容器的最大临时存储请求。为空时,禁用临时存储请求覆盖功能。

其他 config.toml 设置#

设置描述
affinity指定决定哪个节点运行构建的亲和性规则。了解更多关于使用亲和性
allow_privilege_escalation运行所有容器时启用 allowPrivilegeEscalation 标志。当为空时,它不会在容器的 SecurityContext 中定义 allowPrivilegeEscalation 标志,并允许 Kubernetes 使用默认的特权升级行为。
allowed_images可以在 .gitlab-ci.yml 中指定的镜像的通配符列表。如果不存在,则允许所有镜像(相当于 ["*/*:*"])。查看详细信息
allowed_pull_policies可以在 .gitlab-ci.yml 文件或 config.toml 文件中指定的拉取策略列表。
allowed_services可以在 .gitlab-ci.yml 中指定的服务的通配符列表。如果不存在,则允许所有镜像(相当于 ["*/*:*"])。查看详细信息
automount_service_account_token控制服务帐户令牌是否自动挂载在构建 pod 中的布尔值。
bearer_token用于启动构建 pods 的默认承载令牌。
bearer_token_overwrite_allowed允许项目指定用于创建构建 pod 的承载令牌的布尔值。
build_container_security_context为构建容器设置一个容器安全上下文。 了解更多关于安全上下文
cap_add指定应添加到作业 pod 容器中的 Linux 能力。了解更多关于 Kubernetes 执行器中的能力配置
cap_drop指定应从作业 pod 容器中删除的 Linux 能力。了解更多关于 Kubernetes 执行器中的能力配置
cleanup_grace_period_seconds当作业完成时,Pod 需要优雅终止的持续时间(以秒为单位)。在此期间之后,进程会被强制终止并发送 kill 信号。如果指定了 terminationGracePeriodSeconds,则忽略此项。
dns_policy指定构建 pod 时应使用的 DNS 策略:nonedefaultcluster-firstcluster-first-with-host-net。如果未设置,则使用 Kubernetes 的默认策略 (cluster-first)。
dns_config指定构建 pod 时应使用的 DNS 配置。了解更多关于使用 pod 的 DNS 配置
helper_container_security_context为辅助容器设置一个容器安全上下文。了解更多关于安全上下文
helper_image(高级) 覆盖默认的辅助镜像,用于克隆存储库和上传产物。
helper_image_flavor设置辅助镜像风格(alpinealpine3.18alpine3.19alpine3.21ubuntu)。默认为 alpine。使用 alpinealpine3.19 相同。
host_aliases添加到所有容器中的额外主机名别名列表。了解更多关于使用额外主机别名
image_pull_secrets包含 Kubernetes docker-registry 秘密名称的数组,用于从私有注册表中认证 Docker 镜像拉取。
init_permissions_container_security_context为初始化权限容器设置一个容器安全上下文。了解更多关于安全上下文
namespace运行 Kubernetes Pods 的命名空间。
namespace_per_job将作业隔离在单独的命名空间中。如果启用,则忽略 namespacenamespace_overwrite_allowed
namespace_overwrite_allowed用于验证命名空间覆盖环境变量内容的正则表达式(见下文)。为空时,禁用命名空间覆盖功能。
node_selector格式为 string=stringkey=value 对(在环境变量的情况下为 string:string)。设置此项会将 pods 的创建限制为与所有 key=value 对匹配的 Kubernetes 节点。了解更多关于使用节点选择器
node_tolerations格式为 string=string:string"key=value" = "Effect" 对表。设置此项允许 pods 调度到具有所有或部分容忍污点的节点。仅通过环境变量配置可以提供一个容忍度。keyvalueeffect 与 Kubernetes pod 容忍配置中的相应字段名匹配。
pod_annotations格式为 string=stringkey=value 对表。table 包含一个要添加到 runner 创建的每个构建 pod 的注释列表。这些值可以包括用于扩展的环境变量。pod 注释可以在每个构建中被覆盖。
pod_annotations_overwrite_allowed用于验证 pod 注释覆盖环境变量内容的正则表达式。为空时,禁用 pod 注释覆盖功能。
pod_labels格式为 string=stringkey=value 对表。table 包含一个要添加到 runner 创建的每个构建 pod 的标签列表。这些值可以包括用于扩展的环境变量。pod 标签可以在每个构建中通过使用 pod_labels_overwrite_allowed 覆盖。
pod_labels_overwrite_allowed用于验证 pod 标签覆盖环境变量内容的正则表达式。为空时,禁用 pod 标签覆盖功能。请注意,runner.gitlab.com 标签命名空间中的 pod 标签不能被覆盖。
pod_security_context通过配置文件配置,为构建 pod 设置一个 pod 安全上下文。了解更多关于安全上下文
pod_termination_grace_period_secondsPod 级别设置,确定 pod 需要优雅终止的持续时间(以秒为单位)。之后,进程会被强制停止并发送 kill 信号。如果指定了 terminationGracePeriodSeconds,则忽略此项。
poll_intervalRunner 轮询刚创建的 Kubernetes pod 以检查其状态的频率(以秒为单位)(默认为 3)。
poll_timeout在 Runner 尝试连接到刚创建的容器之前需要经过的时间(以秒为单位)。使用此设置可在队列中排队比集群一次能处理的更多构建(默认为 180)。
cleanup_resources_timeout作业完成后 Kubernetes 资源清理的总时间。支持的语法:1h30m300s10m。默认为 5 分钟(5m)。
priority_class_name指定要设置为 pod 的优先级类。如果未设置,则使用默认优先级类。
privileged运行带有特权标志的容器。
pull_policy指定镜像拉取策略:neverif-not-presentalways。如果未设置,则使用集群的镜像默认拉取策略。有关详细信息和如何设置多个拉取策略的说明,请参见使用拉取策略。另请参见if-not-presentnever 安全注意事项。您还可以限制拉取策略
resource_availability_check_max_attempts检查资源(服务帐户和/或拉取秘密)集是否可用的最大尝试次数。每次尝试之间有 5 秒的间隔。在极狐GitLab 15.0 中引入。了解更多关于准备步骤期间的资源检查
runtime_class_name要用于所有创建的 pods 的运行时类。如果集群不支持该功能,作业将退出或失败。
service_container_security_context为服务容器设置一个容器安全上下文。了解更多关于安全上下文
scheduler_name用于调度构建 pods 的调度器。
service_account作业/执行器 pods 使用的默认服务帐户与 Kubernetes API 通信。
service_account_overwrite_allowed用于验证服务帐户覆盖环境变量内容的正则表达式。为空时,禁用服务帐户覆盖功能。
services使用sidecar 模式附加到构建容器的服务列表。了解更多关于使用服务
use_service_account_image_pull_secrets启用后,执行器创建的 pod 缺少 imagePullSecrets。这会导致使用 imagePullSecrets 从服务帐户 创建 pod(如果已设置)。
terminationGracePeriodSeconds在 pod 中运行的进程发送终止信号后的持续时间,直到进程被强制停止并发送 kill 信号。弃用,建议使用 cleanup_grace_period_secondspod_termination_grace_period_seconds
volumes通过配置文件配置,挂载在构建容器中的卷列表。了解更多关于使用卷
pod_spec此设置是一个实验。覆盖 runner manager 生成的 pod 规范的列表配置,用于运行 CI 作业的 pod。可以设置所有列出的 Kubernetes Pod 规范 属性。有关更多信息,请参见覆盖生成的 pod 规范(实验)
retry_limit与 Kubernetes API 通信的最大尝试次数。每次尝试之间的重试间隔基于回退算法,起始时间为 500 毫秒。
retry_backoff_max自定义最大回退值,以毫秒为单位,表示每次尝试的重试间隔。默认值为 2000 毫秒,不能低于 500 毫秒。默认的每次尝试的最大重试间隔为 2 秒,可以通过 retry_backoff_max 自定义。
retry_limits每个请求错误的重试次数。
logs_base_dir要添加到生成的路径以存储构建日志的基本目录。有关更多信息,请参见更改构建日志和脚本的基本目录
scripts_base_dir要添加到生成的路径以存储构建脚本的基本目录。有关更多信息,请参见更改构建日志和脚本的基本目录

配置示例#

以下示例显示了 Kubernetes 执行器的 config.toml 文件的示例配置。

toml
1concurrent = 4 2 3[[runners]] 4 name = "myRunner" 5 url = "https://jihulab.com/ci" 6 token = "......" 7 executor = "kubernetes" 8 [runners.kubernetes] 9 host = "https://45.67.34.123:4892" 10 cert_file = "/etc/ssl/kubernetes/api.crt" 11 key_file = "/etc/ssl/kubernetes/api.key" 12 ca_file = "/etc/ssl/kubernetes/ca.crt" 13 namespace = "gitlab" 14 namespace_overwrite_allowed = "ci-.*" 15 bearer_token_overwrite_allowed = true 16 privileged = true 17 cpu_limit = "1" 18 memory_limit = "1Gi" 19 service_cpu_limit = "1" 20 service_memory_limit = "1Gi" 21 helper_cpu_limit = "500m" 22 helper_memory_limit = "100Mi" 23 poll_interval = 5 24 poll_timeout = 3600 25 dns_policy = "cluster-first" 26 priority_class_name = "priority-1" 27 logs_base_dir = "/tmp" 28 scripts_base_dir = "/tmp" 29 [runners.kubernetes.node_selector] 30 gitlab = "true" 31 [runners.kubernetes.node_tolerations] 32 "node-role.kubernetes.io/master" = "NoSchedule" 33 "custom.toleration=value" = "NoSchedule" 34 "empty.value=" = "PreferNoSchedule" 35 "onlyKey" = ""

配置执行器服务帐户#

要配置执行器服务帐户,可以设置 KUBERNETES_SERVICE_ACCOUNT 环境变量或使用 --kubernetes-service-account 标志。

Pods 和容器#

您可以配置 pods 和容器以控制作业的执行方式。

作业 pods 的默认标签#

您不能通过 runner 配置或 `.gitlab-ci.yml` 文件覆盖这些标签。 任何在 `runner.gitlab.com` 命名空间中设置或修改标签的尝试 都会被忽略并记录为调试消息。
描述
project.runner.gitlab.com/id项目的 ID,在极狐GitLab 实例中是唯一的。
project.runner.gitlab.com/name项目的名称。
project.runner.gitlab.com/namespace-id项目的命名空间的 ID。
project.runner.gitlab.com/namespace项目的命名空间的名称。
project.runner.gitlab.com/root-namespace项目的根命名空间的 ID。例如,/gitlab-org/group-a/subgroup-a/project,其中根命名空间是 gitlab-org
manager.runner.gitlab.com/name启动此作业的 runner 配置的名称。
manager.runner.gitlab.com/id-short启动作业的 runner 配置的 ID。
job.runner.gitlab.com/podKubernetes 执行器使用的内部标签。

作业 pods 的默认注释#

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

以下注释默认添加在运行作业的 Pod 上:

描述
job.runner.gitlab.com/id作业的 ID,在极狐GitLab 实例中是唯一的。
job.runner.gitlab.com/url作业详情的 URL。
job.runner.gitlab.com/sha项目构建的提交修订版本。
job.runner.gitlab.com/before_sha分支或标签上存在的前一个最新提交。
job.runner.gitlab.com/ref项目构建的分支或标签名称。
job.runner.gitlab.com/name作业的名称。
job.runner.gitlab.com/timeout作业执行超时的时间格式。例如,'2h3m0.5s'。
project.runner.gitlab.com/id作业的项目 ID。

要覆盖默认注释,请在极狐GitLab Runner 配置中使用 pod_annotations。 您还可以在 .gitlab-ci.yml 文件 中为每个 CI/CD 作业覆盖注释。

Pod 生命周期#

Pod 的生命周期 可能会受到以下因素的影响:

  • TOML 配置文件中设置 pod_termination_grace_period_seconds 属性。 Pod 上运行的进程可以在发送 TERM 信号后运行指定的持续时间。 如果 Pod 在此期间未成功终止,则会发送 kill 信号。
  • 启用 FF_USE_POD_ACTIVE_DEADLINE_SECONDS 功能标志。 启用后,如果作业超时,运行 CI/CD 作业的 Pod 将被标记为失败,所有相关的容器将被终止。要让极狐GitLab 首先超时作业, activeDeadlineSeconds 被设置为 配置的超时 + 1 秒
如果您启用 `FF_USE_POD_ACTIVE_DEADLINE_SECONDS` 功能标志并将 `pod_termination_grace_period_seconds` 设置为非零值,CI/CD 作业 pod 不会立即终止。Pod `terminationGracePeriods` 确保 pod 仅在过期时才被终止。

覆盖 pod 容忍度#

要覆盖 Kubernetes pod 容忍度:

  1. config.toml 或 Helm values.yaml 文件中,要启用 CI 作业 pod 容忍度的覆盖,为 node_tolerations_overwrite_allowed 定义一个正则表达式。 此正则表达式用于验证以 KUBERNETES_NODE_TOLERATIONS_ 开头的 CI 变量名称的值。

    toml
    1runners: 2 ... 3 config: | 4 [[runners]] 5 [runners.kubernetes] 6 node_tolerations_overwrite_allowed = ".*"
  2. .gitlab-ci.yml 文件中,定义一个或多个 CI 变量以覆盖 CI 作业 pod 容忍度。

    yaml
    1variables: 2 KUBERNETES_NODE_TOLERATIONS_1: 'node-role.kubernetes.io/master:NoSchedule' 3 KUBERNETES_NODE_TOLERATIONS_2: 'custom.toleration=value:NoSchedule' 4 KUBERNETES_NODE_TOLERATIONS_3: 'empty.value=:PreferNoSchedule' 5 KUBERNETES_NODE_TOLERATIONS_4: 'onlyKey' 6 KUBERNETES_NODE_TOLERATIONS_5: '' # 容忍所有污点

覆盖 pod 标签#

要为每个 CI/CD 作业覆盖 Kubernetes pod 标签:

  1. .config.yaml 文件中,为 pod_labels_overwrite_allowed 定义一个正则表达式。

  2. .gitlab-ci.yml 文件中,设置 KUBERNETES_POD_LABELS_* 变量,其值为 key=value。Pod 标签将被覆盖为 key=value。您可以应用多个值:

    yaml
    variables: KUBERNETES_POD_LABELS_1: "Key1=Val1" KUBERNETES_POD_LABELS_2: "Key2=Val2" KUBERNETES_POD_LABELS_3: "Key3=Val3"
`runner.gitlab.com` 命名空间中的标签是只读的。极狐GitLab 会忽略任何添加、修改或删除这些极狐GitLab 内部标签的尝试。

覆盖 pod 注释#

要为每个 CI/CD 作业覆盖 Kubernetes pod 注释:

  1. .config.yaml 文件中,为 pod_annotations_overwrite_allowed 定义一个正则表达式。

  2. .gitlab-ci.yml 文件中,设置 KUBERNETES_POD_ANNOTATIONS_* 变量,并使用 key=value 作为值。 Pod 注释将被覆盖为 key=value。您可以指定多个注释:

    yaml
    variables: KUBERNETES_POD_ANNOTATIONS_1: "Key1=Val1" KUBERNETES_POD_ANNOTATIONS_2: "Key2=Val2" KUBERNETES_POD_ANNOTATIONS_3: "Key3=Val3"

在以下示例中,设置了 pod_annotationspod_annotations_overwrite_allowed。 此配置允许覆盖 config.toml 中配置的任何 pod_annotations

toml
1[[runners]] 2 # 通常配置 3 executor = "kubernetes" 4 [runners.kubernetes] 5 image = "alpine" 6 pod_annotations_overwrite_allowed = ".*" 7 [runners.kubernetes.pod_annotations] 8 "Key1" = "Val1" 9 "Key2" = "Val2" 10 "Key3" = "Val3" 11 "Key4" = "Val4"

覆盖生成的 pod 规范#

  • 状态:Beta
History
    • 在极狐GitLab Runner 15.10 中引入。

此功能处于 beta 阶段。我们强烈建议您在将此功能用于生产集群之前,先在测试 Kubernetes 集群上使用它。要使用此功能,您必须启用 FF_USE_ADVANCED_POD_SPEC_CONFIGURATION 功能标志

要修改 runner manager 生成的 PodSpec,请在 config.toml 文件中使用 pod_spec 设置。

pod_spec 设置:

  • 覆盖并完成生成的 pod 规范的字段。
  • 覆盖您在 [runners.kubernetes] 中设置的配置值。

您可以配置多个 pod_spec 设置。

设置描述
name自定义 pod_spec 的名称。
patch_path在生成最终 PodSpec 对象之前定义要应用的更改的文件路径。该文件必须是 JSON 或 YAML 文件。
patch描述在生成最终 PodSpec 对象之前要应用的更改的 JSON 或 YAML 格式字符串。
patch_typerunner 用于将指定更改应用于极狐GitLab Runner 生成的 PodSpec 对象的策略。接受的值为 mergejsonstrategic

在同一个 pod_spec 配置中,不能同时设置 patch_pathpatch,否则会发生错误。

config.toml 中多个 pod_spec 配置的示例:

toml
1[[runners]] 2 [runners.kubernetes] 3 [[runners.kubernetes.pod_spec]] 4 name = "hostname" 5 patch = ''' 6 hostname: "custom-pod-hostname" 7 ''' 8 patch_type = "merge" 9 [[runners.kubernetes.pod_spec]] 10 name = "subdomain" 11 patch = ''' 12 subdomain: "subdomain" 13 ''' 14 patch_type = "strategic" 15 [[runners.kubernetes.pod_spec]] 16 name = "terminationGracePeriodSeconds" 17 patch = ''' 18 [{"op": "replace", "path": "/terminationGracePeriodSeconds", "value": 60}] 19 ''' 20 patch_type = "json"

合并补丁策略#

merge 补丁策略在现有 PodSpec 上应用键值替换。如果您使用此策略,config.toml 中的 pod_spec 配置将 覆盖 生成的最终 PodSpec 对象之前的值。由于值会被完全覆盖,您应该谨慎使用此补丁策略。

具有 merge 补丁策略的 pod_spec 配置示例:

toml
1concurrent = 1 2check_interval = 1 3log_level = "debug" 4shutdown_timeout = 0 5 6[session_server] 7 session_timeout = 1800 8 9[[runners]] 10 name = "" 11 url = "https://gitlab.example.com" 12 id = 0 13 token = "__REDACTED__" 14 token_obtained_at = 0001-01-01T00:00:00Z 15 token_expires_at = 0001-01-01T00:00:00Z 16 executor = "kubernetes" 17 shell = "bash" 18 environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"] 19 [runners.kubernetes] 20 image = "alpine" 21 ... 22 [[runners.kubernetes.pod_spec]] 23 name = "build envvars" 24 patch = ''' 25 containers: 26 - env: 27 - name: env1 28 value: "value1" 29 - name: env2 30 value: "value2" 31 name: build 32 ''' 33 patch_type = "merge"

使用此配置,最终 PodSpec 只有一个名为 build 的容器,其中包含两个环境变量 env1env2。上面的示例会使相关的 CI 作业失败,因为:

  • helper 容器规范被删除。
  • build 容器规范丢失了极狐GitLab Runner 设置的所有必要配置。

为了防止作业失败,在本例中,pod_spec 必须包含由极狐GitLab Runner 生成的未修改的属性。

JSON patch 策略#

json patch 策略使用 JSON Patch 规范来控制 PodSpec 对象和数组的更新。您无法在 array 属性上使用此策略。

以下是使用 json patch 策略的 pod_spec 配置示例。在此配置中,向现有的 nodeSelector 添加了一个新的 key: value pair。现有的值不会被覆盖。

toml
1concurrent = 1 2check_interval = 1 3log_level = "debug" 4shutdown_timeout = 0 5 6[session_server] 7 session_timeout = 1800 8 9[[runners]] 10 name = "" 11 url = "https://gitlab.example.com" 12 id = 0 13 token = "__REDACTED__" 14 token_obtained_at = 0001-01-01T00:00:00Z 15 token_expires_at = 0001-01-01T00:00:00Z 16 executor = "kubernetes" 17 shell = "bash" 18 environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"] 19 [runners.kubernetes] 20 image = "alpine" 21 ... 22 [[runners.kubernetes.pod_spec]] 23 name = "val1 node" 24 patch = ''' 25 { "op": "add", "path": "/nodeSelector", "value": { key1: "val1" } } 26 ''' 27 patch_type = "json"

战略性 patch 策略#

strategic patch 策略使用应用于 PodSpec 对象每个字段的现有 patchStrategy

以下是使用 strategic patch 策略的 pod_spec 配置示例。在此配置中,一个 resource request 被设置在构建容器上。

toml
1concurrent = 1 2check_interval = 1 3log_level = "debug" 4shutdown_timeout = 0 5 6[session_server] 7 session_timeout = 1800 8 9[[runners]] 10 name = "" 11 url = "https://gitlab.example.com" 12 id = 0 13 token = "__REDACTED__" 14 token_obtained_at = 0001-01-01T00:00:00Z 15 token_expires_at = 0001-01-01T00:00:00Z 16 executor = "kubernetes" 17 shell = "bash" 18 environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"] 19 [runners.kubernetes] 20 image = "alpine" 21 ... 22 [[runners.kubernetes.pod_spec]] 23 name = "cpu request 500m" 24 patch = ''' 25 containers: 26 - name: build 27 resources: 28 requests: 29 cpu: "500m" 30 ''' 31 patch_type = "strategic"

在此配置中,一个 resource request 被设置在构建容器上。

最佳实践#

  1. 在生产环境部署前,在测试环境中测试添加的 pod_spec
  2. 确保 pod_spec 配置不会对极狐GitLab Runner 生成的规范产生负面影响。
  3. 不要使用 merge patch 策略进行复杂的 pod 规范更新。
  4. 在可用时,尽量使用 config.toml。例如,以下配置会用自定义 pod_spec 中设置的环境变量替换极狐GitLab Runner 首次设置的环境变量,而不是将环境变量添加到现有列表中。
toml
1concurrent = 1 2check_interval = 1 3log_level = "debug" 4shutdown_timeout = 0 5 6[session_server] 7 session_timeout = 1800 8 9[[runners]] 10 name = "" 11 url = "https://gitlab.example.com" 12 id = 0 13 token = "__REDACTED__" 14 token_obtained_at = 0001-01-01T00:00:00Z 15 token_expires_at = 0001-01-01T00:00:00Z 16 executor = "kubernetes" 17 shell = "bash" 18 environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true", "CUSTOM_VAR=value"] 19 [runners.kubernetes] 20 image = "alpine" 21 ... 22 [[runners.kubernetes.pod_spec]] 23 name = "build envvars" 24 patch = ''' 25 containers: 26 - env: 27 - name: env1 28 value: "value1" 29 name: build 30 ''' 31 patch_type = "strategic"

通过修改 Pod Spec 为每个构建作业创建一个 PVC#

要为每个构建作业创建一个 PersistentVolumeClaim,请确保查看如何启用 Pod Spec 功能

Kubernetes 允许您创建附加到 pod 生命周期的临时 PersistentVolumeClaim。如果在您的 Kubernetes 集群上启用了 动态供应,该方法有效。每个 PVC 都可以请求一个新的 Volume。该 volume 也与 pod 的生命周期绑定。

在启用 动态供应 后,可以如下修改 config.toml 来创建一个临时 PVC

toml
1[[runners.kubernetes.pod_spec]] 2 name = "ephemeral-pvc" 3 patch = ''' 4 containers: 5 - name: build 6 volumeMounts: 7 - name: builds 8 mountPath: /builds 9 - name: helper 10 volumeMounts: 11 - name: builds 12 mountPath: /builds 13 volumes: 14 - name: builds 15 ephemeral: 16 volumeClaimTemplate: 17 spec: 18 storageClassName: <The Storage Class that will dynamically provision a Volume> 19 accessModes: [ ReadWriteOnce ] 20 resources: 21 requests: 22 storage: 1Gi 23 '''

设置 pod 的安全策略#

config.toml 中配置 安全上下文 以为构建 pod 设置安全策略。

使用以下选项:

选项类型必需描述
fs_groupint应用于 pod 中所有容器的特殊补充组。
run_as_groupint用于运行容器进程入口点的 GID。
run_as_non_rootboolean表示容器必须以非 root 用户身份运行。
run_as_userint用于运行容器进程入口点的 UID。
supplemental_groupsint 列表除容器的主 GID 外,应用于每个容器中第一个进程的组列表。
selinux_typestring应用于 pod 中所有容器的 SELinux 类型标签。

config.toml 中的 pod 安全上下文示例:

toml
1concurrent = %(concurrent)s 2check_interval = 30 3 [[runners]] 4 name = "myRunner" 5 url = "gitlab.example.com" 6 executor = "kubernetes" 7 [runners.kubernetes] 8 helper_image = "gitlab-registry.example.com/helper:latest" 9 [runners.kubernetes.pod_security_context] 10 run_as_non_root = true 11 run_as_user = 59417 12 run_as_group = 59417 13 fs_group = 59417

移除旧的 runner pods#

History
    • 在 GitLab Runner 14.6 中引入。

有时旧的 runner pods 未被清除。当 runner 管理器错误地关闭时可能会发生这种情况。

为了解决这种情况,您可以使用极狐GitLab Runner Pod Cleanup 应用程序来调度旧 pods 的清理。有关更多信息,请参阅:

  • 极狐GitLab Runner Pod Cleanup 项目的 README
  • 极狐GitLab Runner Pod Cleanup 文档

设置容器的安全策略#

History
    • 在 GitLab Runner 14.5 中引入。

config.toml 执行器中配置 容器安全上下文 以为构建、助手或服务 pods 设置容器安全策略。

使用以下选项:

选项类型必需描述
run_as_groupint用于运行容器进程入口点的 GID。
run_as_non_rootboolean表示容器必须以非 root 用户身份运行。
run_as_userint用于运行容器进程入口点的 UID。
capabilities.addstring 列表运行容器时要添加的能力。
capabilities.dropstring 列表运行容器时要删除的能力。
selinux_typestring与容器进程关联的 SELinux 类型标签。

在以下 config.toml 示例中,安全上下文配置:

  • 设置 pod 安全上下文。
  • 覆盖构建和助手容器的 run_as_userrun_as_group
  • 指定所有服务容器继承 pod 安全上下文中的 run_as_userrun_as_group
toml
1concurrent = 4 2check_interval = 30 3 [[runners]] 4 name = "myRunner" 5 url = "gitlab.example.com" 6 executor = "kubernetes" 7 [runners.kubernetes] 8 helper_image = "gitlab-registry.example.com/helper:latest" 9 [runners.kubernetes.pod_security_context] 10 run_as_non_root = true 11 run_as_user = 59417 12 run_as_group = 59417 13 fs_group = 59417 14 [runners.kubernetes.init_permissions_container_security_context] 15 run_as_user = 1000 16 run_as_group = 1000 17 [runners.kubernetes.build_container_security_context] 18 run_as_user = 65534 19 run_as_group = 65534 20 [runners.kubernetes.build_container_security_context.capabilities] 21 add = ["NET_ADMIN"] 22 [runners.kubernetes.helper_container_security_context] 23 run_as_user = 1000 24 run_as_group = 1000 25 [runners.kubernetes.service_container_security_context] 26 run_as_user = 1000 27 run_as_group = 1000

设置拉取策略#

config.toml 文件中使用 pull_policy 参数来指定单个或多个拉取策略。该策略控制图像的获取和更新方式,并应用于构建图像、助手图像和任何服务。

要确定使用哪个策略,请参阅 Kubernetes 文档关于拉取策略的说明

单个拉取策略:

toml
[runners.kubernetes] pull_policy = "never"

多个拉取策略:

toml
[runners.kubernetes] # 使用多个拉取策略 pull_policy = ["always", "if-not-present"]

当您定义多个策略时,每个策略会被尝试,直到成功获取图像。例如,当您使用 [ always, if-not-present ] 时,如果 always 策略因临时注册表问题失败,则使用 if-not-present 策略。

要重试失败的拉取:

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

极狐GitLab 的命名约定与 Kubernetes 的不同。

Runner 拉取策略Kubernetes 拉取策略描述
blankblank使用 Kubernetes 指定的默认策略。
if-not-presentIfNotPresent只有当图像在执行作业的节点上不存在时才会拉取。使用此拉取策略前请查看 安全注意事项
alwaysAlways每次执行作业时都会拉取图像。
neverNever从不拉取图像,需要节点上已存在。

指定容器能力#

您可以指定在容器中使用的 Kubernetes 能力

要指定容器能力,请在 config.toml 中使用 cap_addcap_drop 选项。容器运行时也可以定义一个默认的能力列表,例如 Docker 或 container。

有一个 能力列表 是 runner 默认删除的。在 cap_add 选项中列出的能力不会被删除。

config.toml 文件中的配置示例:

toml
1concurrent = 1 2check_interval = 30 3[[runners]] 4 name = "myRunner" 5 url = "gitlab.example.com" 6 executor = "kubernetes" 7 [runners.kubernetes] 8 # ... 9 cap_add = ["SYS_TIME", "IPC_LOCK"] 10 cap_drop = ["SYS_ADMIN"] 11 # ...

指定能力时:

  • 用户定义的 cap_drop 优先于用户定义的 cap_add。如果您在两个设置中定义了相同的能力,则仅将 cap_drop 中的能力传递给容器。
  • 从传递给容器配置的能力标识符中删除 CAP_ 前缀。例如,如果您想添加或删除 CAP_SYS_TIME 能力,在配置文件中,输入字符串 SYS_TIME
  • Kubernetes 集群的所有者可以定义 PodSecurityPolicy,其中指定的能力被允许、限制或默认添加。这些规则优先于任何用户定义的配置。

重写容器资源#

您可以为每个 CI/CD 作业重写 Kubernetes CPU 和内存分配。您可以为构建、助手和服务容器应用请求和限制设置。

要重写容器资源,请在 .gitlab-ci.yml 文件中使用以下变量。

这些变量的值被限制在该资源的 最大重写 设置内。如果未为某个资源设置最大重写,则该变量不被使用。

yaml
1 variables: 2 KUBERNETES_CPU_REQUEST: "3" 3 KUBERNETES_CPU_LIMIT: "5" 4 KUBERNETES_MEMORY_REQUEST: "2Gi" 5 KUBERNETES_MEMORY_LIMIT: "4Gi" 6 KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "512Mi" 7 KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "1Gi" 8 9 KUBERNETES_HELPER_CPU_REQUEST: "3" 10 KUBERNETES_HELPER_CPU_LIMIT: "5" 11 KUBERNETES_HELPER_MEMORY_REQUEST: "2Gi" 12 KUBERNETES_HELPER_MEMORY_LIMIT: "4Gi" 13 KUBERNETES_HELPER_EPHEMERAL_STORAGE_REQUEST: "512Mi" 14 KUBERNETES_HELPER_EPHEMERAL_STORAGE_LIMIT: "1Gi" 15 16 KUBERNETES_SERVICE_CPU_REQUEST: "3" 17 KUBERNETES_SERVICE_CPU_LIMIT: "5" 18 KUBERNETES_SERVICE_MEMORY_REQUEST: "2Gi" 19 KUBERNETES_SERVICE_MEMORY_LIMIT: "4Gi" 20 KUBERNETES_SERVICE_EPHEMERAL_STORAGE_REQUEST: "512Mi" 21 KUBERNETES_SERVICE_EPHEMERAL_STORAGE_LIMIT: "1Gi"

定义服务列表#

History
    • 在 GitLab Runner 16.9 中为 HEALTCHECK_TCP_SERVICES 引入支持。

config.toml 中定义 服务 列表。

toml
1concurrent = 1 2check_interval = 30 3 [[runners]] 4 name = "myRunner" 5 url = "gitlab.example.com" 6 executor = "kubernetes" 7 [runners.kubernetes] 8 helper_image = "gitlab-registy.example.com/helper:latest" 9 [[runners.kubernetes.services]] 10 name = "postgres:12-alpine" 11 alias = "db1" 12 [[runners.kubernetes.services]] 13 name = "registry.example.com/svc1" 14 alias = "svc1" 15 entrypoint = ["entrypoint.sh"] 16 command = ["executable","param1","param2"] 17 environment = ["ENV=value1", "ENV2=value2"]

如果服务环境中包括 HEALTHCHECK_TCP_PORT,极狐GitLab Runner 会在服务响应该端口之前等待,然后再启动用户的 CI 脚本。您还可以在 .gitlab-ci.ymlservices 部分中配置 HEALTHCHECK_TCP_PORT 环境变量。

重写服务容器资源#

如果一个作业有多个服务容器,您可以为每个服务容器设置明确的资源请求和限制。使用每个服务中的变量属性来重写 .gitlab-ci.yml 中指定的容器资源。

yaml
1 services: 2 - name: redis:5 3 alias: redis5 4 variables: 5 KUBERNETES_SERVICE_CPU_REQUEST: "3" 6 KUBERNETES_SERVICE_CPU_LIMIT: "6" 7 KUBERNETES_SERVICE_MEMORY_REQUEST: "3Gi" 8 KUBERNETES_SERVICE_MEMORY_LIMIT: "6Gi" 9 KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "2Gi" 10 KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "3Gi" 11 - name: postgres:12 12 alias: MY_relational-database.12 13 variables: 14 KUBERNETES_CPU_REQUEST: "2" 15 KUBERNETES_CPU_LIMIT: "4" 16 KUBERNETES_MEMORY_REQUEST: "1Gi" 17 KUBERNETES_MEMORY_LIMIT: "2Gi" 18 KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "1Gi" 19 KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "2Gi"

这些特定设置优先于作业的常规设置。值仍然受到该资源的 最大重写设置 的限制。

重写 Kubernetes 默认服务账户#

要在 .gitlab-ci.yml 文件中为每个 CI/CD 作业重写 Kubernetes 服务账户,请设置变量 KUBERNETES_SERVICE_ACCOUNT_OVERWRITE

您可以使用此变量指定附加到命名空间的服务账户,这在复杂的 RBAC 配置中可能需要。

yaml
variables: KUBERNETES_SERVICE_ACCOUNT_OVERWRITE: ci-service-account

要确保在 CI 运行期间仅使用指定的服务账户,请定义一个正则表达式:

  • 对于 service_account_overwrite_allowed 设置。
  • 对于 KUBERNETES_SERVICE_ACCOUNT_OVERWRITE_ALLOWED 环境变量。

如果您没有设置其中任何一个,则重写被禁用。

设置 RuntimeClass#

History
    • 在 GitLab Runner 14.9 中引入。

使用 runtime_class_name 为每个作业容器设置 RuntimeClass

如果您指定了一个 RuntimeClass 名称,但没有在集群中配置它,或者不支持该功能,则执行器无法创建作业。

toml
1concurrent = 1 2check_interval = 30 3 [[runners]] 4 name = "myRunner" 5 url = "gitlab.example.com" 6 executor = "kubernetes" 7 [runners.kubernetes] 8 runtime_class_name = "myclass"

更改构建日志和脚本的基础目录#

History
    • 在 GitLab Runner 17.2 中引入。

您可以更改将 emptyDir 卷挂载到 pod 用于构建日志和脚本的目录。您可以使用该目录来:

  • 运行具有修改过图像的作业 pods。
  • 以非特权用户身份运行。
  • 自定义 SecurityContext 设置。

要更改目录:

  • 对于构建日志,设置 logs_base_dir
  • 对于构建脚本,设置 scripts_base_dir

预期值是一个不带尾部斜杠的基础目录字符串(例如,/tmp/mydir/example)。目录必须已经存在。

此值会在生成的构建日志和脚本路径前加上前缀。例如:

toml
1 [[runners]] 2 name = "myRunner" 3 url = "gitlab.example.com" 4 executor = "kubernetes" 5 [runners.kubernetes] 6 logs_base_dir = "/tmp" 7 scripts_base_dir = "/tmp"

此配置将导致 emptyDir 卷挂载在:

  • /tmp/logs-${CI_PROJECT_ID}-${CI_JOB_ID} 用于构建日志,而不是默认的 /logs-${CI_PROJECT_ID}-${CI_JOB_ID}
  • /tmp/scripts-${CI_PROJECT_ID}-${CI_JOB_ID} 用于构建脚本。

用户命名空间#

在 Kubernetes 1.30 及更高版本中,您可以使用 用户命名空间 将在容器中运行的用户与主机上的用户隔离。在容器中以 root 身份运行的进程可以在主机上以不同的非特权用户身份运行。

使用用户命名空间,您可以更好地控制用于运行 CI/CD 作业的镜像。需要额外设置的操作(例如以 root 身份运行)也可以在不增加主机攻击面的情况下运行。

要使用此功能,请确保您的集群已正确配置。以下示例为 hostUsers 键添加 pod_spec 并禁用特权 pods 和权限提升:

toml
1 [[runners]] 2 environment = ["FF_USE_ADVANCED_POD_SPEC_CONFIGURATION=true"] 3 builds_dir = "/tmp/builds" 4 [runners.kubernetes] 5 logs_base_dir = "/tmp" 6 scripts_base_dir = "/tmp" 7 privileged = false 8 allowPrivilegeEscalation = false 9 [[runners.kubernetes.pod_spec]] 10 name = "hostUsers" 11 patch = ''' 12 [{"op": "add", "path": "/hostUsers", "value": false}] 13 ''' 14 patch_type = "json"

使用用户命名空间时,您不能使用默认路径作为构建目录 (builds_dir)、构建日志 (logs_base_dir) 或构建脚本 (scripts_base_dir)。即使是容器的 root 用户也没有权限挂载卷。它们也不能在容器文件系统的根目录中创建目录。

相反,您可以更改构建日志和脚本的基础目录。您还可以通过设置 [[runners]].builds_dir 来更改构建目录。

操作系统、架构和 Windows 内核版本#

极狐GitLab Runner 使用 Kubernetes 执行器可以在不同操作系统上运行构建,如果配置的集群有运行这些操作系统的节点。

系统确定助手镜像的操作系统、架构和 Windows 内核版本(如果适用)。然后使用这些参数进行构建的其他方面,例如要使用的容器或镜像。

以下图表说明了系统如何检测这些详细信息:

Rendering chart...

以下是唯一影响构建的操作系统、架构和 Windows 内核版本选择的参数。

  • helper_image_autoset_arch_and_os 配置
  • kubernetes.io/oskubernetes.io/archnode.kubernetes.io/windows-build 标签选择器来自:
    • node_selector 配置
    • node_selector 重写

其他参数不会影响上述选择过程。但是,您可以使用诸如 affinity 之类的参数来进一步限制构建调度的节点。

节点#

指定执行构建的节点#

使用 node_selector 选项指定 Kubernetes 集群中的哪个节点可以用于执行构建。它是 string=string 格式的 key=value 对(在环境变量的情况下为 string:string)。

Runner 使用提供的信息来确定构建的操作系统和架构。这确保了使用正确的 助手镜像。默认的操作系统和架构是 linux/amd64

您可以使用特定标签来调度具有不同操作系统和架构的节点。

linux/arm64 的示例#

toml
1 [[runners]] 2 name = "myRunner" 3 url = "gitlab.example.com" 4 executor = "kubernetes" 5 6 [runners.kubernetes.node_selector] 7 "kubernetes.io/arch" = "arm64" 8 "kubernetes.io/os" = "linux"

windows/amd64 的示例#

Kubernetes 对 Windows 有某些 限制。如果您使用进程隔离,还必须使用 node.kubernetes.io/windows-build 标签提供特定的 Windows 构建版本。

toml
1 [[runners]] 2 name = "myRunner" 3 url = "gitlab.example.com" 4 executor = "kubernetes" 5 6 # 必须启用 FF_USE_POWERSHELL_PATH_RESOLVER 功能标志,以便 PowerShell 在 Runner 在 Linux 环境中运行但目标是 Windows 节点时正确解析路径。 7 environment = ["FF_USE_POWERSHELL_PATH_RESOLVER=true"] 8 9 [runners.kubernetes.node_selector] 10 "kubernetes.io/arch" = "amd64" 11 "kubernetes.io/os" = "windows" 12 "node.kubernetes.io/windows-build" = "10.0.20348"

重写节点选择器#

要重写节点选择器:

  1. config.toml 或 Helm values.yaml 文件中,启用节点选择器的重写:

    toml
    1runners: 2 ... 3 config: | 4 [[runners]] 5 [runners.kubernetes] 6 node_selector_overwrite_allowed = ".*"
  2. .gitlab-ci.yml 文件中,定义变量以重写节点选择器:

    yaml
    variables: KUBERNETES_NODE_SELECTOR_* = ''

在以下示例中,要重写 Kubernetes 节点架构,在 config.toml.gitlab-ci.yml 文件中配置设置:

toml
1concurrent = 1 2check_interval = 1 3log_level = "debug" 4shutdown_timeout = 0 5 6listen_address = ':9252' 7 8[session_server] 9 session_timeout = 1800 10 11[[runners]] 12 name = "" 13 url = "https://gitlab.com/" 14 id = 0 15 token = "__REDACTED__" 16 token_obtained_at = "0001-01-01T00:00:00Z" 17 token_expires_at = "0001-01-01T00:00:00Z" 18 executor = "kubernetes" 19 shell = "bash" 20 [runners.kubernetes] 21 host = "" 22 bearer_token_overwrite_allowed = false 23 image = "alpine" 24 namespace = "" 25 namespace_overwrite_allowed = "" 26 pod_labels_overwrite_allowed = "" 27 service_account_overwrite_allowed = "" 28 pod_annotations_overwrite_allowed = "" 29 node_selector_overwrite_allowed = "kubernetes.io/arch=.*" # <--- 允许架构的重写

定义节点亲和性的列表#

定义一个 节点亲和性 列表,在构建时添加到 pod 规范中。

`node_affinities` 不决定构建应在哪个操作系统上运行,只有 `node_selectors`。有关更多信息,请参阅 [操作系统、架构和 Windows 内核版本](#operating-system-architecture-and-windows-kernel-version)。 `config.toml` 中的配置示例:
toml
1concurrent = 1 2[[runners]] 3 name = "myRunner" 4 url = "gitlab.example.com" 5 executor = "kubernetes" 6 [runners.kubernetes] 7 [runners.kubernetes.affinity] 8 [runners.kubernetes.affinity.node_affinity] 9 [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution]] 10 weight = 100 11 [runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference] 12 [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_expressions]] 13 key = "cpu_speed" 14 operator = "In" 15 values = ["fast"] 16 [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_expressions]] 17 key = "mem_speed" 18 operator = "In" 19 values = ["fast"] 20 [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution]] 21 weight = 50 22 [runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference] 23 [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_expressions]] 24 key = "core_count" 25 operator = "In" 26 values = ["high", "32"] 27 [[runners.kubernetes.affinity.node_affinity.preferred_during_scheduling_ignored_during_execution.preference.match_fields]] 28 key = "cpu_type" 29 operator = "In" 30 values = ["arm64"] 31 [runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution] 32 [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms]] 33 [[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms.match_expressions]] 34 key = "kubernetes.io/e2e-az-name" 35 operator = "In" 36 values = [ 37 "e2e-az1", 38 "e2e-az2" 39 ]

定义 pod 调度的节点#

History
    • 在 GitLab Runner 14.3 中引入。

使用 pod 亲和性和反亲和性来限制节点 您的 pod 有资格 调度的节点,基于其他 pods 上的标签。

config.toml 中的配置示例:

toml
1concurrent = 1 2[[runners]] 3 name = "myRunner" 4 url = "gitlab.example.com" 5 executor = "kubernetes" 6 [runners.kubernetes] 7 [runners.kubernetes.affinity] 8 [runners.kubernetes.affinity.pod_affinity] 9 [[runners.kubernetes.affinity.pod_affinity.required_during_scheduling_ignored_during_execution]] 10 topology_key = "failure-domain.beta.kubernetes.io/zone" 11 namespaces = ["namespace_1", "namespace_2"] 12 [runners.kubernetes.affinity.pod_affinity.required_during_scheduling_ignored_during_execution.label_selector] 13 [[runners.kubernetes.affinity.pod_affinity.required_during_scheduling_ignored_during_execution.label_selector.match_expressions]] 14 key = "security" 15 operator = "In" 16 values = ["S1"] 17 [[runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution]] 18 weight = 100 19 [runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term] 20 topology_key = "failure-domain.beta.kubernetes.io/zone" 21 [runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector] 22 [[runners.kubernetes.affinity.pod_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector.match_expressions]] 23 key = "security_2" 24 operator = "In" 25 values = ["S2"] 26 [runners.kubernetes.affinity.pod_anti_affinity] 27 [[runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution]] 28 topology_key = "failure-domain.beta.kubernetes.io/zone" 29 namespaces = ["namespace_1", "namespace_2"] 30 [runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.label_selector] 31 [[runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.label_selector.match_expressions]] 32 key = "security" 33 operator = "In" 34 values = ["S1"] 35 [runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.namespace_selector] 36 [[runners.kubernetes.affinity.pod_anti_affinity.required_during_scheduling_ignored_during_execution.namespace_selector.match_expressions]] 37 key = "security" 38 operator = "In" 39 values = ["S1"] 40 [[runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution]] 41 weight = 100 42 [runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term] 43 topology_key = "failure-domain.beta.kubernetes.io/zone" 44 [runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector] 45 [[runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.label_selector.match_expressions]] 46 key = "security_2" 47 operator = "In" 48 values = ["S2"] 49 [runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.namespace_selector] 50 [[runners.kubernetes.affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution.pod_affinity_term.namespace_selector.match_expressions]] 51 key = "security_2" 52 operator = "In" 53 values = ["S2"]

网络#

配置容器生命周期钩子#

History
    • 在 GitLab Runner 14.2 中引入。

使用 容器生命周期钩子 在执行相应生命周期钩子时运行为处理程序配置的代码。

您可以配置两种类型的钩子:PreStopPostStart。每种钩子仅允许设置一种类型的处理程序。

config.toml 文件中的配置示例:

toml
1[[runners]] 2 name = "kubernetes" 3 url = "https://gitlab.example.com/" 4 executor = "kubernetes" 5 token = "yrnZW46BrtBFqM7xDzE7dddd" 6 [runners.kubernetes] 7 image = "alpine:3.11" 8 privileged = true 9 namespace = "default" 10 [runners.kubernetes.container_lifecycle.post_start.exec] 11 command = ["touch", "/builds/postStart.txt"] 12 [runners.kubernetes.container_lifecycle.pre_stop.http_get] 13 port = 8080 14 host = "localhost" 15 path = "/test" 16 [[runners.kubernetes.container_lifecycle.pre_stop.http_get.http_headers]] 17 name = "header_name_1" 18 value = "header_value_1" 19 [[runners.kubernetes.container_lifecycle.pre_stop.http_get.http_headers]] 20 name = "header_name_2" 21 value = "header_value_2"

使用以下设置配置每个生命周期钩子:

选项类型必需描述
execKubernetesLifecycleExecActionExec 指定要执行的操作。
http_getKubernetesLifecycleHTTPGetHTTPGet 指定要执行的 HTTP 请求。
tcp_socketKubernetesLifecycleTcpSocketTCPsocket 指定涉及 TCP 端口的操作。

KubernetesLifecycleExecAction#

选项类型必需描述
commandstring list在容器内执行的命令行。

KubernetesLifecycleHTTPGet#

选项类型必需描述
portint访问容器上的端口号。
hoststring连接的主机名,默认为 pod IP(可选)。
pathstring访问 HTTP 服务器的路径(可选)。
schemestring用于连接主机的方案。默认为 HTTP(可选)。
http_headersKubernetesLifecycleHTTPGetHeader list设置在请求中的自定义头(可选)。

KubernetesLifecycleHTTPGetHeader#

选项类型必需描述
namestringHTTP 头名称。
valuestringHTTP 头值。

KubernetesLifecycleTcpSocket#

选项类型必需描述
portint访问容器上的端口号。
hoststring连接的主机名,默认为 pod IP(可选)。

配置 Pod 的 DNS 设置#

使用以下选项配置 Pod 的 DNS 设置

选项类型是否必需描述
nameserversstring 列表用作 Pod 的 DNS 服务器的 IP 地址列表。
optionsKubernetesDNSConfigOption一个可选的对象列表,每个对象可以有一个名称属性(必需)和一个值属性(可选)。
searchesstring 列表Pod 中的主机名查找的 DNS 搜索域列表。

config.toml 文件中的示例配置:

toml
1concurrent = 1 2check_interval = 30 3[[runners]] 4 name = "myRunner" 5 url = "https://gitlab.example.com" 6 token = "__REDACTED__" 7 executor = "kubernetes" 8 [runners.kubernetes] 9 image = "alpine:latest" 10 [runners.kubernetes.dns_config] 11 nameservers = [ 12 "1.2.3.4", 13 ] 14 searches = [ 15 "ns1.svc.cluster-domain.example", 16 "my.dns.search.suffix", 17 ] 18 19 [[runners.kubernetes.dns_config.options]] 20 name = "ndots" 21 value = "2" 22 23 [[runners.kubernetes.dns_config.options]] 24 name = "edns0"

KubernetesDNSConfigOption#

选项类型是否必需描述
namestring配置选项名称。
value*string配置选项值。

默认丢弃能力列表#

极狐GitLab Runner 默认情况下会丢弃以下能力。

用户定义的 cap_add 优先于默认丢弃能力列表。如果要添加默认情况下丢弃的能力,请将其添加到 cap_add

  • NET_RAW

添加额外的主机别名#

此功能在 Kubernetes 1.7 及更高版本中可用。

配置一个 主机别名 以指示 Kubernetes 在容器的 /etc/hosts 文件中添加条目。

使用以下选项:

选项类型是否必需描述
IPstring要附加主机的 IP 地址。
Hostnamesstring 列表附加到 IP 的主机名别名列表。

config.toml 文件中的示例配置:

toml
1concurrent = 4 2 3[[runners]] 4 # 常规配置 5 executor = "kubernetes" 6 [runners.kubernetes] 7 [[runners.kubernetes.host_aliases]] 8 ip = "127.0.0.1" 9 hostnames = ["web1", "web2"] 10 [[runners.kubernetes.host_aliases]] 11 ip = "192.168.1.1" 12 hostnames = ["web14", "web15"]

您还可以使用命令行参数 --kubernetes-host_aliases 和 JSON 输入配置主机别名。例如:

shell
gitlab-runner register --kubernetes-host_aliases '[{"ip":"192.168.1.100","hostnames":["myservice.local"]},{"ip":"192.168.1.101","hostnames":["otherservice.local"]}]'

#

使用 Kubernetes 执行器的缓存#

当缓存与 Kubernetes 执行器一起使用时,会在 Pod 上挂载一个名为 /cache 的卷。在作业执行期间,如果需要缓存数据,runner 会检查是否有可用的缓存数据。如果在缓存卷上有压缩文件,则缓存数据可用。

要设置缓存卷,请在 config.toml 文件中使用 cache_dir 设置。

  • 如果可用,压缩文件会被解压缩到构建文件夹中,然后可以在作业中使用。
  • 如果不可用,则从配置的存储中下载缓存数据,并将其保存到 cache dir 中作为压缩文件。然后将压缩文件解压缩到 build 文件夹中。

配置卷类型#

您可以挂载以下卷类型:

  • hostPath
  • persistentVolumeClaim
  • configMap
  • secret
  • emptyDir
  • csi

多个卷类型的配置示例:

toml
1concurrent = 4 2 3[[runners]] 4 # 常规配置 5 executor = "kubernetes" 6 [runners.kubernetes] 7 [[runners.kubernetes.volumes.host_path]] 8 name = "hostpath-1" 9 mount_path = "/path/to/mount/point" 10 read_only = true 11 host_path = "/path/on/host" 12 [[runners.kubernetes.volumes.host_path]] 13 name = "hostpath-2" 14 mount_path = "/path/to/mount/point_2" 15 read_only = true 16 [[runners.kubernetes.volumes.pvc]] 17 name = "pvc-1" 18 mount_path = "/path/to/mount/point1" 19 [[runners.kubernetes.volumes.config_map]] 20 name = "config-map-1" 21 mount_path = "/path/to/directory" 22 [runners.kubernetes.volumes.config_map.items] 23 "key_1" = "relative/path/to/key_1_file" 24 "key_2" = "key_2" 25 [[runners.kubernetes.volumes.secret]] 26 name = "secrets" 27 mount_path = "/path/to/directory1" 28 read_only = true 29 [runners.kubernetes.volumes.secret.items] 30 "secret_1" = "relative/path/to/secret_1_file" 31 [[runners.kubernetes.volumes.empty_dir]] 32 name = "empty-dir" 33 mount_path = "/path/to/empty_dir" 34 medium = "Memory" 35 [[runners.kubernetes.volumes.csi]] 36 name = "csi-volume" 37 mount_path = "/path/to/csi/volume" 38 driver = "my-csi-driver" 39 [runners.kubernetes.volumes.csi.volume_attributes] 40 size = "2Gi"

hostPath#

配置 hostPath 以指示 Kubernetes 在容器中挂载指定的主机路径。

config.toml 文件中使用以下选项:

选项类型是否必需描述
namestring卷的名称。
mount_pathstring卷在容器中挂载的位置。
sub_pathstring在挂载卷内使用的 子路径,而不是根路径。
host_pathstring主机上作为卷挂载的路径。如果未指定值,则默认为 mount_path 的相同路径。
read_onlyboolean将卷设置为只读模式。默认为 false
mount_propagationstring在容器之间共享挂载的卷。有关更多信息,请参阅 Mount Propagation

persistentVolumeClaim#

配置 persistentVolumeClaim 以指示 Kubernetes 使用在 Kubernetes 集群中定义的 persistentVolumeClaim 并将其挂载在容器中。

config.toml 文件中使用以下选项:

选项类型是否必需描述
namestring卷的名称,同时也是应使用的 PersistentVolumeClaim 的名称。支持变量。有关更多信息,请参阅 Persistent per-concurrency build volumes
mount_pathstring卷在容器中挂载的位置。
read_onlyboolean将卷设置为只读模式(默认为 false)。
sub_pathstring在卷中挂载 子路径,而不是根路径。
mount_propagationstring设置卷的挂载传播模式。有关更多详细信息,请参阅 Kubernetes mount propagation

configMap#

配置 configMap 卷以指示 Kubernetes 使用在 Kubernetes 集群中定义的 configMap 并将其挂载在容器中。

config.toml 中使用以下选项:

选项类型是否必需描述
namestring卷的名称,同时也是应使用的 configMap 的名称。
mount_pathstring卷在容器中挂载的位置。
read_onlyboolean将卷设置为只读模式(默认为 false)。
sub_pathstring在卷中挂载 子路径,而不是根路径。
itemsmap[string]string应使用的 configMap 中键的键到路径映射。

configMap 中的每个键会转换为一个文件,并存储在挂载路径中。默认情况下:

  • 包含所有键。
  • 使用 configMap 键作为文件名。
  • 值存储在文件内容中。

要更改默认的键和值存储,请使用 items 选项。如果使用 items 选项,则仅指定的键会添加到卷中,所有其他键会被跳过。

如果使用不存在的键,作业会在 Pod 创建阶段失败。

secret#

配置一个 secret 以指示 Kubernetes 使用在 Kubernetes 集群中定义的 secret 并将其挂载在容器中。

config.toml 文件中使用以下选项:

选项类型是否必需描述
namestring卷的名称,同时也是应使用的 secret 的名称。
mount_pathstring卷在容器中挂载的位置。
read_onlyboolean将卷设置为只读模式(默认为 false)。
sub_pathstring在卷中挂载 子路径,而不是根路径。
itemsmap[string]string应使用的 configMap 中键的键到路径映射。

从选定 secret 中的每个键会转换为一个文件,并存储在选定的挂载路径中。默认情况下:

  • 包含所有键。
  • 使用 configMap 键作为文件名。
  • 值存储在文件内容中。

要更改默认的键和值存储,请使用 items 选项。如果使用 items 选项,则仅指定的键会添加到卷中,所有其他键会被跳过。

如果使用不存在的键,作业会在 Pod 创建阶段失败。

emptyDir#

配置一个 emptyDir 以指示 Kubernetes 在容器中挂载一个空目录。

config.toml 文件中使用以下选项:

选项类型是否必需描述
namestring卷的名称。
mount_pathstring卷在容器中挂载的位置。
sub_pathstring在卷中挂载 子路径,而不是根路径。
mediumstring"Memory" 提供一个 tmpfs,否则默认为节点磁盘存储(默认为 "")。
size_limitstringemptyDir 卷所需的本地存储总量。

csi#

配置一个 容器存储接口 (csi) 卷 以指示 Kubernetes 使用自定义 csi 驱动程序将任意存储系统挂载在容器中。

config.toml 中使用以下选项:

选项类型是否必需描述
namestring卷的名称。
mount_pathstring卷在容器中挂载的位置。
driverstring指定要使用的卷驱动程序名称的字符串值。
fs_typestring指定文件系统类型名称的字符串值(例如,ext4xfsntfs)。
volume_attributesmap[string]stringcsi 卷属性的键值对映射。
sub_pathstring在卷中挂载 子路径,而不是根路径。
read_onlyboolean将卷设置为只读模式(默认为 false)。

在服务容器上挂载卷#

为构建容器定义的卷也会自动挂载到所有服务容器中。您可以使用此功能作为 services_tmpfs(仅适用于 Docker 执行器)的替代方案,将数据库存储挂载到 RAM 中以加快测试速度。

config.toml 文件中的示例配置:

toml
1[[runners]] 2 # 常规配置 3 executor = "kubernetes" 4 [runners.kubernetes] 5 [[runners.kubernetes.volumes.empty_dir]] 6 name = "mysql-tmpfs" 7 mount_path = "/var/lib/mysql" 8 medium = "Memory"

自定义卷挂载#

要为作业存储构建目录,请定义自定义卷挂载到配置的 builds_dir(默认为 /builds)。如果您使用 pvc,根据 访问模式,您可能仅限于在一个节点上运行作业。

config.toml 文件中的示例配置:

toml
1concurrent = 4 2 3[[runners]] 4 # 常规配置 5 executor = "kubernetes" 6 builds_dir = "/builds" 7 [runners.kubernetes] 8 [[runners.kubernetes.volumes.empty_dir]] 9 name = "repo" 10 mount_path = "/builds" 11 medium = "Memory"

每个并发构建卷的持久化#

History
    • 在 GitLab 16.3 中为 pvc.name 引入了变量注入支持。

Kubernetes CI 作业中的构建目录默认是临时的。如果您希望在作业之间持久化 Git 克隆(以使 GIT_STRATEGY=fetch 工作),则必须为构建文件夹挂载一个持久卷声明。由于多个作业可以并发运行,您必须使用一个 ReadWriteMany 卷,或者为同一 runner 上的每个潜在并发作业使用一个卷。后者可能更具性能优势。以下是此类配置的示例:

toml
1concurrent = 4 2 3[[runners]] 4 executor = "kubernetes" 5 builds_dir = "/mnt/builds" 6 [runners.kubernetes] 7 [[runners.kubernetes.volumes.pvc]] 8 # CI_CONCURRENT_ID 标识同一 runner 的并行作业。 9 name = "build-pvc-$CI_CONCURRENT_ID" 10 mount_path = "/mnt/builds"

在此示例中,您需要自己创建名为 build-pvc-0build-pvc-3 的持久卷声明。根据 runner 的 concurrent 设置创建相应的数量。

使用助手镜像#

设置安全策略后,助手镜像 必须符合该策略。该镜像不从 root 组获得权限,因此您必须确保用户 ID 是 root 组的一部分。

如果您只需要 `nonroot` 环境,您可以使用 [极狐GitLab Runner UBI](https://gitlab.com/gitlab-org/ci-cd/gitlab-runner-ubi-images/container_registry/1766421) OpenShift 容器平台镜像而不是助手镜像。您还可以使用 [极狐GitLab Runner Helper UBI](https://gitlab.com/gitlab-org/ci-cd/gitlab-runner-ubi-images/container_registry/1766433) OpenShift 容器平台镜像。

以下示例创建一个名为 nonroot 的用户和组,并将助手镜像设置为以该用户身份运行。

Dockerfile
1ARG tag 2FROM registry.gitlab.com/gitlab-org/ci-cd/gitlab-runner-ubi-images/gitlab-runner-helper-ocp:${tag} 3USER root 4RUN groupadd -g 59417 nonroot && \ 5 useradd -u 59417 nonroot -g nonroot 6WORKDIR /home/nonroot 7USER 59417:59417

在构建中使用 Docker#

当您在构建中使用 Docker 时,需要注意几个事项。

暴露的 /var/run/docker.sock#

如果使用 runners.kubernetes.volumes.host_path 选项将主机的 /var/run/docker.sock 暴露到构建容器中,会涉及风险。在与生产容器相同的集群中运行构建时要小心。节点的容器可以从构建容器中访问。

使用 docker:dind#

如果运行 docker:dind,也称为 docker-in-docker 镜像,容器必须以特权模式运行。这可能带来潜在的风险并导致其他问题。

Docker 守护进程作为一个单独的容器在 Pod 中运行,因为它作为 service 启动,通常在 .gitlab-ci.yml 中。Pod 中的容器仅共享分配给它们的卷和 IP 地址,它们使用 localhost 相互通信。docker:dind 容器不共享 /var/run/docker.sock,而 docker 二进制文件尝试默认使用它。

要配置客户端使用 TCP 与其他容器中的 Docker 守护进程通信,请在构建容器中包含以下环境变量:

  • DOCKER_HOST=tcp://<hostname>:2375 用于无 TLS 连接。
  • DOCKER_HOST=tcp://<hostname>:2376 用于 TLS 连接。

对于 hostname,设置为:

  • 对于极狐GitLab Runner 12.7 及更早版本,以及 Kubernetes 1.6 及更早版本,使用 localhost
  • 对于极狐GitLab Runner 12.8 及更高版本,以及 Kubernetes 1.7 及更高版本,使用 docker

在 Docker 19.03 及更高版本中,默认启用 TLS,但您必须将证书映射到您的客户端。您可以为 Docker-in-Docker 启用非 TLS 连接或挂载证书。有关更多信息,请参见 使用 Docker In Docker 工作流与 Docker 执行器

防止主机内核暴露#

如果使用 docker:dind/var/run/docker.sock,则 Docker 守护进程可以访问主机机器的底层内核。这意味着在构建 Docker 镜像时,Pod 中设置的任何 limits 都不起作用。Docker 守护进程报告节点的全部容量,而不管 Kubernetes 对 Docker 构建容器施加的限制。

如果以特权模式运行构建容器,或者如果暴露了 /var/run/docker.sock,则主机内核可能会暴露给构建容器。要尽量减少暴露,请在 node_selector 选项中指定一个标签。这确保节点在部署任何容器之前匹配标签。例如,如果指定标签 role=ci,则构建容器仅在标记为 role=ci 的节点上运行,所有其他生产服务在其他节点上运行。

要进一步分离构建容器,可以使用节点 污点。污点可以防止其他 Pod 在与构建 Pod 相同的节点上调度,而无需为其他 Pod 进行额外配置。

使用 kaniko 构建 Docker 镜像#

您可以使用 kaniko 在 Kubernetes 集群中构建 Docker 镜像。

Kaniko 在没有 Docker 守护进程的情况下工作,并在没有特权访问的情况下构建镜像。

在使用 kaniko 构建 多阶段 Dockerfiles 时存在一个已知问题。如果流水线作业包括一个 after_script 部分,当执行 after_script 部分时会失败,并显示以下错误消息。作业仍然会成功完成。

shell
OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: chdir to cwd ("/workspace") set in config.json failed: no such file or directory: unknown

该部分失败的原因是 kaniko 在构建多阶段 Dockerfile 时删除了其容器的 WORKDIR。这阻止了 kubectl exec(以及类似的 SDK API)附加到容器。

此问题有两个解决方法:

  • 在 kaniko 执行器调用中添加 --ignore-path /workspace
  • 在作业的 script 中在 kaniko 执行器调用之后添加 mkdir -p /workspace

限制 Docker 镜像和服务#

History
    • 在极狐GitLab Runner 14.2 中为 Kubernetes 执行器添加。

您可以限制用于运行作业的 Docker 镜像。为此,请指定通配符模式。例如,只允许从您的私有 Docker 注册表中获取镜像:

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

或者,限制为来自此注册表的特定镜像列表:

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

限制 Docker 拉取策略#

History
    • 在极狐GitLab 15.1 中引入。

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

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

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

toml
1[[runners]] 2 (...) 3 executor = "kubernetes" 4 [runners.kubernetes] 5 (...) 6 allowed_pull_policies = ["always", "if-not-present"]
  • 如果未指定 allowed_pull_policies,则默认为 pull_policy 关键字中的值。
  • 如果未指定 pull_policy,则使用集群的镜像 默认拉取策略
  • 现有的 pull_policy 关键字 不能包含 allowed_pull_policies 中未指定的拉取策略。如果包含,作业将返回错误。

作业执行#

History

极狐GitLab Runner 默认使用 kube attach 而不是 kube exec。这应该可以避免在网络不稳定的环境中出现作业在中途被标记为成功的问题。

配置对 Kubernetes API 的请求尝试次数#

默认情况下,Kubernetes 执行器在五次失败尝试后重试特定请求到 Kubernetes API。延迟由一个 500 毫秒的基准和一个可自定义的上限控制,默认值为两秒。要配置重试次数,请在 config.toml 文件中使用 retry_limit 选项。同样,对于回退上限,使用 retry_backoff_max 选项。以下故障会自动重试:

  • error dialing backend
  • TLS handshake timeout
  • read: connection timed out
  • connect: connection timed out
  • Timeout occurred
  • http2: client connection lost
  • connection refused
  • tls: internal error
  • io.unexpected EOF
  • syscall.ECONNRESET
  • syscall.ECONNREFUSED
  • syscall.ECONNABORTED
  • syscall.EPIPE

要控制每个错误的重试次数,请使用 retry_limits 选项。retry_limits 指定每个错误的重试次数,并且是错误消息到重试次数的映射。错误消息可以是 Kubernetes API 返回的错误消息的子字符串。retry_limits 选项优先于 retry_limit 选项。

例如,将 retry_limits 选项配置为在您的环境中将 TLS 相关错误重试 10 次,而不是默认的五次:

toml
1[[runners]] 2 name = "myRunner" 3 url = "https://gitlab.example.com/" 4 executor = "kubernetes" 5 [runners.kubernetes] 6 retry_limit = 5 7 8 [runners.kubernetes.retry_limits] 9 "TLS handshake timeout" = 10 10 "tls: internal error" = 10

要为完全不同的错误(例如 exceeded quota)重试 20 次:

toml
1[[runners]] 2 name = "myRunner" 3 url = "https://gitlab.example.com/" 4 executor = "kubernetes" 5 [runners.kubernetes] 6 retry_limit = 5 7 8 [runners.kubernetes.retry_limits] 9 "exceeded quota" = 20

容器入口点已知问题#

History
    • 在极狐GitLab Runner 14.5 中引入。
    • 在极狐GitLab Runner 15.1 中更新。
在 15.0 中,极狐GitLab Runner 在与 Kubernetes 执行器一起使用时,使用 Docker 镜像中定义的入口点。GitLab 15.1 及更高版本中,当设置 `FF_KUBERNETES_HONOR_ENTRYPOINT` 时,Kubernetes 执行器使用 Docker 镜像中定义的入口点。

容器入口点有以下已知问题:

  • 如果在镜像的 Dockerfile 中定义了一个入口点,它必须打开一个有效的 shell。否则,作业会挂起。

    • 系统将命令作为 args 传递给构建容器,以打开一个 shell。
  • 文件类型 CI/CD 变量 在入口点执行时不会写入磁盘。该文件仅在脚本执行期间在作业中可访问。

  • 以下 CI/CD 变量在入口点中不可访问。您可以使用 before_script 在运行脚本命令之前进行任何设置更改:

在极狐GitLab Runner 17.4 之前:

  • 入口点日志不会转发到构建的日志。
  • 使用 Kubernetes 执行器和 kube exec 时,极狐GitLab Runner 不会等待入口点打开 shell(见上文的 说明)。

从极狐GitLab Runner 17.4 开始,入口点日志现在会被转发。系统会等待入口点运行并生成 shell。这有以下影响:

  • 如果设置了 FF_KUBERNETES_HONOR_ENTRYPOINT,并且镜像的入口点耗时超过 poll_timeout(默认:180 秒),则构建失败。需要调整 poll_timeout 值(以及可能的 poll_interval)以适应入口点的预期运行时间。
  • FF_KUBERNETES_HONOR_ENTRYPOINT FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY 被设置时,系统会在构建容器中添加一个 启动探针,以便知道何时入口点生成 shell。如果自定义入口点使用提供的 args 来生成期望的 shell,则启动探针会自动解决。然而,如果容器镜像在不使用通过 args 传递的命令生成 shell,则入口点必须通过在构建目录的根目录中创建一个名为 .gitlab-startup-marker 的文件来解决启动探针。 启动探针每 poll_interval 检查一次 .gitlab-startup-marker 文件。如果在 poll_timeout 内未找到该文件,则该 Pod 被视为不健康,系统将中止构建。

限制对作业变量的访问#

使用 Kubernetes 执行器时,有权访问 Kubernetes 集群的用户可以读取作业中使用的变量。默认情况下,作业变量存储在:

  • Pod 的环境部分

要限制对作业变量数据的访问,您应使用基于角色的访问控制 (RBAC)。当您使用 RBAC 时,只有极狐GitLab 管理员才能访问极狐GitLab Runner 使用的命名空间。

如果您需要其他用户访问极狐GitLab Runner 命名空间,请在极狐GitLab Runner 命名空间中设置以下 verbs 以限制用户访问:

  • 对于 podsconfigmaps
    • get
    • watch
    • list
  • 对于 pods/execpods/attach,使用 create

授权用户的示例 RBAC 定义:

yaml
1kind: Role 2apiVersion: rbac.authorization.k8s.io/v1 3metadata: 4 name: gitlab-runner-authorized-users 5rules: 6- apiGroups: [""] 7 resources: ["configmaps", "pods"] 8 verbs: ["get", "watch", "list"] 9- apiGroups: [""] 10 resources: ["pods/exec", "pods/attach"] 11 verbs: ["create"]

在准备步骤期间检查资源#

History
    • 在极狐GitLab 15.0 中引入。
    • 在极狐GitLab 15.2 中更新。

先决条件:

  • 设置了 image_pull_secretsservice_account
  • resource_availability_check_max_attempts 设置为大于零的数字。
  • 使用带有 getlist 权限的 Kubernetes serviceAccount

极狐GitLab Runner 以每次尝试之间 5 秒的间隔检查新的服务账户或秘密是否可用。

  • 在极狐GitLab 15.0 和 15.1 中,您无法禁用此功能,并且当设置了负值时默认为 5
  • 在极狐GitLab 15.0.1、15.1.1、15.2 及更高版本中,默认情况下禁用此功能。要启用此功能,请将 resource_availability_check_max_attempts 设置为 0 以外的任何值。您设置的值定义了 runner 检查服务账户或秘密的次数。

覆盖 Kubernetes 命名空间#

先决条件:

  • 在极狐GitLab Runner Helm 图表的 values.yml 文件中,将 rbac.clusterWideAccess 设置为 true
  • 在核心 API 组中配置了 runner 的 权限

您可以覆盖 Kubernetes 命名空间以指定一个用于 CI 的命名空间,并向其部署一组自定义 Pod。极狐GitLab Runner 生成的 Pod 位于覆盖的命名空间中,以便在 CI 阶段期间启用容器之间的访问。

要为每个 CI/CD 作业覆盖 Kubernetes 命名空间,请在 .gitlab-ci.yml 文件中设置 KUBERNETES_NAMESPACE_OVERWRITE 变量。

yaml
variables: KUBERNETES_NAMESPACE_OVERWRITE: ci-${CI_COMMIT_REF_SLUG}
此变量不会在您的集群上创建命名空间。请确保在运行作业之前该命名空间存在。

要在 CI 运行期间仅使用指定的命名空间,请在 config.toml 文件中为 namespace_overwrite_allowed 定义一个正则表达式:

toml
[runners.kubernetes] ... namespace_overwrite_allowed = "ci-.*"