前言
前面我们讲的 GitOps 都是在管 Kubernetes 集群内的资源。但一个完整的应用系统还包括 VPC、数据库、负载均衡器等云资源。这些基础设施能否也用 GitOps 管理?答案是 Terraform + GitOps,也叫 "GitOps for Infrastructure"。
一、为什么基础设施也需要 GitOps
传统基础设施管理的问题
运维人员 → AWS Console 手动创建 VPC/EC2/RDS
- 没有审计记录
- 环境不一致(开发/测试/生产手动建)
- 灾难恢复困难(谁记得建了什么?)
- 权限管理混乱
GitOps for Infrastructure 的价值
Git 仓库(Terraform 代码)
├── VPC、子网、路由表
├── RDS 实例
├── IAM 策略
├── S3 桶
└── CloudWatch 告警
↓ GitOps Controller
自动 plan & apply
→ 基础设施与 Git 声明一致
二、Terraform 基础回顾
基本工作流
bash
# 初始化
terraform init
# 查看变更计划
terraform plan
# 应用变更
terraform apply
# 销毁资源
terraform destroy
示例:创建 AWS VPC
hcl
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "production-vpc"
ManagedBy = "terraform"
}
}
# 子网
resource "aws_subnet" "public" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 1}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "public-subnet-${count.index + 1}"
}
}
# 输出
output "vpc_id" {
value = aws_vpc.main.id
}
三、Terraform Controller:Terraform Operator for Kubernetes
方案对比
| 方案 | 原理 | 优势 | 劣势 |
|---|---|---|---|
| Terraform Controller (Flux) | TF 代码存 Git,Controller 执行 | 与 Flux 深度集成,CRD 管理 | 功能较新 |
| Terraform Operator (KubeVela) | CRD 定义 TF 模块 | 灵活,支持多云 | 依赖 KubeVela |
| Atlantis | PR 驱动,手动 approve | 成熟稳定 | 非 GitOps 自动化 |
| Crossplane | 原生 K8s CRD 管理云资源 | 真正的 K8s 原生 | 学习曲线高 |
安装 Terraform Controller (Flux)
bash
# 添加 Helm 仓库
helm repo add tf-controller https://tf-controller.github.io/tf-controller
helm repo update
# 安装
helm install tf-controller tf-controller/tf-controller \
--namespace tf-system \
--create-namespace \
--set rbac.create=true \
--set serviceAccount.create=true
四、用 Terraform Controller 管理基础设施
Terraform 资源 CRD
yaml
apiVersion: tf.isaaguilar.com/v1alpha2
kind: Terraform
metadata:
name: aws-vpc
namespace: default
spec:
tfdir: git::https://github.com/org/infra-repo.git//vpc?ref=main
# 也可以用本地路径或 OCI 镜像
# tfdir: /tmp/terraform/vpc
# 并发执行
parallelism: 4
# 审批策略
approvePlan: auto # auto = 自动 apply,manual = 需手动
# 变量
vars:
- key: region
value: "us-east-1"
- key: environment
value: "production"
- key: vpc_cidr
value: "10.0.0.0/16"
# 敏感变量通过 Secret 引用
varsFrom:
- key: aws-credentials
kind: Secret
name: aws-creds
# 状态存储配置
backend:
s3:
bucket: terraform-state-prod
key: aws-vpc/terraform.tfstate
region: us-east-1
# 执行前 Hook
preInit:
- "terraform fmt -check"
# 输出到 Secret
outputs:
- key: vpc_id
moduleOutputName: vpc_id
完整示例:管理 AWS RDS
hcl
# infra-repo/rds/main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
variable "instance_class" {
type = string
default = "db.t3.medium"
}
variable "allocated_storage" {
type = number
default = 20
}
resource "aws_db_instance" "main" {
identifier = "production-db"
engine = "postgres"
engine_version = "15.4"
instance_class = var.instance_class
allocated_storage = var.allocated_storage
db_name = "appdb"
username = "admin"
password = var.db_password
vpc_id = var.vpc_id
subnet_ids = var.subnet_ids
skip_final_snapshot = false
final_snapshot_identifier = "production-db-final"
backup_retention_period = 7
backup_window = "03:00-05:00"
maintenance_window = "Mon:05:00-Mon:07:00"
tags = {
Environment = "production"
ManagedBy = "terraform-gitops"
}
}
output "db_endpoint" {
value = aws_db_instance.main.endpoint
sensitive = true
}
yaml
# GitOps 仓库中的 Terraform CR
apiVersion: tf.isaaguilar.com/v1alpha2
kind: Terraform
metadata:
name: production-rds
namespace: default
spec:
tfdir: git::https://github.com/org/infra-repo.git//rds?ref=main
approvePlan: auto
vars:
- key: instance_class
value: "db.r6g.large"
- key: allocated_storage
value: "100"
- key: vpc_id
value: "vpc-abc123"
- key: subnet_ids
value: '["subnet-aaa","subnet-bbb","subnet-ccc"]'
varsFrom:
- key: DB_PASSWORD
kind: Secret
name: rds-credentials
backend:
s3:
bucket: terraform-state-prod
key: rds/terraform.tfstate
region: us-east-1
outputs:
- key: db_endpoint
moduleOutputName: db_endpoint
输出跨资源引用
yaml
# VPC Terraform 输出 vpc_id
# RDS Terraform 引用 VPC 的输出值
apiVersion: tf.isaaguilar.com/v1alpha2
kind: Terraform
metadata:
name: production-rds
spec:
tfdir: git::https://github.com/org/infra-repo.git//rds?ref=main
vars:
- key: vpc_id
# 引用另一个 Terraform 资源的输出
value: "${production-vpc.vpc_id}"
五、GitOps 工作流
完整流水线
开发者修改 Terraform 代码
↓
提交 PR 到 Git 仓库
↓
Atlantis / TF Controller 执行 terraform plan
↓
PR 评论显示 plan 结果
↓
Code Review & Approve
↓
Merge to main
↓
TF Controller 自动 terraform apply
↓
基础设施变更生效
↓
状态写回 S3 后端
目录结构
infra-repo/
├── .sops.yaml # SOPS 加密配置
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── rds/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── eks/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── environments/
│ ├── staging/
│ │ ├── vpc.yaml # TF Controller CR
│ │ ├── rds.yaml
│ │ └── eks.yaml
│ └── production/
│ ├── vpc.yaml
│ ├── rds.yaml
│ └── eks.yaml
└── policies/
└── cost-guardrails.yaml # 成本控制策略
六、Atlantis:PR 驱动的 Terraform
安装 Atlantis
bash
# Helm 安装
helm repo add atlantis https://runatlantis.github.io/helm-charts
helm repo update
helm install atlantis atlantis/atlantis \
--namespace atlantis \
--create-namespace \
--set github.user=your-bot \
--set github.token=ghp_xxx \
--set github.secret=your-webhook-secret \
--set atlantis.url=https://atlantis.example.com
atlantis.yaml 配置
yaml
# 仓库根目录的 atlantis.yaml
version: 3
projects:
- name: staging-vpc
dir: environments/staging/vpc
workspace: staging
autoplan:
when_modified: ["*.tf", "*.tfvars"]
enabled: true
apply_requirements: [approved, mergeable]
- name: production-vpc
dir: environments/production/vpc
workspace: production
autoplan:
when_modified: ["*.tf"]
enabled: true
apply_requirements: [approved, mergeable, undiverged]
- name: production-rds
dir: environments/production/rds
workspace: production
autoplan:
when_modified: ["*.tf"]
enabled: true
apply_requirements: [approved, mergeable]
PR 工作流
1. 开发者提交 PR → 修改 RDS 实例类型
2. Atlantis 自动执行 terraform plan
3. PR 评论显示:
"Plan: 1 to add, 0 to change, 0 to destroy"
"aws_db_instance.main: instance_class db.t3.medium → db.r6g.large"
4. Reviewer 审核 plan 结果
5. 评论 "atlantis apply -d environments/production/rds"
6. Atlantis 执行 terraform apply
7. 基础设施变更生效
七、安全与最佳实践
状态管理
hcl
# 使用远程 S3 后端 + DynamoDB 锁
terraform {
backend "s3" {
bucket = "terraform-state-prod"
key = "infra/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
# DynamoDB 锁表(防并发)
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
权限隔离
yaml
# 生产环境使用独立 ServiceAccount + IRSA
apiVersion: v1
kind: ServiceAccount
metadata:
name: terraform-production
namespace: tf-system
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/terraform-prod-role
---
# Terraform CR 使用该 SA
apiVersion: tf.isaaguigar.com/v1alpha2
kind: Terraform
metadata:
name: production-rds
spec:
serviceAccount: terraform-production
成本防护
yaml
# 在 Terraform 模块中添加成本预估
spec:
prePlan:
- "infracost breakdown --path . --format json --out-file infracost.json"
- "infracost diff --path infracost.json --compare-to main"
postPlan:
- "if [ $(cat infracost-diff.json | jq '.totalMonthlyCost' | tr -d '\"' | awk '{print int($1)}') -gt 100 ]; then echo 'Cost exceeds $100/month limit'; exit 1; fi"
⚠️ 踩坑提示 :
永远不要删除
terraform.tfstate文件生产环境
approvePlan设为manual,配合 PR 审批使用
terraform import接管手动创建的资源,避免 State 冲突Terraform 版本固定,避免自动升级导致 breaking change
要点回顾
| 维度 | Kubernetes GitOps | Infrastructure GitOps |
|---|---|---|
| 管理对象 | K8s 资源(Deployment/Service) | 云资源(VPC/RDS/S3) |
| 工具 | ArgoCD / Flux | Terraform Controller / Atlantis |
| 声明式 | YAML CRD | HCL 代码 |
| 状态管理 | etcd | S3 + DynamoDB |
| 审批方式 | 自动同步 | PR 驱动 |
- Terraform Controller 将 Terraform 引入 K8s GitOps 生态
- Atlantis 适合 PR 驱动的工作流
- 远程状态 + DynamoDB 锁是生产标配
- 跨资源输出实现 VPC → RDS → EKS 的引用链
- 成本防护用 Infracost 在 plan 阶段拦截
下一篇预告
应用交付、渐进式发布、基础设施管理都有了。下一篇 【GitOps·落地篇】企业级 GitOps 平台架构:迁移路径与最佳实践 将从全局视角讲解如何搭建企业级 GitOps 平台,以及从传统模式到 GitOps 的迁移路径。