1.4.5.1. 持续集成流水线的治理

目前持续集成流水线已经成为了许多软件项目的标准配置,也是要推进我们所说的大规模 Terraform 模块治理的基础,没有持续集成流水线,我们我们就无法强制所有模块遵循我们确立的各种标准和规范。

市面上有许多非常优秀的持续集成解决方案,考虑到 Terraform Registry 默认从 GitHub 仓库同步 Terraform 模块,以及 GitHub Actions 本身已经是一个非常成熟和被广泛应用的流水线方案,所以本书将以 GitHub Actions 为主。

凭借直觉,我们可以利用各种成熟的 Action 拼接一个简单的流水线,例如:

name: Terraform CI

on:
  pull_request:

jobs:
  terraform:
    name: Terraform Validation and Planning
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Terraform
        uses: hashicorp/setup-terraform@v3

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan for each example
        run: |
          has_error=false

          if [ ! -d "examples" ]; then
            echo "No 'examples' folder found."
            exit 0
          fi

          cd examples

          for d in */; do
            if [ -d "$d" ]; then
              if ls "$d"/*.tf > /dev/null 2>&1; then
                echo "==> Checking $d"
                cd "$d" || { echo "Failed to enter directory $d"; has_error=true; cd ..; continue; }

                terraform init -input=false || has_error=true
                terraform plan -input=false || has_error=true

                cd ..
              else
                echo "No Terraform configuration files found in $d, skipping."
              fi
            fi
          done

          cd ..

          if [ "$has_error" = true ]; then
            echo "At least one 'examples' folder failed."
            exit 1
          fi

          echo "All 'examples' folders passed."
          exit 0

上述工作流在维护单个 Terraform 模块的代码仓库时还可以勉强发挥作用,然而当我们要同时维护数百个模块的代码仓库时,这种方法就会暴露出以下问题:

  • 重复维护:每次需要更新工作流程逻辑时,必须在所有仓库中手动修改,工作量巨大,容易出错。
  • 一致性问题:手动更新可能导致不同仓库之间的工作流程版本不一致,增加了维护难度。
  • 扩展性差:难以快速引入新的功能或最佳实践,因为需要在所有仓库中逐一实施。

试想一下,假如我们决定要在 terraform init 之前添加一条检查,确认所有 Terraform 代码都已经被正确格式化了,我们就需要向数百个代码仓库提交相同的变更,这将是一个非常糟糕的体验。

1.4.5.1.1. 可复用工作流程和复合操作

GitHub Actions 提供了两种机制来实现工作流程的复用和模块化:

1.4.5.1.1.1. 可复用工作流(Reusable Workflows)

可复用工作流允许我们将整个工作流程定义为一个独立的 YAML 文件,并在其他工作流程中通过 uses 关键字引用它。这使得多个仓库可以共享同一个工作流程定义,从而实现集中管理。

优势:

  • 集中管理:所有的工作流程逻辑集中在一个仓库中,便于维护和更新。
  • 减少重复:避免在多个仓库中复制相同的工作流程代码。
  • 版本控制:可以通过 Git 标签或分支来控制工作流程的版本,确保不同项目使用兼容的版本。

使用方法:

  1. 在一个仓库中创建可复用工作流程文件(例如 .github/workflows/terraform.yml),并在 on 字段中添加 workflow_call 触发器。
  2. 在其他仓库的工作流程中,通过 uses 关键字引用该可复用工作流程,例如:
jobs:
  terraform:
    uses: org-name/repo-name/.github/workflows/terraform.yml@v1
    secrets: inherit

这样,所有引用该工作流程的仓库都会自动使用最新的定义,简化了维护工作。

1.4.5.1.1.2. 复合操作(Composite Actions)

复合操作允许我们将多个步骤组合成一个自定义的操作,可以在工作流程的步骤中调用。这对于封装常用的步骤组合非常有用,例如 Terraform 的初始化、格式检查和验证等。

优势:

  • 模块化:将常用的步骤组合成一个操作,便于复用。
  • 简化工作流程:调用复合操作可以使工作流程文件更简洁。
  • 易于维护:更新复合操作的逻辑会自动影响所有引用它的工作流程。

使用方法:

  1. 在仓库中创建复合操作目录(例如 .github/actions/terraform-setup),并在其中创建 action.yml 文件,定义操作的输入和步骤。
  2. 在工作流程中,通过 uses 关键字调用该复合操作,例如:
steps:
  - uses: ./.github/actions/terraform-setup

通过这种方式,我们可以将常用的操作封装成模块,供多个工作流程复用,提高了工作流程的可维护性和一致性。

1.4.5.1.2. 中央操作仓库 (Centralized Actions Repository)

如果我们只是把可复用工作流和复合操作的定义 YAML 文件保存在每一个 Terraform 模块的代码仓库中,那么我们实际上没有任何改善,每一次的更新还是需要同时升级数百个代码仓库。我们可以采用集中式管理的策略,将可复用的工作流程和复合操作集中存放在一个专用的仓库中。这样,所有的模块仓库都可以引用这些集中管理的工作流程,实现统一的 CI/CD 流程。

1.4.5.1.3. 实践案例:集中管理 Terraform 模块的 GitHub Actions 工作流程

在大规模维护 Terraform 模块时,集中管理 GitHub Actions 工作流程可以显著提高效率和一致性。以下是两个采用集中式管理策略的组织案例:

1.4.5.1.3.1. Cloud Posse 的集中式工作流程管理

Cloud Posse 通过 cloudposse/github-actions-workflows 仓库,集中管理其组织内的可复用 GitHub Actions 工作流程。这些工作流程涵盖了从构建、测试到部署的各个阶段,供多个仓库引用,确保了 CI/CD 流程的一致性和可维护性。

此外,Cloud Posse 还提供了 cloudposse/github-actions-workflows-terraform-module 仓库,专门用于管理 Terraform 模块的工作流程。通过在模块仓库中引用这些集中管理的工作流程,Cloud Posse 实现了工作流程的标准化和集中维护。

1.4.5.1.3.2. Azure Verified Modules 的 Scaffold 项目

Azure Verified Modules 提供了 Azure/tfmod-scaffold 项目,作为 Terraform 模块的模板,包含了标准的 GitHub Actions 工作流程、Makefile 和脚本。开发者可以基于该模板快速创建新的模块仓库,确保了项目结构和工作流程的一致性。

results matching ""

    No results matching ""