Terraform基础设施即代码多环境管理与状态隔离实践方案

基础设施即代码(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/

(0)
小编小编
上一篇 2小时前
下一篇 2小时前

相关推荐