了解 Terraform 函数、表达式和元参数 - AWS 规范性指导

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

了解 Terraform 函数、表达式和元参数

对使用声明式配置文件而不是常见编程语言的 IaC 工具的一种批评是,它们使实现自定义编程逻辑变得更加困难。在 Terraform 配置中,这个问题是通过使用函数、表达式和元参数来解决的。

函数

使用代码来配置基础架构的最大优势之一是能够存储常见的工作流程并一次又一次地重复使用它们,通常每次都传递不同的参数。Terraform 函数与 AWS CloudFormation 内部函数类似,尽管它们的语法与编程语言中函数的调用方式更为相似。在本指南的示例中,你可能已经注意到一些 Terraform 函数,例如 substrconcat、lengt hbase64decode。 CloudFormation 与内部函数一样,Terraform 有一系列可在您的配置中使用的内置函数。例如,如果特定的资源属性采用一个非常大的 JSON 对象,而直接粘贴到文件中效率低下,则可以将该对象放在 .json 文件中,然后使用 Terraform 函数对其进行访问。在以下示例中,该file函数以字符串形式返回文件内容,然后该jsondecode函数将其转换为对象类型。

resource "example_resource" "example_resource_name" { json_object = jsondecode(file("/path/to/file.json")) }

Expressions

Terraform 还允许使用条件表达式,条件表达式与 CloudFormation condition函数类似,不同之处在于它们使用更传统的三元运算符语法。在以下示例中,两个表达式返回的结果完全相同。第二个例子是 Terraform 所说的 s pl at 表达式。星号会让 Terraform 循环浏览列表并仅使用每个项目的id属性来创建一个新列表。

resource "example_resource" "example_resource_name" { boolean_value = var.value ? true : false numeric_value = var.value > 0 ? 1 : 0 string_value = var.value == "change_me" ? "New value" : var.value string_value_2 = var.value != "change_me" ? var.value : "New value" } There are two ways to express for loops in a Terraform configuration: resource "example_resource" "example_resource_name" { list_value = [for object in var.ids : object.id] list_value_2 = var.ids[*].id }

元参数

在前面的代码示例中,list_valuelist_value_2被称为参数。你可能已经熟悉其中一些元参数了。Terraform 还有一些元参数,它们的作用就像参数一样,但有一些额外的功能:

  • de pends_on 元参数与该属性非常相似。 CloudFormation DependsOn

  • 提供者元参数允许您同时使用多个提供程序配置。

  • 生命周期元参数允许您自定义资源设置,类似于中的删除和删除策略。 CloudFormation

其他元参数允许将函数和表达式功能直接添加到资源中。例如,count 元参数是同时创建多个相似资源的有用机制。以下示例演示了如何在不使用count元参数的情况下创建两个亚马逊弹性容器服务 (Amazon EKS) 集群。

resource "aws_eks_cluster" "example_0" { name = "example_0" role_arn = aws_iam_role.cluster_role.arn vpc_config { endpoint_private_access = true endpoint_public_access = true subnet_ids = var.subnet_ids[0] } } resource "aws_eks_cluster" "example_1" { name = "example_1" role_arn = aws_iam_role.cluster_role.arn vpc_config { endpoint_private_access = true endpoint_public_access = true subnet_ids = var.subnet_ids[1] } }

以下示例演示如何使用count元参数创建两个 Amazon EKS 集群。

resource "aws_eks_cluster" "clusters" { count = 2 name = "cluster_${count.index}" role_arn = aws_iam_role.cluster_role.arn vpc_config { endpoint_private_access = true endpoint_public_access = true subnet_ids = var.subnet_ids[count.index] } }

要为每个单位命名,您可以访问资源块中的列表索引,网址为count.index。但是,如果你想创建多个稍微复杂一点的类似资源怎么办? 这就是 for_ each 元参数的用武之地。for_each元参数与非常相似count,不同之处在于你传入的是列表或对象,而不是数字。Terraform 为列表或对象的每个成员创建一个新资源。它与您设置时类似count = length(list),不同之处在于您可以访问列表的内容而不是循环索引。

这既适用于项目列表,也适用于单个对象。以下示例将创建两个以 ID id-0 和作id-1为 ID 的资源。

variable "ids" { default = [ { id = "id-0" }, { id = "id-1" }, ] } resource "example_resource" "example_resource_name" { # If your list fails, you might have to call "toset" on it to convert it to a set for_each = toset(var.ids) id = each.value }

以下示例还将创建两个资源,一个用于贵宾犬 Sparky,另一个用于吉娃娃 Fluffy。

variable "dogs" { default = { poodle = "Sparky" chihuahua = "Fluffy" } } resource "example_resource" "example_resource_name" { for_each = var.dogs breed = each.key name = each.value }

就像你可以使用 count.index 访问 count.index 中的循环索引一样,你可以使用每个对象访问 for_each 循环中每个项目的键和值。由于 for_each 会迭代列表和对象,因此跟踪每个键和值可能会有些混乱。下表显示了使用 for_each 元参数的不同方式以及如何在每次迭代时引用这些值。

示例 for_each 类型 第一次迭代 第二次迭代
A
[“poodle”, “chihuahua”]
each.key = "poodle" each.value = null
each.key = "chihuahua" each.value = null
B
[ { type = "poodle", name = "Sparky" }, { type = "chihuahua", name = "Fluffy" } ]
each.key = { type = “poodle”, name = “Sparky” } each.value = null
each.key = { type = “chihuahua”, name = “Fluffy” } each.value = null
C
{ poodle = “Sparky”, chihuahua = “Fluffy” }
each.key = “poodle” each.value = “Sparky”
each.key = “chihuahua” each.value = “Fluffy”
D
{ dogs = { poodle = “Sparky”, chihuahua = “Fluffy” }, cats = { persian = “Felix”, burmese = “Morris” } }
each.key = “dogs” each.value = { poodle = “Sparky”, chihuahua = “Fluffy” }
each.key = “cats” each.value = { persian = “Felix”, burmese = “Morris” }
E
{ dogs = [ { type = “poodle”, name = “Sparky” }, { type = “chihuahua”, name = “Fluffy” } ], cats = [ { type = “persian”, name = “Felix” }, { type = “burmese”, name = “Morris” } ] }
each.key = “dogs” each.value = [ { type = “poodle”, name = “Sparky” }, { type = “chihuahua”, name = “Fluffy” } ]
each.key = “cats” each.value = [ { type = “persian”, name = “Felix” }, { type = “burmese”, name = “Morris” } ]

 

因此var.animals,如果等于行 E,则可以使用以下代码为每只动物创建一个资源。

resource "example_resource" "example_resource_name" { for_each = var.animals type = each.key breeds = each.value[*].type names = each.value[*].name }

或者,您可以使用以下代码为每只动物创建两个资源。

resource "example_resource" "example_resource_name" { for_each = var.animals.dogs type = "dogs" breeds = each.value.type names = each.value.name } resource "example_resource" "example_resource_name" { for_each = var.animals.cats type = "cats" breeds = each.value.type names = each.value.name }