3. HCL语法与资源定义基础

在 Terraform 中,HCL(HashiCorp Configuration Language)是描述基础设施的声明式语言。要写出第一个可维护的云数据库实例资源定义,不能只把参数硬编码在资源块里,而应理解变量、输出、局部值、数据类型、表达式与内置函数如何协同工作。本节以阿里云 RDS MySQL 实例为例,逐步构建一个结构清晰、可复用、可验证的资源配置。

一、从硬编码到参数化:变量与数据类型

最直接的资源定义是把所有参数写死:

resource "alicloud_db_instance" "demo" {
  engine               = "MySQL"
  engine_version       = "8.0"
  instance_type        = "mysql.n2.medium.2c"
  instance_storage     = 50
  instance_charge_type = "Postpaid"
  vswitch_id           = "vsw-bp1xxxxxx"
  security_ips         = ["10.0.0.0/8"]
}

这种写法在单环境演示中可行,但一旦需要区分开发、测试、生产,就会产生大量重复。HCL 的 variable 块用于声明输入变量,每个变量应明确类型。常用类型包括:string、number、bool、list(string)、map(string)、object({...})。类型不仅是文档,Terraform 会在计划阶段做类型转换与校验,类型不匹配会直接报错。

variable "db_engine_version" {
  type        = string
  default     = "8.0"
  description = "RDS MySQL 引擎版本"
}

variable "db_instance_type" {
  type        = string
  description = "实例规格,例如 mysql.n2.medium.2c"
}

variable "db_storage_gb" {
  type        = number
  default     = 50
  validation {
    condition     = var.db_storage_gb >= 20 && var.db_storage_gb <= 1000
    error_message = "存储必须在 20GB 到 1000GB 之间。"
  }
}

variable "db_security_ips" {
  type    = list(string)
  default = ["10.0.0.0/8"]
}

这里 validation 块是 HCL 表达式与内置函数的典型应用:condition 返回布尔值,只有为真才通过。变量可以来自命令行 -var、terraform.tfvars 或环境变量 TF_VAR_,优先级由 Terraform 规定,实际使用时建议统一放在 terraform.tfvars 中,避免隐式覆盖。

二、局部值:把重复表达式收敛到一处

当多个资源需要共享同一命名规则或标签时,locals 比变量更合适。变量是外部输入,局部值是内部计算。例如数据库实例名需要带环境前缀,且长度受限:

locals {
  name_prefix = "${var.env}-${var.project}"
  db_name     = substr(replace(lower(local.name_prefix), "_", "-"), 0, 30)
  common_tags = {
    Env     = var.env
    Project = var.project
    Managed = "terraform"
  }
}

其中 lower、replace、substr 都是内置函数。表达式 "${var.env}-${var.project}" 使用插值语法,把变量拼接成字符串。局部值在每次 plan/apply 时重新计算,不单独存储状态,因此适合放派生值。

三、资源定义:把变量、局部值与表达式接入实例

现在把前面的输入接入资源块。注意 instance_storage 使用 var.db_storage_gb,security_ips 使用列表变量,tags 使用局部值:

resource "alicloud_db_instance" "mysql" {
  engine               = "MySQL"
  engine_version       = var.db_engine_version
  instance_type        = var.db_instance_type
  instance_storage     = var.db_storage_gb
  instance_charge_type = "Postpaid"
  instance_name        = local.db_name
  vswitch_id           = var.vswitch_id
  security_ips         = var.db_security_ips
  tags                 = local.common_tags
}

这里体现了 HCL 的核心分工:变量负责外部差异,局部值负责内部派生,资源块负责声明目标状态。Terraform 不执行“创建步骤”,而是把资源块与状态文件对比,计算出需要新增、修改或删除的对象。

四、输出:让结果可被引用与验证

资源创建后,需要把连接地址、端口等关键信息暴露出来。output 块可以引用资源属性,属性通过 资源类型.资源名.属性 访问:

output "db_connection_string" {
  value       = alicloud_db_instance.mysql.connection_string
  description = "RDS 内网连接地址"
}

output "db_port" {
  value = alicloud_db_instance.mysql.port
}

output "db_summary" {
  value = {
    name    = alicloud_db_instance.mysql.instance_name
    engine  = alicloud_db_instance.mysql.engine_version
    storage = alicloud_db_instance.mysql.instance_storage
  }
}

输出值在 terraform apply 结束后打印,也可被其他模块通过 module.xxx.db_port 引用。若输出包含敏感信息,应加 sensitive = true,避免明文出现在日志中。

五、表达式与内置函数在数据库场景中的实际用法

除了字符串拼接,表达式还支持条件、集合操作和函数组合。例如根据环境决定是否开启高可用:

locals {
  is_prod      = var.env == "prod"
  category     = local.is_prod ? "HighAvailability" : "Basic"
  backup_days  = local.is_prod ? 30 : 7
  zone_count   = length(var.availability_zones)
}

条件表达式 条件 ? 真值 : 假值 在数据库规格选择中非常常见。length 返回列表元素个数,可用于校验可用区数量。再如 join 把安全 IP 列表拼成逗号分隔字符串,cidrhost 计算子网内主机地址,coalesce 返回第一个非空值,这些函数都能减少硬编码。

需要特别注意的是,内置函数不能随意嵌套导致可读性下降。建议把复杂表达式拆到 locals 中,并给局部值起有业务含义的名字,例如 db_name、common_tags,而不是 tmp1、tmp2。

六、一个可执行的最小示例与验证方式

把上述片段组织成完整配置后,执行顺序如下:先 terraform init 初始化 provider,再 terraform validate 检查语法与类型,然后 terraform plan -var-file="prod.tfvars" 查看计划。计划输出中应能看到 + alicloud_db_instance.mysql,并显示 instance_storage = 50、engine_version = "8.0" 等具体值。若变量类型错误,例如把 db_storage_gb 写成字符串 "50",Terraform 会尝试转换;若写成 "fifty",则直接报类型错误。若 validation 不通过,会在 plan 阶段提示存储范围错误。

应用完成后,terraform output db_connection_string 可单独读取连接地址,terraform state show alicloud_db_instance.mysql 可查看状态中的实际属性。通过对比计划值与输出值,可以判断资源是否按预期创建。若输出为空,通常说明资源属性尚未就绪或名称写错,应回到资源块检查属性引用路径。

HCL 数据库资源定义:输入 → 派生 → 资源 → 输出 variable 输入 db_engine_version: string db_instance_type: string db_storage_gb: number db_security_ips: list(string) env / project: string validation 校验范围 locals 派生 name_prefix = env-project db_name = substr(replace(...)) common_tags = { Env, Project } category = prod ? HA : Basic backup_days = prod ? 30 : 7 表达式 + 内置函数 resource 声明 alicloud_db_instance.mysql engine = "MySQL" engine_version = var... instance_storage = var... security_ips = var... tags = local.common_tags output connection _string port db_summary sensitive 执行与验证链 terraform init → terraform validate → terraform plan -var-file=prod.tfvars → terraform apply → terraform output plan 阶段检查类型、validation 与表达式;apply 后通过 output 与 state show 核对实际属性。 本节关键内置函数 lower / replace / substr:规范化实例名 length:统计可用区数量 join:拼接安全 IP 列表 coalesce:取第一个非空值 条件表达式 ? ::按环境选择规格 cidrhost:计算子网主机地址