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 可查看状态中的实际属性。通过对比计划值与输出值,可以判断资源是否按预期创建。若输出为空,通常说明资源属性尚未就绪或名称写错,应回到资源块检查属性引用路径。