Three gear icons in different colors to represent optimization of DevSecOps workflows

使用 GitLab 的条件式 CI/CD 管道优化 DevSecOps 工作流

作者头像GitLab阅读 9 分钟

CI/CD 管道可以很简单也可以很复杂,但使它们高效的关键在于定义何时以及如何运行的规则。通过使用规则,您可以创建更智能的 CI/CD 管道,从而提高团队生产力并使组织能够更快地迭代。在本指南中,您将了解不同类型的 CI/CD 管道、它们的用例以及如何通过利用规则创建高效的 DevSecOps 工作流。

了解 GitLab 管道

管道是 GitLab 的 持续集成持续交付/持续部署 框架中的顶级组件。它由 作业 组成,作业是要执行的任务列表。作业被组织成 阶段,阶段定义作业运行的顺序。

管道可以具有 基本配置,其中作业在每个阶段并发运行。管道也可以具有复杂的设置,例如 父子管道合并列车多项目管道 或更高级的 有向无环图 (DAG) 管道。DAG 管道是用于复杂依赖关系的更高级设置。

下图是 gitlab-runner 管道 的表示,显示了作业依赖关系。

Depiction of a gitlab-runner pipeline showing job dependencies used in CI/CD frameworks

下图描绘了 DAG 管道。

Depiction of a Directed Acyclic Graph pipeline with numerous crisscross colored lines connecting two horizontal ends.

GitLab 管道的复杂性通常由特定用例决定。例如,一个用例可能需要测试应用程序并将其打包到容器中;在这种情况下,GitLab 管道甚至可以用于将容器部署到 Kubernetes 或容器注册表等编排器。另一个用例可能涉及构建针对不同平台且具有不同依赖项的应用程序,这就是我们的 DAG 管道大放异彩的地方。

探索 CI/CD 规则

在 GitLab 中,CI/CD 规则是管理管道中作业流程的关键。GitLab CI/CD 的强大功能之一是能够控制 CI/CD 作业何时运行,这可能取决于上下文、所做的更改、工作流规则、CI/CD 变量的值或自定义条件。除了使用rules 之外,您还可以使用以下关键字控制 CI/CD 管道的流程

  • needs:建立作业之间的关系,通常用于 DAG 管道
  • only:定义作业何时应运行
  • except:定义作业何时不应运行
  • workflow:控制何时创建管道

注意:onlyexcept 不应与 rules 一起使用,因为这可能导致意外行为。您将在后续部分中详细了解如何有效地使用rules

规则功能简介

rules 确定作业在管道中是否以及何时运行。如果定义了多个rules,则它们将依次评估,直到找到匹配的rule,此时,作业将根据指定的配置执行。

rules 可以使用关键字 ifchangesexistsallow_failureneedsvariables 定义。

rules:if

if 关键字评估是否应将作业添加到管道中。评估是根据作业或管道范围内定义的 CI/CD 变量预定义的 CI/CD 变量 的值进行的。

yaml
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 计划。

yaml
job:
  script:
    - terraform plan

  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        - terraform/**/*.tf

在此示例中,仅当在terraform 文件夹及其子目录中更改了扩展名为.tf 的文件时,才会执行terraform 计划。另一条规则确保为 合并请求管道 执行该作业。

如下所示,changes 规则可以使用paths 搜索特定文件中的更改

yaml
job:
  script:
    - terraform plan

  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        paths:
          - terraform/main.tf

还可以将源引用(分支、标签、提交)中的文件更改与 Git 存储库中的其他引用进行比较。仅当源引用与 rules:changes:compare_to 中定义的指定引用值不同时,CI/CD 作业才会执行。此值可以是 Git 提交 SHA、标签或分支名称。以下示例将源引用与当前生产分支refs/head/production 进行比较。

yaml
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 类似,您可以仅在特定文件存在时执行 CI/CD 作业,方法是使用 rules:exists 规则。例如,您可以运行一个作业来检查是否存在Gemfile.lock 文件。以下示例使用 bundler-audit 项目 审核 Ruby 项目中宝石的漏洞版本或不安全的宝石源。

yaml
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 规则设置为truefalse。当未指定规则时,它默认为false

yaml
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:needsGitLab 16 中引入,默认情况下处于禁用状态,可以使用introduce_rules_with_needs 功能标志 启用。needs 规则用于按顺序执行作业,而无需等待同一阶段中的其他作业完成。当与rules 一起使用时,它会在满足指定条件时覆盖作业的needs 规范。

yaml
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-prodqa-checks。这可以允许根据上下文实现额外的检查。

rules:variables

在某些情况下,您可能只需要在特定条件下使用某些变量,或者它们的值可能会根据内容而改变。rules:variables 规则允许您在满足特定条件时定义变量,从而能够创建更动态的 CI/CD 执行工作流。

yaml
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

yaml
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 脚本,并且会根据检测到的文件、使用的 ref 或定义的变量自动创建管道,从而提高生产力。

安全和质量保证

CI/CD 管道的核心功能之一是在代码部署到生产环境之前捕获错误或漏洞。使用 CI/CD 规则,安全和质量保证团队可以根据特定触发器动态运行额外的检查。例如,当检测到未经批准的文件扩展名时,可以添加恶意软件扫描;或者当对代码库进行重大更改时,可以自动添加更高级的性能测试。借助 GitLab 内置的安全功能,只需几行代码即可在管道中集成安全措施。

yaml
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 生命周期,使其成为寻求单一平台来管理代码和运营数据的团队的热门选择。

关注 MDN

订阅 MDN 电子邮件,不错过最新的 Web 开发趋势、技巧和最佳实践。