跳到主要内容

Provider 与资源

Provider 是 Terraform 与基础设施平台交互的桥梁,Resource 是 Terraform 管理的基础设施组件。本章将详细介绍 Provider 的配置方法和常用资源的管理。

Provider 详解

Provider 是 Terraform 插件,用于与云提供商、SaaS 平台或其他 API 交互。每个 Provider 都暴露了一组资源类型和数据源。

Provider 配置结构

provider "<NAME>" {
# 配置参数
}

常用 Provider 配置示例

AWS Provider

# 基本配置
provider "aws" {
region = "us-east-1"
}

# 高级配置
provider "aws" {
region = "us-east-1"

# 假设角色
assume_role {
role_arn = "arn:aws:iam::123456789012:role/TerraformRole"
session_name = "terraform-session"
}

# 默认标签(应用到所有资源)
default_tags {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
Project = "MyProject"
}
}

# 重试配置
retry_mode = "adaptive"
max_retries = 5
}

# 多区域配置(使用别名)
provider "aws" {
alias = "us_east"
region = "us-east-1"
}

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

provider "aws" {
alias = "eu"
region = "eu-west-1"
}

阿里云 Provider

provider "alicloud" {
region = "cn-hangzhou"

# 访问密钥(推荐通过环境变量或配置文件设置)
# access_key = "your-access-key"
# secret_key = "your-secret-key"
}

# 多区域配置
provider "alicloud" {
alias = "beijing"
region = "cn-beijing"
}

Azure Provider

provider "azurerm" {
features {}

subscription_id = "your-subscription-id"
tenant_id = "your-tenant-id"
}

# 多订阅配置
provider "azurerm" {
alias = "production"
features {}
subscription_id = "prod-subscription-id"
}

Google Cloud Provider

provider "google" {
project = "my-project-id"
region = "us-central1"
zone = "us-central1-a"
}

# 多项目配置
provider "google" {
alias = "production"
project = "prod-project-id"
region = "us-central1"
}

Kubernetes Provider

provider "kubernetes" {
config_path = "~/.kube/config"
}

# 使用证书认证
provider "kubernetes" {
host = "https://kubernetes-cluster-endpoint"

client_certificate = file("~/.kube/client-cert.pem")
client_key = file("~/.kube/client-key.pem")
cluster_ca_certificate = file("~/.kube/ca-cert.pem")
}

Docker Provider

provider "docker" {
host = "unix:///var/run/docker.sock"
}

# 远程 Docker 主机
provider "docker" {
alias = "remote"
host = "tcp://remote-docker-host:2376"

ca_material = file("~/.docker/ca.pem")
cert_material = file("~/.docker/cert.pem")
key_material = file("~/.docker/key.pem")
}

多 Provider 使用

当配置了多个相同类型的 Provider 时,使用 provider 元参数指定使用哪个:

# 创建美国东部的资源
resource "aws_instance" "east" {
provider = aws.us_east

ami = "ami-12345678"
instance_type = "t2.micro"
}

# 创建美国西部的资源
resource "aws_instance" "west" {
provider = aws.us_west

ami = "ami-87654321"
instance_type = "t2.micro"
}

资源管理

资源基本结构

resource "<PROVIDER>_<TYPE>" "<NAME>" {
# 资源参数
}

常用 AWS 资源

EC2 实例

# 查询最新的 Amazon Linux AMI
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]

filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}

# 创建 EC2 实例
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
key_name = "my-key-pair"

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

root_block_device {
volume_size = 20
volume_type = "gp3"
}

user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "Hello from Terraform" > /var/www/html/index.html
EOF

tags = {
Name = "WebServer"
}
}

VPC 和网络

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

tags = {
Name = "MainVPC"
}
}

# 互联网网关
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id

tags = {
Name = "MainIGW"
}
}

# 子网
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true

tags = {
Name = "PublicSubnet"
}
}

# 路由表
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}

tags = {
Name = "PublicRouteTable"
}
}

# 路由表关联
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}

安全组

resource "aws_security_group" "web" {
name_prefix = "web-sg"
vpc_id = aws_vpc.main.id

# 入站规则
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP"
}

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

ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
description = "SSH"
}

# 出站规则
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "All outbound traffic"
}

tags = {
Name = "WebSecurityGroup"
}
}

S3 存储桶

# 存储桶
resource "aws_s3_bucket" "assets" {
bucket = "my-company-assets"
}

# 存储桶版本控制
resource "aws_s3_bucket_versioning" "assets" {
bucket = aws_s3_bucket.assets.id

versioning_configuration {
status = "Enabled"
}
}

# 存储桶加密
resource "aws_s3_bucket_server_side_encryption_configuration" "assets" {
bucket = aws_s3_bucket.assets.id

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

# 存储桶公共访问阻止
resource "aws_s3_bucket_public_access_block" "assets" {
bucket = aws_s3_bucket.assets.id

block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

RDS 数据库

resource "aws_db_instance" "main" {
identifier = "main-database"

engine = "postgres"
engine_version = "15.4"
instance_class = "db.t3.micro"

allocated_storage = 20
max_allocated_storage = 100
storage_type = "gp3"
storage_encrypted = true

db_name = "myapp"
username = "dbadmin"
password = var.db_password

vpc_security_group_ids = [aws_security_group.database.id]
db_subnet_group_name = aws_db_subnet_group.main.name

backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "Mon:04:00-Mon:05:00"

skip_final_snapshot = true

tags = {
Name = "MainDatabase"
}
}

常用阿里云资源

# VPC
resource "alicloud_vpc" "main" {
vpc_name = "main-vpc"
cidr_block = "10.0.0.0/16"
}

# 交换机(子网)
resource "alicloud_vswitch" "public" {
vpc_id = alicloud_vpc.main.id
cidr_block = "10.0.1.0/24"
zone_id = "cn-hangzhou-a"
vswitch_name = "public-vswitch"
}

# ECS 实例
resource "alicloud_instance" "web" {
instance_name = "web-server"
image_id = "centos_7_9_x64_20G_alibase_20231201.vhd"
instance_type = "ecs.t5-lc1m2.small"

vswitch_id = alicloud_vswitch.public.id
security_groups = [alicloud_security_group.web.id]

internet_max_bandwidth_out = 10

system_disk_category = "cloud_efficiency"
system_disk_size = 40
}

# 安全组
resource "alicloud_security_group" "web" {
name = "web-sg"
vpc_id = alicloud_vpc.main.id
}

resource "alicloud_security_group_rule" "http" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "80/80"
priority = 1
security_group_id = alicloud_security_group.web.id
cidr_ip = "0.0.0.0/0"
}

资源依赖

Terraform 通过引用自动推断资源依赖关系,但有时需要显式指定。

隐式依赖

通过引用其他资源的属性自动建立依赖:

resource "aws_instance" "web" {
# 隐式依赖:Terraform 知道要先创建安全组
vpc_security_group_ids = [aws_security_group.web.id]
}

显式依赖(depends_on)

当资源之间没有属性引用,但需要控制创建顺序时使用:

resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t2.micro"

depends_on = [
aws_iam_role_policy_attachment.web,
aws_cloudwatch_log_group.web
]
}

资源生命周期

通过 lifecycle 元参数控制资源的生命周期行为:

resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t2.micro"

lifecycle {
# 防止资源被销毁(terraform destroy 时跳过)
prevent_destroy = true

# 创建新资源后再销毁旧资源(用于零停机部署)
create_before_destroy = true

# 忽略特定属性的变更
ignore_changes = [
tags["LastModified"],
user_data
]

# 替换资源时触发的条件
replace_triggered_by = [
aws_security_group.web.id
]
}
}

数据源

数据源用于查询现有资源的信息:

# 查询可用区
data "aws_availability_zones" "available" {
state = "available"
}

# 查询 AMI
data "aws_ami" "ubuntu" {
most_recent = true

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}

filter {
name = "virtualization-type"
values = ["hvm"]
}

owners = ["099720109477"] # Canonical
}

# 查询现有的 VPC
data "aws_vpc" "default" {
default = true
}

# 查询子网
data "aws_subnets" "public" {
filter {
name = "vpc-id"
values = [data.aws_vpc.default.id]
}

tags = {
Type = "public"
}
}

# 使用数据源
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
subnet_id = data.aws_subnets.public.ids[0]
}

资源计数和循环

count 参数

# 创建多个相同资源
resource "aws_instance" "web" {
count = 3

ami = "ami-12345678"
instance_type = "t2.micro"

tags = {
Name = "web-${count.index + 1}"
}
}

# 条件创建
resource "aws_instance" "monitoring" {
count = var.enable_monitoring ? 1 : 0

ami = "ami-12345678"
instance_type = "t2.micro"
}

for_each 参数

# 基于集合创建资源
resource "aws_instance" "web" {
for_each = toset(["a", "b", "c"])

ami = "ami-12345678"
instance_type = "t2.micro"

tags = {
Name = "web-${each.value}"
}
}

# 基于映射创建资源
resource "aws_security_group_rule" "ingress" {
for_each = {
http = { port = 80, cidr = "0.0.0.0/0" }
https = { port = 443, cidr = "0.0.0.0/0" }
ssh = { port = 22, cidr = "10.0.0.0/8" }
}

type = "ingress"
from_port = each.value.port
to_port = each.value.port
protocol = "tcp"
cidr_blocks = [each.value.cidr]
security_group_id = aws_security_group.web.id
description = each.key
}

下一步

了解了 Provider 和资源后,我们将学习 状态管理,掌握 Terraform 如何跟踪和管理基础设施状态。