Terraform 函数:让你的基础设施获得超能力

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

Source: Dev.to

引言

在 AWS 30 天挑战期间,我花了整整两天时间探索 Terraform 的内置函数。它们把许多冗长、易出错的配置转化为简洁、可投入生产的代码。下面是我发现的最实用的模式,每个都配有实际示例。

使用 Terraform 控制台

在编辑 main.tf 之前,先启动交互式控制台来测试表达式:

terraform console
> lower("HELLO WORLD")
"hello world"

> max(5, 12, 9)
12

> split(",", "80,443,8080")
[
  "80",
  "443",
  "8080",
]

> reverse(["a", "b", "c"])
[
  "c",
  "b",
  "a",
]

控制台让你在不进行任何部署的情况下验证逻辑。

1. 规范化资源名称

问题 – AWS 资源通常要求使用小写、连字符的名称。

解决方案

locals {
  clean_name = lower(replace(var.project_name, " ", "-"))
}

resource "aws_resourcegroups_group" "project" {
  name = local.clean_name
}

lower()replace() 对保持命名一致性至关重要。

2. 清理 S3 Bucket 名称

问题 – S3 Bucket 名称必须小写、不能包含下划线或特殊字符,且长度 ≤ 63 字符。

解决方案

locals {
  sanitized_bucket_name = substr(
    lower(
      replace(
        replace(var.bucket_name_input, "_", "-"),
        "/[^a-z0-9-]/", ""
      )
    ),
    0,
    63
  )
}

嵌套函数让你一次性完成下划线替换、非法字符剔除、转小写以及截断。

3. 从 CSV 生成安全组规则

问题 – 将逗号分隔的端口列表转换为单独的 ingress 块。

解决方案

variable "allowed_ports" {
  default = "80,443,8080"
}

locals {
  ports_list = split(",", var.allowed_ports)
}

resource "aws_security_group" "web" {
  name = "web-sg"

  dynamic "ingress" {
    for_each = local.ports_list
    content {
      from_port   = tonumber(ingress.value)
      to_port     = tonumber(ingress.value)
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  }
}

split() 将字符串转为列表,进而驱动 dynamic 块。

4. 根据环境选择实例类型

问题 – 不同环境需要不同的实例规格。

解决方案

variable "environment" {
  default = "dev"
}

locals {
  instance_types = {
    dev     = "t3.micro"
    staging = "t3.small"
    prod    = "t3.large"
  }

  selected_type = lookup(local.instance_types, var.environment, "t3.micro")
}

resource "aws_instance" "app" {
  ami           = var.ami_id
  instance_type = local.selected_type
}

lookup() 提供基于映射的条件逻辑,并带有安全的默认值。

5. 验证实例类型模式

问题 – 强制实例类型遵循公司命名约定(例如 t2.*t3.*)。

解决方案

variable "instance_type" {
  type = string

  validation {
    condition     = can(regex("^(t2|t3)\\.", var.instance_type))
    error_message = "Instance type must start with 't2.' or 't3.'"
  }
}

regex() 检查模式,can() 则在匹配失败时安全返回 false 而不是报错。

6. 命名与密钥处理

问题 – 确保备份名称遵循约定并且密码保持机密。

解决方案

variable "backup_name" {
  type = string

  validation {
    condition     = endswith(var.backup_name, "-backup")
    error_message = "Backup name must end with '-backup'"
  }
}

variable "db_password" {
  type      = string
  sensitive = true
}

output "backup_info" {
  value = {
    name     = var.backup_name
    password = sensitive(var.db_password)
  }
  sensitive = true
}

endswith()/startswith() 用于字符串校验,sensitive() 防止机密泄露。

7. 成本计算

问题 – 计算月度总费用、应用抵扣并找出单项最高支出。

解决方案

variable "monthly_costs" {
  default = [120.50, 85.00, 200.75, 50.00]
}

variable "credit" {
  default = -50.00  # Negative credit
}

locals {
  total_cost    = sum(var.monthly_costs)
  actual_credit = abs(var.credit)
  final_cost    = max(local.total_cost - local.actual_credit, 0)
  highest_cost  = max(var.monthly_costs...)
}

output "cost_summary" {
  value = {
    total_before_credit = local.total_cost
    credit_applied      = local.actual_credit
    final_bill          = local.final_cost
    highest_single_cost = local.highest_cost
  }
}

sum()abs()max() 以及展开运算符 (...) 让算术运算变得直观。

8. 时间戳格式化

问题 – 为标签和资源名称生成统一的时间戳。

解决方案

locals {
  current_time = timestamp()

  formatted_tags = {
    CreatedAt  = formatdate("YYYY-MM-DD hh:mm:ss ZZZ", local.current_time)
    BackupDate = formatdate("YYYY-MM-DD", local.current_time)
    Year       = formatdate("YYYY", local.current_time)
  }
}

resource "aws_s3_bucket" "backups" {
  bucket = "backups-${formatdate("YYYY-MM-DD", timestamp())}"
  tags   = local.formatted_tags
}

timestamp() 返回 UTC 时间,formatdate() 让你按需塑形。

9. 读取 JSON 配置并存储密钥

问题 – 加载包含数据库凭证的 JSON 文件并将其存入 AWS Secrets Manager。

解决方案

locals {
  # Verify the file exists
  config_exists = fileexists("${path.module}/config/database.json")

  # Read and decode JSON (only if the file is present)
  db_config = jsondecode(
    file("${path.module}/config/database.json")
  )
}

resource "aws_secretsmanager_secret" "db" {
  name = "db-credentials"
}

resource "aws_secretsmanager_secret_version" "db_version" {
  secret_id     = aws_secretsmanager_secret.db.id
  secret_string = jsonencode(local.db_config)
}
Back to Blog

相关文章

阅读更多 »

第12天:AWS Terraform 函数

Terraform 中的高级函数 基于第 11 天所介绍的基础函数,今天我们将探索更多能够增强 Terraform 的专用函数……