HCL 语法基础:语言结构、变量、输出值、局部值与数据类型
HCL(HashiCorp Configuration Language)是 Terraform 的核心配置语言,所有基础设施资源、变量、输出和逻辑都通过 HCL 表达。掌握 HCL 的语法结构、变量系统、输出值、局部值以及数据类型,是编写可维护、可复用 Terraform 配置的基石。本章将系统拆解这些核心概念,并通过表格、代码示例和结构图帮助你快速建立清晰认知。
2.1 HCL 语言结构
HCL 配置文件以 .tf 为扩展名,采用声明式语法。一个典型的 Terraform 配置由以下顶级块(Block)组成:
- terraform {}:配置 Terraform 自身行为,如后端存储、所需 Provider 版本。
- provider {}:声明云平台或服务提供商(如 AWS、Azure、阿里云)。
- resource {}:定义具体的基础设施资源(如虚拟机、VPC、数据库)。
- variable {}:声明输入变量,使配置可参数化。
- output {}:定义输出值,用于向外部暴露资源属性。
- locals {}:定义局部值,用于简化表达式和避免重复。
- data {}:引用外部已有资源的数据源。
HCL 块的基本语法格式如下:
<块类型> "<标签>" "<名称>" {
<参数> = <值>
<嵌套块> {
<参数> = <值>
}
}
例如,定义一个阿里云 ECS 实例:
resource "alicloud_instance" "web" {
instance_name = "web-server"
image_id = "ubuntu_22_04_x64_20G_alibase_20240926.vhd"
instance_type = "ecs.g6.large"
security_groups = [alicloud_security_group.default.id]
}
💡 提示: HCL 是声明式语言,你只需描述“最终状态”,Terraform 自动计算如何从当前状态迁移到目标状态。这与 Ansible、Shell 等过程式工具形成鲜明对比。
2.2 变量(variable)
变量是 Terraform 配置的输入参数,用于将环境差异、敏感信息、部署参数从代码中抽离出来,实现配置的通用化与复用。
2.2.1 变量声明
变量通过 variable 块声明,支持以下元参数:
| 元参数 | 说明 | 是否必填 |
|---|---|---|
type |
指定变量的数据类型,如 string、number、list(string)、map(string) 等 |
否(默认 any) |
default |
设置默认值,若未赋值则使用该值 | 否 |
description |
变量的描述信息,用于文档生成和团队协作 | 否 |
validation |
自定义校验规则,确保输入值符合预期 | 否 |
sensitive |
标记为敏感变量,在日志和输出中隐藏值 | 否(默认 false) |
nullable |
是否允许变量为 null |
否(默认 true) |
变量声明示例:
variable "region" {
description = "部署目标地域"
type = string
default = "cn-hangzhou"
}
variable "instance_count" {
description = "ECS 实例数量"
type = number
default = 2
validation {
condition = var.instance_count > 0 && var.instance_count <= 10
error_message = "实例数量必须在 1 到 10 之间。"
}
}
variable "tags" {
description = "资源标签"
type = map(string)
default = {
Environment = "dev"
Project = "terraform-course"
}
}
variable "db_password" {
description = "数据库密码"
type = string
sensitive = true
}
2.2.2 变量赋值方式
Terraform 支持多种变量赋值方式,优先级从高到低排列:
- 命令行
-var参数:terraform apply -var="region=us-east-1" - 变量文件
.tfvars:自动加载terraform.tfvars或*.auto.tfvars - 环境变量
TF_VAR_前缀:export TF_VAR_region=ap-southeast-1 - 默认值:变量声明中的
default
⚠️ 注意: 敏感变量(如密码、密钥)不要写在
.tfvars 文件中并提交到版本控制。建议使用环境变量或 Terraform Cloud 的敏感变量功能。
2.3 输出值(output)
输出值用于从 Terraform 状态中提取资源属性,供外部系统、CI/CD 管道或运维人员使用。输出值在 terraform apply 后显示在终端,也可通过 terraform output 命令随时查询。
输出值声明语法:
output "<名称>" {
value = <表达式>
description = "输出描述"
sensitive = true # 可选,隐藏输出值
depends_on = [] # 可选,显式依赖
}
实际示例:
output "instance_public_ip" {
description = "ECS 实例公网 IP"
value = alicloud_instance.web.public_ip
}
output "rds_connection_string" {
description = "RDS 数据库连接地址"
value = alicloud_db_instance.default.connection_string
sensitive = false
}
output "db_password" {
description = "数据库密码(仅用于初始化)"
value = var.db_password
sensitive = true
}
📌 最佳实践: 将所有对外暴露的资源标识(IP、域名、连接串、ARN)都定义为输出值。这样团队成员无需登录云控制台,即可通过
terraform output 获取部署结果。
2.4 局部值(local)
局部值类似于编程语言中的局部变量,用于在模块内部简化复杂表达式、避免重复计算、提高可读性。局部值只在当前模块内可见,不会暴露给调用方。
局部值声明语法:
locals {
<名称> = <表达式>
<名称> = <表达式>
}
实际示例:
locals {
# 组合资源名称前缀
name_prefix = "${var.project}-${var.environment}"
# 根据环境选择实例规格
instance_type = var.environment == "production" ? "ecs.g7.4xlarge" : "ecs.g6.large"
# 通用标签
common_tags = {
Name = local.name_prefix
Environment = var.environment
ManagedBy = "Terraform"
}
# 计算子网 CIDR 列表
subnet_cidrs = [for i in range(var.subnet_count) : cidrsubnet(var.vpc_cidr, 8, i)]
}
在资源中引用局部值:
resource "alicloud_instance" "app" {
instance_name = local.name_prefix
instance_type = local.instance_type
tags = local.common_tags
}
💡 提示: 当同一个表达式在多个资源或输出中重复出现时,优先使用
locals 提取为局部值。这不仅能减少代码冗余,还能让后续修改只需改动一处。
2.5 数据类型与表达式
HCL 支持丰富的数据类型和表达式,用于构建灵活、动态的配置。
2.5.1 基本数据类型
| 类型 | 关键字 | 示例 |
|---|---|---|
| 字符串 | string |
"cn-hangzhou" |
| 数字 | number |
42、3.14 |
| 布尔值 | bool |
true、false |
| 空值 | null |
null |
2.5.2 复合数据类型
| 类型 | 关键字 | 示例 | 说明 |
|---|---|---|---|
| 列表 | list(<类型>) |
["dev", "staging", "prod"] |
有序集合,索引从 0 开始 |
| 映射 | map(<类型>) |
{ env = "dev", region = "cn-hangzhou" } |
键值对集合,键为字符串 |
| 对象 | object({...}) |
{ name = string, age = number } |
结构化类型,字段名和类型固定 |
| 元组 | tuple([...]) |
["us-east-1", 80, true] |
有序集合,每个元素类型可不同 |
| 集合 | set(<类型>) |
["dev", "prod"] |
无序不重复集合 |
2.5.3 常用表达式
- 条件表达式:
condition ? true_value : false_value - for 表达式:
[for item in list : item.id]或{for k, v in map : k => v} - 字符串插值:
"${var.name}-${var.env}" - 函数调用:
length(var.subnets)、cidrsubnet("10.0.0.0/16", 8, 1) - 属性引用:
alicloud_instance.web.id、var.region - 合并与查找:
merge(map1, map2)、lookup(map, key, default)
表达式综合示例:
locals {
# 条件选择实例规格
instance_type = var.environment == "production" ? "ecs.g7.4xlarge" : "ecs.g6.large"
# 从 CIDR 列表生成子网名称
subnet_names = [for i, cidr in local.subnet_cidrs : "${local.name_prefix}-subnet-${i}"]
# 合并默认标签和自定义标签
all_tags = merge(local.common_tags, var.extra_tags)
}
2.6 HCL 核心概念关系图
下图展示了 HCL 配置中变量、局部值、资源、输出值之间的数据流向与依赖关系:
2.7 变量与局部值对比
| 对比维度 | variable | locals |
|---|---|---|
| 来源 | 外部输入(命令行、文件、环境变量) | 模块内部定义 |
| 作用域 | 全局(可被子模块引用) | 仅当前模块 |
| 可变性 | 每次 apply 可重新赋值 | 定义后不可变 |
| 敏感标记 | 支持 sensitive = true |
不支持 |
| 默认值 | 支持 default |
必须显式赋值 |
| 典型用途 | 环境差异、密码、地域、实例规格 | 名称拼接、标签合并、CIDR 计算 |
2.8 数据类型选择与校验最佳实践
- 优先使用强类型:为变量指定具体类型(如
string、number、list(string)),避免使用any,以便 Terraform 在 plan 阶段捕获类型错误。 - 使用
validation块:对变量值进行范围、长度、正则校验,将错误提前暴露。 - 对象类型用于复杂结构:当变量包含多个关联字段时,使用
object({...})而非多个独立变量,提高可读性。 - 避免在
locals中执行敏感计算:locals的值会在日志和状态文件中明文存储,敏感信息应通过variable的sensitive标记处理。
📌 本章小结: HCL 的变量、输出值、局部值和数据类型构成了 Terraform 配置的“参数化骨架”。变量负责接收外部输入,局部值负责内部计算与简化,输出值负责对外暴露结果,数据类型与表达式则提供了构建动态配置的语法工具。掌握这些基础,后续章节的模块化、多环境管理和弹性伸缩编排将水到渠成。