# 使用Terraform在AWS上实践基础设施即代码
简介
通过AWS控制台手动管理云基础设施容易出错且无法扩展。HashiCorp的Terraform让你可以将基础设施定义为代码(IaC),实现版本控制、可重现性和自动化。
本教程将构建一个生产就绪的AWS环境:
- 带有公共和私有子网的自定义VPC
- 带安全组的EC2 Web服务器
- 私有子网中的RDS MySQL数据库
- 方便访问资源的输出值
- 拥有IAM凭证的AWS账户
- 已安装Terraform >= 1.6
- 基本了解AWS网络
前置条件
步骤1: 安装和配置Terraform
# 安装Terraform (macOS)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# 验证安装
terraform version
# 配置AWS凭证
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_REGION="ap-northeast-1"
步骤2: 项目结构
terraform-aws-demo/
├── main.tf # 根模块
├── variables.tf # 输入变量
├── outputs.tf # 输出值
├── terraform.tfvars # 变量值
├── modules/
│ ├── vpc/
│ ├── ec2/
│ └── rds/
步骤3: 定义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.project_name}-vpc"
Environment = var.environment
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-${count.index + 1}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.project_name}-private-${count.index + 1}"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
}
步骤4: 定义EC2模块
# modules/ec2/main.tf
resource "aws_security_group" "web" {
name_prefix = "${var.project_name}-web-"
vpc_id = var.vpc_id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.ssh_cidr]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
subnet_id = var.subnet_id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd php php-mysqlnd
systemctl start httpd
systemctl enable httpd
EOF
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.project_name}-web"
}
}
步骤5: 定义RDS模块
# modules/rds/main.tf
resource "aws_db_subnet_group" "main" {
name = "${var.project_name}-db-subnet"
subnet_ids = var.private_subnet_ids
}
resource "aws_security_group" "db" {
name_prefix = "${var.project_name}-db-"
vpc_id = var.vpc_id
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [var.web_sg_id]
}
}
resource "aws_db_instance" "main" {
identifier = "${var.project_name}-db"
engine = "mysql"
engine_version = "8.0"
instance_class = var.db_instance_class
allocated_storage = 20
storage_encrypted = true
db_name = var.db_name
username = var.db_username
password = var.db_password
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.db.id]
skip_final_snapshot = true
}
步骤6: 部署基础设施
# 初始化
terraform init
# 预览变更
terraform plan
# 应用变更
terraform apply -auto-approve
# 查看输出
terraform output
# 完成后销毁(避免产生费用!)
terraform destroy -auto-approve
最佳实践
terraform fmt和terraform validateterraform.tfvars中,使用环境变量或AWS Secrets Manager总结
本教程涵盖了:
Terraform让基础设施具有可重现性和可审计性。结合CI/CD流水线实现完全自动化部署。