Terraform 本地值 #
什么是本地值? #
本地值(Locals)允许你为表达式分配一个名称,然后在配置中多次引用该名称。它类似于编程语言中的局部变量,用于简化配置、避免重复代码。
text
┌─────────────────────────────────────────────────────────────┐
│ 本地值的作用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 避免重复 │ │ 简化表达式 │ │ 集中管理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ - DRY 原则 │
│ - 复杂表达式命名 │
│ - 统一配置管理 │
│ │
└─────────────────────────────────────────────────────────────┘
本地值定义 #
基本语法 #
hcl
locals {
<NAME> = <EXPRESSION>
}
简单示例 #
hcl
locals {
environment = "dev"
region = "us-east-1"
project = "my-project"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Environment = local.environment
Region = local.region
Project = local.project
}
}
多个本地值 #
hcl
locals {
environment = var.environment
project = var.project_name
common_tags = {
Environment = local.environment
Project = local.project
ManagedBy = "terraform"
CreatedAt = timestamp()
}
name_prefix = "${local.project}-${local.environment}"
}
使用场景 #
1. 标签管理 #
hcl
locals {
common_tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "terraform"
Owner = var.owner
}
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = merge(
local.common_tags,
{ Name = "${var.project_name}-vpc" }
)
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidr
tags = merge(
local.common_tags,
{ Name = "${var.project_name}-public-subnet" }
)
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = merge(
local.common_tags,
{ Name = "${var.project_name}-web-server" }
)
}
2. 命名约定 #
hcl
locals {
name_prefix = "${var.project_name}-${var.environment}"
vpc_name = "${local.name_prefix}-vpc"
public_subnet_name = "${local.name_prefix}-public-subnet"
private_subnet_name = "${local.name_prefix}-private-subnet"
alb_name = "${local.name_prefix}-alb"
asg_name = "${local.name_prefix}-asg"
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = {
Name = local.vpc_name
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidr
tags = {
Name = local.public_subnet_name
}
}
3. 计算值 #
hcl
locals {
vpc_cidr = "10.0.0.0/16"
public_subnet_cidrs = [
cidrsubnet(local.vpc_cidr, 8, 0),
cidrsubnet(local.vpc_cidr, 8, 1),
cidrsubnet(local.vpc_cidr, 8, 2)
]
private_subnet_cidrs = [
cidrsubnet(local.vpc_cidr, 8, 10),
cidrsubnet(local.vpc_cidr, 8, 11),
cidrsubnet(local.vpc_cidr, 8, 12)
]
}
resource "aws_subnet" "public" {
count = length(local.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = local.public_subnet_cidrs[count.index]
}
4. 条件表达式 #
hcl
locals {
instance_type = var.environment == "prod" ? "t2.large" : "t2.micro"
enable_monitoring = var.environment == "prod" ? true : false
log_retention_days = {
dev = 7
staging = 14
prod = 30
}
retention = local.log_retention_days[var.environment]
}
resource "aws_instance" "example" {
instance_type = local.instance_type
monitoring = local.enable_monitoring
}
5. 复杂转换 #
hcl
variable "server_configs" {
default = [
{
name = "web"
type = "t2.micro"
port = 80
},
{
name = "api"
type = "t2.small"
port = 8080
}
]
}
locals {
server_map = {
for config in var.server_configs : config.name => config
}
server_names = [for config in var.server_configs : config.name]
ports = [for config in var.server_configs : config.port]
}
resource "aws_instance" "server" {
for_each = local.server_map
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value.type
tags = {
Name = each.key
}
}
6. 合并配置 #
hcl
locals {
default_instance_config = {
instance_type = "t2.micro"
monitoring = false
delete_on_termination = true
volume_size = 20
}
prod_instance_config = {
instance_type = "t2.large"
monitoring = true
delete_on_termination = false
volume_size = 100
}
instance_config = var.environment == "prod"
? merge(local.default_instance_config, local.prod_instance_config)
: local.default_instance_config
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = local.instance_config.instance_type
monitoring = local.instance_config.monitoring
root_block_device {
delete_on_termination = local.instance_config.delete_on_termination
volume_size = local.instance_config.volume_size
}
}
本地值 vs 变量 #
text
┌─────────────────────────────────────────────────────────────┐
│ 本地值 vs 变量 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 变量(Variable): │
│ - 用户输入 │
│ - 可以被外部覆盖 │
│ - 可以设置默认值 │
│ - 用于参数化配置 │
│ │
│ 本地值(Locals): │
│ - 内部计算 │
│ - 不能被外部覆盖 │
│ - 必须有值 │
│ - 用于简化表达式 │
│ │
│ 选择原则: │
│ - 需要用户输入?用变量 │
│ - 需要复用计算结果?用本地值 │
│ │
└─────────────────────────────────────────────────────────────┘
高级用法 #
嵌套本地值 #
hcl
locals {
environment = var.environment
project = var.project_name
name_prefix = "${local.project}-${local.environment}"
tags = {
Environment = local.environment
Project = local.project
NamePrefix = local.name_prefix
}
resource_names = {
vpc = "${local.name_prefix}-vpc"
subnet = "${local.name_prefix}-subnet"
instance = "${local.name_prefix}-instance"
}
}
使用函数 #
hcl
locals {
vpc_cidr = "10.0.0.0/16"
subnet_cidrs = [
for i in range(3) : cidrsubnet(local.vpc_cidr, 8, i)
]
availability_zones = slice(
data.aws_availability_zones.available.names,
0, 3
)
subnet_az_mapping = {
for i, cidr in local.subnet_cidrs :
local.availability_zones[i] => cidr
}
}
data "aws_availability_zones" "available" {
state = "available"
}
文件内容 #
hcl
locals {
user_data = templatefile("${path.module}/user_data.sh.tpl", {
environment = var.environment
region = var.region
})
policy_document = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "s3:GetObject"
Effect = "Allow"
Resource = "arn:aws:s3:::${var.bucket_name}/*"
}
]
})
}
resource "aws_instance" "example" {
user_data = local.user_data
}
resource "aws_iam_policy" "example" {
policy = local.policy_document
}
条件资源创建 #
hcl
locals {
create_vpc = var.vpc_id == null
vpc_id = local.create_vpc ? aws_vpc.main[0].id : var.vpc_id
create_instance = var.instance_count > 0
}
resource "aws_vpc" "main" {
count = local.create_vpc ? 1 : 0
cidr_block = var.vpc_cidr
}
resource "aws_subnet" "main" {
vpc_id = local.vpc_id
cidr_block = var.subnet_cidr
}
resource "aws_instance" "example" {
count = local.create_instance ? var.instance_count : 0
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
subnet_id = aws_subnet.main.id
}
文件组织 #
单独文件 #
text
project/
├── main.tf
├── variables.tf
├── outputs.tf
├── locals.tf 本地值定义
└── terraform.tfvars
locals.tf 示例 #
hcl
locals {
environment = var.environment
project = var.project_name
region = var.region
name_prefix = "${local.project}-${local.environment}"
common_tags = {
Environment = local.environment
Project = local.project
Region = local.region
ManagedBy = "terraform"
}
vpc_cidr = var.vpc_cidr
public_subnet_cidrs = [
for i in range(3) : cidrsubnet(local.vpc_cidr, 8, i)
]
private_subnet_cidrs = [
for i in range(3) : cidrsubnet(local.vpc_cidr, 8, i + 10)
]
instance_config = {
dev = {
instance_type = "t2.micro"
volume_size = 20
}
staging = {
instance_type = "t2.small"
volume_size = 50
}
prod = {
instance_type = "t2.large"
volume_size = 100
}
}
current_config = local.instance_config[local.environment]
}
最佳实践 #
1. 命名清晰 #
hcl
locals {
common_tags = {
Environment = var.environment
Project = var.project_name
}
vpc_cidr = "10.0.0.0/16"
public_subnet_cidrs = [
cidrsubnet(local.vpc_cidr, 8, 0),
cidrsubnet(local.vpc_cidr, 8, 1)
]
}
2. 避免过度使用 #
hcl
locals {
environment = var.environment
}
resource "aws_instance" "example" {
tags = {
Environment = local.environment
}
}
更好的做法:
hcl
resource "aws_instance" "example" {
tags = {
Environment = var.environment
}
}
3. 集中管理标签 #
hcl
locals {
common_tags = merge(
var.default_tags,
{
Environment = var.environment
Project = var.project_name
ManagedBy = "terraform"
}
)
}
4. 使用描述性名称 #
hcl
locals {
vpc_cidr_block = "10.0.0.0/16"
public_subnet_cidr_blocks = [
cidrsubnet(local.vpc_cidr_block, 8, 0),
cidrsubnet(local.vpc_cidr_block, 8, 1)
]
private_subnet_cidr_blocks = [
cidrsubnet(local.vpc_cidr_block, 8, 10),
cidrsubnet(local.vpc_cidr_block, 8, 11)
]
}
完整示例 #
hcl
locals {
environment = var.environment
project = var.project_name
region = var.region
name_prefix = "${local.project}-${local.environment}"
common_tags = merge(
var.default_tags,
{
Environment = local.environment
Project = local.project
Region = local.region
ManagedBy = "terraform"
CreatedAt = timestamp()
}
)
vpc_cidr = var.vpc_cidr
azs = slice(data.aws_availability_zones.available.names, 0, 3)
public_subnet_cidrs = [
for i in range(3) : cidrsubnet(local.vpc_cidr, 8, i)
]
private_subnet_cidrs = [
for i in range(3) : cidrsubnet(local.vpc_cidr, 8, i + 10)
]
subnet_tags = [
for i, cidr in local.public_subnet_cidrs : merge(
local.common_tags,
{
Name = "${local.name_prefix}-public-${local.azs[i]}"
Tier = "public"
}
)
]
instance_config = {
dev = {
instance_type = "t2.micro"
volume_size = 20
monitoring = false
}
staging = {
instance_type = "t2.small"
volume_size = 50
monitoring = true
}
prod = {
instance_type = "t2.large"
volume_size = 100
monitoring = true
}
}
current_instance_config = local.instance_config[local.environment]
user_data = templatefile("${path.module}/user_data.sh.tpl", {
environment = local.environment
region = local.region
project = local.project
})
}
data "aws_availability_zones" "available" {
state = "available"
}
下一步 #
掌握了本地值后,接下来学习 数据源,了解如何查询和引用已有的基础设施资源!
最后更新:2026-03-29