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 如何跟踪和管理基础设施状态。