资源群组
- Tier: 基础版,专业版,旗舰版
- Offering: JihuLab.com, 私有化部署
默认情况下,极狐GitLab CI/CD 中的流水线是并发运行的。并发性是改善合并请求反馈循环的重要因素,但在某些情况下,您可能希望限制部署作业的并发性,使其逐个运行。使用资源组来战略性地控制作业的并发性,以安全地优化您的持续部署工作流程。
添加资源组
您只能为一个资源组添加一个资源。
假设您有以下流水线配置(存储库中的 .gitlab-ci.yml 文件):
yaml1build: 2 stage: build 3 script: echo "Your build script" 4 5deploy: 6 stage: deploy 7 script: echo "Your deployment script" 8 environment: production
每次您推送一个新的提交到分支时,它都会运行一个新的流水线,该流水线包含两个作业 build 和 deploy。但如果在短时间内推送多个提交,多个流水线会同时启动运行,例如:
- 第一个流水线运行作业 build -> deploy
- 第二个流水线运行作业 build -> deploy
在这种情况下,来自不同流水线的 deploy 作业可能会同时运行到 production 环境。对同一基础设施运行多个部署脚本可能会损坏/混淆实例,并在最坏情况下使其处于损坏状态。
为了确保 deploy 作业一次只运行一个,您可以为并发敏感作业指定 resource_group 关键字:
yamldeploy: # ... resource_group: production
通过此配置,确保了部署的安全性,同时您仍然可以并发运行 build 作业,以最大化流水线效率。
前提条件
- 基础的 极狐GitLab CI/CD 流水线 知识
- 基础的 极狐GitLab 环境和部署 知识
- 至少具有项目的开发者角色以配置 CI/CD 流水线。
处理模式
您可以选择一种处理模式来战略性地控制作业并发性,以满足您的部署偏好。支持以下模式:
-
Unordered: 这是限制运行作业并发性的默认处理模式。当您不关心作业执行顺序时,这是最简单的选项。它会在作业准备好运行时开始处理。
-
Oldest first: 此处理模式限制作业并发性。当资源空闲时,它会从即将到来的作业列表(created、scheduled 或 waiting_for_resource 状态)中选择第一个作业,该列表按流水线 ID 升序排序。
当您希望确保作业从最早的流水线执行时,此模式效率较高。与 unordered 模式相比,在流水线效率方面不如前者,但对于连续部署来说更安全。
-
Newest first: 此处理模式限制作业并发性。当资源空闲时,它会从即将到来的作业列表(created、scheduled 或 waiting_for_resource 状态)中选择第一个作业,该列表按流水线 ID 降序排序。
当您希望确保作业从最新的流水线执行并通过 防止过时的部署作业 功能来防止所有旧的部署作业时,此模式效率较高。这是流水线效率方面最有效的选项,但您必须确保每个部署作业是幂等的。
更改处理模式
要更改资源组的处理模式,您必须使用 API 并发送请求以 编辑现有资源组,指定 process_mode:
- unordered
- oldest_first
- newest_first
处理模式之间差异的示例
考虑以下 .gitlab-ci.yml,我们有两个作业 build 和 deploy,每个作业在其自己的阶段运行,并且 deploy 作业设置了资源组为 production:
yaml1build: 2 stage: build 3 script: echo "Your build script" 4 5deploy: 6 stage: deploy 7 script: echo "Your deployment script" 8 environment: production 9 resource_group: production
如果在短时间内向项目推送三个提交,这意味着三个流水线几乎同时运行:
- 第一个流水线运行作业 build -> deploy。我们称这个部署作业为 deploy-1。
- 第二个流水线运行作业 build -> deploy。我们称这个部署作业为 deploy-2。
- 第三个流水线运行作业 build -> deploy。我们称这个部署作业为 deploy-3。
根据资源组的处理模式:
- 如果处理模式设置为 unordered:
- deploy-1、deploy-2 和 deploy-3 不会同时运行。
- 作业执行顺序没有保证,例如,deploy-1 可以在 deploy-3 之前或之后运行。
- 如果处理模式是 oldest_first:
- deploy-1、deploy-2 和 deploy-3 不会同时运行。
- deploy-1 首先运行,deploy-2 第二个运行,deploy-3 最后运行。
- 如果处理模式是 newest_first:
- deploy-1、deploy-2 和 deploy-3 不会同时运行。
- deploy-3 首先运行,deploy-2 第二个运行,deploy-1 最后运行。
使用跨项目/父子流水线进行流水线级别的并发控制
您可以为对并发执行敏感的下游流水线定义 resource_group。trigger 关键字 可以触发下游流水线,并且 resource_group 关键字 可以与之共存。resource_group 在控制部署流水线的并发性方面是有效的,而其他作业可以继续并发运行。
以下示例在项目中有两个流水线配置。当流水线开始运行时,非敏感作业首先执行,并且不受其他流水线的并发执行影响。然而,极狐GitLab 确保在触发部署(子)流水线之前没有其他部署流水线正在运行。如果其他部署流水线正在运行,极狐GitLab 会等待这些流水线完成后再运行另一个。
yaml1# .gitlab-ci.yml (parent pipeline) 2 3build: 4 stage: build 5 script: echo "Building..." 6 7test: 8 stage: test 9 script: echo "Testing..." 10 11deploy: 12 stage: deploy 13 trigger: 14 include: deploy.gitlab-ci.yml 15 strategy: depend 16 resource_group: AWS-production
yaml1# deploy.gitlab-ci.yml (child pipeline) 2 3stages: 4 - provision 5 - deploy 6 7provision: 8 stage: provision 9 script: echo "Provisioning..." 10 11deployment: 12 stage: deploy 13 script: echo "Deploying..." 14 environment: production
您必须定义 strategy: depend 与 trigger 关键字。这确保在下游流水线完成之前锁定不会释放。
相关主题
故障排除
避免流水线配置中的死锁
由于 oldest_first 处理模式 强制按流水线顺序执行作业,因此有一种情况它与其他 CI 功能不兼容。
例如,当您运行需要与父流水线相同资源组的 子流水线 时,可能会发生死锁。以下是一个 不良 设置示例:
yaml1# BAD 2test: 3 stage: test 4 trigger: 5 include: child-pipeline-requires-production-resource-group.yml 6 strategy: depend 7 8deploy: 9 stage: deploy 10 script: echo 11 resource_group: production 12 environment: production
在父流水线中,它运行 test 作业,随后运行子流水线,而 strategy: depend 选项 使 test 作业等待子流水线完成。父流水线在下一个阶段运行 deploy 作业,该作业需要来自 production 资源组的资源。如果处理模式是 oldest_first,它会从最旧的流水线执行作业,意味着 deploy 作业是下一个执行的。
然而,子流水线也需要来自 production 资源组的资源。因为子流水线比父流水线更新,子流水线等待 deploy 作业完成,而这永远不会发生。
在这种情况下,您应该在父流水线配置中指定 resource_group 关键字:
yaml1# GOOD 2test: 3 stage: test 4 trigger: 5 include: child-pipeline.yml 6 strategy: depend 7 resource_group: production # 在父流水线中指定资源组 8 9deploy: 10 stage: deploy 11 script: echo 12 resource_group: production 13 environment: production
作业卡在“等待资源”
有时,作业会挂起并显示消息 Waiting for resource: <resource_group>。要解决此问题,首先检查资源组是否正常工作:
-
转到作业详情页面。
-
如果资源已分配给作业,请选择 查看当前使用资源的作业 并检查作业状态。
- 如果状态是 running 或 pending,该功能正常工作。等待作业完成并释放资源。
- 如果状态是 created 并且 处理模式 是 Oldest first 或 Newest first,该功能正常工作。访问作业的流水线页面,并检查阻止执行的上游阶段或作业。
- 如果不符合上述条件,该功能可能无法正常工作。向极狐GitLab 报告问题。
-
如果 查看当前使用资源的作业 不可用,则资源未分配给作业。相反,检查资源的即将到来的作业。
- 使用 REST API 获取资源的即将到来的作业。
- 验证资源组的 处理模式 是 Oldest first。
- 找到即将到来的作业列表中的第一个作业,并使用 GraphQL 获取作业详情。
- 如果第一个作业的流水线是较旧的流水线,请尝试取消流水线或作业本身。
- 可选。如果下一个即将到来的作业仍在不应运行的较旧流水线中,请重复此过程。
- 如果问题仍然存在,向极狐GitLab 报告问题。
复杂或繁忙流水线中的竞争条件
如果您无法通过上述解决方案解决问题,您可能遇到了已知的竞争条件问题。竞争条件发生在复杂或繁忙的流水线中。例如,如果您有:
- 包含多个子流水线的流水线。
- 单个项目中同时运行多个流水线。
作为临时解决方案,您可以:
-
启动一个新的流水线。
-
重新运行一个已完成的作业,该作业与卡住的作业具有相同的资源组。
例如,如果您有一个 setup_job 和一个 deploy_job,它们具有相同的资源组,setup_job 可能会完成,而 deploy_job 在“等待资源”时卡住。重新运行 setup_job 以重新启动整个过程,并允许 deploy_job 完成。
通过 GraphQL 获取作业详情
您可以从 GraphQL API 获取作业信息。如果您使用 跨项目/父子流水线的流水线级别并发控制,您应该使用 GraphQL API,因为触发作业无法从 UI 访问。
要从 GraphQL API 获取作业信息:
-
转到流水线详情页面。
-
选择 作业 标签并找到卡住作业的 ID。
-
转到 交互式 GraphQL 浏览器。
-
运行以下查询:
graphql1{ 2 project(fullPath: "<fullpath-to-your-project>") { 3 name 4 job(id: "gid://gitlab/Ci::Build/<job-id>") { 5 name 6 status 7 detailedStatus { 8 action { 9 path 10 buttonTitle 11 } 12 } 13 } 14 } 15}
job.detailedStatus.action.path 字段包含使用资源的作业 ID。
-
运行以下查询并根据上述标准检查 job.status 字段。您还可以从 pipeline.path 字段访问流水线页面。
graphql1{ 2 project(fullPath: "<fullpath-to-your-project>") { 3 name 4 job(id: "gid://gitlab/Ci::Build/<job-id-currently-using-the-resource>") { 5 name 6 status 7 pipeline { 8 path 9 } 10 } 11 } 12}