Terrafrom 基本语法

369次阅读
没有评论

基本语法

语法简介

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"  
    }
  } 
}
1166
xadocker
版权声明:本站原创文章,由 xadocker 2022-04-03发表,共计11538字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码
载入中...
0.295