HCL 语法基础
HCL 简介
HCL(HashiCorp Configuration Language)是 Terraform 使用的配置语言。它是一种声明式语言,专门为定义基础设施而设计。
HCL 特点
- 人类可读:类似 JSON,但更简洁
- 声明式:描述想要的状态,而非步骤
- 支持注释:单行和多行注释
- 类型安全:支持字符串、数字、布尔、列表、映射等类型
基本语法
块(Block)
块是 HCL 的基本结构单元:
# 基本块语法
<BLOCK_TYPE> "<BLOCK_LABEL>" "<BLOCK_LABEL>" {
# 块体
<IDENTIFIER> = <EXPRESSION>
}
# 示例
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
参数(Argument)
参数是块内的键值对:
resource "aws_instance" "web" {
# 参数名 = 参数值
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
# 参数值可以是表达式
count = var.instance_count
}
注释
# 单行注释
// 也可以使用双斜杠
/*
多行注释
可以跨越多行
*/
resource "aws_instance" "web" {
ami = "ami-xxx" # 行尾注释
}
数据类型
基本类型
字符串(String):
variable "region" {
default = "us-east-1"
}
# 多行字符串
variable "user_data" {
default = <<-EOT
#!/bin/bash
echo "Hello World"
apt-get update
EOT
}
# 字符串插值
locals {
instance_name = "web-${var.environment}"
message = "Instance type is ${var.instance_type}"
}
数字(Number):
variable "instance_count" {
default = 3
}
variable "disk_size" {
default = 100.5
}
布尔(Bool):
variable "enable_monitoring" {
default = true
}
variable "is_production" {
default = false
}
null:
variable "optional_setting" {
default = null
}
集合类型
列表(List):
variable "availability_zones" {
type = list(string)
default = [
"us-east-1a",
"us-east-1b",
"us-east-1c"
]
}
# 访问列表元素
locals {
first_az = var.availability_zones[0]
second_az = var.availability_zones[1]
}
# 列表可以包含不同类型
variable "mixed_list" {
default = ["string", 123, true]
}
集合(Set):
variable "allowed_ips" {
type = set(string)
default = [
"10.0.1.0/24",
"10.0.2.0/24"
]
}
映射(Map):
variable "instance_types" {
type = map(string)
default = {
dev = "t2.micro"
prod = "t2.large"
}
}
# 访问映射值
locals {
dev_type = var.instance_types["dev"]
prod_type = var.instance_types["prod"]
}
# 带类型的映射
variable "tags" {
type = map(string)
default = {
Environment = "Production"
Project = "MyApp"
}
}
对象(Object):
variable "server_config" {
type = object({
instance_type = string
disk_size = number
enable_backup = bool
})
default = {
instance_type = "t2.micro"
disk_size = 100
enable_backup = true
}
}
# 访问对象属性
locals {
instance_type = var.server_config.instance_type
}
元组(Tuple):
variable "connection_info" {
type = tuple([string, number, bool])
default = ["localhost", 8080, true]
}
表达式
算术运算
locals {
# 基本运算
sum = 2 + 3 # 5
difference = 10 - 5 # 5
product = 4 * 5 # 20
quotient = 20 / 4 # 5
remainder = 10 % 3 # 1
# 负数
negative = -5
# 复杂表达式
result = (10 + 5) * 2 # 30
}
比较运算
locals {
equal = 5 == 5 # true
not_equal = 5 != 3 # true
greater = 10 > 5 # true
greater_eq = 10 >= 10 # true
less = 5 < 10 # true
less_eq = 5 <= 5 # true
}
逻辑运算
locals {
and_result = true && false # false
or_result = true || false # true
not_result = !true # false
# 复杂条件
is_valid = var.count > 0 && var.count < 100
}
条件表达式
# 三元运算符
locals {
instance_type = var.environment == "prod" ? "t2.large" : "t2.micro"
# 嵌套条件
size = var.environment == "prod" ? 100 : (
var.environment == "staging" ? 50 : 10
)
}
resource "aws_instance" "web" {
instance_type = var.is_production ? "t2.large" : "t2.micro"
tags = {
Environment = var.environment == "prod" ? "Production" : "Development"
}
}
函数
Terraform 提供了许多内置函数。
字符串函数
locals {
# 连接字符串
full_name = join("-", ["web", "server", "01"]) # "web-server-01"
# 分割字符串
parts = split("-", "web-server-01") # ["web", "server", "01"]
# 大小写转换
upper_text = upper("hello") # "HELLO"
lower_text = lower("WORLD") # "world"
title_text = title("hello world") # "Hello World"
# 替换
replaced = replace("hello world", "world", "terraform") # "hello terraform"
# 去除空格
trimmed = trim(" hello ") # "hello"
# 格式化
formatted = format("Hello %s", "World") # "Hello World"
# 子字符串
substring = substr("hello world", 0, 5) # "hello"
}
数值函数
locals {
# 最大最小值
maximum = max(5, 12, 9) # 12
minimum = min(5, 12, 9) # 5
# 绝对值
abs_value = abs(-5) # 5
# 向上取整
ceil_value = ceil(5.2) # 6
# 向下取整
floor_value = floor(5.9) # 5
# 对数
log_value = log(8, 2) # 3
# 幂运算
pow_value = pow(2, 3) # 8
}
集合函数
locals {
# 列表长度
list_length = length(["a", "b", "c"]) # 3
# 合并列表
merged = concat(["a", "b"], ["c", "d"]) # ["a", "b", "c", "d"]
# 去重
unique_list = distinct(["a", "b", "a", "c"]) # ["a", "b", "c"]
# 包含检查
contains_item = contains(["a", "b", "c"], "b") # true
# 索引
index_of = index(["a", "b", "c"], "b") # 1
# 切片
sliced = slice(["a", "b", "c", "d"], 1, 3) # ["b", "c"]
# 反转
reversed = reverse(["a", "b", "c"]) # ["c", "b", "a"]
# 排序
sorted = sort(["c", "a", "b"]) # ["a", "b", "c"]
}
映射函数
locals {
map1 = { a = 1, b = 2 }
map2 = { b = 3, c = 4 }
# 合并映射
merged_map = merge(map1, map2) # { a = 1, b = 3, c = 4 }
# 获取键列表
keys_list = keys(map1) # ["a", "b"]
# 获取值列表
values_list = values(map1) # [1, 2]
# 查找值
lookup_value = lookup(map1, "a", "default") # 1
lookup_missing = lookup(map1, "z", "default") # "default"
}
时间函数
locals {
# 当前时间戳
current_time = timestamp() # "2024-01-09T10:00:00Z"
# 格式化时间
formatted_time = formatdate("YYYY-MM-DD", timestamp())
}
编码函数
locals {
# Base64 编码
encoded = base64encode("hello")
decoded = base64decode(encoded)
# JSON 编码
json_string = jsonencode({
name = "example"
age = 30
})
# JSON 解码
json_object = jsondecode(json_string)
# URL 编码
url_encoded = urlencode("hello world")
}
文件系统函数
locals {
# 读取文件
file_content = file("${path.module}/config.txt")
# 读取文件列表
file_list = fileset("${path.module}", "*.tf")
# 路径处理
abs_path = abspath("./main.tf")
dir_name = dirname("/path/to/file.txt") # "/path/to"
base_name = basename("/path/to/file.txt") # "file.txt"
}
变量引用
输入变量引用
variable "instance_type" {
default = "t2.micro"
}
resource "aws_instance" "web" {
instance_type = var.instance_type
}
本地变量引用
locals {
common_tags = {
Environment = "Production"
ManagedBy = "Terraform"
}
}
resource "aws_instance" "web" {
tags = local.common_tags
}
资源属性引用
resource "aws_instance" "web" {
ami = "ami-xxx"
# ...
}
resource "aws_eip" "web_ip" {
instance = aws_instance.web.id
}
output "instance_ip" {
value = aws_instance.web.public_ip
}
数据源引用
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
}
循环和条件
for 表达式(列表)
variable "users" {
default = ["alice", "bob", "charlie"]
}
locals {
# 转换为大写
upper_users = [for u in var.users : upper(u)]
# ["ALICE", "BOB", "CHARLIE"]
# 带条件的过滤
long_names = [for u in var.users : u if length(u) > 4]
# ["alice", "charlie"]
# 带索引
indexed = [for i, u in var.users : "${i}-${u}"]
# ["0-alice", "1-bob", "2-charlie"]
}
for 表达式(映射)
variable "instance_types" {
default = {
web = "t2.micro"
db = "t2.small"
}
}
locals {
# 转换映射
upper_keys = {
for k, v in var.instance_types : upper(k) => v
}
# { WEB = "t2.micro", DB = "t2.small" }
# 过滤映射
filtered = {
for k, v in var.instance_types : k => v if v == "t2.micro"
}
# { web = "t2.micro" }
}
count 元参数
variable "instance_count" {
default = 3
}
resource "aws_instance" "web" {
count = var.instance_count
ami = "ami-xxx"
instance_type = "t2.micro"
tags = {
Name = "web-${count.index}"
}
}
# 访问资源
output "instance_ids" {
value = aws_instance.web[*].id
}
for_each 元参数
variable "instances" {
default = {
web = "t2.micro"
db = "t2.small"
}
}
resource "aws_instance" "servers" {
for_each = var.instances
ami = "ami-xxx"
instance_type = each.value
tags = {
Name = each.key
}
}
# 访问资源
output "instance_ips" {
value = {
for k, instance in aws_instance.servers : k => instance.public_ip
}
}
dynamic 块
variable "ingress_rules" {
default = [
{ port = 80, protocol = "tcp" },
{ port = 443, protocol = "tcp" },
]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = ingress.value.protocol
cidr_blocks = ["0.0.0.0/0"]
}
}
}
最佳实践
1. 使用有意义的命名
# ❌ 不好
resource "aws_instance" "i" {
ami = "ami-xxx"
}
# ✅ 好
resource "aws_instance" "web_server" {
ami = "ami-xxx"
}
2. 使用注释
# Production web server configuration
resource "aws_instance" "web" {
ami = "ami-xxx" # Ubuntu 20.04 LTS
instance_type = "t2.micro" # Free tier eligible
}
3. 格式化代码
# 自动格式化
terraform fmt
# 递归格式化
terraform fmt -recursive
4. 验证语法
# 验证配置
terraform validate
5. 使用本地变量简化
# ❌ 重复代码
resource "aws_instance" "web" {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
Project = "MyApp"
}
}
resource "aws_instance" "db" {
tags = {
Environment = "Production"
ManagedBy = "Terraform"
Project = "MyApp"
}
}
# ✅ 使用本地变量
locals {
common_tags = {
Environment = "Production"
ManagedBy = "Terraform"
Project = "MyApp"
}
}
resource "aws_instance" "web" {
tags = merge(local.common_tags, {
Name = "Web Server"
})
}
resource "aws_instance" "db" {
tags = merge(local.common_tags, {
Name = "Database"
})
}
总结
HCL 语法要点:
- 块结构:资源、变量、输出等都是块
- 数据类型:字符串、数字、布尔、列表、映射、对象
- 表达式:算术、比较、逻辑、条件
- 函数:字符串、数值、集合、编码等内置函数
- 引用:变量、资源、数据源引用
- 循环:for 表达式、count、for_each
- 最佳实践:命名规范、注释、格式化
掌握 HCL 语法是编写高质量 Terraform 代码的基础!
下一章:Provider 和资源管理