第10天— Terraform 条件表达式、动态块和 Splat 表达式

发布: (2025年12月4日 GMT+8 00:56)
5 min read
原文: Dev.to

Source: Dev.to

条件表达式

条件表达式会评估一个条件,并根据条件为真或为假返回两个值中的一个。

语法

condition ? true_value : false_value

使用场景

  • 根据环境(devprod)选择实例类型
  • 根据配置启用/禁用监控
  • 根据地区选择不同的 AMI
  • 为不同环境设置不同的资源计数
  • 应用特定环境的标签

好处

  • 单一配置即可支持多个环境
  • 减少代码重复
  • 使环境差异显式化
  • 简化配置管理
  • 易于理解和维护

何时使用

  • 环境特定的配置
  • 功能标记(启用/禁用功能)
  • 条件资源创建
  • 区域特定设置
  • 成本优化(在开发环境使用更小的资源)

建议使用的情况

  • 逻辑复杂且条件众多(此时请使用 locals
  • 当单独的环境文件更清晰时
  • 当所有环境应保持完全相同

示例

resource "aws_instance" "conditional_example" {
  ami           = "ami-28765345876"
  instance_type = var.environment == "prod" ? "t3.large" : "t2.micro"

  tags = {
    Name = "conditional-instance-${var.environment}"
  }
}

运行 terraform plan 会显示基于 environment 变量选择的实例类型:

terraform plan
data.aws_ami.amazon_linux: Reading...
data.aws_ami.amazon_linux: Read complete after 1s [id=ami-02610f36df0c59544]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  + create

# aws_instance.conditional_example will be created
+ resource "aws_instance" "conditional_example" {
    + ami           = "ami-02610f36df0c59544"
    + instance_type = "t2.micro"
    # ... other attributes omitted for brevity
}

在此示例中,如果 var.environment 被设置为 "prod",实例类型将为 t3.large;否则默认使用 t2.micro

动态块

动态块根据集合(列表或映射)生成资源内部的多个嵌套块,省去手动重复相似块配置的需求。

语法

dynamic "block_name" {
  for_each = var.collection
  content {
    # 使用 each.key 和 each.value 的块配置
  }
}
  • for_each 用于遍历列表或映射。
  • content 定义每个生成块的内容。
  • 通过 each.keyeach.value 访问值。

使用场景

  • 安全组的入站/出站规则
  • EC2 实例上的多个 EBS 卷
  • IAM 策略语句
  • 负载均衡器监听器
  • 路由表路由
  • 任何需要重复的嵌套块结构

好处

  • 消除重复代码
  • 轻松添加或删除条目
  • 配置由变量驱动
  • 代码更清晰、更易维护
  • 支持复杂的数据结构

何时使用

  • 多个相似的嵌套块
  • 配置数量可变
  • 安全组规则
  • 内联策略
  • 任意重复的块模式

建议使用的情况

  • 单个或少量静态块(开销不值得)
  • 当它使代码更难阅读时
  • 对于顶层资源请使用 countfor_each(而非动态块)

示例

resource "aws_security_group" "dynamic_sg" {
  name        = "dynamic-sg-${var.environment}"
  description = "Security group with dynamic rules"

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

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

  tags = {
    Name = "dynamic-sg-${var.environment}"
  }
}
variable "ingress_rules" {
  description = "List of ingress rules for security group"
  type = list(object({
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
    description = string
  }))
  default = [
    {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
      description = "HTTP"
    },
    {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
      description = "HTTPS"
    }
  ]
}

运行 terraform plan 会显示动态创建的入站规则:

# aws_security_group.dynamic_sg will be created
+ resource "aws_security_group" "dynamic_sg" {
    + arn         = (known after apply)
    + description = "Security group with dynamic rules"
    + egress      = [
        {
          + cidr_blocks = ["0.0.0.0/0"]
          + from_port   = 0
          + protocol    = "-1"
          + to_port     = 0
        }
      ]
    + ingress = [
        {
          + from_port   = 80
          + to_port     = 80
          + protocol    = "tcp"
          + cidr_blocks = ["0.0.0.0/0"]
          + description = "HTTP"
        },
        {
          + from_port   = 443
          + to_port     = 443
          + protocol    = "tcp"
          + cidr_blocks = ["0.0.0.0/0"]
          + description = "HTTPS"
        }
      ]
    # ... other attributes omitted for brevity
}

动态块遍历 var.ingress_rules,为每条规则创建一个 ingress 块,无需手动复制。

Terraform 动态块示意图

Back to Blog

相关文章

阅读更多 »