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