4. HCL语法精要与网络资源定义
在 Terraform 中,HCL(HashiCorp Configuration Language)是描述基础设施的唯一入口。网络资源自动化部署的可靠性,很大程度上取决于我们能否用 HCL 准确表达“要创建什么、依赖什么、暴露什么”。本节以企业网络场景为主线,把资源块、变量、输出、数据类型、表达式和内置函数串成一条可落地的配置链。
资源块:网络资源的声明单元
资源块是 Terraform 管理对象的最小声明单位,语法为 resource "类型" "本地名" { ... }。类型决定调用哪个 Provider 的 API,本地名用于在同一模块内引用。以阿里云 VPC 与交换机为例:
resource "alicloud_vpc" "prod" {
vpc_name = "prod-vpc"
cidr_block = "10.20.0.0/16"
}
resource "alicloud_vswitch" "app" {
vpc_id = alicloud_vpc.prod.id
cidr_block = "10.20.1.0/24"
zone_id = "cn-hangzhou-h"
vswitch_name = "app-switch"
}
这里 alicloud_vpc.prod.id 是隐式引用,Terraform 会据此建立依赖关系:先建 VPC,再建交换机。资源块中的参数名必须与 Provider Schema 一致,写错会在 terraform validate 阶段报错,而不是等到 apply 才失败。
变量:把网络参数从代码中抽离
企业网络通常按环境、地域、网段划分。把这些值硬编码在资源块里,会导致复制粘贴和人为错误。变量块 variable 用于声明输入,支持类型、默认值、描述和校验。
variable "env" {
type = string
description = "环境标识"
default = "prod"
}
variable "vpc_cidr" {
type = string
default = "10.20.0.0/16"
validation {
condition = can(cidrnetmask(var.vpc_cidr))
error_message = "vpc_cidr 必须是合法 CIDR。"
}
}
variable "azs" {
type = list(string)
default = ["cn-hangzhou-h", "cn-hangzhou-i"]
}
变量值可通过 -var、terraform.tfvars 或环境变量 TF_VAR_ 传入。优先级从高到低为:命令行 -var、*.auto.tfvars、terraform.tfvars、环境变量、默认值。生产环境建议把 terraform.tfvars 纳入版本控制,敏感值用 Vault 或 CI 变量注入。
数据类型:约束网络参数的形状
HCL 的基础类型包括 string、number、bool,复合类型包括 list、set、map、object、tuple。网络场景中,网段列表用 list(string),可用区到网段的映射用 map(string),而包含名称、CIDR、网关的完整子网定义更适合 object:
variable "subnets" {
type = map(object({
cidr = string
az = string
}))
default = {
app = { cidr = "10.20.1.0/24", az = "cn-hangzhou-h" }
db = { cidr = "10.20.2.0/24", az = "cn-hangzhou-i" }
}
}
类型约束越精确,错误越早暴露。若把 subnets 写成 map(any),虽然能通过,但后续引用 each.value.cidr 时缺少类型保护,容易在运行时才报错。
表达式与内置函数:让网络定义具备计算能力
表达式用于在资源块中做引用、条件判断和集合遍历。常用形式包括:
- 条件表达式:
var.env == "prod" ? "10.20.0.0/16" : "10.30.0.0/16" - for 表达式:
[for s in var.azs : "${var.env}-${s}"] - 展开表达式:
alicloud_vswitch.app[*].id
内置函数在网络资源定义中尤其高频。例如用 cidrsubnet 从 VPC 网段自动切分子网,避免手工计算:
resource "alicloud_vswitch" "app" {
vpc_id = alicloud_vpc.prod.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, 1)
zone_id = var.azs[0]
}
当 var.vpc_cidr = "10.20.0.0/16" 时,cidrsubnet(..., 8, 1) 得到 10.20.1.0/24。类似地,cidrhost 可计算网关地址,lookup 可从 map 中按 key 取值,merge 可合并标签,try 可处理可选属性。
输出:把网络结果交给下游
输出块 output 用于暴露资源属性,供其他模块、CI 流水线或人工查看。网络模块通常输出 VPC ID、交换机 ID 列表和网段信息:
output "vpc_id" {
value = alicloud_vpc.prod.id
}
output "vswitch_ids" {
value = [for s in alicloud_vswitch.app : s.id]
}
输出值可以是敏感值,此时应加 sensitive = true,避免在日志中明文打印。跨模块引用时,通过 module.network.vpc_id 获取,形成模块间的数据流。
综合示例:一条完整的网络定义链
把上述元素组合起来,一个可复用的网络模块大致如下:变量接收环境与网段,资源块创建 VPC 和多个交换机,表达式与函数完成子网切分,输出暴露关键 ID。其数据流与依赖关系可用下图表示:
图中左侧是输入变量,中间是表达式与函数对变量做变换,右侧是资源块消费变换结果,底部输出把资源属性交给下游。这条链的每一环都可以独立测试:terraform console 可验证函数结果,terraform plan 可观察资源变更,terraform output 可确认暴露值。
terraform console 验证 cidrsubnet、lookup 等函数在目标网段上的输出,再写入资源块,可显著减少 plan 阶段的反复调整。sensitive = true 只控制 CLI 输出,不会加密 state 文件,state 仍需远端加密存储。