Terraform作为HashiCorp推出的基础设施即代码(IaC)工具,通过声明式配置语言HCL描述云资源拓扑,实现基础设施的版本化管理与自动化部署。DevOps实践中Terraform的核心挑战在于多环境(dev/staging/prod)配置隔离、State状态文件安全管理、Module模块复用三个方向。合理的状态管理策略能避免团队协作中的状态冲突与资源漂移。
Terraform多环境架构设计与工作区隔离
多环境管理有三种主流模式:目录隔离、工作区隔离、变量文件隔离。目录隔离为每个环境创建独立目录和独立State,最安全但代码重复较多。工作区隔离使用terraform workspace在同一配置下切换不同State,适合配置差异小的场景。变量文件隔离通过不同的terraform.tfvars文件区分环境参数。
生产环境推荐目录隔离模式,配合Module复用消除重复代码。目录结构设计:
infra/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── eks/
│ └── rds/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── backend.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ │ ├── main.tf
│ │ ├── backend.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ ├── backend.tf
│ └── terraform.tfvars
└── README.md
每个环境目录引用相同的Module,通过传入不同变量实现差异化配置。dev环境可降低副本数和实例规格,prod环境配置多可用区和高可用参数。
State状态文件远程存储与锁定机制配置
Terraform State文件记录了基础设施的实际状态,是plan和apply的基础。本地State文件存在三大风险:无法团队协作、无历史版本、含敏感信息明文。生产环境必须使用远程Backend存储。
S3 + DynamoDB是AWS环境的标准方案:S3存储State文件并开启版本控制,DynamoDB提供状态锁防止并发执行冲突。锁定机制确保同一时刻只有一个Terraform进程能修改State,避免覆盖式更新导致的资源丢失。
# environments/prod/backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state-prod"
key = "prod/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# 初始化远程后端的S3和DynamoDB(一次性引导资源)
# bootstrap.tf - 用本地State创建远程存储基础设施
resource "aws_s3_bucket" "terraform_state" {
bucket = "mycompany-terraform-state-prod"
lifecycle {
prevent_destroy = true # 防止误删State存储桶
}
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Module模块化设计与版本化复用
Module封装了一组相关资源的配置,通过input variables接收参数,通过outputs暴露结果。良好的Module设计应保持单一职责、提供合理默认值、不硬编码环境相关信息。
# modules/vpc/main.tf
variable "cidr_block" {
type = string
default = "10.0.0.0/16"
}
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "environment must be dev, staging, or prod."
}
}
variable "enable_nat_gateway" {
type = bool
default = true
}
variable "single_nat_gateway" {
type = bool
default = false # prod环境设为false(每AZ一个NAT),dev设为true(共享NAT)
}
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
output "vpc_id" {
value = aws_vpc.main.id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
环境目录引用Module时通过source指定路径或Git版本:
# environments/prod/main.tf
module "vpc" {
source = "../../modules/vpc"
cidr_block = "10.1.0.0/16"
environment = "prod"
enable_nat_gateway = true
single_nat_gateway = false # 生产环境每AZ独立NAT
}
module "eks" {
source = "../../modules/eks"
vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnet_ids
cluster_version = "1.30"
node_group_size = 3
environment = "prod"
}
module "rds" {
source = "../../modules/rds"
vpc_id = module.vpc.vpc_id
db_size = "db.r6g.xlarge"
multi_az = true
environment = "prod"
}
CI/CD流水线集成与Plan/Apply自动化
Terraform应纳入CI/CD流水线实现自动化管理。典型流程为:PR提交触发terraform fmt + validate + plan,人工Review plan输出,合并后触发apply。GitHub Actions配置示例:
# .github/workflows/terraform.yml
name: Terraform CI/CD
on:
pull_request:
paths: ["environments/**"]
push:
branches: [main]
paths: ["environments/**"]
jobs:
plan:
runs-on: ubuntu-latest
defaults:
run:
working-directory: environments/prod
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- uses: hashicorp/setup-terraform@v3
- run: terraform fmt -check -recursive
- run: terraform init
- run: terraform validate
- run: terraform plan -no-color
continue-on-error: true
- uses: actions/github-script@v7
if: github.event_name == 'pull_request'
with:
script: |
const output = `Terraform Plan Output:\n${{ steps.plan.outputs.stdout }}`
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
apply:
needs: plan
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE }}
aws-region: ap-northeast-1
- uses: hashicorp/setup-terraform@v3
- run: cd environments/prod && terraform init
- run: cd environments/prod && terraform apply -auto-approve
State漂移检测与资源导入
基础设施因手动修改或外部操作偏离Terraform配置时产生State漂移。定期执行terraform plan检查是否存在非预期的变更输出。CI/CD中可设置定时任务运行plan并告警。
手动创建或通过Console创建的资源需要通过terraform import导入State管理。导入操作不会生成配置文件,需手动编写对应的resource配置:
# 导入已存在的S3桶到State
terraform import aws_s3_bucket.my_bucket my-existing-bucket-name
# 导入后需在配置文件中补充对应的resource块
# terraform show可查看导入资源属性,据此补全配置
import命令只导入State不修改资源。对于复杂资源(如RDS实例及其子资源参数组、安全组),需要逐一导入或使用import block(Terraform 1.5+)批量导入。
# Terraform 1.5+ 的import block(可在plan阶段预览导入)
import {
to = aws_s3_bucket.my_bucket
id = "my-existing-bucket-name"
}
import {
to = aws_db_instance.main
id = "mydb-instance-identifier"
}
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/terraform-ji-chu-she-shi-ji-dai-ma-duo-huan-jing-bu-shu-yu/