为什么 GitFlow 在基础设施上失败
Source: Dev.to
TL;DR
在 Terraform 中使用 GitFlow(长期特性或环境分支)往往会导致 状态漂移 和脆弱的流水线。与应用代码不同,基础设施即代码(IaC)还有第三维——状态——它无法通过 git merge 合并。
制胜策略: 使用 基于主干的开发(Trunk‑Based Development)。把 main 当作唯一的真相来源。通过注入环境特定的变量(.tfvars),在环境之间(Dev → Stage → Prod)提升 相同的 代码提交,而不是在环境分支之间合并代码。
核心问题:“第三维”
在标准的应用开发中,你管理两个主要维度:
- 代码: Git 中的逻辑。
- 构建: 在服务器上运行的产物。
如果代码在 Git 中可以工作,通常构建也能正常运行。
在 Terraform 中还有第三个、占主导地位的维度:状态(terraform.tfstate)。
状态将你的 Git 配置映射到 AWS/Azure/GCP 的真实 API。即使你把状态远程存储(S3、Terraform Cloud)以避免 JSON 合并冲突,也无法仅靠 Git 解决 逻辑分歧。
当你在 Terraform 中使用 GitFlow 时,就把代码和状态解耦了。
GitFlow 陷阱:“状态踩踏”和“幽灵”
一种常见的反模式是把 Git 分支映射到环境:
feature/new-db→ 沙箱dev→ 开发main→ 生产
场景
设想两位 DevOps 工程师 Alice 和 Bob 同时在不同特性上工作。
- Alice 从
develop分出feature/add-redis分支。她添加一个 Redis 集群并部署到沙箱环境进行测试。 - Bob 从
develop分出feature/resize-vpc分支。他修改 VPC CIDR 并部署到 同一个 沙箱环境(或另一个)。
因为 Terraform 按 地址 在状态文件中跟踪资源,Alice 和 Bob 现在处于竞争状态。
后果
当 Alice 或 Bob 最终合并回 develop 时,他们只是在合并文本文件。Git 无法合并 实时的基础设施状态。于是会出现“干净”的 Git 历史,却与云提供商的混乱现实相矛盾,导致下一次部署时很可能失败。
- 共享环境风险(状态踩踏): 他们的锁相互覆盖或因状态文件与分支不同步而覆盖资源。
- 独立环境风险(幽灵基础设施): 如果特性分支在动态环境中创建了资源,合并后删除分支却没有运行
terraform destroy,这些资源会继续在云上运行,成为“孤儿”,每月计费却不在任何代码库中。
解决方案:基于主干的开发
在基于主干的开发(TBD)中,main 上的每一次提交都可能被部署。不要维护长期分支。
工作流
不再通过在分支之间移动代码来提升(例如把 dev 合并到 prod),而是 提升产物。在 Terraform 中,“产物”就是你的模块代码加上特定的提交 SHA。
所有环境使用 相同的代码,仅更改 输入变量。
流水线架构
实际实现
将仓库结构划分为逻辑基础设施(代码)和环境配置(变量)两部分。
目录结构
/my-infra
/modules
/vpc
/k8s
main.tf # 通用入口点
variables.tf # 仅定义变量
config/
dev.tfvars # 开发环境特定值(例如 instance_type = "t3.micro")
prod.tfvars # 生产环境特定值(例如 instance_type = "m5.large")
CI/CD 命令逻辑
开发阶段
# 使用后端配置(通常是部分配置)进行初始化
terraform init -backend-config="bucket=my-tf-state-dev"
# 使用该环境的特定变量进行计划
terraform plan -var-file="config/dev.tfvars" -out=tfplan
# 严格按照计划执行
terraform apply tfplan
生产提升
# 同样的代码,不同的状态后端和变量
terraform init -backend-config="bucket=my-tf-state-prod"
terraform plan -var-file="config/prod.tfvars" -out=tfplan
terraform apply tfplan
为什么更安全
- 不可变性: 在开发中测试通过的 Terraform 代码就是在生产中运行的代码。不存在 Dev 与 Prod 分支之间的“糟糕合并”。
- 状态隔离: 开发和生产拥有完全独立的状态文件(由后端配置决定),互不干扰。
- 快速反馈: 若提交在开发阶段失败,流水线会中止,永远不会进入生产。
例外:共享模块
在 Terraform 中有一个特定领域需要使用 语义化版本 …(内容续)