Terraform 基础知识

目录

  1. 什么是 Terraform
  2. 核心概念
  3. 基本工作流程
  4. 配置文件语法
  5. 状态管理
  6. Provider 系统
  7. 模块系统
  8. 常用命令
  9. 实际应用示例
  10. 最佳实践

一、什么是 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:本地名称(在配置中引用用)
  • buckettags:资源参数

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 的作用

  1. 映射关系:配置 → 真实资源
  2. 元数据:记录资源间的依赖关系
  3. 性能优化:避免每次都查询所有资源
  4. 协作:团队成员共享基础设施状态

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!

做了什么

  1. 下载 Provider 插件到 .terraform/ 目录
  2. 初始化 Backend(State 存储位置)
  3. 创建依赖锁文件 .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 官方服务)
  • ConsuletcdHTTP

优点

  • ✅ 团队协作:多人共享同一 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  # 不会在命令行输出中显示
}

最佳实践

  1. ✅ 使用远程 Backend 并启用加密
  2. ✅ 限制 State 文件的访问权限
  3. ✅ 不要将 State 文件提交到 Git
  4. ✅ 使用 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 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. 多云支持:统一的语法管理不同云平台
  3. 状态管理:追踪和管理实际基础设施
  4. 执行计划:变更前预览,降低风险
  5. 模块化:提高代码复用性和可维护性

学习路径建议

初级 (1-2周)
├── 理解 IaC 概念
├── 掌握基本命令 (init, plan, apply, destroy)
├── 学习 HCL 语法
└── 完成简单的单资源部署

中级 (2-4周)
├── 掌握变量和输出
├── 理解 State 管理
├── 使用远程 Backend
├── 创建和使用模块
└── 多 Provider 配置

高级 (1-2个月)
├── 复杂的依赖管理
├── 动态块和高级函数
├── CI/CD 集成
├── 团队协作最佳实践
└── 安全和合规

专家级
├── 自定义 Provider 开发
├── 复杂的企业级架构
├── 性能优化
└── 故障排查和恢复

相关资源