资源组 (BASIC ALL)

默认情况下,极狐GitLab CI/CD 中的流水线并行运行。并行化是改善合并请求中反馈循环的重要因素,但是,在某些情况下,您可能希望限制部署作业的并发性,来逐个运行它们。 使用资源组从战略上控制作业的并发性,来安全地优化您的持续部署工作流程。

添加资源组

您应具有以下流水线配置(仓库中的.gitlab-ci.yml 文件):

build:
  stage: build
  script: echo "Your build script"

deploy:
  stage: deploy
  script: echo "Your deployment script"
  environment: production

每次将新提交推送到分支时,它都会运行一个新流水线,其中包含两个作业 builddeploy。但是如果您在短时间内推送多个提交,多个流水线会同时开始运行,例如:

  • 第一个流水线运行作业 build -> deploy
  • 第二个流水线运行作业 build -> deploy

在这种情况下,跨不同流水线的 deploy 作业可以同时运行到 production 环境中。对同一基础架构运行多个部署脚本可能会损害/混淆实例,并在最坏的情况下使其处于损坏状态。

为确保 deploy 作业每次只运行一次,您可以为并发敏感作业指定 resource_group 关键字

deploy:
  ...
  resource_group: production

使用此配置,可以确保部署的安全性,同时您仍然可以同时运行 build 作业,最大限度地提高流水线效率。

要求

限制

一个资源只能附加到一个资源组。

流程模式

  • 引入于 14.3 版本。
  • 功能标志 ci_resource_group_process_modes 删除于 14.4 版本。
  • 一般可用于 14.4 版本。

您可以选择一种流程模式来战略性地控制您的部署作业并发。 支持以下模式:

  • 无序:这是限制运行作业并发的默认流程模式。当您不关心作业的执行顺序时,这是最简单的选择。只要作业准备好运行,它就会开始处理作业。
  • 最早在前:这种模式限制了作业的并发性。当资源空闲时,它会在即将到来的作业(createdscheduledwaiting_for_resource 状态)列表中,按流水线 ID 升序排序选择第一个作业。

    当您要确保从最旧的流水线开始执行作业时,此模式非常有效。就流水线效率而言,与“无序”模式相比,它的效率较低,但对于持续部署来说更安全。

  • 最新在前:这种模式限制了作业的并发性。当资源空闲时,它会在即将到来的作业(createdscheduledwaiting_for_resource 状态)列表中,按流水线 ID 降序排序选择第一个作业。

    当您希望确保从最新流水线执行作业并使用跳过过时的部署作业功能。就流水线效率而言,这是最有效的选项,但您必须确保每个部署作业都是幂等的。

更改流程模式

要更改资源组的流程模式,您必须使用 API 并发送请求,通过指定 process_mode 编辑现有资源组

  • unordered
  • oldest_first
  • newest_first

流程模式之间的差异示例

考虑以下 .gitlab-ci.yml,其中我们有两个作业 builddeploy,每个作业都在各自的阶段运行,并且 deploy 作业有一个资源组设置为 production

build:
  stage: build
  script: echo "Your build script"

deploy:
  stage: deploy
  script: echo "Your deployment script"
  environment: production
  resource_group: production

如果在短时间内将三个提交推送到项目,这意味着三个流水线几乎同时运行:

  • 第一个流水线运行作业 build -> deploy。我们将此部署作业称为 deploy-1
  • 第二个流水线运行作业 build -> deploy。我们将此部署作业称为 deploy-2
  • 第三个流水线运行作业 build -> deploy。我们将此部署作业称为 deploy-3

根据资源组的流程模式:

  • 如果设置为 unordered
    • deploy-1deploy-2deploy-3 不会并行运行。
    • 作业执行顺序无法保证,例如,deploy-1 可以在 deploy-3 运行之前或之后运行。
  • 如果设置为 oldest_first
    • deploy-1deploy-2deploy-3 不会并行运行。
    • deploy-1 首先运行,deploy-2 第二个运行,deploy-3 最后运行。
  • 如果设置为 newest_first
    • deploy-1deploy-2deploy-3 不会并行运行。
    • deploy-3 首先运行,deploy-2 第二个运行,deploy-1 最后运行。

跨项目/父子流水线的流水线级并发控制

您可以为对并发执行敏感的下游流水线定义 resource_grouptrigger 关键字可以触发下游流水线,resource_group 关键字可以与之共存。resource_group 可以有效控制部署流水线的并发,而其他作业可以继续并发运行。

以下示例在一个项目中有两个流水线配置。当流水线开始运行时,非敏感作业首先执行,不受其他流水线中并发执行的影响。 但是,极狐GitLab 确保在触发部署(子)流水线之前没有其他部署流水线正在运行。如果其他部署流水线正在运行,极狐GitLab 会等到这些流水线完成后再运行另一个。

# .gitlab-ci.yml (parent pipeline)

build:
  stage: build
  script: echo "Building..."

test:
  stage: test
  script: echo "Testing..."

deploy:
  stage: deploy
  trigger:
    include: deploy.gitlab-ci.yml
    strategy: depend
  resource_group: AWS-production
# deploy.gitlab-ci.yml (child pipeline)

stages:
  - provision
  - deploy

provision:
  stage: provision
  script: echo "Provisioning..."

deployment:
  stage: deploy
  script: echo "Deploying..."
  environment: production

您必须使用 trigger 关键字定义 strategy:depend。这确保了在下游流水线完成之前不会释放锁。

API

查看 API 文档

相关功能

阅读更多,了解如何使用极狐GitLab 进行安全部署

故障排除

避免流水线配置中的死锁

因为 oldest_first 模式强制作业按流水线顺序执行,所以有时它不能很好地与其他 CI 功能配合使用。

例如,当您运行需要与父流水线相同的资源组的子流水线 时,可能会发生死锁。以下是一个错误设置的示例:

# BAD
test:
  stage: test
  trigger:
    include: child-pipeline-requires-production-resource-group.yml
    strategy: depend

deploy:
  stage: deploy
  script: echo
  resource_group: production
  environment: production

在父流水线中,它运行 test 作业,test 作业运行子流水线,并且 strategy:depend 选项使 test 作业等到子流水线已完成。 父流水线在下一阶段运行 deploy 作业,这需要 production 资源组中的资源。 如果进程模式是 oldest_first,它会从最旧的流水线执行作业,这意味着接下来会执行 deploy 作业。

但是,子流水线还需要来自 production 资源组的资源。 因为子流水线比父流水线更新,所以子流水线一直要等到 deploy 作业完成,这是永远不会发生的事情。

在这种情况下,您应该在父流水线配置中指定 resource_group 关键字:

# GOOD
test:
  stage: test
  trigger:
    include: child-pipeline.yml
    strategy: depend
  resource_group: production # Specify the resource group in the parent pipeline

deploy:
  stage: deploy
  script: echo
  resource_group: production
  environment: production

作业阻塞:”Waiting for resource”

有时,作业挂起并显示消息 Waiting for resource: <resource_group>。要解决此问题,首先检查资源组是否正常工作:

  1. 进入作业详情页面。
  2. 选择 查看当前使用资源的作业
  3. 查看作业状态:
    • 如果状态为 runningpending,则该功能正常运行。等到作业完成并释放资源。
    • 如果状态不是 runningpending,则该功能可能无法正常工作。

您还可以从 GraphQL API 获取作业信息。如果您对跨项目/父子流水线使用流水线级并发控制,则应使用 GraphQL API,因为无法从 UI 访问触发器作业。

要从 GraphQL API 获取作业信息:

  1. 进入流水线详情页面。
  2. 选择 作业 选项卡并找到阻塞作业的 ID。
  3. 前往 GraphiQL 资源管理器
  4. 运行以下查询:

     {
       project(fullPath: "<fullpath-to-your-project>") {
         name
         job(id: "gid://gitlab/Ci::Bridge/<job-id>") {
           name
           detailedStatus {
             action {
               path
               buttonTitle
             }
           }
         }
       }
     }
    

    job.detailedStatus.action.path 字段包含使用该资源的作业 ID。

  5. 运行以下查询并根据上述条件检查 job.status 字段。您还可以从 pipeline.path 字段访问流水线页面。

     {
       project(fullPath: "<fullpath-to-your-project>") {
         name
         job(id: "gid://gitlab/Ci::Bridge/<job-id-currently-using-the-resource>") {
           name
           status
           pipeline {
             path
           }
         }
       }
     }