terraform-infrastructure-as-code

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Terraform Infrastructure as Code - Comprehensive Guide

Terraform基础设施即代码 - 全面指南

Table of Contents

目录

Introduction to Terraform

Terraform简介

Terraform is an open-source Infrastructure as Code (IaC) tool created by HashiCorp that enables you to define and provision infrastructure using a declarative configuration language called HashiCorp Configuration Language (HCL). Terraform manages external resources such as public cloud infrastructure, private cloud infrastructure, network appliances, and software as a service.
Terraform是HashiCorp开发的开源基础设施即代码(IaC)工具,允许你使用名为HashiCorp配置语言(HCL)的声明式配置语言来定义和置备基础设施。Terraform可以管理外部资源,如公有云基础设施、私有云基础设施、网络设备以及软件即服务。

Key Benefits

核心优势

  • Declarative Configuration: Define what your infrastructure should look like, not how to create it
  • Cloud-Agnostic: Works with multiple cloud providers and services
  • Version Control: Infrastructure code can be versioned and reviewed
  • Plan Before Apply: Preview changes before applying them
  • Resource Graph: Automatically manages dependencies between resources
  • State Management: Tracks the current state of your infrastructure
  • 声明式配置:定义基础设施的目标状态,而非创建步骤
  • 跨云兼容:支持多个云提供商和服务
  • 版本控制:基础设施代码可进行版本控制和评审
  • 先规划后应用:在应用变更前预览效果
  • 资源图:自动管理资源之间的依赖关系
  • 状态管理:跟踪基础设施的当前状态

Terraform Workflow

Terraform工作流

bash
undefined
bash
undefined

Initialize Terraform working directory

初始化Terraform工作目录

terraform init
terraform init

Initialize and upgrade provider versions

初始化并升级提供商版本

terraform init -upgrade
terraform init -upgrade

Initialize with backend configuration

使用后端配置初始化

terraform init -backend-config="bucket=my-state-bucket"
terraform init -backend-config="bucket=my-state-bucket"

Generate a plan

生成执行计划

terraform plan
terraform plan

Save plan to file for later apply

将计划保存到文件以便后续应用

terraform plan -out=tfplan
terraform plan -out=tfplan

Plan with specific variable values

使用特定变量值生成计划

terraform plan -var="region=us-west-2" -var="instance_type=t2.micro"
terraform plan -var="region=us-west-2" -var="instance_type=t2.micro"

Apply with interactive approval

交互式确认后应用变更

terraform apply
terraform apply

Auto-approve without confirmation

自动批准无需确认

terraform apply -auto-approve
terraform apply -auto-approve

Apply a saved plan file

应用保存的计划文件

terraform apply tfplan
terraform apply tfplan

Destroy with confirmation prompt

带确认提示销毁资源

terraform destroy
terraform destroy

Auto-approve destruction

自动批准销毁

terraform destroy -auto-approve
undefined
terraform destroy -auto-approve
undefined

Core Concepts

核心概念

1. Resources

1. 资源

Resources are the most fundamental elements in Terraform. They represent infrastructure objects like virtual machines, networks, databases, or DNS records.
hcl
undefined
资源是Terraform中最基础的元素,代表虚拟机、网络、数据库或DNS记录等基础设施对象。
hcl
undefined

Basic resource declaration

基础资源声明

resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro"
tags = { Name = "WebServer" Environment = "production" } }
undefined
resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro"
tags = { Name = "WebServer" Environment = "production" } }
undefined

2. Providers

2. 提供商

Providers are plugins that allow Terraform to interact with cloud platforms, SaaS providers, and other APIs.
hcl
undefined
提供商是允许Terraform与云平台、SaaS提供商及其他API交互的插件。
hcl
undefined

AWS provider configuration

AWS提供商配置

provider "aws" { region = "us-west-2"
default_tags { tags = { ManagedBy = "Terraform" Project = "MyApp" } } }
undefined
provider "aws" { region = "us-west-2"
default_tags { tags = { ManagedBy = "Terraform" Project = "MyApp" } } }
undefined

3. State

3. 状态

Terraform stores information about your infrastructure in a state file. This state is used to map real-world resources to your configuration and track metadata.
Terraform将基础设施的信息存储在状态文件中,该状态用于将现实世界的资源映射到你的配置并跟踪元数据。

4. Configuration Language (HCL)

4. 配置语言(HCL)

HCL is designed to be both human-readable and machine-friendly, making it ideal for infrastructure configuration.
HCL设计为兼具人类可读性和机器友好性,非常适合基础设施配置。

Resources

资源

Resources are the building blocks of Terraform configurations. Each resource block describes one or more infrastructure objects.
资源是Terraform配置的构建块,每个资源块描述一个或多个基础设施对象。

Basic Resource Syntax

基础资源语法

hcl
resource "resource_type" "resource_name" {
  argument1 = "value1"
  argument2 = "value2"

  nested_block {
    nested_argument = "nested_value"
  }
}
hcl
resource "resource_type" "resource_name" {
  argument1 = "value1"
  argument2 = "value2"

  nested_block {
    nested_argument = "nested_value"
  }
}

Resource Examples

资源示例

AWS EC2 Instance

AWS EC2实例

hcl
resource "aws_instance" "app_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  key_name      = "my-keypair"

  vpc_security_group_ids = [aws_security_group.app.id]
  subnet_id              = aws_subnet.public.id

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, World!" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

  tags = {
    Name        = "AppServer"
    Environment = "production"
    ManagedBy   = "Terraform"
  }
}
hcl
resource "aws_instance" "app_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  key_name      = "my-keypair"

  vpc_security_group_ids = [aws_security_group.app.id]
  subnet_id              = aws_subnet.public.id

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, World!" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

  tags = {
    Name        = "AppServer"
    Environment = "production"
    ManagedBy   = "Terraform"
  }
}

AWS VPC

AWS VPC

hcl
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "main-vpc"
  }
}

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-west-2a"
  map_public_ip_on_launch = true

  tags = {
    Name = "public-subnet"
  }
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-west-2a"

  tags = {
    Name = "private-subnet"
  }
}
hcl
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "main-vpc"
  }
}

resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-west-2a"
  map_public_ip_on_launch = true

  tags = {
    Name = "public-subnet"
  }
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-west-2a"

  tags = {
    Name = "private-subnet"
  }
}

AWS S3 Bucket

AWS S3存储桶

hcl
resource "aws_s3_bucket" "data" {
  bucket = "my-app-data-bucket-12345"

  tags = {
    Name        = "Data Bucket"
    Environment = "production"
  }
}

resource "aws_s3_bucket_versioning" "data" {
  bucket = aws_s3_bucket.data.id

  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
  bucket = aws_s3_bucket.data.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}
hcl
resource "aws_s3_bucket" "data" {
  bucket = "my-app-data-bucket-12345"

  tags = {
    Name        = "Data Bucket"
    Environment = "production"
  }
}

resource "aws_s3_bucket_versioning" "data" {
  bucket = aws_s3_bucket.data.id

  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
  bucket = aws_s3_bucket.data.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

AWS Security Group

AWS安全组

hcl
resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Security group for web servers"
  vpc_id      = aws_vpc.main.id

  ingress {
    description = "HTTP from anywhere"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTPS from anywhere"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web-security-group"
  }
}
hcl
resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Security group for web servers"
  vpc_id      = aws_vpc.main.id

  ingress {
    description = "HTTP from anywhere"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "HTTPS from anywhere"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web-security-group"
  }
}

Resource Lifecycle

资源生命周期

hcl
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  lifecycle {
    create_before_destroy = true
    prevent_destroy       = true
    ignore_changes        = [tags]
  }
}
Lifecycle options:
  • create_before_destroy
    : Create new resource before destroying the old one
  • prevent_destroy
    : Prevent accidental destruction of resources
  • ignore_changes
    : Ignore changes to specified attributes
  • replace_triggered_by
    : Force replacement when specific resources change
hcl
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  lifecycle {
    replace_triggered_by = [
      aws_iam_policy.example.id
    ]
  }
}
hcl
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  lifecycle {
    create_before_destroy = true
    prevent_destroy       = true
    ignore_changes        = [tags]
  }
}
生命周期选项:
  • create_before_destroy
    : 创建新资源后再销毁旧资源
  • prevent_destroy
    : 防止意外销毁资源
  • ignore_changes
    : 忽略指定属性的变更
  • replace_triggered_by
    : 当特定资源变更时强制替换当前资源
hcl
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  lifecycle {
    replace_triggered_by = [
      aws_iam_policy.example.id
    ]
  }
}

Data Sources

数据源

Data sources allow Terraform to use information defined outside of Terraform, or defined by another separate Terraform configuration.
数据源允许Terraform使用Terraform外部定义的信息,或由其他独立Terraform配置定义的信息。

Data Source Syntax

数据源语法

hcl
data "resource_type" "name" {
  # Query parameters
}
hcl
data "resource_type" "name" {
  # 查询参数
}

Data Source Examples

数据源示例

hcl
undefined
hcl
undefined

Query existing AWS resources

查询现有AWS资源

data "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical
filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] } }
data "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical
filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] } }

Use data source in resource

在资源中使用数据源

resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id instance_type = "t2.micro" }
resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id instance_type = "t2.micro" }

Query availability zones

查询可用区

data "aws_availability_zones" "available" { state = "available" }
data "aws_availability_zones" "available" { state = "available" }

Query VPC

查询VPC

data "aws_vpc" "default" { default = true }
data "aws_vpc" "default" { default = true }

Query remote state

查询远程状态

data "terraform_remote_state" "network" { backend = "s3"
config = { bucket = "terraform-state" key = "network/terraform.tfstate" region = "us-west-2" } }
data "terraform_remote_state" "network" { backend = "s3"
config = { bucket = "terraform-state" key = "network/terraform.tfstate" region = "us-west-2" } }

Use remote state outputs

使用远程状态输出

resource "aws_instance" "app" { ami = data.aws_ami.ubuntu.id instance_type = "t2.micro" subnet_id = data.terraform_remote_state.network.outputs.subnet_id
availability_zone = data.aws_availability_zones.available.names[0] }
undefined
resource "aws_instance" "app" { ami = data.aws_ami.ubuntu.id instance_type = "t2.micro" subnet_id = data.terraform_remote_state.network.outputs.subnet_id
availability_zone = data.aws_availability_zones.available.names[0] }
undefined

Common Data Sources

常见数据源

hcl
undefined
hcl
undefined

AWS Account ID

AWS账户ID

data "aws_caller_identity" "current" {}
output "account_id" { value = data.aws_caller_identity.current.account_id }
data "aws_caller_identity" "current" {}
output "account_id" { value = data.aws_caller_identity.current.account_id }

AWS Region

AWS区域

data "aws_region" "current" {}
output "region" { value = data.aws_region.current.name }
data "aws_region" "current" {}
output "region" { value = data.aws_region.current.name }

Route53 Zone

Route53区域

data "aws_route53_zone" "primary" { name = "example.com" }
data "aws_route53_zone" "primary" { name = "example.com" }

IAM Policy Document

IAM策略文档

data "aws_iam_policy_document" "assume_role" { statement { actions = ["sts:AssumeRole"]
principals {
  type        = "Service"
  identifiers = ["ec2.amazonaws.com"]
}
} }
undefined
data "aws_iam_policy_document" "assume_role" { statement { actions = ["sts:AssumeRole"]
principals {
  type        = "Service"
  identifiers = ["ec2.amazonaws.com"]
}
} }
undefined

Variables and Outputs

变量与输出

Input Variables

输入变量

Variables allow you to parameterize your configurations for reusability.
hcl
undefined
变量允许你将配置参数化以实现复用。
hcl
undefined

Simple variable

简单变量

variable "region" { type = string default = "us-west-2" description = "AWS region for resources" }
variable "region" { type = string default = "us-west-2" description = "AWS资源所在区域" }

Variable with validation

带验证的变量

variable "instance_type" { type = string default = "t2.micro"
validation { condition = contains(["t2.micro", "t2.small", "t2.medium"], var.instance_type) error_message = "Instance type must be t2.micro, t2.small, or t2.medium." } }
variable "instance_type" { type = string default = "t2.micro"
validation { condition = contains(["t2.micro", "t2.small", "t2.medium"], var.instance_type) error_message = "实例类型必须是t2.micro、t2.small或t2.medium。" } }

Complex type variable

复杂类型变量

variable "vpc_config" { type = object({ cidr_block = string azs = list(string) private_subnets = list(string) public_subnets = list(string) })
default = { cidr_block = "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"] } }
undefined
variable "vpc_config" { type = object({ cidr_block = string azs = list(string) private_subnets = list(string) public_subnets = list(string) })
default = { cidr_block = "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"] } }
undefined

Variable Types

变量类型

hcl
undefined
hcl
undefined

String variable

字符串变量

variable "environment" { type = string default = "development" }
variable "environment" { type = string default = "development" }

Number variable

数字变量

variable "instance_count" { type = number default = 3 }
variable "instance_count" { type = number default = 3 }

Boolean variable

布尔变量

variable "enable_monitoring" { type = bool default = true }
variable "enable_monitoring" { type = bool default = true }

List variable

列表变量

variable "availability_zones" { type = list(string) default = ["us-west-2a", "us-west-2b", "us-west-2c"] }
variable "availability_zones" { type = list(string) default = ["us-west-2a", "us-west-2b", "us-west-2c"] }

Map variable

映射变量

variable "ami_ids" { type = map(string) default = { us-west-2 = "ami-0c55b159cbfafe1f0" us-east-1 = "ami-0b69ea66ff7391e80" } }
variable "ami_ids" { type = map(string) default = { us-west-2 = "ami-0c55b159cbfafe1f0" us-east-1 = "ami-0b69ea66ff7391e80" } }

Object variable

对象变量

variable "database_config" { type = object({ engine = string engine_version = string instance_class = string allocated_storage = number })
default = { engine = "postgres" engine_version = "13.7" instance_class = "db.t3.micro" allocated_storage = 20 } }
undefined
variable "database_config" { type = object({ engine = string engine_version = string instance_class = string allocated_storage = number })
default = { engine = "postgres" engine_version = "13.7" instance_class = "db.t3.micro" allocated_storage = 20 } }
undefined

Setting Variables

设置变量

bash
undefined
bash
undefined

Command line

命令行设置

terraform apply -var="region=us-east-1" -var="instance_count=5"
terraform apply -var="region=us-east-1" -var="instance_count=5"

Variable files

变量文件

terraform apply -var-file="production.tfvars"
terraform apply -var-file="production.tfvars"

Environment variables

环境变量

export TF_VAR_region=us-east-1 terraform apply

**terraform.tfvars:**
```hcl
region         = "us-west-2"
instance_count = 3
environment    = "production"
export TF_VAR_region=us-east-1 terraform apply

**terraform.tfvars:**
```hcl
region         = "us-west-2"
instance_count = 3
environment    = "production"

Output Values

输出值

Outputs make information about your infrastructure available for other configurations or display to users.
hcl
undefined
输出值可将基础设施信息提供给其他配置或展示给用户。
hcl
undefined

Simple output

简单输出

output "instance_ip" { value = aws_instance.web.public_ip description = "The public IP of the web server" }
output "instance_ip" { value = aws_instance.web.public_ip description = "Web服务器的公网IP" }

Output with sensitive data

敏感数据输出

output "database_password" { value = aws_db_instance.main.password sensitive = true }
output "database_password" { value = aws_db_instance.main.password sensitive = true }

Complex output

复杂输出

output "instance_details" { value = { id = aws_instance.web.id public_ip = aws_instance.web.public_ip private_ip = aws_instance.web.private_ip arn = aws_instance.web.arn } description = "Complete instance information" }
output "instance_details" { value = { id = aws_instance.web.id public_ip = aws_instance.web.public_ip private_ip = aws_instance.web.private_ip arn = aws_instance.web.arn } description = "完整的实例信息" }

Output with depends_on

带依赖的输出

output "vpc_ready" { value = "VPC and subnets are ready" depends_on = [ aws_vpc.main, aws_subnet.private, aws_subnet.public ] }
undefined
output "vpc_ready" { value = "VPC和子网已就绪" depends_on = [ aws_vpc.main, aws_subnet.private, aws_subnet.public ] }
undefined

Using Outputs

使用输出

bash
undefined
bash
undefined

Show all outputs

显示所有输出

terraform output
terraform output

Get specific output value

获取特定输出值

terraform output instance_ip
terraform output instance_ip

Output in JSON format

以JSON格式输出

terraform output -json
terraform output -json

Use output in scripts

在脚本中使用输出

INSTANCE_IP=$(terraform output -raw instance_ip) echo "Server IP: $INSTANCE_IP"
undefined
INSTANCE_IP=$(terraform output -raw instance_ip) echo "服务器IP: $INSTANCE_IP"
undefined

Local Values

本地值

Local values assign a name to an expression for reuse within a module.
hcl
locals {
  common_tags = {
    ManagedBy   = "Terraform"
    Environment = var.environment
    Project     = "MyApp"
  }

  name_prefix = "${var.project_name}-${var.environment}"

  availability_zones = slice(data.aws_availability_zones.available.names, 0, 3)
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  tags = merge(
    local.common_tags,
    {
      Name = "${local.name_prefix}-web-server"
    }
  )
}
本地值为表达式分配名称,以便在模块内复用。
hcl
locals {
  common_tags = {
    ManagedBy   = "Terraform"
    Environment = var.environment
    Project     = "MyApp"
  }

  name_prefix = "${var.project_name}-${var.environment}"

  availability_zones = slice(data.aws_availability_zones.available.names, 0, 3)
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  tags = merge(
    local.common_tags,
    {
      Name = "${local.name_prefix}-web-server"
    }
  )
}

Modules

模块

Modules are containers for multiple resources that are used together. They enable you to create reusable components.
模块是用于组合多个资源的容器,可帮助你创建可复用的组件。

Module Structure

模块结构

modules/
└── vpc/
    ├── main.tf
    ├── variables.tf
    ├── outputs.tf
    └── README.md
modules/
└── vpc/
    ├── main.tf
    ├── variables.tf
    ├── outputs.tf
    └── README.md

Creating a Module

创建模块

modules/vpc/main.tf:
hcl
resource "aws_vpc" "main" {
  cidr_block           = var.cidr_block
  enable_dns_hostnames = var.enable_dns_hostnames
  enable_dns_support   = var.enable_dns_support

  tags = merge(
    var.tags,
    {
      Name = var.name
    }
  )
}

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 = merge(
    var.tags,
    {
      Name = "${var.name}-public-${count.index + 1}"
      Type = "public"
    }
  )
}

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 = merge(
    var.tags,
    {
      Name = "${var.name}-private-${count.index + 1}"
      Type = "private"
    }
  )
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    var.tags,
    {
      Name = "${var.name}-igw"
    }
  )
}
modules/vpc/variables.tf:
hcl
variable "name" {
  description = "Name prefix for VPC resources"
  type        = string
}

variable "cidr_block" {
  description = "CIDR block for VPC"
  type        = string
}

variable "public_subnet_cidrs" {
  description = "CIDR blocks for public subnets"
  type        = list(string)
}

variable "private_subnet_cidrs" {
  description = "CIDR blocks for private subnets"
  type        = list(string)
}

variable "availability_zones" {
  description = "Availability zones for subnets"
  type        = list(string)
}

variable "enable_dns_hostnames" {
  description = "Enable DNS hostnames in VPC"
  type        = bool
  default     = true
}

variable "enable_dns_support" {
  description = "Enable DNS support in VPC"
  type        = bool
  default     = true
}

variable "tags" {
  description = "Tags to apply to resources"
  type        = map(string)
  default     = {}
}
modules/vpc/outputs.tf:
hcl
output "vpc_id" {
  description = "ID of the VPC"
  value       = aws_vpc.main.id
}

output "vpc_cidr" {
  description = "CIDR block of the VPC"
  value       = aws_vpc.main.cidr_block
}

output "public_subnet_ids" {
  description = "IDs of public subnets"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "IDs of private subnets"
  value       = aws_subnet.private[*].id
}

output "internet_gateway_id" {
  description = "ID of the internet gateway"
  value       = aws_internet_gateway.main.id
}
modules/vpc/main.tf:
hcl
resource "aws_vpc" "main" {
  cidr_block           = var.cidr_block
  enable_dns_hostnames = var.enable_dns_hostnames
  enable_dns_support   = var.enable_dns_support

  tags = merge(
    var.tags,
    {
      Name = var.name
    }
  )
}

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 = merge(
    var.tags,
    {
      Name = "${var.name}-public-${count.index + 1}"
      Type = "public"
    }
  )
}

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 = merge(
    var.tags,
    {
      Name = "${var.name}-private-${count.index + 1}"
      Type = "private"
    }
  )
}

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = merge(
    var.tags,
    {
      Name = "${var.name}-igw"
    }
  )
}
modules/vpc/variables.tf:
hcl
variable "name" {
  description = "VPC资源的名称前缀"
  type        = string
}

variable "cidr_block" {
  description = "VPC的CIDR块"
  type        = string
}

variable "public_subnet_cidrs" {
  description = "公有子网的CIDR块"
  type        = list(string)
}

variable "private_subnet_cidrs" {
  description = "私有子网的CIDR块"
  type        = list(string)
}

variable "availability_zones" {
  description = "子网所在的可用区"
  type        = list(string)
}

variable "enable_dns_hostnames" {
  description = "在VPC中启用DNS主机名"
  type        = bool
  default     = true
}

variable "enable_dns_support" {
  description = "在VPC中启用DNS支持"
  type        = bool
  default     = true
}

variable "tags" {
  description = "应用于资源的标签"
  type        = map(string)
  default     = {}
}
modules/vpc/outputs.tf:
hcl
output "vpc_id" {
  description = "VPC的ID"
  value       = aws_vpc.main.id
}

output "vpc_cidr" {
  description = "VPC的CIDR块"
  value       = aws_vpc.main.cidr_block
}

output "public_subnet_ids" {
  description = "公有子网的ID"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "私有子网的ID"
  value       = aws_subnet.private[*].id
}

output "internet_gateway_id" {
  description = "互联网网关的ID"
  value       = aws_internet_gateway.main.id
}

Using Modules

使用模块

hcl
undefined
hcl
undefined

Using a module from local path

使用本地路径的模块

module "vpc" { source = "./modules/vpc"
cidr_block = "10.0.0.0/16" region = var.region
tags = { Environment = "production" ManagedBy = "terraform" } }
module "vpc" { source = "./modules/vpc"
cidr_block = "10.0.0.0/16" region = var.region
tags = { Environment = "production" ManagedBy = "terraform" } }

Using a module from Terraform Registry

使用Terraform Registry中的模块

module "s3_bucket" { source = "terraform-aws-modules/s3-bucket/aws" version = "3.15.0"
bucket = "my-application-bucket" acl = "private"
versioning = { enabled = true } }
module "s3_bucket" { source = "terraform-aws-modules/s3-bucket/aws" version = "3.15.0"
bucket = "my-application-bucket" acl = "private"
versioning = { enabled = true } }

Using module outputs

使用模块输出

resource "aws_instance" "app" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" subnet_id = module.vpc.private_subnet_ids[0]
tags = { Name = "App Server" } }
resource "aws_instance" "app" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" subnet_id = module.vpc.private_subnet_ids[0]
tags = { Name = "App Server" } }

Module with count

带count的模块

module "web_servers" { count = 3 source = "./modules/web-server"
name = "web-${count.index}" subnet = module.vpc.public_subnet_ids[count.index] }
module "web_servers" { count = 3 source = "./modules/web-server"
name = "web-${count.index}" subnet = module.vpc.public_subnet_ids[count.index] }

Module with for_each

带for_each的模块

module "environments" { for_each = toset(["dev", "staging", "prod"]) source = "./modules/environment"
env_name = each.key vpc_cidr = "10.${index(["dev", "staging", "prod"], each.key)}.0.0/16" }
undefined
module "environments" { for_each = toset(["dev", "staging", "prod"]) source = "./modules/environment"
env_name = each.key vpc_cidr = "10.${index(["dev", "staging", "prod"], each.key)}.0.0/16" }
undefined

Module Sources

模块源

hcl
undefined
hcl
undefined

Local path

本地路径

module "vpc" { source = "./modules/vpc" }
module "vpc" { source = "./modules/vpc" }

Terraform Registry

Terraform Registry

module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.1.0" }
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.1.0" }

GitHub

GitHub

module "vpc" { source = "github.com/terraform-aws-modules/terraform-aws-vpc" }
module "vpc" { source = "github.com/terraform-aws-modules/terraform-aws-vpc" }

GitHub with specific branch

指定分支的GitHub

module "vpc" { source = "github.com/terraform-aws-modules/terraform-aws-vpc?ref=v5.1.0" }
module "vpc" { source = "github.com/terraform-aws-modules/terraform-aws-vpc?ref=v5.1.0" }

Git

Git

S3 bucket

S3存储桶

undefined
undefined

Module Versioning

模块版本控制

hcl
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"  # Any version 5.x
}

module "s3" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = ">= 3.0, < 4.0"  # Between 3.0 and 4.0
}
hcl
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"  # 任何5.x版本
}

module "s3" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = ">= 3.0, < 4.0"  # 3.0到4.0之间的版本
}

State Management

状态管理

Terraform state is a critical component that maps your configuration to real-world resources.
Terraform状态是将配置映射到现实世界资源的关键组件。

Local State

本地状态

By default, Terraform stores state locally in a file named
terraform.tfstate
.
hcl
terraform {
  backend "local" {
    path = "terraform.tfstate"
  }
}
默认情况下,Terraform将状态本地存储在名为
terraform.tfstate
的文件中。
hcl
terraform {
  backend "local" {
    path = "terraform.tfstate"
  }
}

Remote State

远程状态

Remote state enables team collaboration and provides better security and reliability.
远程状态支持团队协作,并提供更好的安全性和可靠性。

S3 Backend

S3后端

hcl
undefined
hcl
undefined

S3 backend configuration

S3后端配置

terraform { backend "s3" { bucket = "my-terraform-state" key = "production/terraform.tfstate" region = "us-west-2" encrypt = true dynamodb_table = "terraform-locks" } }

**Setup DynamoDB for state locking:**
```hcl
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }

  tags = {
    Name = "Terraform State Lock Table"
  }
}
terraform { backend "s3" { bucket = "my-terraform-state" key = "production/terraform.tfstate" region = "us-west-2" encrypt = true dynamodb_table = "terraform-locks" } }

**设置DynamoDB用于状态锁定:**
```hcl
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }

  tags = {
    Name = "Terraform状态锁定表"
  }
}

Azure Backend

Azure后端

hcl
terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-rg"
    storage_account_name = "tfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
  }
}
hcl
terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-rg"
    storage_account_name = "tfstate"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
  }
}

Terraform Cloud Backend

Terraform Cloud后端

hcl
terraform {
  cloud {
    organization = "my-organization"

    workspaces {
      name = "production"
    }
  }
}
hcl
terraform {
  cloud {
    organization = "my-organization"

    workspaces {
      name = "production"
    }
  }
}

Consul Backend

Consul后端

hcl
terraform {
  backend "consul" {
    address = "consul.example.com:8500"
    scheme  = "https"
    path    = "terraform/production"
  }
}
hcl
terraform {
  backend "consul" {
    address = "consul.example.com:8500"
    scheme  = "https"
    path    = "terraform/production"
  }
}

State Commands

状态命令

bash
undefined
bash
undefined

List all resources in state

列出状态中的所有资源

terraform state list
terraform state list

Show specific resource details

显示特定资源的详细信息

terraform state show aws_instance.example
terraform state show aws_instance.example

Remove resource from state (doesn't destroy)

从状态中移除资源(不销毁)

terraform state rm aws_instance.example
terraform state rm aws_instance.example

Move resource to new address

将资源移动到新地址

terraform state mv aws_instance.example aws_instance.web_server
terraform state mv aws_instance.example aws_instance.web_server

Show current state

显示当前状态

terraform show
terraform show

Show specific plan file

显示特定计划文件

terraform show tfplan
terraform show tfplan

Output state in JSON format

以JSON格式输出状态

terraform show -json > state.json
terraform show -json > state.json

Pull remote state

拉取远程状态

terraform state pull > terraform.tfstate
terraform state pull > terraform.tfstate

Push local state to remote

将本地状态推送到远程

terraform state push terraform.tfstate
undefined
terraform state push terraform.tfstate
undefined

State Locking

状态锁定

State locking prevents concurrent operations that could corrupt your state.
hcl
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}
状态锁定可防止并发操作导致状态损坏。
hcl
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}

Importing Existing Resources

导入现有资源

bash
undefined
bash
undefined

Import AWS instance

导入AWS实例

terraform import aws_instance.example i-0abc123def456
terraform import aws_instance.example i-0abc123def456

Import with module

导入模块中的资源

terraform import module.network.aws_vpc.main vpc-0123456789abcdef

**Configuration needed before import:**
```hcl
resource "aws_instance" "example" {
  # Configuration will be populated after import
  # Define the basic structure matching the resource
}
terraform import module.network.aws_vpc.main vpc-0123456789abcdef

**导入前需要的配置:**
```hcl
resource "aws_instance" "example" {
  # 导入后会填充配置
  # 定义与资源匹配的基本结构
}

State Migration

状态迁移

bash
undefined
bash
undefined

Initialize with backend

使用后端初始化

terraform init
terraform init

Migrate from local to remote

从本地迁移到远程

terraform init -migrate-state
terraform init -migrate-state

Backend configuration from CLI

从命令行指定后端配置

terraform init -backend-config="bucket=my-other-bucket"
-backend-config="key=my-state"
undefined
terraform init -backend-config="bucket=my-other-bucket"
-backend-config="key=my-state"
undefined

Workspaces

工作区

Workspaces allow you to manage multiple instances of a single configuration.
工作区允许你管理单个配置的多个实例。

Workspace Commands

工作区命令

bash
undefined
bash
undefined

List workspaces

列出工作区

terraform workspace list
terraform workspace list

Create new workspace

创建新工作区

terraform workspace new production
terraform workspace new production

Switch to workspace

切换工作区

terraform workspace select staging
terraform workspace select staging

Show current workspace

显示当前工作区

terraform workspace show
terraform workspace show

Delete workspace

删除工作区

terraform workspace delete development
undefined
terraform workspace delete development
undefined

Workspace Workflow

工作区工作流

bash
undefined
bash
undefined

Example workflow:

示例工作流:

terraform workspace new development terraform apply # Creates resources in development workspace
terraform workspace new staging terraform apply # Creates separate resources in staging workspace
terraform workspace new production terraform apply # Creates separate resources in production workspace
undefined
terraform workspace new development terraform apply # 在development工作区创建资源
terraform workspace new staging terraform apply # 在staging工作区创建独立资源
terraform workspace new production terraform apply # 在production工作区创建独立资源
undefined

Using Workspace in Configuration

在配置中使用工作区

hcl
locals {
  environment = terraform.workspace
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = terraform.workspace == "production" ? "t3.large" : "t3.micro"

  tags = {
    Name        = "web-${terraform.workspace}"
    Environment = terraform.workspace
  }
}
hcl
locals {
  environment = terraform.workspace
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = terraform.workspace == "production" ? "t3.large" : "t3.micro"

  tags = {
    Name        = "web-${terraform.workspace}"
    Environment = terraform.workspace
  }
}

Workspace-specific variables

工作区特定变量

variable "instance_counts" { type = map(number) default = { development = 1 staging = 2 production = 5 } }
resource "aws_instance" "app" { count = var.instance_counts[terraform.workspace]
ami = var.ami_id instance_type = "t3.micro"
tags = { Name = "app-${terraform.workspace}-${count.index + 1}" } }
undefined
variable "instance_counts" { type = map(number) default = { development = 1 staging = 2 production = 5 } }
resource "aws_instance" "app" { count = var.instance_counts[terraform.workspace]
ami = var.ami_id instance_type = "t3.micro"
tags = { Name = "app-${terraform.workspace}-${count.index + 1}" } }
undefined

Workspace State Isolation

工作区状态隔离

Each workspace has its own state file:
  • terraform.tfstate.d/development/terraform.tfstate
  • terraform.tfstate.d/staging/terraform.tfstate
  • terraform.tfstate.d/production/terraform.tfstate
每个工作区都有自己的状态文件:
  • terraform.tfstate.d/development/terraform.tfstate
  • terraform.tfstate.d/staging/terraform.tfstate
  • terraform.tfstate.d/production/terraform.tfstate

Provider Configuration

提供商配置

Providers are plugins that enable Terraform to interact with cloud platforms and other services.
提供商是使Terraform能够与云平台和其他服务交互的插件。

Single Provider

单个提供商

hcl
terraform {
  required_version = ">= 1.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region

  default_tags {
    tags = {
      ManagedBy = "Terraform"
      Project   = "MyApp"
    }
  }
}
hcl
terraform {
  required_version = ">= 1.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region

  default_tags {
    tags = {
      ManagedBy = "Terraform"
      Project   = "MyApp"
    }
  }
}

Multiple Provider Instances (Aliases)

多个提供商实例(别名)

hcl
provider "aws" {
  alias  = "east"
  region = "us-east-1"
}

provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

resource "aws_instance" "east_server" {
  provider = aws.east

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

resource "aws_instance" "west_server" {
  provider = aws.west

  ami           = "ami-0123456789abcdef"
  instance_type = "t2.micro"
}
hcl
provider "aws" {
  alias  = "east"
  region = "us-east-1"
}

provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

resource "aws_instance" "east_server" {
  provider = aws.east

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

resource "aws_instance" "west_server" {
  provider = aws.west

  ami           = "ami-0123456789abcdef"
  instance_type = "t2.micro"
}

Multi-Cloud Setup

多云设置

hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}

provider "azurerm" {
  features {}
  subscription_id = var.azure_subscription_id
}

provider "google" {
  project = var.gcp_project_id
  region  = "us-central1"
}
hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}

provider "azurerm" {
  features {}
  subscription_id = var.azure_subscription_id
}

provider "google" {
  project = var.gcp_project_id
  region  = "us-central1"
}

AWS resources

AWS资源

resource "aws_s3_bucket" "data" { bucket = "my-data-bucket" }
resource "aws_s3_bucket" "data" { bucket = "my-data-bucket" }

Azure resources

Azure资源

resource "azurerm_storage_account" "data" { name = "mydatastorageacct" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location account_tier = "Standard" account_replication_type = "LRS" }
resource "azurerm_storage_account" "data" { name = "mydatastorageacct" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location account_tier = "Standard" account_replication_type = "LRS" }

GCP resources

GCP资源

resource "google_storage_bucket" "data" { name = "my-data-bucket-gcp" location = "US" }
undefined
resource "google_storage_bucket" "data" { name = "my-data-bucket-gcp" location = "US" }
undefined

Provider Configuration in Modules

模块中的提供商配置

hcl
undefined
hcl
undefined

Root module

根模块

provider "aws" { region = "us-west-2" }
provider "aws" { alias = "dr" region = "us-east-1" }
module "app" { source = "./modules/app"
providers = { aws = aws aws.dr = aws.dr } }

**Module configuration:**
```hcl
provider "aws" { region = "us-west-2" }
provider "aws" { alias = "dr" region = "us-east-1" }
module "app" { source = "./modules/app"
providers = { aws = aws aws.dr = aws.dr } }

**模块配置:**
```hcl

modules/app/main.tf

modules/app/main.tf

terraform { required_providers { aws = { source = "hashicorp/aws" configuration_aliases = [aws.dr] } } }
resource "aws_instance" "primary" { provider = aws

...

}
resource "aws_instance" "dr" { provider = aws.dr

...

}
undefined
terraform { required_providers { aws = { source = "hashicorp/aws" configuration_aliases = [aws.dr] } } }
resource "aws_instance" "primary" { provider = aws

...

}
resource "aws_instance" "dr" { provider = aws.dr

...

}
undefined

Advanced Features

高级功能

Dynamic Blocks

动态块

Dynamic blocks allow you to dynamically construct repeatable nested blocks.
hcl
variable "ingress_rules" {
  type = list(object({
    description = string
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))

  default = [
    {
      description = "HTTP"
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      description = "HTTPS"
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}

resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Security group for web servers"
  vpc_id      = aws_vpc.main.id

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      description = ingress.value.description
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
动态块允许你动态构建可重复的嵌套块。
hcl
variable "ingress_rules" {
  type = list(object({
    description = string
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))

  default = [
    {
      description = "HTTP"
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      description = "HTTPS"
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  ]
}

resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Web服务器安全组"
  vpc_id      = aws_vpc.main.id

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      description = ingress.value.description
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

For_Each Meta-Argument

For_Each元参数

hcl
resource "aws_s3_bucket" "buckets" {
  for_each = toset(["logs", "data", "backups"])

  bucket = "my-app-${each.key}"

  tags = {
    Purpose = each.key
  }
}
hcl
resource "aws_s3_bucket" "buckets" {
  for_each = toset(["logs", "data", "backups"])

  bucket = "my-app-${each.key}"

  tags = {
    Purpose = each.key
  }
}

With map

配合映射使用

variable "instances" { type = map(object({ ami = string instance_type = string }))
default = { web = { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro" } app = { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.small" } } }
resource "aws_instance" "servers" { for_each = var.instances
ami = each.value.ami instance_type = each.value.instance_type
tags = { Name = each.key } }
undefined
variable "instances" { type = map(object({ ami = string instance_type = string }))
default = { web = { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro" } app = { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.small" } } }
resource "aws_instance" "servers" { for_each = var.instances
ami = each.value.ami instance_type = each.value.instance_type
tags = { Name = each.key } }
undefined

Count Meta-Argument

Count元参数

hcl
resource "aws_instance" "servers" {
  count = 3

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = {
    Name = "server-${count.index}"
  }
}
hcl
resource "aws_instance" "servers" {
  count = 3

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = {
    Name = "server-${count.index}"
  }
}

Conditional resource creation

条件式资源创建

variable "create_db" { type = bool default = true }
resource "aws_db_instance" "database" { count = var.create_db ? 1 : 0
engine = "postgres" instance_class = "db.t3.micro" allocated_storage = 20 }
undefined
variable "create_db" { type = bool default = true }
resource "aws_db_instance" "database" { count = var.create_db ? 1 : 0
engine = "postgres" instance_class = "db.t3.micro" allocated_storage = 20 }
undefined

Conditional Expressions

条件表达式

hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.environment == "production" ? "t3.large" : "t3.micro"

  tags = {
    Name = var.environment == "production" ? "prod-web" : "dev-web"
  }
}

locals {
  instance_count = var.environment == "production" ? 5 : var.environment == "staging" ? 2 : 1
}
hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.environment == "production" ? "t3.large" : "t3.micro"

  tags = {
    Name = var.environment == "production" ? "prod-web" : "dev-web"
  }
}

locals {
  instance_count = var.environment == "production" ? 5 : var.environment == "staging" ? 2 : 1
}

Functions

函数

hcl
locals {
  # String functions
  name_upper = upper(var.name)
  name_lower = lower(var.name)
  name_title = title(var.name)

  # Collection functions
  subnet_count = length(var.subnet_cidrs)
  first_az     = element(var.availability_zones, 0)
  all_azs      = join(",", var.availability_zones)

  # Numeric functions
  min_instances = min(var.instance_count, 10)
  max_instances = max(var.instance_count, 1)

  # Type conversion
  instance_count_string = tostring(var.instance_count)
  az_set                = toset(var.availability_zones)

  # Map functions
  merged_tags = merge(var.common_tags, var.specific_tags)

  # File functions
  user_data = file("${path.module}/scripts/init.sh")
  config    = templatefile("${path.module}/templates/config.tpl", {
    environment = var.environment
    region      = var.region
  })

  # Encoding functions
  encoded = base64encode("secret data")
  decoded = base64decode(var.encoded_data)

  # Date/Time functions
  timestamp = timestamp()

  # IP Network functions
  cidr_subnets = cidrsubnets("10.0.0.0/16", 8, 8, 8, 8)
}
hcl
locals {
  # 字符串函数
  name_upper = upper(var.name)
  name_lower = lower(var.name)
  name_title = title(var.name)

  # 集合函数
  subnet_count = length(var.subnet_cidrs)
  first_az     = element(var.availability_zones, 0)
  all_azs      = join(",", var.availability_zones)

  # 数值函数
  min_instances = min(var.instance_count, 10)
  max_instances = max(var.instance_count, 1)

  # 类型转换
  instance_count_string = tostring(var.instance_count)
  az_set                = toset(var.availability_zones)

  # 映射函数
  merged_tags = merge(var.common_tags, var.specific_tags)

  # 文件函数
  user_data = file("${path.module}/scripts/init.sh")
  config    = templatefile("${path.module}/templates/config.tpl", {
    environment = var.environment
    region      = var.region
  })

  # 编码函数
  encoded = base64encode("secret data")
  decoded = base64decode(var.encoded_data)

  # 日期/时间函数
  timestamp = timestamp()

  # IP网络函数
  cidr_subnets = cidrsubnets("10.0.0.0/16", 8, 8, 8, 8)
}

Terraform Functions in Practice

Terraform函数实践

hcl
undefined
hcl
undefined

Creating multiple subnets across availability zones

在可用区中创建多个子网

locals { subnet_cidrs = cidrsubnets(var.vpc_cidr, 8, 8, 8, 8) }
data "aws_availability_zones" "available" { state = "available" }
resource "aws_subnet" "public" { count = 3
vpc_id = aws_vpc.main.id cidr_block = local.subnet_cidrs[count.index] availability_zone = data.aws_availability_zones.available.names[count.index]
tags = { Name = "public-${count.index + 1}" } }
undefined
locals { subnet_cidrs = cidrsubnets(var.vpc_cidr, 8, 8, 8, 8) }
data "aws_availability_zones" "available" { state = "available" }
resource "aws_subnet" "public" { count = 3
vpc_id = aws_vpc.main.id cidr_block = local.subnet_cidrs[count.index] availability_zone = data.aws_availability_zones.available.names[count.index]
tags = { Name = "public-${count.index + 1}" } }
undefined

Dependencies

依赖关系

Implicit Dependencies

隐式依赖

Terraform automatically infers dependencies from resource references.
hcl
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id  # Implicit dependency
  cidr_block = "10.0.1.0/24"
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.public.id  # Implicit dependency
}
Terraform会自动从资源引用中推断依赖关系。
hcl
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id  # 隐式依赖
  cidr_block = "10.0.1.0/24"
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.public.id  # 隐式依赖
}

Explicit Dependencies

显式依赖

Use
depends_on
when dependencies cannot be inferred automatically.
hcl
resource "aws_instance" "app" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  depends_on = [aws_db_instance.database]
}

resource "aws_db_instance" "database" {
  engine            = "postgres"
  instance_class    = "db.t3.micro"
  allocated_storage = 20
}
当依赖关系无法自动推断时,使用
depends_on
hcl
resource "aws_instance" "app" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  depends_on = [aws_db_instance.database]
}

resource "aws_db_instance" "database" {
  engine            = "postgres"
  instance_class    = "db.t3.micro"
  allocated_storage = 20
}

Module Dependencies

模块依赖

hcl
module "vpc" {
  source = "./modules/vpc"

  cidr_block = "10.0.0.0/16"
}

module "app" {
  source = "./modules/app"

  vpc_id    = module.vpc.vpc_id
  subnet_id = module.vpc.private_subnet_ids[0]

  depends_on = [module.vpc]
}
hcl
module "vpc" {
  source = "./modules/vpc"

  cidr_block = "10.0.0.0/16"
}

module "app" {
  source = "./modules/app"

  vpc_id    = module.vpc.vpc_id
  subnet_id = module.vpc.private_subnet_ids[0]

  depends_on = [module.vpc]
}

Provisioners

置备器

Provisioners are used to execute scripts on a local or remote machine as part of resource creation or destruction.
置备器用于在资源创建或销毁时在本地或远程机器上执行脚本。

Local-Exec Provisioner

Local-Exec置备器

hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"

  provisioner "local-exec" {
    command = "echo ${self.private_ip} >> private_ips.txt"
  }

  provisioner "local-exec" {
    when    = destroy
    command = "echo 'Instance ${self.id} destroyed' >> destroy_log.txt"
  }
}
hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"

  provisioner "local-exec" {
    command = "echo ${self.private_ip} >> private_ips.txt"
  }

  provisioner "local-exec" {
    when    = destroy
    command = "echo 'Instance ${self.id} destroyed' >> destroy_log.txt"
  }
}

Remote-Exec Provisioner

Remote-Exec置备器

hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"
  key_name      = var.key_name

  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file(var.private_key_path)
    host        = self.public_ip
  }

  provisioner "remote-exec" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y nginx",
      "sudo systemctl start nginx",
      "sudo systemctl enable nginx"
    ]
  }
}
hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"
  key_name      = var.key_name

  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file(var.private_key_path)
    host        = self.public_ip
  }

  provisioner "remote-exec" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y nginx",
      "sudo systemctl start nginx",
      "sudo systemctl enable nginx"
    ]
  }
}

File Provisioner

File置备器

hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"
  key_name      = var.key_name

  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file(var.private_key_path)
    host        = self.public_ip
  }

  provisioner "file" {
    source      = "scripts/init.sh"
    destination = "/tmp/init.sh"
  }

  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/init.sh",
      "sudo /tmp/init.sh"
    ]
  }
}
hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"
  key_name      = var.key_name

  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file(var.private_key_path)
    host        = self.public_ip
  }

  provisioner "file" {
    source      = "scripts/init.sh"
    destination = "/tmp/init.sh"
  }

  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/init.sh",
      "sudo /tmp/init.sh"
    ]
  }
}

Provisioner Failure Behavior

置备器失败行为

hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"

  provisioner "local-exec" {
    command     = "./configure.sh"
    on_failure  = continue  # or fail (default)
  }
}
hcl
resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t2.micro"

  provisioner "local-exec" {
    command     = "./configure.sh"
    on_failure  = continue  # 或fail(默认)
  }
}

Best Practices

最佳实践

1. State Management

1. 状态管理

  • Always use remote state for team collaboration
  • Enable state locking to prevent concurrent modifications
  • Enable encryption for sensitive data
  • Regular state backups for disaster recovery
  • 始终使用远程状态以支持团队协作
  • 启用状态锁定防止并发修改
  • 启用加密保护敏感数据
  • 定期备份状态用于灾难恢复

2. Code Organization

2. 代码组织

project/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   └── production/
├── modules/
│   ├── vpc/
│   ├── compute/
│   └── database/
└── global/
    └── s3/
project/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   └── production/
├── modules/
│   ├── vpc/
│   ├── compute/
│   └── database/
└── global/
    └── s3/

3. Variable Management

3. 变量管理

hcl
undefined
hcl
undefined

Use meaningful descriptions

使用有意义的描述

variable "instance_type" { description = "EC2 instance type for web servers" type = string default = "t3.micro" }
variable "instance_type" { description = "Web服务器使用的EC2实例类型" type = string default = "t3.micro" }

Use validation

使用验证

variable "environment" { description = "Deployment environment" type = string
validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "Environment must be dev, staging, or production." } }
undefined
variable "environment" { description = "部署环境" type = string
validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "环境必须是dev、staging或production。" } }
undefined

4. Naming Conventions

4. 命名约定

hcl
undefined
hcl
undefined

Resource naming

资源命名

resource "aws_instance" "web_server" { # Use descriptive names tags = { Name = "${var.project}-${var.environment}-web-${count.index + 1}" } }
resource "aws_instance" "web_server" { # 使用描述性名称 tags = { Name = "${var.project}-${var.environment}-web-${count.index + 1}" } }

Module naming

模块命名

module "vpc_production" { source = "./modules/vpc" }
undefined
module "vpc_production" { source = "./modules/vpc" }
undefined

5. DRY Principle

5. DRY原则

hcl
undefined
hcl
undefined

Use locals for repeated values

使用本地值存储重复值

locals { common_tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" CostCenter = var.cost_center } }
resource "aws_instance" "web" { tags = merge( local.common_tags, { Name = "web-server" Role = "webserver" } ) }
undefined
locals { common_tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" CostCenter = var.cost_center } }
resource "aws_instance" "web" { tags = merge( local.common_tags, { Name = "web-server" Role = "webserver" } ) }
undefined

6. Security Best Practices

6. 安全最佳实践

hcl
undefined
hcl
undefined

Never hardcode credentials

永远不要硬编码凭证

BAD

错误示例

provider "aws" { access_key = "AKIAIOSFODNN7EXAMPLE" secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" }
provider "aws" { access_key = "AKIAIOSFODNN7EXAMPLE" secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" }

GOOD - Use environment variables or IAM roles

正确示例 - 使用环境变量或IAM角色

provider "aws" {

Credentials from environment or IAM role

}
provider "aws" {

从环境变量或IAM角色获取凭证

}

Use sensitive flag for outputs

对输出使用敏感标记

output "database_password" { value = aws_db_instance.main.password sensitive = true }
output "database_password" { value = aws_db_instance.main.password sensitive = true }

Encrypt sensitive data

加密敏感数据

resource "aws_s3_bucket" "data" { bucket = "my-data-bucket" }
resource "aws_s3_bucket_server_side_encryption_configuration" "data" { bucket = aws_s3_bucket.data.id
rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } }
undefined
resource "aws_s3_bucket" "data" { bucket = "my-data-bucket" }
resource "aws_s3_bucket_server_side_encryption_configuration" "data" { bucket = aws_s3_bucket.data.id
rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } }
undefined

7. Testing

7. 测试

bash
undefined
bash
undefined

Validate syntax

验证语法

terraform validate
terraform validate

Format code

格式化代码

terraform fmt -recursive
terraform fmt -recursive

Plan before apply

先规划后应用

terraform plan -out=tfplan
terraform plan -out=tfplan

Review plan

评审计划

terraform show tfplan
undefined
terraform show tfplan
undefined

8. Version Control

8. 版本控制

.gitignore:
undefined
.gitignore:
undefined

Local .terraform directories

本地.terraform目录

*/.terraform/
*/.terraform/

.tfstate files

.tfstate文件

*.tfstate .tfstate.
*.tfstate .tfstate.

Crash log files

崩溃日志文件

crash.log crash.*.log
crash.log crash.*.log

Exclude variable files that may contain sensitive data

排除可能包含敏感数据的变量文件

*.tfvars *.tfvars.json
*.tfvars *.tfvars.json

Ignore override files

忽略覆盖文件

override.tf override.tf.json *_override.tf *_override.tf.json
override.tf override.tf.json *_override.tf *_override.tf.json

CLI configuration files

CLI配置文件

.terraformrc terraform.rc
.terraformrc terraform.rc

Plan files

计划文件

*.tfplan
undefined
*.tfplan
undefined

9. Module Best Practices

9. 模块最佳实践

hcl
undefined
hcl
undefined

Module versioning

模块版本控制

module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" # Pin to major version }
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0" # 固定主版本 }

Module documentation

模块文档

Always include README.md with:

始终包含README.md,内容包括:

- Description

- 描述

- Requirements

- 要求

- Providers

- 提供商

- Inputs

- 输入

- Outputs

- 输出

- Example usage

- 使用示例

undefined
undefined

10. Resource Tagging

10. 资源标记

hcl
undefined
hcl
undefined

Consistent tagging strategy

一致的标记策略

locals { required_tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" Owner = var.owner_email CostCenter = var.cost_center Compliance = var.compliance_level } }
locals { required_tags = { Project = var.project_name Environment = var.environment ManagedBy = "Terraform" Owner = var.owner_email CostCenter = var.cost_center Compliance = var.compliance_level } }

Use default tags at provider level

在提供商级别使用默认标记

provider "aws" { region = var.region
default_tags { tags = local.required_tags } }
undefined
provider "aws" { region = var.region
default_tags { tags = local.required_tags } }
undefined

CI/CD Integration

CI/CD集成

GitHub Actions

GitHub Actions

.github/workflows/terraform.yml:
yaml
name: Terraform

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  TF_VERSION: 1.5.0

jobs:
  terraform:
    name: Terraform
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Format
        run: terraform fmt -check -recursive

      - name: Terraform Init
        run: terraform init
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        run: terraform plan -no-color
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        run: terraform apply -auto-approve
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
.github/workflows/terraform.yml:
yaml
name: Terraform

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  TF_VERSION: 1.5.0

jobs:
  terraform:
    name: Terraform
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Terraform Format
        run: terraform fmt -check -recursive

      - name: Terraform Init
        run: terraform init
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        run: terraform plan -no-color
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        run: terraform apply -auto-approve
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

GitLab CI

GitLab CI

.gitlab-ci.yml:
yaml
image:
  name: hashicorp/terraform:1.5.0
  entrypoint: [""]

stages:
  - validate
  - plan
  - apply

before_script:
  - terraform init

validate:
  stage: validate
  script:
    - terraform validate
    - terraform fmt -check -recursive

plan:
  stage: plan
  script:
    - terraform plan -out=tfplan
  artifacts:
    paths:
      - tfplan
    expire_in: 1 week

apply:
  stage: apply
  script:
    - terraform apply -auto-approve tfplan
  dependencies:
    - plan
  only:
    - main
  when: manual
.gitlab-ci.yml:
yaml
image:
  name: hashicorp/terraform:1.5.0
  entrypoint: [""]

stages:
  - validate
  - plan
  - apply

before_script:
  - terraform init

validate:
  stage: validate
  script:
    - terraform validate
    - terraform fmt -check -recursive

plan:
  stage: plan
  script:
    - terraform plan -out=tfplan
  artifacts:
    paths:
      - tfplan
    expire_in: 1 week

apply:
  stage: apply
  script:
    - terraform apply -auto-approve tfplan
  dependencies:
    - plan
  only:
    - main
  when: manual

Jenkins Pipeline

Jenkins Pipeline

Jenkinsfile:
groovy
pipeline {
    agent any

    environment {
        TF_VERSION = '1.5.0'
        AWS_CREDENTIALS = credentials('aws-credentials')
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Terraform Init') {
            steps {
                sh 'terraform init'
            }
        }

        stage('Terraform Validate') {
            steps {
                sh 'terraform validate'
                sh 'terraform fmt -check -recursive'
            }
        }

        stage('Terraform Plan') {
            steps {
                sh 'terraform plan -out=tfplan'
            }
        }

        stage('Terraform Apply') {
            when {
                branch 'main'
            }
            steps {
                input message: 'Apply Terraform changes?', ok: 'Apply'
                sh 'terraform apply -auto-approve tfplan'
            }
        }
    }

    post {
        always {
            cleanWs()
        }
    }
}
Jenkinsfile:
groovy
pipeline {
    agent any

    environment {
        TF_VERSION = '1.5.0'
        AWS_CREDENTIALS = credentials('aws-credentials')
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Terraform Init') {
            steps {
                sh 'terraform init'
            }
        }

        stage('Terraform Validate') {
            steps {
                sh 'terraform validate'
                sh 'terraform fmt -check -recursive'
            }
        }

        stage('Terraform Plan') {
            steps {
                sh 'terraform plan -out=tfplan'
            }
        }

        stage('Terraform Apply') {
            when {
                branch 'main'
            }
            steps {
                input message: 'Apply Terraform changes?', ok: 'Apply'
                sh 'terraform apply -auto-approve tfplan'
            }
        }
    }

    post {
        always {
            cleanWs()
        }
    }
}

Azure DevOps

Azure DevOps

azure-pipelines.yml:
yaml
trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

variables:
  - name: terraformVersion
    value: '1.5.0'

stages:
  - stage: Validate
    jobs:
      - job: ValidateTerraform
        steps:
          - task: TerraformInstaller@0
            inputs:
              terraformVersion: $(terraformVersion)

          - task: TerraformTaskV2@2
            displayName: 'Terraform Init'
            inputs:
              provider: 'aws'
              command: 'init'
              backendServiceAWS: 'AWS-Connection'

          - task: TerraformTaskV2@2
            displayName: 'Terraform Validate'
            inputs:
              provider: 'aws'
              command: 'validate'

          - script: terraform fmt -check -recursive
            displayName: 'Terraform Format Check'

  - stage: Plan
    dependsOn: Validate
    jobs:
      - job: PlanTerraform
        steps:
          - task: TerraformTaskV2@2
            displayName: 'Terraform Plan'
            inputs:
              provider: 'aws'
              command: 'plan'
              commandOptions: '-out=tfplan'

  - stage: Apply
    dependsOn: Plan
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    jobs:
      - deployment: ApplyTerraform
        environment: 'production'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: TerraformTaskV2@2
                  displayName: 'Terraform Apply'
                  inputs:
                    provider: 'aws'
                    command: 'apply'
                    commandOptions: '-auto-approve tfplan'
azure-pipelines.yml:
yaml
trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

variables:
  - name: terraformVersion
    value: '1.5.0'

stages:
  - stage: Validate
    jobs:
      - job: ValidateTerraform
        steps:
          - task: TerraformInstaller@0
            inputs:
              terraformVersion: $(terraformVersion)

          - task: TerraformTaskV2@2
            displayName: 'Terraform Init'
            inputs:
              provider: 'aws'
              command: 'init'
              backendServiceAWS: 'AWS-Connection'

          - task: TerraformTaskV2@2
            displayName: 'Terraform Validate'
            inputs:
              provider: 'aws'
              command: 'validate'

          - script: terraform fmt -check -recursive
            displayName: 'Terraform Format Check'

  - stage: Plan
    dependsOn: Validate
    jobs:
      - job: PlanTerraform
        steps:
          - task: TerraformTaskV2@2
            displayName: 'Terraform Plan'
            inputs:
              provider: 'aws'
              command: 'plan'
              commandOptions: '-out=tfplan'

  - stage: Apply
    dependsOn: Plan
    condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
    jobs:
      - deployment: ApplyTerraform
        environment: 'production'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: TerraformTaskV2@2
                  displayName: 'Terraform Apply'
                  inputs:
                    provider: 'aws'
                    command: 'apply'
                    commandOptions: '-auto-approve tfplan'

Pre-commit Hooks

Pre-commit Hooks

.pre-commit-config.yaml:
yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.81.0
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_docs
      - id: terraform_tflint
      - id: terraform_tfsec
      - id: terraform_checkov
.pre-commit-config.yaml:
yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.81.0
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_docs
      - id: terraform_tflint
      - id: terraform_tfsec
      - id: terraform_checkov

Automated Testing

自动化测试

test/terraform_test.go:
go
package test

import (
    "testing"
    "github.com/gruntwork-io/terratest/modules/terraform"
    "github.com/stretchr/testify/assert"
)

func TestTerraformVPC(t *testing.T) {
    terraformOptions := &terraform.Options{
        TerraformDir: "../examples/vpc",

        Vars: map[string]interface{}{
            "cidr_block": "10.0.0.0/16",
            "region":     "us-west-2",
        },
    }

    defer terraform.Destroy(t, terraformOptions)

    terraform.InitAndApply(t, terraformOptions)

    vpcId := terraform.Output(t, terraformOptions, "vpc_id")
    assert.NotEmpty(t, vpcId)
}
test/terraform_test.go:
go
package test

import (
    "testing"
    "github.com/gruntwork-io/terratest/modules/terraform"
    "github.com/stretchr/testify/assert"
)

func TestTerraformVPC(t *testing.T) {
    terraformOptions := &terraform.Options{
        TerraformDir: "../examples/vpc",

        Vars: map[string]interface{}{
            "cidr_block": "10.0.0.0/16",
            "region":     "us-west-2",
        },
    }

    defer terraform.Destroy(t, terraformOptions)

    terraform.InitAndApply(t, terraformOptions)

    vpcId := terraform.Output(t, terraformOptions, "vpc_id")
    assert.NotEmpty(t, vpcId)
}

Additional Commands and Tools

其他命令和工具

Terraform Console

Terraform控制台

bash
undefined
bash
undefined

Start console

启动控制台

terraform console
terraform console

Example session:

示例会话:

aws_instance.example.public_ip "54.183.22.100" var.region "us-west-2" length(aws_instance.example.tags) 3
undefined
aws_instance.example.public_ip "54.183.22.100" var.region "us-west-2" length(aws_instance.example.tags) 3
undefined

Terraform Graph

Terraform图

bash
undefined
bash
undefined

Generate graph in DOT format

生成DOT格式的图

terraform graph > graph.dot
terraform graph > graph.dot

Convert to image with Graphviz

使用Graphviz转换为图片

terraform graph | dot -Tpng > graph.png
terraform graph | dot -Tpng > graph.png

Generate graph for specific plan

为特定计划生成图

terraform graph -type=plan > plan-graph.dot
undefined
terraform graph -type=plan > plan-graph.dot
undefined

Terraform Taint

Terraform标记为脏

bash
undefined
bash
undefined

Taint a resource (mark for recreation)

将资源标记为脏(标记为需要重新创建)

terraform taint aws_instance.example
terraform taint aws_instance.example

Untaint a resource

取消标记

terraform untaint aws_instance.example
undefined
terraform untaint aws_instance.example
undefined

Terraform Providers

Terraform提供商

bash
undefined
bash
undefined

List required providers

列出所需提供商

terraform providers
terraform providers

Show provider schemas

显示提供商架构

terraform providers schema -json > schemas.json
terraform providers schema -json > schemas.json

Lock provider versions

锁定提供商版本

terraform providers lock
undefined
terraform providers lock
undefined

Conclusion

总结

This comprehensive guide covers the essential aspects of Terraform Infrastructure as Code, from basic concepts to advanced patterns and CI/CD integration. By following these practices and patterns, you can build maintainable, scalable, and secure infrastructure deployments across any cloud provider.
Key takeaways:
  • Use modules for reusable components
  • Implement remote state with locking for team collaboration
  • Leverage workspaces for environment isolation
  • Follow security best practices and never hardcode credentials
  • Integrate Terraform into CI/CD pipelines for automated deployments
  • Use validation, formatting, and testing tools
  • Maintain clear documentation and consistent naming conventions
  • Implement proper tagging strategies for resource management
Terraform enables infrastructure teams to adopt DevOps practices, improve collaboration, reduce manual errors, and accelerate deployment cycles while maintaining full control and visibility over infrastructure changes.
本全面指南涵盖了Terraform基础设施即代码的基本概念到高级模式和CI/CD集成等关键方面。通过遵循这些实践和模式,你可以在任何云提供商上构建可维护、可扩展且安全的基础设施部署。
核心要点:
  • 使用模块创建可复用组件
  • 实现带锁定的远程状态以支持团队协作
  • 利用工作区实现环境隔离
  • 遵循安全最佳实践,永远不要硬编码凭证
  • 将Terraform集成到CI/CD管道以实现自动化部署
  • 使用验证、格式化和测试工具
  • 保持清晰的文档和一致的命名约定
  • 实施适当的标记策略以进行资源管理
Terraform使基础设施团队能够采用DevOps实践,改善协作,减少手动错误,加速部署周期,同时保持对基础设施变更的完全控制和可见性。