CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Terraform 基础设施即代码/课时/CI 中的 Terraform
RawBlame
课时目录12 节

Terraform 基础设施即代码

  1. 01Terraform 是什么
  2. 02HCL 语法
  3. 03init 与 Provider
  4. 04plan 与 apply
  5. 05State 管理
  6. 06变量与输出
  7. 07Module 复用
  8. 08AWS 资源示例
  9. 09Terraform 与 K8s
  10. 10CI 中的 Terraform
  11. 11Terraform vs Helm
  12. 12综合练习

CI 中的 Terraform

plan on PR、apply on merge;与 github-actions 衔接。

30 分钟

CI 中的 Terraform

这一课你将能做到

  1. 在流水线里串起 fmt、validate、init、plan、apply 的标准作业链
  2. 用工作区(workspace)和环境变量在 CI 中区分 dev/prod,并理解审批门怎么设
  3. 配置定期漂移检测,看懂 plan 非零退出码在自动化里的含义

为什么要学

Terraform 最终不会只跑在你自己电脑上:多人协作时,每个人的本机环境、版本、凭证都不同,把 apply 收进 CI 才有统一的执行环境、完整的日志和谁在什么时候改了什么的审计记录。成熟团队的标配是:合并前 PR 自动跑 plan 贴在评论里,合并后人工点按钮 apply,每天凌晨再跑一次 plan 做漂移检测。这一课给你可以直接落地的流水线骨架,GitHub Actions 和 GitLab CI 各来一份。

人话:本机 apply 像自己在家炒菜,咸淡随缘、没人看见;CI 流水线像中央厨房——摄像头全程录像、上菜前有人尝咸淡(plan 审批)、每天还检查各门店有没有偷改配方(漂移检测)。

先建立图像

标准流水线阶段:

代码推送 / Pull Request
        │
        ▼
fmt -check ──► validate ──► init ──► plan(产出计划,人工评审)
                                         │
                                   合并 + 审批门
                                         ▼
                                   apply(执行计划文件)
                                         │
                                   定时 cron:plan -detailed-exitcode(漂移检测)

退出码约定(自动化全靠它):

命令退出码含义
plan 普通0 成功 / 非 0 失败—
plan -detailed-exitcode0 无差异1 出错
plan -detailed-exitcode2 有差异漂移检测就看它

跟着做

步骤 1:本地先跑通质量三连

在任一 Terraform 项目目录:

terraform fmt -check -recursive
terraform init -backend=false
terraform validate
  • fmt -check 只检查不改文件,格式不规范就返回非零(本机想自动修就去掉 -check)
  • init -backend=false 只装 provider 不碰后端,CI 校验阶段常用
  • validate 查语法和引用错误,但不检查凭证和云上状态

建议把这三行配成提交前钩子或 IDE 保存动作,问题不过夜。

步骤 2:GitHub Actions 骨架

在仓库建 .github/workflows/terraform.yml:

name: terraform

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read
  pull-requests: write
  id-token: write   # 用 OIDC 换取云凭证,不存长期 AK/SK

jobs:
  terraform:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: infra

    steps:
      - uses: actions/checkout@v4

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.7.*"

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gh-actions-tf
          aws-region: ap-northeast-1

      - name: fmt
        run: terraform fmt -check -recursive

      - name: validate
        run: |
          terraform init -backend=false
          terraform validate

      - name: plan
        id: plan
        run: |
          terraform init
          terraform plan -out=tfplan -var-file=envs/dev.tfvars

      - name: apply(仅 main 分支)
        if: github.ref == 'refs/heads/main'
        run: terraform apply tfplan

重点不是逐行背,而是理解三处设计:凭证走 OIDC 角色(GitHub 与 AWS 信任关系,无需长期密钥);plan 产物 tfplan 在同一 job 的步骤间传递;apply 限定 main 分支并由分支保护/评审门把关。

步骤 3:GitLab CI 骨架

.gitlab-ci.yml:

stages: [check, plan, apply]

image: hashicorp/terraform:1.7

variables:
  TF_ROOT: infra
  TF_VARS: envs/dev.tfvars

before_script:
  - cd ${TF_ROOT}

fmt:
  stage: check
  script: terraform fmt -check -recursive

validate:
  stage: check
  script:
    - terraform init -backend=false
    - terraform validate

plan:
  stage: plan
  script:
    - terraform init
    - terraform plan -out=tfplan -var-file=${TF_VARS}
  artifacts:
    paths: [infra/tfplan]

apply:
  stage: apply
  script: terraform apply tfplan
  when: manual   # 人工点按钮执行:生产环境的审批门
  only: [main]

when: manual 就是 GitLab 里的人工审批;计划文件用 artifacts 从 plan 阶段传给 apply 阶段。GitHub Actions 跨 job 传文件则用 actions/upload-artifact。

步骤 4:用工作区或变量切环境

方式一:同一套配置用 workspace(适合差异小的临时环境):

terraform workspace new prod
terraform workspace select prod
terraform plan -var-file=envs/prod.tfvars

方式二(更推荐用于强隔离):CI 变量 TF_VARS=envs/prod.tfvars 指向独立 tfvars,state key 也通过不同前缀/目录隔离。生产流水线单独一条,审批人、执行窗口都与开发环境分开。

给变量传 CI 密钥:

env:
  TF_VAR_db_password: ${SECRET_DB_PASSWORD}

值来自流水线加密变量/Secret,不进任何文件。

步骤 5:漂移检测

新增一个定时任务,只跑 plan 不 apply:

drift:
  stage: plan
  script:
    - terraform init
    - terraform plan -detailed-exitcode -var-file=envs/prod.tfvars
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"

退出码为 2 时说明云上状态和代码不一致:可能是有人控制台手改、云厂商侧自动扩缩、或上次 apply 部分失败。任务应发告警(IM/邮件),由人判断是把现实改回代码(重新 apply),还是把现实吸收进代码。

步骤 6:把 plan 贴到 PR(协作关键)

让评审者不下载日志就能看到计划:GitHub 可用 hashicorp/setup-terraform 的输出配合评论动作;GitLab 用 terraform show tfplan 输出到 job 日志或 MR comment。团队约定:PR 没有 plan 截图/评论不批,这是把「看计划」变成肌肉记忆的流程手段。

讲清楚要点

  1. CI 里的 Terraform 版本也要钉:setup-terraform 指定版本或用 Docker 镜像 tag,避免 runner 升级带来意外。
  2. 凭证优先级:OIDC 联邦角色 > 短期 token > CI 加密变量里的 AK/SK;最后一种要定期轮换并最小权限。
  3. apply 必须有审批门:PR 评审 + main 分支保护 + manual job,三道里至少占两道。
  4. 计划文件要防篡改:严格做法是 plan 与 apply 在同一可信流水线、对 tfplan 做哈希校验;超时未执行应重新 plan。
  5. 不要在 CI 里频繁 -target:流水线里出现 target 通常意味着流程出了问题,应修正整体配置。

你可能会懵的地方

  • plan 和 apply 能放两个 job 吗?计划文件怎么传? 能,也是推荐做法(plan 可被多人看、apply 受门禁控)。用 artifacts 上传 tfplan,apply job 下载后执行;文件包含敏感信息,artifact 保留时间要设短。

  • OIDC 不支持 / 还没配,怎么办? 暂时用 CI 平台的加密变量存 AK/SK,配最小权限 + 轮换计划,并尽快迁移到 OIDC,这是目前云上 CI 的最佳实践。

  • workspace 为什么不被推荐当多环境主方案? 它只在 state 路径上加前缀,变量、权限、执行窗口仍是同一套,容易误把小规格 apply 到生产;独立目录/流水线 + 独立 state key 隔离更彻底。

  • 漂移检测天天报差异,但没人处理怎么办? 告警疲劳等于没有检测。先收敛存量差异(吸收或修复),再把告警接入真正有人盯的频道,并区分「预期内的云侧变化」和「异常手改」。

  • plan 在 PR 上跑会写 state 吗? plan 不写 state,但远程后端会短暂加读锁;并发量极大时注意 DynamoDB 读容量,一般不是问题。

错法对照

错法问题正解
长期 AK/SK 明文存 CI 变量还不轮换泄露即全账号沦陷OIDC 角色或定期轮换最小密钥
apply job 无 manual、无分支保护合并即改生产加审批门,限制触发条件
fmt/validate 跳过只跑 apply低级错误进生产质量三连设为必过门禁
漂移检测发现差异自动 apply把野改动「洗白」只告警,人工判断后处理
一条流水线混用所有环境变量误操作面大每环境独立 pipeline 与 tfvars

卡点急救

  1. CI 中 init 拉不到 provider:runner 出口网络受限。配置缓存目录、网络镜像,或允许访问 registry 域名。
  2. apply 报 state lock 且任务已失败:确认无其他流水线在跑,terraform force-unlock;并排查为什么任务崩溃没释放锁(极少见,多为进程被强杀)。
  3. OIDC 角色 Assume 失败:核对信任策略的 aud/sub 条件(仓库、分支、组织),用 STS 解码错误信息;先在手动操作中验证角色可用。

面试常问

  • 描述一套生产级 Terraform CI/CD 流程。 PR 触发 fmt、validate、init、plan,计划贴在 PR 中供评审;合并主分支后由人工门禁执行 apply(使用同一份 plan 文件);凭证用 OIDC 联邦短期角色;定时任务跑 plan -detailed-exitcode 做漂移检测并告警。

  • 什么是漂移?怎么检测和处理? 云上真实状态偏离代码声明,多由控制台手改或外部系统自动变更引起。定期 plan(退出码 2)发现,人工评估后:若改动合理则更新代码,若违规则重新 apply 收敛,禁止盲目自动修复。

  • CI 中如何安全传递云凭证? 首选 OIDC 联邦身份(GitHub/GitLab → 云角色),每次任务拿短期令牌;退而求其次用加密 CI 变量配合最小权限和轮换;禁止写入 .tf 或镜像。

自测三问

  1. fmt -check、validate、plan 三者各拦得住什么类型的问题?
  2. plan 与 apply 拆成两个 job 时,怎么保证执行的是被评审的那份计划?
  3. 漂移检测退出码 2 代表什么?收到告警你的排查顺序是什么?

小结一句话

生产级 Terraform 流水线 = 质量三连 + PR plan 评审 + 门禁 apply + 定时漂移检测,凭证一律 OIDC 短期角色,apply 永远留人工开关。

延伸

  • Automate Terraform with GitHub Actions 官方教程
  • Running Terraform in Automation 自动化指南
  • Plan 退出码 detailed-exitcode
  • 下一课:Terraform vs Helm——两个工具的职责边界。
加载本节练习…
← 上一课Terraform 与 K8s下一课 →Terraform vs Helm