基础设施即代码(IaC)的成熟实践离不开多环境管理能力。开发、测试、预发布、生产四个环境各自独立运行,配置参数和网络拓扑存在差异,手动逐环境维护不仅效率低下,更极易引入配置漂移。Terraform通过工作区(Workspace)、目录隔离和模块化三种策略实现多环境管理,每种策略各有适用场景和限制条件。本文给出完整的多环境Terraform架构设计和状态隔离方案。
多环境隔离策略选型对比
Terraform多环境管理有三种主流策略:Workspace隔离、目录隔离和Terragrunt分层。Workspace隔离在同一目录下通过terraform workspace切换环境,状态文件自动隔离,配置简单但变量管理不够直观,环境差异大时代码中充斥大量条件判断。目录隔离为每个环境建立独立目录,各目录维护独立的main.tf和变量文件,配置透明度高但模块更新需同步多份代码。Terragrunt在目录隔离基础上引入依赖管理和远程状态配置继承,减少重复代码但引入额外工具依赖。
生产环境推荐目录隔离+模块化组合方案:共享逻辑抽成模块,环境差异通过变量文件表达。目录结构如下:
infra/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── ecs/
│ └── rds/
├── envs/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── backend.tf
│ │ ├── terraform.tfvars
│ │ └── providers.tf
│ ├── staging/
│ └── prod/
└── shared/
└── remote_state.tf
模块化设计与变量抽象
模块是Terraform代码复用的核心单元。好的模块设计遵循单一职责原则,一个模块管理一类资源。VPC模块负责网络基础设施,ECS模块负责计算资源,RDS模块负责数据库。模块的输入变量应充分暴露可配置项,同时为非关键参数设置合理默认值:
# modules/vpc/variables.tf
variable "vpc_cidr" {
type = string
description = "VPC CIDR block"
}
variable "environment" {
type = string
description = "Environment name (dev/staging/prod)"
}
variable "enable_nat_gateway" {
type = bool
default = true
description = "Whether to create NAT Gateway for private subnets"
}
variable "single_nat_gateway" {
type = bool
default = false
description = "Use single NAT Gateway to reduce cost"
}
variable "availability_zones" {
type = list(string)
default = ["ap-east-1a", "ap-east-1b", "ap-east-1c"]
}
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 10)
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.environment}-private-${count.index}"
Environment = var.environment
}
}
环境差异化配置与条件资源创建
各环境的差异集中体现在terraform.tfvars变量文件中。开发环境使用较小的实例规格和单NAT网关降低成本,生产环境使用多可用区部署和双NAT网关保证高可用:
# envs/dev/terraform.tfvars
environment = "dev"
vpc_cidr = "10.0.0.0/16"
enable_nat_gateway = true
single_nat_gateway = true
ecs_instance_type = "t3.medium"
rds_instance_class = "db.t3.medium"
rds_multi_az = false
# envs/prod/terraform.tfvars
environment = "prod"
vpc_cidr = "10.100.0.0/16"
enable_nat_gateway = true
single_nat_gateway = false
ecs_instance_type = "c6i.4xlarge"
rds_instance_class = "db.r6g.2xlarge"
rds_multi_az = true
backup_retention_days = 30
模块内部通过条件表达式控制资源创建。生产环境需要WAF和CloudFront,开发环境不需要,通过count实现条件创建:
# 仅在生产环境创建WAF
resource "aws_wafv2_web_acl" "main" {
count = var.environment == "prod" ? 1 : 0
name = "${var.environment}-waf"
scope = "REGIONAL"
description = "WAF for ${var.environment} environment"
default_action {
allow {}
}
rule {
name = "rate-limit-rule"
priority = 1
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
sampled_requests_enabled = true
cloudwatch_metrics_enabled = true
metric_name = "rate-limit"
}
}
}
远程状态存储与状态锁定
Terraform状态文件记录资源的实时映射关系,多环境必须使用远程后端存储并启用状态锁定。S3后端配合DynamoDB锁定表是AWS环境的标配方案:
# envs/prod/backend.tf
terraform {
backend "s3" {
bucket = "yunthe-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
kms_key_id = "arn:aws:kms:ap-east-1:123456789:key/xxx"
}
}
# 创建DynamoDB锁定表(一次性操作)
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
状态隔离的关键是每个环境使用不同的state key路径。dev环境使用dev/terraform.tfstate,prod环境使用prod/terraform.tfstate,互不干扰。状态文件启用S3服务端加密(SSE-KMS),防止敏感信息泄露。
跨环境资源引用与数据源
多个环境之间经常需要互相引用资源输出。例如staging环境需要引用dev环境的VPC Peering连接,生产环境需要引用日志账号的S3 Bucket。Terraform通过terraform_remote_state数据源读取其他环境的状态输出:
# 在staging环境中引用dev环境的VPC ID
data "terraform_remote_state" "dev" {
backend = "s3"
config = {
bucket = "yunthe-terraform-state"
key = "dev/terraform.tfstate"
region = "ap-east-1"
}
}
resource "aws_vpc_peering_connection" "dev_to_staging" {
vpc_id = data.terraform_remote_state.dev.outputs.vpc_id
peer_vpc_id = aws_vpc.main.id
auto_accept = true
tags = {
Name = "dev-to-staging-peering"
}
}
跨环境引用要避免循环依赖。A环境引用B的状态,B又引用A的状态,会导致Terraform初始化失败。架构设计时明确环境间的依赖方向:低环境向高环境单向引用,或者通过共享数据账号解耦。
Plan差异审查与变更自动化
多环境Terraform的变更审批流程通过CI/CD流水线落地。开发环境允许自动apply,预发布环境需要Plan审查后手动确认,生产环境必须经过双重审批。流水线配置核心是terraform plan的输出解析和人工审批关卡:
# GitHub Actions工作流示例
- name: Terraform Plan
run: |
cd envs/${{ env.ENVIRONMENT }}
terraform plan -out=tfplan
terraform show -no-color tfplan > plan_output.txt
- name: Check Production Approval
if: env.ENVIRONMENT == 'prod'
uses: peter-evans/create-or-update-comment@v3
with:
body-path: plan_output.txt
- name: Manual Approval
if: env.ENVIRONMENT == 'prod'
uses: peter-evans/enable-github-actions@v1
environment: production-approval
多环境Terraform管理的核心是模块化+目录隔离+远程状态三件套。模块保证代码复用和环境间一致性,目录隔离让每个环境的配置独立可追溯,远程状态配合锁定保证团队协作安全。配合CI/CD流水线的分级审批机制,实现从开发到生产的配置安全流转。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/terraform-ji-chu-she-shi-ji-dai-ma-duo-huan-jing-guan-li-yu/