介绍
Terraform使用的Hashicorp 配置语言 (HCL)提供了许多其他编程语言中存在的有用结构和功能。在基础架构代码中使用循环可以大大减少代码重复并提高可读性,从而使未来的重构更容易并具有更大的灵活性。HCL 还提供了一些常见的数据结构,例如列表和映射(在其他语言中也分别称为数组和字典),以及执行路径分支的条件。
Terraform 的独特之处在于能够手动指定所依赖的资源。虽然它在运行代码时构建的执行图已经包含检测到的链接(在大多数情况下都是正确的),但您可能会发现自己需要强制一个 Terraform 无法检测到的依赖关系。
在本文中,我们将回顾 HCL 提供的数据结构、它的资源循环功能(count
键for_each
、 和for
),编写条件来处理已知和未知值,以及明确指定资源之间的依赖关系。
先决条件
-
一个 DigitalOcean 帐户。如果您没有,请注册一个新帐户。
-
DigitalOcean 个人访问令牌,您可以通过 DigitalOcean 控制面板创建。可以在此链接中找到执行此操作的说明:如何生成个人访问令牌。
-
Terraform 安装在您的本地计算机上,并使用 DigitalOcean 提供商设置了一个项目。完成步骤1和步骤2中的如何使用Terraform与DigitalOcean教程,并确保该项目命名文件夹
terraform-flexibility
,而不是loadbalance
。在步骤 2 中,您不需要包含pvt_key
变量和 SSH 密钥资源。 -
添加到您的 DigitalOcean 帐户的完全注册的域名。有关如何执行此操作的说明,请访问官方文档。
注意:本教程已专门使用 Terraform 进行了测试0.13
。
HCL 中的数据类型
在本节中,在您详细了解 HCL 的循环和其他使您的代码更加灵活的功能之前,我们将首先介绍可用的数据类型及其用途。
Hashicorp 配置语言支持原始和复杂的数据类型。原始数据类型是字符串、数字和布尔值,它们是不能从其他类型派生的基本类型。另一方面,复杂类型将多个值组合成一个。两种类型的复数值是结构类型和集合类型。
结构类型允许将不同类型的值组合在一起。主要示例是用于指定基础架构外观的资源定义。与结构类型相比,集合类型也对值进行分组,但仅限于相同类型的值。我们感兴趣的 HCL 中可用的三种集合类型是列表、映射和集合。
列表
列表类似于其他编程语言中的数组。它们包含已知数量的相同类型的元素,可以使用数组符号 ( []
) 通过它们的整数索引访问这些元素,从 0 开始。这是一个列表变量声明的示例,其中包含您将部署的 Droplet 的名称在接下来的步骤中:
variable "droplet_names" {
type = list(string)
default = ["first", "second", "third"]
}
对于type
,您明确指定它是一个元素类型为字符串的列表,然后提供其default
值。括号中枚举的值表示 HCL 中的列表。
地图
映射是键值对的集合,其中每个值都使用其类型的键进行访问string
。有两种在大括号内指定映射的方法:使用冒号 ( :
) 或等号 ( =
) 指定值。在这两种情况下,值都必须用引号引起来。使用冒号时,也必须将键括起来。
以下包含不同环境的 Droplet 名称的地图定义使用等号编写:
variable "droplet_env_names" {
type = map(string)
default = {
development = "dev-droplet"
staging = "staging-droplet"
production = "prod-droplet"
}
}
如果键以数字开头,则必须使用冒号语法:
variable "droplet_env_names" {
type = map(string)
default = {
"1-development": "dev-droplet"
"2-staging": "staging-droplet"
"3-production": "prod-droplet"
}
}
套
集合不支持元素排序,这意味着不能保证遍历集合每次都产生相同的顺序,并且不能以有针对性的方式访问它们的元素。它们包含仅重复一次的唯一元素,多次指定相同的元素将导致它们合并,并且集合中仅存在一个实例。
声明一个集合类似于声明一个列表,唯一的区别是变量的类型:
variable "droplet_names" {
type = set(string)
default = ["first", "second", "third", "fourth"]
}
既然您已经了解了 HCL 提供的数据结构类型并回顾了我们将在本教程中使用的列表、映射和集合的语法,您将继续尝试一些灵活的方法来部署多个实例Terraform 中的相同资源。
使用count
密钥设置资源数量
在本节中,您将使用count
密钥创建同一资源的多个实例。该count
关键是适用于所有资源,指定如何它的许多实例创建参数。
您将通过编写 Droplet 资源来了解它是如何工作的,该资源将存储在droplets.tf
作为先决条件的一部分创建的项目目录中的名为 的文件中。通过运行创建并打开它进行编辑:
- nano droplets.tf
添加以下几行:
resource "digitalocean_droplet" "test_droplet" {
count = 3
image = "ubuntu-18-04-x64"
name = "web"
region = "fra1"
size = "s-1vcpu-1gb"
}
此代码定义了一个名为 的 Droplet 资源test_droplet
,运行 Ubuntu 18.04 和 1GB RAM。
请注意, 的值count
设置为3
,这意味着 Terraform 将尝试创建同一资源的三个实例。完成后,保存并关闭文件。
您可以通过运行以下命令来规划项目以查看 Terraform 将采取的操作:
- terraform plan -var "do_token=${DO_PAT}"
输出将类似于:
Output...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# digitalocean_droplet.test_droplet[0] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
name = "web"
...
}
# digitalocean_droplet.test_droplet[1] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
name = "web"
...
}
# digitalocean_droplet.test_droplet[2] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
name = "web"
...
}
Plan: 3 to add, 0 to change, 0 to destroy.
...
Terraform 将创建 的三个实例的输出详细信息test_droplet
,所有实例都具有相同的名称web
。虽然可能,但不是首选,所以让我们修改 Droplet 定义,使每个实例的名称不同。打开droplets.tf
编辑:
- nano droplets.tf
修改突出显示的行:
resource "digitalocean_droplet" "test_droplet" {
count = 3
image = "ubuntu-18-04-x64"
name = "web.${count.index}"
region = "fra1"
size = "s-1vcpu-1gb"
}
保存并关闭文件。
该count
对象提供了index
参数,该参数包含当前迭代的索引,从 0 开始。使用字符串插值将当前索引替换为 Droplet 的名称,这允许您通过替换变量来动态构建字符串。您可以再次计划项目以查看更改:
- terraform plan -var "do_token=${DO_PAT}"
输出将类似于:
Output...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# digitalocean_droplet.test_droplet[0] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
name = "web.0"
...
}
# digitalocean_droplet.test_droplet[1] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
name = "web.1"
...
}
# digitalocean_droplet.test_droplet[2] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
name = "web.2"
...
}
Plan: 3 to add, 0 to change, 0 to destroy.
...
这一次, 的三个实例test_droplet
将在它们的名称中包含它们的索引,使它们更易于跟踪。
您现在知道如何使用count
密钥创建资源的多个实例,以及在供应期间获取和使用实例的索引。接下来,您将学习如何从列表中获取 Droplet 的名称。
从列表中获取 Droplet 名称
在同一资源的多个实例需要自定义名称的情况下,您可以从您定义的列表变量中动态检索它们。在本教程的其余部分,您将看到几种从名称列表中自动部署 Droplet 的方法,从而提高灵活性和易用性。
您首先需要定义一个包含 Droplet 名称的列表。创建一个名为的文件variables.tf
并打开它进行编辑:
- nano variables.tf
添加以下几行:
variable "droplet_names" {
type = list(string)
default = ["first", "second", "third", "fourth"]
}
保存并关闭文件。此代码定义了一个名为列表droplet_names
,包含字符串first
,second
,third
,和fourth
。
打开droplets.tf
编辑:
- nano droplets.tf
修改突出显示的行:
resource "digitalocean_droplet" "test_droplet" {
count = length(var.droplet_names)
image = "ubuntu-18-04-x64"
name = var.droplet_names[count.index]
region = "fra1"
size = "s-1vcpu-1gb"
}
为了提高灵活性,您无需手动指定固定数量的元素,而是将droplet_names
列表的长度传递给count
参数,该参数将始终返回列表中的元素数量。对于名称,您count.index
使用数组括号表示法获取位于 的列表元素。完成后保存并关闭文件。
尝试重新规划项目。您将收到类似于以下内容的输出:
Output...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# digitalocean_droplet.test_droplet[0] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "first"
...
}
# digitalocean_droplet.test_droplet[1] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "second"
...
}
# digitalocean_droplet.test_droplet[2] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "third"
...
}
# digitalocean_droplet.test_droplet[3] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "fourth"
...
Plan: 4 to add, 0 to change, 0 to destroy.
...
作为修改的结果,将部署四个 Droplet,依次以droplet_names
列表中的元素命名。
您已经了解了count
、它的特性和语法,并将它与一个列表一起使用来修改资源实例。您现在将看到它的缺点,以及如何克服它们。
了解缺点 count
既然您知道了 count 是如何使用的,那么在修改与它一起使用的列表时,您将看到它的缺点。
让我们尝试将 Droplets 部署到云端:
- terraform apply -var "do_token=${DO_PAT}"
输入yes
提示时。输出的结尾将与此类似:
OutputApply complete! Resources: 4 added, 0 changed, 0 destroyed.
现在让我们通过扩大droplet_names
列表再创建一个 Droplet 实例。打开variables.tf
编辑:
- nano variables.tf
在列表的开头添加一个新元素:
variable "droplet_names" {
type = list(string)
default = ["zero", "first", "second", "third", "fourth"]
}
完成后,保存并关闭文件。
计划项目:
- terraform plan -var "do_token=${DO_PAT}"
您将收到如下输出:
Output...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
~ update in-place
Terraform will perform the following actions:
# digitalocean_droplet.test_droplet[0] will be updated in-place
~ resource "digitalocean_droplet" "test_droplet" {
...
~ name = "first" -> "zero"
...
}
# digitalocean_droplet.test_droplet[1] will be updated in-place
~ resource "digitalocean_droplet" "test_droplet" {
...
~ name = "second" -> "first"
...
}
# digitalocean_droplet.test_droplet[2] will be updated in-place
~ resource "digitalocean_droplet" "test_droplet" {
...
~ name = "third" -> "second"
...
}
# digitalocean_droplet.test_droplet[3] will be updated in-place
~ resource "digitalocean_droplet" "test_droplet" {
...
~ name = "fourth" -> "third"
...
}
# digitalocean_droplet.test_droplet[4] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "fourth"
...
}
Plan: 1 to add, 4 to change, 0 to destroy.
...
输出显示 Terraform 将重命名前四个 Droplet 并创建名为 的第五个fourth
,因为它将实例视为有序列表,并通过元素在列表中的索引号来标识元素 (Droplets)。这就是 Terraform 最初考虑四个 Droplet 的方式:
索引号 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
液滴名称 | 第一的 | 第二 | 第三 | 第四 |
当新的 Dropletzero
添加到开头时,其内部列表表示如下所示:
索引号 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
液滴名称 | 零 | 第一的 | 第二 | 第三 | 第四 |
最初的四个液滴现在向右移动了一个位置。然后 Terraform 比较表中表示的两个状态:在位置0
,首先调用 Droplet ,并且由于它在第二个表中不同,因此它计划更新操作。这一直持续到 position 4
,它在第一个表中没有可比较的元素,而是计划了一个 Droplet 配置操作。
这意味着将新元素添加到列表中的任何地方,而不是最后将导致资源在不需要时被修改。如果droplet_names
列表中的元素被删除,将计划类似的更新操作。
不完整的资源跟踪是count
用于部署相同资源的动态数量的不同实例的主要缺点。对于恒定数量的常量实例,这count
是一个运行良好的简单解决方案。但是,在这种情况下,当从变量中提取某些属性时for_each
,本教程稍后将介绍的循环是更好的选择。
引用当前资源(self)
另一个缺点count
是在某些情况下无法通过索引引用资源的任意实例。
主要示例是destroy-time provisioners,它在计划销毁资源时运行。原因是请求的实例可能不存在(它已经被销毁)或者会创建一个相互依赖的循环。在这种情况下,您可以通过self
关键字仅访问当前资源,而不是通过实例列表来引用对象。
为了演示它的用法,您现在将在test_droplet
定义中添加一个销毁时间本地供应商,它会在运行时显示一条消息。打开droplets.tf
编辑:
- nano droplets.tf
添加以下突出显示的行:
resource "digitalocean_droplet" "test_droplet" {
count = length(var.droplet_names)
image = "ubuntu-18-04-x64"
name = var.droplet_names[count.index]
region = "fra1"
size = "s-1vcpu-1gb"
provisioner "local-exec" {
when = destroy
command = "echo 'Droplet ${self.name} is being destroyed!'"
}
}
保存并关闭文件。
在local-exec
供应方运行Terraform上运行在本地计算机上的命令。因为该when
参数设置为destroy
,所以它只会在资源即将被销毁时运行。它运行的命令将一个字符串回显到stdout
,它使用 替换当前资源的名称self.name
。
因为您将在下一节中以不同的方式创建 Droplet,请通过运行以下命令销毁当前部署的 Droplet:
- terraform destroy -var "do_token=${DO_PAT}"
输入yes
提示时。您将收到local-exec
运行四次的配置程序:
Output...
digitalocean_droplet.test_droplet["first"] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet first is being destroyed!'"]
digitalocean_droplet.test_droplet["second"] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet second is being destroyed!'"]
digitalocean_droplet.test_droplet["second"] (local-exec): Droplet second is being destroyed!
digitalocean_droplet.test_droplet["third"] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet third is being destroyed!'"]
digitalocean_droplet.test_droplet["third"] (local-exec): Droplet third is being destroyed!
digitalocean_droplet.test_droplet["fourth"] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet fourth is being destroyed!'"]
digitalocean_droplet.test_droplet["fourth"] (local-exec): Droplet fourth is being destroyed!
digitalocean_droplet.test_droplet["first"] (local-exec): Droplet first is being destroyed!
...
在这一步中,您了解了count
. 您现在将了解for_each
循环结构,它克服了这些问题并适用于更广泛的变量类型数组。
循环使用 for_each
在本节中,您将考虑for_each
循环、其语法以及在定义具有多个实例的资源时如何提高灵活性。
for_each
是每个资源上可用的参数,但与count
需要创建多个实例的不同,它for_each
接受一个映射或一个集合。所提供集合的每个元素都被遍历一次并为其创建一个实例。for_each
使each
关键字下的键和值可用作属性(该对的键和值分别为each.key
和each.value
)。当提供了一个集合时,键和值将是相同的。
因为它提供each
对象中的当前元素,所以您不必像使用列表那样手动访问所需的元素。在集合的情况下,这甚至是不可能的,因为它在内部没有可观察的顺序。也可以传入列表,但必须先使用toset
函数将它们转换为集合。
for_each
除了能够枚举所有三种集合数据类型之外, using 的主要优点是只有实际受影响的元素才会被修改、创建或删除。如果您更改输入中元素的顺序,则不会计划任何操作,如果您从输入中添加、删除或修改元素,则只会为该元素计划适当的操作。
让我们将 Droplet 资源从 转换count
为for_each
,看看它在实践中是如何工作的。droplets.tf
通过运行打开以进行编辑:
- nano droplets.tf
修改突出显示的行:
resource "digitalocean_droplet" "test_droplet" {
for_each = toset(var.droplet_names)
image = "ubuntu-18-04-x64"
name = each.value
region = "fra1"
size = "s-1vcpu-1gb"
}
您可以删除local-exec
供应商。完成后,保存并关闭文件。
第一行替换count
并调用for_each
,droplet_names
使用toset
函数以集合的形式传入列表,该函数会自动转换给定的输入。对于 Droplet 名称,您指定each.value
,它保存 Droplet 名称集中当前元素的值。
通过运行来计划项目:
- terraform plan -var "do_token=${DO_PAT}"
输出将详细说明 Terraform 将采取的步骤:
Output...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# digitalocean_droplet.test_droplet["first"] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "first"
...
}
# digitalocean_droplet.test_droplet["fourth"] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "fourth"
...
}
# digitalocean_droplet.test_droplet["second"] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "second"
...
}
# digitalocean_droplet.test_droplet["third"] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "third"
...
}
# digitalocean_droplet.test_droplet["zero"] will be created
+ resource "digitalocean_droplet" "test_droplet" {
...
+ name = "zero"
...
}
Plan: 5 to add, 0 to change, 0 to destroy.
...
与使用时不同count
,Terraform 现在单独考虑每个实例,而不是作为有序列表的元素。每个实例都链接到给定集合的一个元素,如将创建的每个资源旁边括号中显示的字符串元素所表示。
通过运行将计划应用到云:
- terraform apply -var "do_token=${DO_PAT}"
输入yes
提示时。完成后,您将从droplet_names
列表中删除一个元素以证明其他实例不会受到影响。打开variables.tf
编辑:
- nano variables.tf
将列表修改为如下所示:
variable "droplet_names" {
type = list(string)
default = ["first", "second", "third", "fourth"]
}
保存并关闭文件。
再次规划项目,您将收到以下输出:
Output...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# digitalocean_droplet.test_droplet["zero"] will be destroyed
- resource "digitalocean_droplet" "test_droplet" {
...
- name = "zero" -> null
...
}
Plan: 0 to add, 0 to change, 1 to destroy.
...
这一次,Terraform 将仅销毁已删除的实例 ( zero
),不会触及任何其他实例,这是正确的行为。
在这一步中,您已经了解了for_each
、如何使用它以及它相对于count
. 接下来,您将了解for
循环、其语法和用法,以及何时可以使用它来自动执行某些任务。
循环使用 for
该for
回路适用于集合,并通过应用转换到输入的每个元素创建一个新的集合。输出的确切类型将取决于循环是否被方括号 ( []
) 或大括号 ( {}
)包围,它们分别给出列表或映射。因此,它适用于查询资源并形成结构化输出以供后续处理。
for
循环的一般语法是:
for element in collection:
transform(element)
if condition
与其他编程语言类似,您首先命名遍历变量 ( element
) 并指定collection
要枚举的 。循环体是转换步骤,可选if
子句可用于过滤输入集合。
您现在将使用输出完成几个示例。您将它们存储在一个名为outputs.tf
. 通过运行以下命令创建它以进行编辑:
- nano outputs.tf
添加以下行以输出已部署的 Droplet 名称及其 IP 地址对:
output "ip_addresses" {
value = {
for instance in digitalocean_droplet.test_droplet:
instance.name => instance.ipv4_address
}
}
此代码指定了一个名为 的输出ip_addresses
,并指定了一个for
循环,该循环对test_droplet
您在前面的步骤中自定义的资源实例进行迭代。因为循环被大括号包围,所以它的输出将是一个映射。map 的转换步骤类似于其他编程语言中的lambda 函数,这里它通过将实例名称作为键与其私有 IP 作为其值组合来创建键值对。
保存并关闭文件,然后通过运行以下命令刷新 Terraform 状态以说明新输出:
- terraform refresh -var "do_token=${DO_PAT}"
Terraformrefresh
命令使用云中的实际基础架构状态更新本地状态。
然后,检查输出的内容:
Outputip_addresses = {
"first" = "ip_address"
"fourth" = "ip_address"
"second" = "ip_address"
"third" = "ip_address"
}
Terraform 已经显示了ip_addresses
输出的内容,这是一个由for
循环构建的地图。(条目的顺序对您来说可能会有所不同。)循环将对每个条目的数量无缝地工作——这意味着您可以向droplet_names
列表和新的 Droplet添加一个新元素,无需任何进一步的手动输入即可创建,也会自动显示在此输出中。
通过将for
循环括在方括号中,您可以使输出成为一个列表。例如,您可以仅输出 Droplet IP 地址,这对于可能正在解析数据的外部软件很有用。代码如下所示:
output "ip_addresses" {
value = [
for instance in digitalocean_droplet.test_droplet:
instance.ipv4_address
]
}
此处,转换步骤仅选择 IP 地址属性。它将给出以下输出:
Outputip_addresses = [
"ip_address",
"ip_address",
"ip_address",
"ip_address",
]
如前所述,您还可以使用if
子句过滤输入集合。如果按fra1
区域过滤循环,您将如何编写循环:
output "ip_addresses" {
value = [
for instance in digitalocean_droplet.test_droplet:
instance.ipv4_address
if instance.region == "fra1"
]
}
在 HCL 中,==
运算符检查两侧的值是否instance.region
相等——这里检查是否等于fra1
。如果是,则检查通过并且将instance
被转换并添加到输出中,否则将被跳过。此代码的输出将与前面的示例相同,因为fra1
根据test_droplet
资源定义,所有 Droplet 实例都在该区域中。if
当您想过滤项目中其他值的输入集合时,条件也很有用,例如 Droplet 大小或分布。
由于您将在下一节中以不同的方式创建资源,因此请通过运行以下命令来销毁当前部署的资源:
- terraform destroy -var "do_token=${DO_PAT}"
输入yes
提示完成该过程时。
我们已经了解了for
循环、它的语法和输出中的使用示例。您现在将了解条件以及如何将它们与count
.
指令和条件
在前面的一节中,您已经看到了count
关键及其工作原理。您现在将了解三元条件运算符,您可以在 Terraform 代码的其他地方使用它们,以及如何将它们与count
.
三元运算符的语法是:
condition ? value_if_true : value_if_false
condition
是一个计算为布尔值(真或假)的表达式。如果条件为真,则表达式的计算结果为value_if_true
。另一方面,如果条件为假,结果将为value_if_false
。
三元运算符的主要用途是根据变量的内容启用或禁用单个资源创建。这可以通过将比较结果(1
或0
)传递给count
所需资源上的键来实现。
让我们添加一个名为 的变量create_droplet
,它将控制是否创建 Droplet。首先,打开variables.tf
编辑:
- nano variables.tf
添加突出显示的行:
variable "droplet_names" {
type = list(string)
default = ["first", "second", "third", "fourth"]
}
variable "create_droplet" {
type = bool
default = true
}
这段代码定义了create_droplet
类型的变量bool
。保存并关闭文件。
然后,要修改 Droplet 声明,请droplets.tf
通过运行打开以进行编辑:
- nano droplets.tf
修改您的文件,如下所示:
resource "digitalocean_droplet" "test_droplet" {
count = var.create_droplet ? 1 : 0
image = "ubuntu-18-04-x64"
name = "test_droplet"
region = "fra1"
size = "s-1vcpu-1gb"
}
对于count
,1
如果create_droplet
变量为真,0
则使用三元运算符返回,如果为假,则将导致没有提供 Droplet。完成后保存并关闭文件。
通过运行将变量设置为 false 来规划项目执行计划:
- terraform plan -var "do_token=${DO_PAT}" -var "create_droplet=false"
您将收到以下输出:
OutputRefreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
因为create_droplet
传入了 的值false
,所以count
实例的 是0
,并且不会创建 Droplet。
您已经了解了如何将三元条件运算符与count
key一起使用,以在选择是否部署所需资源时实现更高级别的灵活性。接下来,您将了解如何为您的资源显式设置资源依赖项。
显式设置资源依赖
在为您的项目创建执行计划时,Terraform 会检测资源之间的依赖链并隐式排序它们,以便它们以适当的顺序构建。在大多数情况下,它能够通过扫描资源中的所有表达式并构建图形来检测关系。
但是,当一项资源需要访问控制设置已经部署在云提供商处以便进行供应时,Terraform 没有明确的迹象表明它们是相关的。反过来,Terraform 不会知道它们在行为上相互依赖。在这种情况下,必须使用depends_on
参数手动指定依赖项。
该depends_on
键可对每个资源和用来指定哪些资源有一个隐藏的相关性的联系。当一个资源依赖于另一个人的行为,而不在其声明中使用它的任何数据时,就会形成隐藏的依赖关系,这会促使 Terraform 以一种方式连接它们。
以下是depends_on
在代码中指定方式的示例:
resource "digitalocean_droplet" "droplet" {
image = "ubuntu-18-04-x64"
name = "web"
region = "fra1"
size = "s-1vcpu-1gb"
depends_on = [
# Resources...
]
}
它接受对其他资源的引用列表,并且不接受任意表达式。
depends_on
应该谨慎使用,并且仅当所有其他选项都用尽时。它的使用意味着您试图声明的内容超出了 Terraform 自动依赖检测系统的边界;这可能意味着资源显式地依赖于比它需要的更多的资源。
您现在已经了解了如何使用depends_on
密钥为资源显式设置附加依赖项,以及何时应该使用它。
结论
在本文中,我们已经介绍了 HCL 可提高代码灵活性和可伸缩性的功能,例如count
用于指定要部署的资源实例数量以及for_each
作为循环集合数据类型和自定义实例的高级方法。如果使用得当,它们会大大减少管理已部署基础架构的代码重复和运营开销。
您还了解了条件和三元运算符,以及如何利用它们来控制是否部署资源。虽然 Terraform 的自动依赖分析系统功能非常强大,但在某些情况下,您可能需要使用depends_on
key手动指定资源依赖关系。
要了解有关 Terraform 的更多信息,请查看我们的如何使用 Terraform 管理基础设施系列。