关于java:Terraform-101-从入门到实践-第五章-HCL语法

3次阅读

共计 5754 个字符,预计需要花费 15 分钟才能阅读完成。

《Terraform 101 从入门到实际》这本小册在南瓜慢说官方网站和 GitHub 两个中央同步更新,书中的示例代码也是放在 GitHub 上,不便大家参考查看。


介绍了 Terraform 一些比拟根底的概念后,咱们能够先理解一下 Terraform 的语法,也就是 HCL 的语法。

变量 Variables

变量是实现代码复用的一种形式,同样的代码不同的变量往往会有不同的成果。而在 Terraform 里,有一个概念十分重要,就是变量都是从属于模块的。变量无奈跨模块援用。即在模块 A 定义的变量 X,无奈在模块 B 中间接援用。但父模块的变量,能够作为子模块的入参;而子模块的输入变量能够被父模块获取。

变量类型

从语言角度

跟任何编程语言一样,变量都是有类型的,Terraform 的变量类型从语言的角度可分为两大类:根本类型和组合类型,具体如下:

根本类型:

  • 字符串 string,如"pkslow.com"
  • 数字 number,如 3195.11
  • 布尔值 bool,如true

组合类型:

  • 列表 list(<T>),如["dev", "uat", "prod"]
  • 汇合 set(<T>),如set(...)
  • 映射 map(<T>),如{name="Larry", age="18"}
  • 对象 object({name1=T1, name2=T2})
  • 元组 tuple([T1,T2,T3…])

如果不想指定某个类型,能够用 any 来示意任意类型;或者不指定,默认为任意类型。

从性能角度

从性能角度来看,变量能够分为输出变量、输入变量和本地变量。

输出变量是模块接管内部变量的形式,它定义在 variable 块中,如下:

variable "image_id" {type = string}

variable "availability_zone_names" {type    = list(string)
  default = ["us-west-1a"]
}

variable "docker_ports" {
  type = list(object({
    internal = number
    external = number
    protocol = string
  }))
  default = [
    {
      internal = 8300
      external = 8300
      protocol = "tcp"
    }
  ]
}

输入变量定义了一个模块对外返回的变量,通过 output 块来定义,如下:

output "instance_ip_addr" {value = aws_instance.server.private_ip}

本地变量是模块内定义且可援用的长期变量,在 locals 块中定义,如下:

locals {
  service_name = "forum"
  owner        = "Community Team"
}

输出变量 Input Variable

输出变量是定义在 variable 块中的,它就像是函数的入参。

定义输出变量

定义 variable 有很多可选属性:

  • 类型 type:指定变量是什么类型;如果没有指定,则能够是任意类型;
  • 默认值 default:变量的默认值,定义后能够不必提供变量的值,留神它的值的类型要与 type 对应上;
  • 阐明 description:阐明这个变量的作用和用处;
  • 校验 validation:提供校验逻辑来判断输出的变量是否非法;
  • 敏感性 sensitive:定义变量是否敏感,如果是则不会显示;默认为false
  • 可空 nullable:如果为 true 则能够为空,否则不能。默认为true

所有属性都显性指定如上面例子所示:

variable "env" {
  type        = string
  default     = "dev"
  description = "environment name"
  sensitive   = false
  nullable    = false
  validation {condition     = contains(["dev", "uat", "prod"], var.env)
    error_message = "The env must be one of dev/uat/prod."
  }
}

这个变量名为 env,示意环境名,默认值为dev,这个值必须为devuatprod中的其中一个。如果输入一个非法的值,会报错:

$ terraform plan -var="env=sit"
╷
│ Error: Invalid value for variable
│ 
│   on input.tf line 1:
│    1: variable "env" {
│ 
│ The env must be one of dev/uat/prod.

应用输出变量

只有定义了变量才能够应用,应用的形式是 var.name。比方这里定义了两个变量envrandom_string_length

variable "env" {
  type        = string
  default     = "dev"
}

variable "random_string_length" {
  type    = number
  default = 10
}

则应用如下:

resource "random_string" "random" {
  length  = var.random_string_length
  lower   = true
  special = false
}

locals {instance_name = "${var.env}-${random_string.random.result}"
}

output "instance_name" {value = local.instance_name}

传入变量到根模块

要从内部传入变量到根模块,有多种形式,常见的有以下几种,按优先级从低到高:

  • 环境变量export TF_VAR_image_id=ami-abc123
  • terraform.tfvars文件;
  • terraform.tfvars.json文件;
  • *.auto.tfvars*.auto.tfvars.json 文件;
  • 命令行参数 -var 传入一个变量;命令行参数 -var-file 传入一个变量的汇合文件;

在实践中,最罕用的还是通过命令行来传入参数,因为个别须要指定不同环境的特定变量,所以会把变量放到文件中,而后通过命令行指定特定环境的主文件:

$ terraform apply -var="env=uat"
$ terraform apply -var-file="prod.tfvars"

prod.tfvars 的内容如下:

env                  = "prod"
random_string_length = 12

咱们能够定义 dev.tfvarsuat.tfvarsprod.tfvars等,要应用不同环境的变量就间接扭转文件名即可。

输入变量 Output Variable

有输出就有输入,输入变量就像是模块的返回值,比方咱们调用一个模块去创立一台服务,那就要获取服务的 IP,这个 IP 当时是不晓得,它是服务器创立完后的后果之一。输入变量有以下作用:

  • 子模块的输入变量能够裸露一些资源的属性;
  • 根模块的输入变量能够在 apply 后输入到控制台;
  • 根模块的输入变量能够通过 remote state 的形式共享给其它 Terraform 配置,作为数据源。

定义输入变量

输入变量须要定义在 output 块中,如下:

output "instance_ip_addr" {value = aws_instance.server.private_ip}

这个 value 能够是 reource 的属性,也能够是各种变量计算后的后果。只有在执行 apply 的时候才会去计算输入变量,像 plan 是不会执行计算的。

还能够定义输入变量的一些属性:

  • description:输入变量的形容,阐明分明这个变量是干嘛的;
  • sensitive:如果是true,就不会在控制台打印进去;
  • depends_on:显性地定义依赖关系。

残缺的定义如下:

output "instance_ip_addr" {
  value       = aws_instance.server.private_ip
  description = "The private IP address of the main server instance."
  sensitive   = false
  depends_on = [
    # Security group rule must be created before this IP address could
    # actually be used, otherwise the services will be unreachable.
    aws_security_group_rule.local_access,
  ]
}

援用输入变量

援用输入变量很容易,表达式为 module.<module name>.<output name>,如果后面的输入变量定义在模块pkslow_server 中,则援用为:module.pkslow_server.instance_ip_addr

本地变量 Local Variable

本地变量有点相似于其它语言代码中的局部变量,在 Terraform 模块中,它的一个重要作用是防止反复计算一个值。

locals {instance_name = "${var.env}-${random_string.random.result}-${var.suffix}"
}

这里定义了一个本地变量 instance_name,它的值是一个简单的表达式。这时咱们能够通过local.xxx 的模式援用,而不必再写简单的表达式了。如下:

output "instance_name" {value = local.instance_name}

这里要特地留神:定义本地变量的关键字是 locals 块,外面能够有多个变量;而援用的关键字是local,并没有s

个别咱们是倡议须要反复援用的简单的表达式才应用本地变量,不然太多本地变量就会影响可读性。

对变量的援用

定义了变量就须要对其进行援用,后面的解说其实曾经讲过了局部变量的援用,这些把所有列出来。

类型 援用形式
资源 Resources <Resource Type>.<Name>
输出变量 Input Variables var.<NAME>
本地变量 Local Values local.<NAME>
子模块的输入 module.<Module Name>.<output Name>
数据源 Data Sources data.<Data Type>.<Name>
门路和 Terraform 相干 path.module:模块所在门路
path.root:根模块的门路
path.cwd:个别与根模块雷同,其它高级用法除外
terraform.workspace:工作区名字
块中的本地变量 count.index:count 循环的下标;
each.key/each.value:for each 循环的键值;
self:在 provisioner 的援用;

下面都是单值的援用,如果是 List 或 Map 这种简单类型,就要应用中括号 [] 来援用。

aws_instance.example[0].id:援用其中一个元素;

aws_instance.example[*].id:援用列表的所有 id 值;

aws_instance.example["a"].id:援用 key 为 a 的元素;

[for value in aws_instance.example: value.id]:返回所有 id 为列表;

运算符

与其它语言一样,Terraform 也有运算符能够用,次要是用于数值计算和逻辑计算。以下运算符按优先级从高到低如下:

  1. !取反,-取负
  2. *乘号,/除号,%取余
  3. +加号,-减号
  4. >>=<<=:比拟符号
  5. ==等于,!=不等于
  6. &&与门
  7. ||或门

当然,用小括号能够扭转这些优良级,如(1 + 2) * 3

留神:对于结构化的数据比拟须要留神类型是否统一。比方 var.list == [] 按理说应该返回 true,而list 为空时。当 [] 理论示意是元组 tuple([]),所以它们不匹配。能够应用length(var.list) == 0 的形式。

条件表达式

条件表达式的作用是在两个值之间选一个,条件为真则选第一个,条件为假则选第二个。模式如下:

condition ? true_value : false_value

示例如下:

env = var.env !=""? var.env :"dev"

意思是给 env 赋值,如果 var.env 不为空就把输出变量 var.env 的值赋给它,如果为空则赋默认值dev

for 表达式

应用 for 表达式能够创立一些简单的值,而且能够应用一些转换和计算对值计算再返回。如将字符串列表转化成大写:

> [for s in ["larry", "Nanhua", "Deng"] : upper(s)]
[
  "LARRY",
  "NANHUA",
  "DENG",
]

能够获取下标和值:

> [for i,v in ["larry", "Nanhua", "Deng"] : "${i}.${v}"]
[
  "0.larry",
  "1.Nanhua",
  "2.Deng",
]

对于 Map 的 for 表达式:

> [for k,v in {name: "Larry Deng", age: 18, webSite: "www.pkslow.com"} : "${k}: ${v}"]
[
  "age: 18",
  "name: Larry Deng",
  "webSite: www.pkslow.com",
]

通过条件过滤数据:

> [for i in range(1, 10) : i*3 if i%2==0]
[
  6,
  12,
  18,
  24,
]

动静块 Dynamic Block

动静块的作用是依据变量反复某一块配置。这在 Terraform 是会遇见的。

resource "aws_elastic_beanstalk_environment" "tfenvtest" {
  name                = "tf-test-name"
  application         = "${aws_elastic_beanstalk_application.tftest.name}"
  solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"

  dynamic "setting" {
    for_each = var.settings
    content {namespace = setting.value["namespace"]
      name = setting.value["name"]
      value = setting.value["value"]
    }
  }
}

比方这里的例子,就会反复 setting 块。反复的次数取决于 for_each 前面跟的变量。

正文完
 0