
Terraform 基础
Terraform 将基础设施作为代码进行管理——版本控制、可审查且可重现。

项目结构
terraform/
├── main.tf
├── variables.tf
├── outputs.tf
├── providers.tf
├── backend.tf
└── modules/
├── vpc/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── ecs/
└── rds/
Provider 和 Backend 设置
# providers.tf
terraform {
required_version = ">= 1.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "terraform"
}
}
}
# backend.tf
terraform {
backend "s3" {
bucket = "myapp-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock" # 防止并发执行
}
}

VPC 模块
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = { Name = "${var.name}-vpc" }
}
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = { Name = "${var.name}-public-${count.index + 1}" }
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + 4)
availability_zone = var.availability_zones[count.index]
tags = { Name = "${var.name}-private-${count.index + 1}" }
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
resource "aws_nat_gateway" "main" {
count = length(var.availability_zones)
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
depends_on = [aws_internet_gateway.main]
}
ECS Fargate 服务
# modules/ecs/main.tf
resource "aws_ecs_cluster" "main" {
name = "${var.name}-cluster"
setting {
name = "containerInsights"
value = "enabled"
}
}
resource "aws_ecs_task_definition" "app" {
family = var.name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.cpu
memory = var.memory
execution_role_arn = aws_iam_role.ecs_execution.arn
task_role_arn = aws_iam_role.ecs_task.arn
container_definitions = jsonencode([{
name = var.name
image = var.container_image
portMappings = [{
containerPort = var.container_port
protocol = "tcp"
}]
environment = [for k, v in var.environment_variables : { name = k, value = v }]
secrets = [for k, v in var.secrets : { name = k, valueFrom = v }]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = "/ecs/${var.name}"
"awslogs-region" = data.aws_region.current.name
"awslogs-stream-prefix" = "ecs"
}
}
healthCheck = {
command = ["CMD-SHELL", "curl -f http://localhost:${var.container_port}/health || exit 1"]
interval = 30
timeout = 10
retries = 3
startPeriod = 60
}
}])
}
resource "aws_ecs_service" "app" {
name = var.name
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = var.desired_count
launch_type = "FARGATE"
network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.app.id]
assign_public_ip = false
}
load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = var.name
container_port = var.container_port
}
deployment_circuit_breaker {
enable = true
rollback = true
}
}

变量和输出
# variables.tf
variable "environment" {
type = string
default = "production"
validation {
condition = contains(["development", "staging", "production"], var.environment)
error_message = "Environment must be development, staging, or production."
}
}
variable "instance_type" {
type = string
default = "t3.medium"
}
# outputs.tf
output "api_url" {
value = "https://${aws_route53_record.api.fqdn}"
description = "API endpoint URL"
}
output "rds_endpoint" {
value = module.rds.endpoint
sensitive = true
}
Terraform CLI 工作流
# 初始化
terraform init
# 计划(查看将要更改的内容)
terraform plan -var-file=prod.tfvars -out=tfplan
# 应用
terraform apply tfplan
# 针对特定资源
terraform apply -target=module.ecs.aws_ecs_service.app
# 销毁(谨慎使用!)
terraform destroy -target=module.ecs
# 导入现有资源
terraform import aws_s3_bucket.existing my-existing-bucket