使用 GitLab 的条件 CI/CD 流水线优化 DevSecOps 工作流程
CI/CD 流水线可以很简单,也可以很复杂,但让它们高效的是定义它们何时以及如何运行的规则。通过使用规则,您可以创建更智能的 CI/CD 流水线,从而提高团队生产力,并使组织能够更快地迭代。在本指南中,您将了解不同类型的 CI/CD 流水线、它们的用例,以及如何通过利用规则来创建高效的 DevSecOps 工作流。
理解 GitLab 流水线
流水线是 GitLab 的 持续集成 和 持续交付/持续部署 框架中的顶级组件。它包含 作业,作业是待执行的任务列表。作业被组织到 阶段 中,阶段定义了作业的运行顺序。
流水线可以具有 基本配置,其中作业在每个阶段并发运行。流水线也可以具有复杂的设置,例如 父子流水线、合并队列、多项目流水线,或者更高级的 有向无环图 (DAG) 流水线。DAG 流水线是更高级的设置,用于处理复杂的依赖关系。
下图是显示作业依赖关系的 gitlab-runner 流水线 的表示。

下图描绘了一个 DAG 流水线。

GitLab 流水线的复杂性通常由具体的用例决定。例如,一个用例可能需要测试应用程序并将其打包成容器;在这种情况下,GitLab 流水线甚至可以用于将容器部署到 Kubernetes 等编排器或容器注册表中。另一个用例可能涉及构建针对具有不同依赖关系的各种平台的应用程序,这时我们的 DAG 流水线就大放异彩。
探索 CI/CD 规则
在 GitLab 中,CI/CD 规则是管理流水线中作业流程的关键。GitLab CI/CD 的强大功能之一是控制 CI/CD 作业何时运行的能力,这可以取决于上下文、所做的更改、工作流规则、CI/CD 变量的值或自定义条件。除了使用 rules,您还可以使用以下关键字来控制 CI/CD 流水线的流程:
needs:建立作业之间的关系,通常在 DAG 流水线中使用only:定义何时应运行作业except:定义何时不应运行作业workflow:控制何时创建流水线
注意: only 和 except 不应与 rules 一起使用,因为这可能导致意外行为。您将在后续章节中了解更多关于有效使用 rules 的信息。
规则功能的简介
rules 决定作业是否在流水线中运行以及何时运行。如果定义了多个 rules,它们将按顺序进行评估,直到找到匹配的 rule,届时将根据指定的配置执行作业。
rules 可以使用 if、changes、exists、allow_failure、needs 和 variables 关键字来定义。
rules:if
if 关键字会评估是否应将作业添加到流水线。评估基于作业或流水线作用域中定义的 CI/CD 变量 和 预定义 CI/CD 变量 的值。
job:
script:
- echo $(date)
rules:
- if: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == $CI_DEFAULT_BRANCH
在上面的 CI/CD 脚本中,作业使用 echo 命令打印当前日期和时间。仅当合并请求的源分支 (CI_MERGE_REQUEST_SOURCE_BRANCH_NAME) 与项目在 合并请求流水线 中的默认分支 (CI_DEFAULT_BRANCH) 相同时,才会执行该作业。您可以使用 == 和 != 运算符进行比较,而 =~ 和 !~ 运算符允许您将变量与正则表达式进行比较。您可以使用 && (AND) 和 || (OR) 运算符以及括号组合多个表达式。
rules:changes
使用 changes 关键字,您可以监视特定文件或文件夹的更改,以执行作业。GitLab 使用 git 的 diffstat 的输出来确定已更改的文件,并将其与为 changes 规则提供的文件数组进行匹配。一个用例是基础设施项目,它存储了不同基础设施组件的资源文件,并且您希望在对 terraform 文件进行更改时执行 terraform plan。
job:
script:
- terraform plan
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- terraform/**/*.tf
在此示例中,仅当 terraform 文件夹及其子目录中的扩展名为 .tf 的文件发生更改时,才会执行 terraform plan。附加规则可确保该作业在 合并请求流水线 中执行。
如下所示,changes 规则可以查找使用 paths 对特定文件的更改。
job:
script:
- terraform plan
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
paths:
- terraform/main.tf
还可以将源引用(分支、标签、提交)中的文件更改与 Git 存储库中的其他引用进行比较。CI/CD 作业仅在源引用与 rules:changes:compare_to 中定义的指定引用值不同时执行。此值可以是 Git 提交 SHA、标签或分支名称。以下示例将源引用与当前生产分支 refs/head/production 进行比较。
job:
script:
- terraform plan
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
paths:
- terraform/main.tf
compare_to: "refs/head/production"
rules:exists
与 changes 类似,您可以使用 rules:exists 规则仅在特定文件存在时才执行 CI/CD 作业。例如,您可以运行一个检查 Gemfile.lock 文件是否存在。以下示例使用 bundler-audit 项目 来审计 Ruby 项目中是否存在易受攻击的 gem 版本或不安全的 gem 源。
job:
script:
- bundle-audit check --format json --output bundle-audit.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
exists:
- Gemfile.lock
rules:allow_failure
在某些情况下,作业的失败不应影响流水线中的后续作业和阶段。这在需要将非阻塞任务作为项目的一部分但又不影响项目的用例中可能很有用。可以将 rules:allow_failure 规则设置为 true 或 false。当未指定规则时,它默认为 false。
job:
script:
- bundle-audit check --format json --output bundle-audit.json
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED == "false"
changes:
exists:
- Gemfile.lock
allow_failure: true
在此示例中,仅当合并请求事件触发流水线且目标分支不受保护时,作业才可能失败。
rules:needs
rules:needs 默认禁用,它在 GitLab 16 中引入,并且可以使用 introduce_rules_with_needs 功能标志 来启用。needs 规则用于在不等待阶段中其他作业完成的情况下按顺序执行作业。当与 rules 一起使用时,如果满足指定的条件,它将覆盖作业的 needs 规范。
stages:
- build
- qa
- deploy
build-dev:
stage: build
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
script: echo "Building dev version..."
build-prod:
stage: build
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script: echo "Building production version..."
qa-checks:
stage: qa
script:
- echo "Running QA checks before publishing to Production...."
deploy:
stage: deploy
needs: ["build-dev"]
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
needs: ["build-prod", "qa-checks"]
- when: on_success # Run the job in other cases
script: echo "Deploying application."
在上面的示例中,deploy 作业在运行之前有一个 build-dev 作业作为依赖项;然而,当提交分支是项目的默认分支时,其依赖项将变为 build-prod 和 qa-checks。这允许根据上下文实现额外的检查。
rules:variables
在某些情况下,您可能只需要在特定条件下才需要某些变量,或者它们的值可能会根据内容而变化。rules:variables 规则允许您在满足特定条件时定义变量,从而实现更动态的 CI/CD 执行工作流。
job:
variables:
DEPLOY_VERSION: "dev"
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
variables:
DEPLOY_VERSION: "stable"
script:
- echo "Deploying $DEPLOY_VERSION version"
workflow:rules
到目前为止,我们已经了解了如何使用 rules 关键字来控制作业在流水线中运行的时间。有时,您想控制整个流水线的行为:这时 workflow:rules 提供了一个强大的选项。workflow:rules 在作业之前进行评估,并优先于作业规则。例如,如果一个作业的规则允许它在特定分支上运行,但是 workflow:rules 设置了在该分支上运行的作业的 when: never,那么这些作业将不会运行。
前面各节中提到的 rules 的所有功能也适用于 workflow:rules。
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: $CI_PIPELINE_SOURCE == "push"
when: never
- when: always
在上面的示例中,CI/CD 流水线会运行,除非由计划或推送事件触发。
GitLab CI/CD 规则的实际应用
在上一个部分,我们探讨了使用 GitLab CI/CD 的 rules 功能的各种方法。在本节中,让我们探索一些实际用例。
开发者体验
DevSecOps 平台的优势之一是它使开发人员能够专注于他们最擅长的事情:编写代码,同时最大限度地减少运维任务。公司的 DevOps 或平台团队可以为开发生命周期的各个阶段创建 CI/CD 模板,并使用规则根据其技术栈添加 CI/CD 作业来处理特定任务。开发人员只需包含默认的 CI/CD 脚本,流水线就会根据检测到的文件、使用的引用或定义的变量自动创建,从而提高生产力。
安全和质量保证
CI/CD 流水线的一个主要功能是在将错误或漏洞部署到生产环境之前捕获它们。通过使用 CI/CD 规则,安全和质量保证团队可以根据特定触发器动态运行额外的检查。例如,当检测到未经批准的文件扩展名时,可以添加恶意软件扫描;或者当代码库发生重大更改时,会自动添加更高级的性能测试。借助 GitLab 内置的安全功能,只需几行代码即可将安全集成到您的流水线中。
include:
# Static
- template: Jobs/Container-Scanning.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Secret-Detection.gitlab-ci.yml
- template: Jobs/SAST-IaC.gitlab-ci.yml
- template: Jobs/Code-Quality.gitlab-ci.yml
- template: Security/Coverage-Fuzzing.gitlab-ci.yml
# Dynamic
- template: Security/DAST.latest.gitlab-ci.yml
- template: Security/BAS.latest.gitlab-ci.yml
- template: Security/DAST-API.latest.gitlab-ci.yml
- template: API-Fuzzing.latest.gitlab-ci.yml
自动化
GitLab CI/CD 规则的强大之处在于其(几乎)无限的自动化 CI/CD 流水线的可能性。GitLab AutoDevOps 就是一个例子。它使用一套有约束力的最佳实践 GitLab CI/CD 模板 和规则来检测使用的技术栈。AutoDevOps 会创建相关的作业,从推送开始,将您的应用程序一直交付到生产环境。您可以查看 AutoDevOps 模板 以了解它如何利用 CI/CD 规则来提高效率。GitLab Duo 提供由 AI 驱动的工作流,有助于简化任务并更快地构建安全软件。
CI/CD 组件利用
随着增长而来的是多次迭代和最佳实践的建立。在构建 CI/CD 流水线时,您的 DevOps 团队可能会创建多个 CI/CD 脚本,并使用 include 关键字在流水线之间重复使用它们。通过 GitLab 16,GitLab 推出了 CI/CD 组件,这是一个实验性功能,允许您的团队创建可重用的 CI/CD 组件并将其发布为目录,以便快速构建更智能的 CI/CD 流水线。您可以了解更多关于 使用 CI/CD 组件 和 组件目录方向 的信息。
总结
在本指南中,我们探讨了 GitLab CI/CD 流水线的不同类型,从理解其基本结构到增强 DevSecOps 工作流的高级配置。GitLab CI/CD 使您能够利用规则来运行更智能的流水线。它与 GitLab Duo 的 AI 驱动的工作流一起,帮助您快速构建安全软件。我们鼓励您利用这些强大的功能来优化您的 DevSecOps 计划。
这是一篇 GitLab 的赞助文章。GitLab 是一个全面的基于 Web 的 DevSecOps 平台,提供 Git 存储库管理、问题跟踪、持续集成和部署流水线功能。它提供开源和专有版本,旨在覆盖整个 DevOps 生命周期,是团队寻求单一平台来管理代码和操作数据的热门选择。