Terraform 基础知识
Terraform 基础知识
目录
一、什么是 Terraform
1.1 定义
Terraform 是 HashiCorp 公司开发的一个开源的基础设施即代码(Infrastructure as Code, IaC)工具。
1.2 核心价值
传统方式 (点击式操作) Terraform 方式 (代码化)
┌─────────────────────┐ ┌─────────────────────┐
│ 1. 登录 AWS Console │ │ 1. 编写配置文件 │
│ 2. 点击创建 S3 │ VS │ 2. terraform apply │
│ 3. 手动配置参数 │ │ 3. 自动创建所有资源 │
│ 4. 重复上述步骤 │ │ 4. 可重复、可追踪 │
└─────────────────────┘ └─────────────────────┘
问题: 优势:
❌ 人为错误 ✅ 一致性
❌ 难以复制 ✅ 版本控制
❌ 无法追踪变更 ✅ 可审计
❌ 文档与实际不一致 ✅ 自动化
1.3 主要特性
| 特性 | 说明 |
|---|---|
| 多云支持 | 支持 AWS、Azure、GCP、阿里云等 200+ 云服务商 |
| 声明式语法 | 描述”想要什么”,而非”如何做” |
| 状态管理 | 追踪实际基础设施与配置的差异 |
| 执行计划 | 在应用前预览将要发生的变更 |
| 资源图 | 自动处理资源之间的依赖关系 |
| 模块化 | 可复用的配置组件 |
1.4 应用场景
┌─────────────────────────────────────────────────────┐
│ Terraform 典型应用场景 │
├─────────────────────────────────────────────────────┤
│ │
│ 🏗️ 多云环境管理 │
│ - 在 AWS、Azure、GCP 上统一管理资源 │
│ │
│ 🔄 灾难恢复 │
│ - 快速在另一个区域重建整个环境 │
│ │
│ 📦 应用部署 │
│ - Kubernetes 集群、数据库、网络等 │
│ │
│ 🧪 环境复制 │
│ - 从生产环境快速创建测试/开发环境 │
│ │
│ 🔐 合规和审计 │
│ - 所有变更都有代码记录和审查 │
│ │
│ 💰 成本管理 │
│ - 通过代码控制资源,避免"僵尸资源" │
└─────────────────────────────────────────────────────┘
二、核心概念
2.1 资源 (Resource)
资源是 Terraform 管理的基础设施组件。
# 示例:创建一个 AWS S3 存储桶
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-unique-bucket-name"
tags = {
Name = "My Bucket"
Environment = "Dev"
}
}
语法结构:
resource "<provider>_<resource_type>" "<local_name>" {
<argument> = <value>
...
}
aws_s3_bucket:资源类型(由 Provider 定义)my_bucket:本地名称(在配置中引用用)bucket、tags:资源参数
2.2 Provider
Provider 是与云服务商 API 交互的插件。
# AWS Provider 配置
provider "aws" {
region = "us-west-2"
access_key = "AKIA..."
secret_key = "..."
}
# Azure Provider 配置
provider "azurerm" {
features {}
subscription_id = "..."
tenant_id = "..."
}
# Google Cloud Provider 配置
provider "google" {
project = "my-project"
region = "us-central1"
}
Provider 的作用:
- 定义可用的资源类型
- 处理 API 认证
- 管理 API 调用和重试逻辑
2.3 State (状态)
State 文件记录 Terraform 管理的实际基础设施状态。
// terraform.tfstate (简化版)
{
"version": 4,
"terraform_version": "1.5.0",
"resources": [
{
"type": "aws_s3_bucket",
"name": "my_bucket",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"attributes": {
"id": "my-unique-bucket-name",
"bucket": "my-unique-bucket-name",
"region": "us-west-2",
"arn": "arn:aws:s3:::my-unique-bucket-name"
}
}
]
}
]
}
State 的作用:
- 映射关系:配置 → 真实资源
- 元数据:记录资源间的依赖关系
- 性能优化:避免每次都查询所有资源
- 协作:团队成员共享基础设施状态
2.4 数据源 (Data Source)
Data Source 用于查询已存在的资源信息。
# 查询已存在的 AWS VPC
data "aws_vpc" "existing_vpc" {
id = "vpc-12345678"
}
# 使用查询到的信息
resource "aws_subnet" "my_subnet" {
vpc_id = data.aws_vpc.existing_vpc.id
cidr_block = "10.0.1.0/24"
}
Resource vs Data Source:
- Resource:Terraform 创建和管理
- Data Source:只读,查询已存在的资源
2.5 变量 (Variables)
变量用于参数化配置,提高复用性。
# 定义变量 (variables.tf)
variable "bucket_name" {
description = "S3 bucket name"
type = string
default = "my-default-bucket"
}
variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
# 使用变量 (main.tf)
resource "aws_s3_bucket" "my_bucket" {
bucket = var.bucket_name
tags = {
Environment = var.environment
}
}
变量赋值方式:
# 1. 命令行
terraform apply -var="bucket_name=my-bucket"
# 2. 变量文件 (terraform.tfvars)
bucket_name = "my-bucket"
environment = "prod"
# 3. 环境变量
export TF_VAR_bucket_name="my-bucket"
# 4. 交互式输入
terraform apply # 会提示输入未设置的变量
2.6 输出 (Outputs)
输出用于展示资源的重要信息。
# outputs.tf
output "bucket_id" {
description = "The ID of the S3 bucket"
value = aws_s3_bucket.my_bucket.id
}
output "bucket_arn" {
description = "The ARN of the S3 bucket"
value = aws_s3_bucket.my_bucket.arn
}
output "bucket_domain_name" {
description = "The domain name of the bucket"
value = aws_s3_bucket.my_bucket.bucket_domain_name
}
执行 apply 后的输出:
Outputs:
bucket_arn = "arn:aws:s3:::my-unique-bucket-name"
bucket_domain_name = "my-unique-bucket-name.s3.amazonaws.com"
bucket_id = "my-unique-bucket-name"
三、基本工作流程
3.1 完整流程图
┌─────────────────────────────────────────────────────┐
│ 1. 编写配置 (Write) │
│ - 创建 .tf 文件 │
│ - 定义想要的基础设施 │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 2. 初始化 (Init) │
│ $ terraform init │
│ - 下载 Provider 插件 │
│ - 初始化 Backend │
│ - 准备工作目录 │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 3. 验证 (Validate) │
│ $ terraform validate │
│ - 检查配置语法 │
│ - 验证资源定义 │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 4. 规划 (Plan) │
│ $ terraform plan │
│ - 对比当前状态与期望状态 │
│ - 生成执行计划 │
│ - 预览将要发生的变更 │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 5. 应用 (Apply) │
│ $ terraform apply │
│ - 执行计划中的变更 │
│ - 创建/更新/删除资源 │
│ - 更新 State 文件 │
└──────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 6. 销毁 (Destroy) - 可选 │
│ $ terraform destroy │
│ - 删除所有管理的资源 │
│ - 清理 State │
└─────────────────────────────────────────────────────┘
3.2 详细命令说明
terraform init
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.10.0...
- Installed hashicorp/aws v5.10.0 (signed by HashiCorp)
Terraform has been successfully initialized!
做了什么:
- 下载 Provider 插件到
.terraform/目录 - 初始化 Backend(State 存储位置)
- 创建依赖锁文件
.terraform.lock.hcl
terraform plan
$ terraform plan
Terraform will perform the following actions:
# aws_s3_bucket.my_bucket will be created
+ resource "aws_s3_bucket" "my_bucket" {
+ acceleration_status = (known after apply)
+ acl = (known after apply)
+ arn = (known after apply)
+ bucket = "my-unique-bucket-name"
+ bucket_domain_name = (known after apply)
+ id = (known after apply)
+ region = (known after apply)
+ tags = {
+ "Environment" = "Dev"
+ "Name" = "My Bucket"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
输出符号:
+创建新资源-删除资源~修改现有资源-/+删除后重建(某些属性无法原地修改)
terraform apply
$ terraform apply
# 显示计划...
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.my_bucket: Creating...
aws_s3_bucket.my_bucket: Creation complete after 3s [id=my-unique-bucket-name]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
bucket_arn = "arn:aws:s3:::my-unique-bucket-name"
bucket_id = "my-unique-bucket-name"
自动批准(谨慎使用):
terraform apply -auto-approve
四、配置文件语法
4.1 HCL (HashiCorp Configuration Language)
Terraform 使用 HCL 语言编写配置文件。
基本语法
# 单行注释
/*
多行注释
*/
# 1. 块 (Block)
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t2.micro"
}
# 2. 参数 (Argument)
name = "value"
# 3. 表达式 (Expression)
instance_count = 2 + 3
region = var.aws_region
4.2 数据类型
# 字符串 (String)
name = "my-bucket"
# 数字 (Number)
port = 8080
# 布尔值 (Bool)
enabled = true
# 列表 (List)
availability_zones = ["us-west-2a", "us-west-2b", "us-west-2c"]
# 映射 (Map)
tags = {
Name = "MyServer"
Environment = "Production"
}
# 对象 (Object)
instance_config = {
instance_type = "t2.micro"
ami = "ami-12345678"
tags = {
Name = "WebServer"
}
}
4.3 引用和插值
# 引用资源属性
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t2.micro"
}
resource "aws_eip" "web_ip" {
instance = aws_instance.web.id # 引用上面的实例 ID
}
# 引用变量
resource "aws_s3_bucket" "data" {
bucket = var.bucket_name # 引用变量
}
# 字符串插值
resource "aws_s3_bucket" "logs" {
bucket = "${var.project_name}-logs-${var.environment}"
# 结果可能是: "myproject-logs-prod"
}
# 引用数据源
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id # 使用查询到的 AMI ID
}
4.4 函数
Terraform 提供了丰富的内置函数:
# 字符串函数
upper("hello") # "HELLO"
lower("HELLO") # "hello"
join("-", ["a", "b"]) # "a-b"
split("-", "a-b-c") # ["a", "b", "c"]
# 数值函数
max(1, 2, 3) # 3
min(1, 2, 3) # 1
# 集合函数
length(["a", "b", "c"]) # 3
concat(["a"], ["b"]) # ["a", "b"]
contains(["a", "b"], "a") # true
# 日期函数
timestamp() # "2026-04-14T10:30:00Z"
# 文件系统函数
file("config.txt") # 读取文件内容
# 示例:在配置中使用函数
resource "aws_s3_bucket" "logs" {
bucket = lower("${var.project_name}-LOGS")
tags = merge(
var.common_tags,
{
Name = "Logs Bucket"
}
)
}
4.5 条件表达式
# 三元运算符
variable "environment" {
default = "dev"
}
resource "aws_instance" "web" {
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"
}
# 使用 count 实现条件创建
variable "create_bucket" {
type = bool
default = true
}
resource "aws_s3_bucket" "optional" {
count = var.create_bucket ? 1 : 0 # 如果为 true 则创建,否则不创建
bucket = "my-optional-bucket"
}
4.6 循环
# for_each:遍历 map 或 set
variable "users" {
default = {
"alice" = "admin"
"bob" = "user"
"carol" = "user"
}
}
resource "aws_iam_user" "users" {
for_each = var.users
name = each.key # "alice", "bob", "carol"
tags = {
Role = each.value # "admin", "user", "user"
}
}
# count:创建多个相同资源
resource "aws_instance" "web" {
count = 3
ami = "ami-12345678"
instance_type = "t2.micro"
tags = {
Name = "web-${count.index}" # web-0, web-1, web-2
}
}
# dynamic 块:动态生成嵌套块
variable "ingress_rules" {
default = [
{ port = 80, protocol = "tcp" },
{ port = 443, protocol = "tcp" },
]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ["0.0.0.0/0"]
}
}
}
五、状态管理
5.1 State 文件的作用
┌─────────────────────────────────────────────────────┐
│ Terraform 的三方对照 │
├─────────────────────────────────────────────────────┤
│ │
│ 配置文件 (.tf) State 文件 真实基础设施 │
│ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 期望状态 │ │ 记录状态 │ │ 实际状态 │ │
│ │ │ │ │ │ │ │
│ │ resource │ │ { │ │ AWS │ │
│ │ "aws_s3.. │◄─►│ "id":.. │◄────►│ 真实S3 │ │
│ │ bucket = │ │ "arn":..│ │ Bucket │ │
│ │ "mybkt" │ │ } │ │ │ │
│ └─────────────┘ └──────────┘ └──────────┘ │
│ │
│ terraform plan 对比这三者,生成执行计划 │
└─────────────────────────────────────────────────────┘
5.2 本地 State vs 远程 State
本地 State(默认)
# 不需要配置,默认存储在本地文件
# terraform.tfstate
优点:
- 简单,无需额外配置
- 适合个人学习和测试
缺点:
- ❌ 无法团队协作
- ❌ 容易丢失
- ❌ 无版本控制
- ❌ 无锁机制(多人同时操作会冲突)
远程 State(推荐)
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-state-lock" # 用于状态锁定
}
}
支持的 Backend 类型:
- S3(AWS):最常用
- Azure Blob Storage(Azure)
- GCS(Google Cloud)
- Terraform Cloud(HashiCorp 官方服务)
- Consul、etcd、HTTP 等
优点:
- ✅ 团队协作:多人共享同一 State
- ✅ 状态锁定:防止并发修改
- ✅ 加密存储:保护敏感信息
- ✅ 版本历史:可回滚
- ✅ 高可用:云服务的可靠性
5.3 State 锁定机制
用户 A DynamoDB 锁表 用户 B
│ │ │
│ terraform apply │ │
├──────────────────────────►│ │
│ 获取锁 ✓ │ │
│ │ │
│ 正在修改资源... │ │
│ │ terraform apply │
│ │◄───────────────────────┤
│ │ 等待锁释放... │
│ │ │
│ apply 完成 │ │
│ 释放锁 │ │
├──────────────────────────►│ │
│ │ 获取锁 ✓ │
│ ├───────────────────────►│
│ │ 开始修改资源 │
5.4 State 命令
# 查看 State 中的资源列表
terraform state list
# 查看特定资源的详细信息
terraform state show aws_s3_bucket.my_bucket
# 移除资源(不删除实际资源,只从 State 中移除)
terraform state rm aws_s3_bucket.my_bucket
# 移动资源(重命名)
terraform state mv aws_s3_bucket.old_name aws_s3_bucket.new_name
# 导入现有资源到 State
terraform import aws_s3_bucket.my_bucket my-existing-bucket
# 拉取远程 State 到本地
terraform state pull > terraform.tfstate.backup
# 推送本地 State 到远程(危险操作)
terraform state push terraform.tfstate
5.5 敏感信息处理
State 文件可能包含敏感信息(密码、密钥等):
# 标记敏感输出
output "db_password" {
value = aws_db_instance.main.password
sensitive = true # 不会在命令行输出中显示
}
最佳实践:
- ✅ 使用远程 Backend 并启用加密
- ✅ 限制 State 文件的访问权限
- ✅ 不要将 State 文件提交到 Git
- ✅ 使用 Vault 或 AWS Secrets Manager 管理敏感数据
六、Provider 系统
6.1 Provider 配置
# 指定所需的 Provider 版本
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 5.x 的任意版本
}
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.0" # 3.0 或更高版本
}
}
required_version = ">= 1.5.0" # Terraform 版本要求
}
# 配置 AWS Provider
provider "aws" {
region = "us-west-2"
access_key = var.aws_access_key
secret_key = var.aws_secret_key
}
6.2 多 Provider 实例(Alias)
在 Remote Backup 场景中很常见:
# 源账户的 Provider
provider "aws" {
alias = "source"
region = "us-west-2"
assume_role {
role_arn = "arn:aws:iam::111111111111:role/terraform"
}
}
# 目标账户的 Provider
provider "aws" {
alias = "destination"
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::222222222222:role/terraform"
}
}
# 在源账户创建 S3 桶
resource "aws_s3_bucket" "source_bucket" {
provider = aws.source
bucket = "source-backup-bucket"
}
# 在目标账户创建 S3 桶
resource "aws_s3_bucket" "destination_bucket" {
provider = aws.destination
bucket = "destination-backup-bucket"
}
# 配置跨账户复制
resource "aws_s3_bucket_replication_configuration" "replication" {
provider = aws.source
bucket = aws_s3_bucket.source_bucket.id
role = aws_iam_role.replication.arn
rule {
id = "replicate-to-remote"
status = "Enabled"
destination {
bucket = aws_s3_bucket.destination_bucket.arn
storage_class = "STANDARD"
}
}
}
6.3 常用 Provider
| Provider | 说明 | 示例资源 |
|---|---|---|
| aws | Amazon Web Services | aws_s3_bucket, aws_ec2_instance |
| azurerm | Microsoft Azure | azurerm_storage_account, azurerm_virtual_machine |
| Google Cloud Platform | google_storage_bucket, google_compute_instance |
|
| kubernetes | Kubernetes 集群 | kubernetes_deployment, kubernetes_service |
| helm | Helm Charts | helm_release |
| vault | HashiCorp Vault | vault_generic_secret |
| github | GitHub 仓库管理 | github_repository, github_team |
七、模块系统
7.1 什么是模块
模块是可复用的 Terraform 配置包。
项目结构:
.
├── main.tf
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── ec2/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── variables.tf
7.2 创建模块
# modules/s3-bucket/main.tf
variable "bucket_name" {
type = string
}
variable "environment" {
type = string
}
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
tags = {
Environment = var.environment
ManagedBy = "Terraform"
}
}
resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = "Enabled"
}
}
# modules/s3-bucket/outputs.tf
output "bucket_id" {
value = aws_s3_bucket.this.id
}
output "bucket_arn" {
value = aws_s3_bucket.this.arn
}
7.3 使用模块
# main.tf
module "app_logs_bucket" {
source = "./modules/s3-bucket"
bucket_name = "my-app-logs"
environment = "production"
}
module "data_backup_bucket" {
source = "./modules/s3-bucket"
bucket_name = "my-app-backups"
environment = "production"
}
# 引用模块的输出
output "logs_bucket_arn" {
value = module.app_logs_bucket.bucket_arn
}
7.4 远程模块
# 从 Terraform Registry 使用模块
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.1.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-west-2a", "us-west-2b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}
# 从 Git 仓库使用模块
module "remote_backup" {
source = "git::https://github.com/myorg/terraform-modules.git//remote-backup?ref=v1.2.0"
source_bucket = "primary-backups"
destination_bucket = "remote-backups"
}
7.5 模块最佳实践
模块设计原则:
├── 单一职责:每个模块只做一件事
├── 可配置:通过变量提供灵活性
├── 输出重要信息:方便其他模块或根配置使用
├── 文档化:提供 README 和示例
└── 版本化:使用 Git tag 管理版本
八、常用命令
8.1 核心命令
# 初始化项目
terraform init
# 格式化代码
terraform fmt
terraform fmt -recursive # 递归格式化所有目录
# 验证配置
terraform validate
# 查看执行计划
terraform plan
terraform plan -out=tfplan # 保存计划到文件
# 应用变更
terraform apply
terraform apply tfplan # 应用保存的计划
terraform apply -auto-approve # 跳过确认
# 销毁资源
terraform destroy
# 查看输出
terraform output
terraform output bucket_id # 查看特定输出
# 查看 Provider 文档
terraform providers
8.2 State 管理命令
# 列出 State 中的资源
terraform state list
# 查看资源详情
terraform state show aws_s3_bucket.my_bucket
# 移除资源
terraform state rm aws_s3_bucket.my_bucket
# 移动/重命名资源
terraform state mv aws_s3_bucket.old aws_s3_bucket.new
# 导入现有资源
terraform import aws_s3_bucket.my_bucket existing-bucket-name
# 刷新 State(同步真实状态)
terraform refresh
8.3 工作空间命令
工作空间用于管理多个环境(dev、staging、prod):
# 列出工作空间
terraform workspace list
# 创建新工作空间
terraform workspace new dev
terraform workspace new prod
# 切换工作空间
terraform workspace select prod
# 查看当前工作空间
terraform workspace show
# 删除工作空间
terraform workspace delete dev
使用场景:
resource "aws_instance" "web" {
instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
tags = {
Environment = terraform.workspace
}
}
8.4 调试命令
# 设置日志级别
export TF_LOG=DEBUG # TRACE, DEBUG, INFO, WARN, ERROR
export TF_LOG_PATH=terraform.log
# 查看 Provider 插件信息
terraform version
terraform providers schema
# 生成资源依赖图
terraform graph | dot -Tpng > graph.png
九、实际应用示例
9.1 完整的 AWS S3 + 复制示例
这是一个简化的 Remote Backup 配置:
# versions.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "remote-backup/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# providers.tf
provider "aws" {
alias = "source"
region = "us-west-2"
assume_role {
role_arn = var.source_account_role
}
}
provider "aws" {
alias = "destination"
region = "us-east-1"
assume_role {
role_arn = var.destination_account_role
}
}
# variables.tf
variable "source_account_role" {
description = "IAM role ARN for source account"
type = string
}
variable "destination_account_role" {
description = "IAM role ARN for destination account"
type = string
}
variable "backup_prefix" {
description = "Prefix for backup objects to replicate"
type = string
default = "databackup/"
}
# main.tf
# 源备份桶
resource "aws_s3_bucket" "source" {
provider = aws.source
bucket = "source-backup-bucket"
tags = {
Name = "Source Backup Bucket"
Purpose = "Remote Backup Source"
ManagedBy = "Terraform"
}
}
# 启用源桶版本控制
resource "aws_s3_bucket_versioning" "source" {
provider = aws.source
bucket = aws_s3_bucket.source.id
versioning_configuration {
status = "Enabled"
}
}
# 目标备份桶
resource "aws_s3_bucket" "destination" {
provider = aws.destination
bucket = "destination-backup-bucket"
tags = {
Name = "Destination Backup Bucket"
Purpose = "Remote Backup Destination"
ManagedBy = "Terraform"
}
}
# 启用目标桶版本控制
resource "aws_s3_bucket_versioning" "destination" {
provider = aws.destination
bucket = aws_s3_bucket.destination.id
versioning_configuration {
status = "Enabled"
}
}
# IAM 角色用于复制
resource "aws_iam_role" "replication" {
provider = aws.source
name = "s3-replication-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "s3.amazonaws.com"
}
}
]
})
}
# IAM 策略用于复制
resource "aws_iam_policy" "replication" {
provider = aws.source
name = "s3-replication-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"s3:GetReplicationConfiguration",
"s3:ListBucket"
]
Effect = "Allow"
Resource = aws_s3_bucket.source.arn
},
{
Action = [
"s3:GetObjectVersionForReplication",
"s3:GetObjectVersionAcl",
"s3:GetObjectVersionTagging"
]
Effect = "Allow"
Resource = "${aws_s3_bucket.source.arn}/*"
},
{
Action = [
"s3:ReplicateObject",
"s3:ReplicateTags"
]
Effect = "Allow"
Resource = "${aws_s3_bucket.destination.arn}/*"
}
]
})
}
# 附加策略到角色
resource "aws_iam_role_policy_attachment" "replication" {
provider = aws.source
role = aws_iam_role.replication.name
policy_arn = aws_iam_policy.replication.arn
}
# 配置 S3 复制规则
resource "aws_s3_bucket_replication_configuration" "replication" {
provider = aws.source
bucket = aws_s3_bucket.source.id
role = aws_iam_role.replication.arn
rule {
id = "replicate-backups"
status = "Enabled"
filter {
prefix = var.backup_prefix
}
delete_marker_replication {
status = "Disabled"
}
destination {
bucket = aws_s3_bucket.destination.arn
storage_class = "STANDARD"
metrics {
status = "Enabled"
}
}
}
depends_on = [
aws_s3_bucket_versioning.source,
aws_s3_bucket_versioning.destination
]
}
# 目标桶策略(允许源账户复制)
resource "aws_s3_bucket_policy" "destination" {
provider = aws.destination
bucket = aws_s3_bucket.destination.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowReplicationFromSource"
Effect = "Allow"
Principal = {
AWS = aws_iam_role.replication.arn
}
Action = [
"s3:ReplicateObject",
"s3:ReplicateTags"
]
Resource = "${aws_s3_bucket.destination.arn}/*"
}
]
})
}
# outputs.tf
output "source_bucket_id" {
description = "Source bucket ID"
value = aws_s3_bucket.source.id
}
output "destination_bucket_id" {
description = "Destination bucket ID"
value = aws_s3_bucket.destination.id
}
output "replication_role_arn" {
description = "Replication IAM role ARN"
value = aws_iam_role.replication.arn
}
9.2 使用方式
# 1. 创建变量文件
cat > terraform.tfvars <<EOF
source_account_role = "arn:aws:iam::111111111111:role/terraform"
destination_account_role = "arn:aws:iam::222222222222:role/terraform"
backup_prefix = "databackup/prod/"
EOF
# 2. 初始化
terraform init
# 3. 查看计划
terraform plan
# 4. 应用配置
terraform apply
# 5. 查看输出
terraform output
十、最佳实践
10.1 项目结构
推荐的目录结构:
terraform-project/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── terraform.tfvars
│ │ └── backend.tf
│ ├── staging/
│ │ └── ...
│ └── prod/
│ └── ...
│
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── README.md
│ ├── s3-bucket/
│ │ └── ...
│ └── ec2-instance/
│ └── ...
│
├── global/
│ ├── iam/
│ └── s3-backend/
│
├── .gitignore
└── README.md
10.2 命名规范
# 资源命名:使用下划线
resource "aws_s3_bucket" "backup_bucket" { # ✅
bucket = "my-backup-bucket"
}
resource "aws_s3_bucket" "backupBucket" { # ❌ 不要使用驼峰
bucket = "my-backup-bucket"
}
# 变量命名:描述性、使用下划线
variable "backup_retention_days" { # ✅
type = number
}
variable "x" { # ❌ 不清晰
type = number
}
# 模块命名:使用连字符
module "remote-backup-config" { # ✅
source = "./modules/remote-backup"
}
10.3 安全实践
# ❌ 不要硬编码敏感信息
provider "aws" {
access_key = "AKIAIOSFODNN7EXAMPLE" # 永远不要这样做!
secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
# ✅ 使用变量 + 环境变量
variable "aws_access_key" {
type = string
sensitive = true
}
provider "aws" {
access_key = var.aws_access_key
}
# 或者使用 AWS IAM Role(最佳实践)
provider "aws" {
assume_role {
role_arn = var.terraform_role_arn
}
}
10.4 .gitignore 配置
# .gitignore
# Terraform 状态文件
*.tfstate
*.tfstate.*
# Terraform 目录
.terraform/
.terraform.lock.hcl
# 变量文件(可能包含敏感信息)
*.tfvars
*.tfvars.json
# 崩溃日志
crash.log
# 本地变量覆盖
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# CLI 配置
.terraformrc
terraform.rc
10.5 版本控制
# ✅ 明确指定版本
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 允许 5.x 的任何版本
}
}
}
# ❌ 不指定版本(可能导致不兼容)
provider "aws" {}
10.6 文档化
# variables.tf
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "backup_retention_days" {
description = <<-EOT
Number of days to retain backups in the destination bucket.
Applies to both current and non-current versions.
Minimum: 1 day, Maximum: 365 days
EOT
type = number
default = 30
validation {
condition = var.backup_retention_days >= 1 && var.backup_retention_days <= 365
error_message = "Backup retention must be between 1 and 365 days."
}
}
10.7 测试
# 使用 terraform validate
terraform validate
# 使用 terraform plan 进行干运行
terraform plan
# 使用 terraform fmt 检查格式
terraform fmt -check -recursive
# 使用 tflint(第三方工具)
tflint
# 使用 terraform-compliance(行为驱动测试)
terraform-compliance -f compliance-tests/ -p tfplan
总结
Terraform 的核心优势
- 基础设施即代码:将基础设施配置版本化、可审查
- 多云支持:统一的语法管理不同云平台
- 状态管理:追踪和管理实际基础设施
- 执行计划:变更前预览,降低风险
- 模块化:提高代码复用性和可维护性
学习路径建议
初级 (1-2周)
├── 理解 IaC 概念
├── 掌握基本命令 (init, plan, apply, destroy)
├── 学习 HCL 语法
└── 完成简单的单资源部署
中级 (2-4周)
├── 掌握变量和输出
├── 理解 State 管理
├── 使用远程 Backend
├── 创建和使用模块
└── 多 Provider 配置
高级 (1-2个月)
├── 复杂的依赖管理
├── 动态块和高级函数
├── CI/CD 集成
├── 团队协作最佳实践
└── 安全和合规
专家级
├── 自定义 Provider 开发
├── 复杂的企业级架构
├── 性能优化
└── 故障排查和恢复
相关资源
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 木素音的小站!