共计 11538 个字符,预计需要花费 29 分钟才能阅读完成。
基本语法
语法简介
Terraform 语言的主要目的是声明基础设施对象的,其语言特性只是为了使资源的定义更加灵活和方便。基本语法如下:
resource "aws_vpc" "main" {
cidr_block = var.base_cidr_block
}
<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
# Block body
<IDENTIFIER> = <EXPRESSION> # Argument
}
其配置语法核心主要围绕两个结构:
- BLOCK:可以当作一个容器,里面声明多种资源对象属性,可以嵌套block
- IDENTIFIER:定义资源属性值
resource "aws_instance" "example" {
# 参数尽量放在同层级块前面
count = 2 # meta-argument first
ami = "abc123"
instance_type = "t2.micro"
network_interface {
# ...
}
lifecycle { # meta-argument block last
create_before_destroy = true
}
}
Terraform 语言是声明性的,描述的是预期目标,而不是达到该目标的步骤。块的顺序和它们组织成的文件通常并不重要;Terraform 在确定操作顺序时仅考虑资源之间的隐式和显式关系。
变量
输入变量
# 未定义default值,则会在执行过程中提示需要为此变量赋值
variable "image_id" {
type = string
# 禁止输入变量为空
nullable = false
}
# 定义了default值,则会在执行过程中默认使用该值
variable "availability_zone_names" {
type = list(string)
default = ["us-west-1a"]
}
variable "docker_ports" {
# 设置sensitive为true,隐藏执行时输出该变量,常用于隐藏敏感信息
sensitive = true
type = list(object({
internal = number
external = number
protocol = string
}))
default = [
{
internal = 8300
external = 8300
protocol = "tcp"
}
]
}
命令行赋值变量
# 执行时赋值
$ terraform apply -var="image_id=ami-abc123"
$ terraform apply -var='image_id_list=["ami-abc123","ami-def456"]'
$ terraform plan -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}' -var=''
通过文件赋值变量,文件后缀为.tfvars
cat >test.tfvars<<'EOF'
image_id = "ami-abc123"
availability_zone_names = [
"us-east-1a",
"us-west-1c",
]
EOF
# 当前模块内有名为terraform.tfvars,可以不指定变量文件,因为默认使用terraform.tfvars或者.auto.tfvars文件
terraform apply -var-file="testing.tfvars"
环境变量方式赋值
# 必须使用该格式定义:TF_VAR_<NAME>
export TF_VAR_image_id=ami-abc123
# terraform apply
断言
# 如果输入的image_id不符合正则表达式的要求,那么regex函数调用会抛出一个错误,这个错误会被can函数捕获,输出false
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
# regex(...) fails if it cannot find a match
condition = can(regex("^ami-", var.image_id))
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
变量优先级
- 环境变量
terraform.tfvars
文件(如果存在的话)terraform.tfvars.json
文件(如果存在的话)- 所有的
.auto.tfvars
或者.auto.tfvars.json
文件,以字母顺序排序处理 - 通过
-var
或是-var-file
命令行参数传递的输入变量,按照在命令行参数中定义的顺序加载
输出值
局部变量
定义局部变量,一个locals可以定义多个值,文件中可以存在多个locals定义,在引用locals值时,需要使用local去使用(注意没有s)
locals {
# Ids for multiple sets of EC2 instances, merged together
instance_ids = concat(aws_instance.blue.*.id, aws_instance.green.*.id)
}
# 调用locals时为local.<name>
locals {
# Common tags to be assigned to all resources
common_tags = {
Service = local.service_name
Owner = local.owner
}
}
Block内基本元参数
depends_on
使用该参数可以解决Terraform无法自动推导资源和模块依赖关系顺序
示例:创建vswitch前需要先创建vpc
[root@node-nfs vpc_terraform]# cat terraform.tf
provider "alicloud" {
access_key = "xxx"
secret_key = "xxx"
region = "cn-guangzhou"
}
resource "alicloud_vpc" "main" {
# VPC名称
vpc_name = "terraform-vpc"
# VPC地址块
cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "main" {
# VPC ID
vpc_id = alicloud_vpc.main.id
# 交换机地址块
cidr_block = "10.1.0.0/24"
# 可用区
availability_zone = "cn-guangzhou-a"
# 资源依赖,会优先创建该依赖资源
depends_on = [alicloud_vpc.main]
}
resource "alicloud_security_group" "default" {
name = "default"
vpc_id = alicloud_vpc.main.id
}
resource "alicloud_security_group_rule" "allow_all_tcp" {
type = "ingress"
ip_protocol = "tcp"
nic_type = "intranet"
policy = "accept"
port_range = "1/65535"
priority = 1
security_group_id = alicloud_security_group.default.id
cidr_ip = "0.0.0.0/0"
}
count
对某种相同类型资源创建多个实例时,需要用到count,同时cout还存在index属性可以引用
示例:创建多个vswtich,同时应用count.index设置不同网段和名字
terraform.tf样例文件
[root@node-nfs demo]# cat >terraform.tf<<'EOF'
provider "alicloud" {
access_key = "xxx"
secret_key = "xxx"
region = "cn-guangzhou"
}
variable "cidr_blocks" {
type = list(string)
description = "cidr for vswitch"
default = ["10.1.0.0/24","10.1.1.0/24","10.1.2.0/24","10.1.3.0/24","10.1.4.0/24"]
}
resource "alicloud_vpc" "main" {
# VPC名称
vpc_name = "terraform-vpc"
# VPC地址块
cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "main" {
# 创建5个vswitch
count = length(var.cidr_blocks)
vswitch_name = "vsw ${count.index}"
# VPC ID
vpc_id = alicloud_vpc.main.id
# 交换机地址块
cidr_block = var.cidr_blocks[count.index]
# 可用区
availability_zone = "cn-guangzhou-a"
# 资源依赖,会优先创建该依赖资源
depends_on = [alicloud_vpc.main]
}
EOF
查看执行计划
[root@node-nfs demo]# terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# alicloud_vpc.main will be created
+ resource "alicloud_vpc" "main" {
+ cidr_block = "10.1.0.0/21"
+ id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ name = (known after apply)
+ resource_group_id = (known after apply)
+ route_table_id = (known after apply)
+ router_id = (known after apply)
+ router_table_id = (known after apply)
+ status = (known after apply)
+ vpc_name = "terraform-vpc"
}
# alicloud_vswitch.main[0] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.0.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw 0"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main[1] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.1.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw 1"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main[2] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.2.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw 2"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main[3] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.3.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw 3"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main[4] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.4.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw 4"
+ zone_id = (known after apply)
}
Plan: 6 to add, 0 to change, 0 to destroy.
╷
│ Warning: "availability_zone": [DEPRECATED] Field 'availability_zone' has been deprecated from provider version 1.119.0. New field 'zone_id' instead.
│
│ with alicloud_vswitch.main,
│ on terraform.tf line 18, in resource "alicloud_vswitch" "main":
│ 18: resource "alicloud_vswitch" "main" {
│
│ (and 5 more similar warnings elsewhere)
╵
for_each
如果彼此之间的参数差异无法直接从count
的下标派生,那么可以使用for_each
terraform.tf样例文件
[root@node-nfs demo]# cat terraform.tf
provider "alicloud" {
access_key = "xxx"
secret_key = "xxx"
region = "cn-guangzhou"
}
variable "cidr_blocks" {
type = map(object({
vsw_name = string
vsw_cidr = string
vsw_zone = string
}))
description = "cidr for vswitch"
default = {
"vsw0" = {
vsw_name = "vsw0"
vsw_cidr = "10.1.0.0/24"
vsw_zone = "cn-guangzhou-a"
}
"vsw1" = {
vsw_name = "vsw1"
vsw_cidr = "10.1.1.0/24"
vsw_zone = "cn-guangzhou-b"
}
"vsw2" = {
vsw_name = "vsw2"
vsw_cidr = "10.1.2.0/24"
vsw_zone = "cn-guangzhou-b"
}
"vsw3" = {
vsw_name = "vsw3"
vsw_cidr = "10.1.3.0/24"
vsw_zone = "cn-guangzhou-a"
}
}
}
resource "alicloud_vpc" "main" {
# VPC名称
vpc_name = "terraform-vpc"
# VPC地址块
cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "main" {
# 创建多个vswitch
for_each = var.cidr_blocks
vswitch_name = each.value.vsw_name
# VPC ID
vpc_id = alicloud_vpc.main.id
# 交换机地址块
cidr_block = each.value.vsw_cidr
# 可用区
availability_zone = each.value.vsw_zone
# 资源依赖,会优先创建该依赖资源
depends_on = [alicloud_vpc.main]
}
查看执行计划
[root@node-nfs demo]# terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# alicloud_vpc.main will be created
+ resource "alicloud_vpc" "main" {
+ cidr_block = "10.1.0.0/21"
+ id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ name = (known after apply)
+ resource_group_id = (known after apply)
+ route_table_id = (known after apply)
+ router_id = (known after apply)
+ router_table_id = (known after apply)
+ status = (known after apply)
+ vpc_name = "terraform-vpc"
}
# alicloud_vswitch.main["vsw0"] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.0.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw0"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main["vsw1"] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-b"
+ cidr_block = "10.1.1.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw1"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main["vsw2"] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-b"
+ cidr_block = "10.1.2.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw2"
+ zone_id = (known after apply)
}
# alicloud_vswitch.main["vsw3"] will be created
+ resource "alicloud_vswitch" "main" {
+ availability_zone = "cn-guangzhou-a"
+ cidr_block = "10.1.3.0/24"
+ id = (known after apply)
+ name = (known after apply)
+ status = (known after apply)
+ vpc_id = (known after apply)
+ vswitch_name = "vsw3"
+ zone_id = (known after apply)
}
Plan: 5 to add, 0 to change, 0 to destroy.
╷
│ Warning: "availability_zone": [DEPRECATED] Field 'availability_zone' has been deprecated from provider version 1.119.0. New field 'zone_id' instead.
│
│ with alicloud_vswitch.main,
│ on terraform.tf line 43, in resource "alicloud_vswitch" "main":
│ 43: resource "alicloud_vswitch" "main" {
│
│ (and 4 more similar warnings elsewhere)
provider
可以单独为block指定provider,未指定则使用全局块provider
terraform.tf样例文件
[root@node-nfs demo]# cat terraform.tf
provider "alicloud" {
alias = network_team
access_key = "networkaccsess"
secret_key = "networksercret"
region = "cn-guangzhou"
}
provider "alicloud" {
alias = sre_team
access_key = "sre_teamaccsess"
secret_key = "sre_teamsercret"
region = "cn-guangzhou"
}
resource "alicloud_vpc" "main" {
# VPC名称
vpc_name = "terraform-vpc"
# VPC地址块
cidr_block = "10.1.0.0/21"
provider = alicloud.network_team
}
timeouts
设置操作超时,不是所有资源都可以设置,所以需要自行查看provider对应的资源文档
resource "aws_db_instance" "example" {
# ...
timeouts {
create = "60m"
delete = "2h"
}
}
常用表达式
for循环,类似python的列表生成器
# 新生成一个大写的元组[]
[for s in var.list : upper(s)]
# 生成一个大写的对象{},该表达式返回一个对象,对象的成员属性名称就是源列表中的元素,值就是对应的大写值
{for s in var.list : s => upper(s)}
# 添加判断
[for s in var.list : upper(s) if s != ""]
# 遍历对象
[for k, v in var.map : length(k) + length(v)]
字符串模板
# 引用值
"Hello, ${var.name}!"
# 逻辑判断后再引用值
"Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
Terraform 模块
通常编写资源文件描述基础架构时,都会分前端、后端、网络、数据库、中间件等,如果所有资源都在一个文件里描述会显得臃肿,这是可以使用terraform模块来划分资源结构,利于聚焦和维护某一类型资源
# 模块结构
[root@node-nfs demo]# tree -a
.
├── modules
│ └── vpc-module
│ ├── main.tf # 模块入口文件
│ ├── providers.tf
│ └── variables.tf # 模块变量文件
├── providers.tf
└── terraform.tf
2 directories, 5 files
其文件内容
[root@node-nfs demo]# cat providers.tf
terraform {
required_providers {
alicloud = {
#source = "aliyun/alicloud"
source = "local-registry/aliyun/alicloud"
version = "1.166.0"
}
}
}
[root@node-nfs demo]# cat terraform.tf
provider "alicloud" {
access_key = "xxx"
secret_key = "xxx"
region = "cn-guangzhou"
}
module "vpc-module" {
source = "./modules/vpc-module"
}
[root@node-nfs demo]# cat modules/vpc-module/providers.tf
terraform {
required_providers {
alicloud = {
#source = "aliyun/alicloud"
source = "local-registry/aliyun/alicloud"
version = "1.166.0"
}
}
}
[root@node-nfs demo]# cat modules/vpc-module/main.tf
provider "alicloud" {
access_key = "xxx"
secret_key = "xxx"
region = "cn-guangzhou"
}
resource "alicloud_vpc" "main" {
# VPC名称
vpc_name = "terraform-vpc"
# VPC地址块
cidr_block = "10.1.0.0/21"
}
resource "alicloud_vswitch" "main" {
# 创建多个vswitch
for_each = var.cidr_blocks
vswitch_name = each.value.vsw_name
# VPC ID
vpc_id = alicloud_vpc.main.id
# 交换机地址块
cidr_block = each.value.vsw_cidr
# 可用区
availability_zone = each.value.vsw_zone
# 资源依赖,会优先创建该依赖资源
depends_on = [alicloud_vpc.main]
}
[root@node-nfs demo]# cat modules/vpc-module/variables.tf
variable "cidr_blocks" {
type = map(object({
vsw_name = string
vsw_cidr = string
vsw_zone = string
}))
description = "cidr for vswitch"
default = {
"vsw0" = {
vsw_name = "vsw0"
vsw_cidr = "10.1.0.0/24"
vsw_zone = "cn-guangzhou-a"
}
"vsw1" = {
vsw_name = "vsw1"
vsw_cidr = "10.1.1.0/24"
vsw_zone = "cn-guangzhou-b"
}
"vsw2" = {
vsw_name = "vsw2"
vsw_cidr = "10.1.2.0/24"
vsw_zone = "cn-guangzhou-b"
}
"vsw3" = {
vsw_name = "vsw3"
vsw_cidr = "10.1.3.0/24"
vsw_zone = "cn-guangzhou-a"
}
}
}