工作区与多环境管理
在实际项目中,通常需要管理多个环境(开发、测试、生产)的基础设施。Terraform 提供了工作区和文件结构两种方式来管理多环境配置。本章将详细介绍这两种方法及其适用场景。
工作区(Workspace)
Terraform 工作区允许在同一配置下维护多个独立的状态文件,每个工作区有自己的状态。
工作区命令
# 列出所有工作区
terraform workspace list
* default
# 创建新工作区
terraform workspace new dev
Created and switched to workspace "dev"!
# 切换工作区
terraform workspace select default
Switched to workspace "default".
# 查看当前工作区
terraform workspace show
dev
# 删除工作区
terraform workspace delete dev
Deleted workspace "dev".
工作区使用场景
工作区适合环境差异较小的情况:
# main.tf
locals {
# 根据工作区确定环境
environment = terraform.workspace == "default" ? "prod" : terraform.workspace
# 环境配置
config = {
dev = {
instance_type = "t2.micro"
instance_count = 1
enable_monitoring = false
}
staging = {
instance_type = "t2.small"
instance_count = 2
enable_monitoring = true
}
prod = {
instance_type = "t2.medium"
instance_count = 3
enable_monitoring = true
}
}
# 获取当前环境配置
env_config = local.config[local.environment]
}
# 使用环境配置
resource "aws_instance" "web" {
count = local.env_config.instance_count
ami = data.aws_ami.amazon_linux.id
instance_type = local.env_config.instance_type
monitoring = local.env_config.enable_monitoring
tags = {
Name = "web-${local.environment}-${count.index + 1}"
Environment = local.environment
}
}
工作区与远程状态
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "terraform.tfstate" # 工作区名称会自动附加
region = "us-east-1"
# 实际存储路径:
# - dev: env:/dev/terraform.tfstate
# - prod: env:/prod/terraform.tfstate
# - default: terraform.tfstate
}
}
工作区命名空间
# 使用工作区命名资源
resource "aws_s3_bucket" "assets" {
bucket = "my-app-assets-${terraform.workspace}"
tags = {
Environment = terraform.workspace
}
}
文件结构方式
对于环境差异较大的项目,推荐使用文件结构方式管理多环境。
推荐的项目结构
terraform-project/
├── modules/ # 可重用模块
│ ├── networking/
│ ├── compute/
│ └── database/
├── environments/ # 环境配置
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ ├── backend.tf # 远程状态配置
│ │ └── terraform.tfvars # 环境变量值
│ ├── staging/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ ├── backend.tf
│ │ └── terraform.tfvars
│ └── prod/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ ├── backend.tf
│ └── terraform.tfvars
├── global/ # 全局资源
│ └── iam/
├── live/ # 实时基础设施(按服务划分)
│ ├── vpc/
│ ├── eks/
│ └── rds/
└── scripts/ # 辅助脚本
├── plan.sh
└── apply.sh
环境配置示例
开发环境
# environments/dev/backend.tf
terraform {
backend "s3" {
bucket = "company-terraform-state"
key = "dev/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
# environments/dev/main.tf
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = "dev"
ManagedBy = "Terraform"
}
}
}
module "vpc" {
source = "../../modules/networking"
vpc_cidr = var.vpc_cidr
availability_zones = var.availability_zones
environment = "dev"
}
module "compute" {
source = "../../modules/compute"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
instance_type = var.instance_type
instance_count = var.instance_count
}
# environments/dev/variables.tf
variable "aws_region" {
type = string
default = "us-east-1"
}
variable "vpc_cidr" {
type = string
default = "10.0.0.0/16"
}
variable "availability_zones" {
type = list(string)
default = ["us-east-1a"]
}
variable "instance_type" {
type = string
default = "t2.micro"
}
variable "instance_count" {
type = number
default = 1
}
# environments/dev/terraform.tfvars
aws_region = "us-east-1"
vpc_cidr = "10.1.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b"]
instance_type = "t2.micro"
instance_count = 2
生产环境
# environments/prod/backend.tf
terraform {
backend "s3" {
bucket = "company-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
# environments/prod/main.tf
# 结构与 dev 类似,但使用不同的变量值
# environments/prod/terraform.tfvars
aws_region = "us-east-1"
vpc_cidr = "10.3.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
instance_type = "t2.large"
instance_count = 5
环境管理策略
策略一:工作区方式
适用场景:
- 环境之间差异较小
- 团队规模较小
- 需要快速切换环境
优点:
- 配置复用,减少重复代码
- 切换环境简单
缺点:
- 权限控制困难
- 容易误操作生产环境
策略二:文件结构方式
适用场景:
- 环境之间差异较大
- 需要严格的权限控制
- 大型团队
优点:
- 环境隔离清晰
- 易于权限管理
- 可以独立版本控制
缺点:
- 配置有一定重复
- 需要维护多个目录
策略三:混合方式
结合两种方式的优点:
terraform-project/
├── modules/
│ └── ...
├── environments/
│ ├── dev/ # 开发环境(文件结构)
│ ├── staging/ # 测试环境(文件结构)
│ └── prod/ # 生产环境(文件结构)
│ ├── us-east-1/ # 使用工作区管理多区域
│ └── eu-west-1/
└── ...
环境部署流程
使用脚本自动化
#!/bin/bash
# scripts/deploy.sh
ENV=$1
ACTION=$2
if [ -z "$ENV" ] || [ -z "$ACTION" ]; then
echo "Usage: $0 <environment> <plan|apply|destroy>"
exit 1
fi
cd "environments/$ENV" || exit 1
case $ACTION in
plan)
terraform init
terraform plan -out=tfplan
;;
apply)
terraform apply tfplan
;;
destroy)
terraform destroy
;;
*)
echo "Unknown action: $ACTION"
exit 1
;;
esac
CI/CD 集成
GitHub Actions 示例
# .github/workflows/terraform.yml
name: Terraform
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
runs-on: ubuntu-latest
environment: ${{ matrix.environment }}
strategy:
matrix:
environment: [dev, staging]
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: "1.6.0"
- name: Terraform Init
run: |
cd environments/${{ matrix.environment }}
terraform init
- name: Terraform Plan
run: |
cd environments/${{ matrix.environment }}
terraform plan
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: |
cd environments/${{ matrix.environment }}
terraform apply -auto-approve
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
环境间依赖
使用远程状态数据源
# environments/prod/main.tf
# 引用开发环境的 VPC 信息
data "terraform_remote_state" "dev" {
backend = "s3"
config = {
bucket = "company-terraform-state"
key = "dev/terraform.tfstate"
region = "us-east-1"
}
}
# 使用开发环境的输出
resource "aws_security_group_rule" "allow_dev" {
type = "ingress"
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = [data.terraform_remote_state.dev.outputs.vpc_cidr]
security_group_id = aws_security_group.database.id
}
环境升级策略
蓝绿部署
# 使用工作区实现蓝绿部署
locals {
deployment_color = terraform.workspace == "blue" ? "blue" : "green"
}
resource "aws_instance" "app" {
count = var.instance_count
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "app-${local.deployment_color}-${count.index + 1}"
Deployment = local.deployment_color
}
}
金丝雀发布
# 逐步切换流量
locals {
canary_percentage = terraform.workspace == "canary" ? 10 : 100
}
resource "aws_lb_target_group_attachment" "app" {
count = length(aws_instance.app)
target_group_arn = aws_lb_target_group.app.arn
target_id = aws_instance.app[count.index].id
port = 80
}
环境清理
自动清理开发环境
# 使用生命周期规则
resource "aws_instance" "dev" {
count = var.environment == "dev" ? 1 : 0
ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
tags = {
Name = "dev-instance"
AutoCleanup = "true"
CreatedAt = timestamp()
}
lifecycle {
prevent_destroy = false
}
}
# 清理脚本
#!/bin/bash
# scripts/cleanup.sh
# 查找并删除标记为 AutoCleanup 的资源
aws ec2 describe-instances \
--filters "Name=tag:AutoCleanup,Values=true" \
--query 'Reservations[*].Instances[*].InstanceId' \
--output text | xargs -I {} aws ec2 terminate-instances --instance-ids {}
最佳实践
1. 环境命名规范
# 推荐的环境命名
- dev / development
- staging / test / qa
- prod / production
- dr / disaster-recovery
# 避免使用
- temp / temporary
- test1 / test2
- my-env
2. 状态隔离
# 每个环境使用独立的 S3 路径
# dev: s3://bucket/env/dev/terraform.tfstate
# prod: s3://bucket/env/prod/terraform.tfstate
terraform {
backend "s3" {
bucket = "company-terraform-state"
key = "env/${var.environment}/terraform.tfstate"
region = "us-east-1"
}
}
3. 权限控制
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::company-terraform-state/env/dev/*"
},
{
"Effect": "Deny",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::company-terraform-state/env/prod/*"
}
]
}
4. 变更审批流程
# 生产环境需要审批
production:
environment:
name: production
url: https://prod.example.com
deployment:
protection_rules:
- type: required_reviewers
reviewers:
- senior-devops
下一步
了解了多环境管理后,我们将学习 最佳实践,掌握生产环境中使用 Terraform 的高级技巧和注意事项。