介绍
Terraform 输出用于从项目状态中提取有关基础设施资源的信息。 使用 Terraform 使用的 Hashicorp 配置语言 (HCL) 的其他功能,可以查询资源信息并将其转换为更复杂的数据结构,例如列表和地图。 输出对于向外部软件提供信息很有用,这些软件可以在创建的基础设施资源上运行。
在本教程中,您将通过创建一个部署 Droplet 的简单基础架构来了解 Terraform 输出语法及其参数。 您还将通过将输出转换为 JSON 以编程方式解析输出。
先决条件
- DigitalOcean 个人访问令牌,您可以通过 DigitalOcean 控制面板创建它。 您可以在 DigitalOcean 产品文档中找到说明,如何创建个人访问令牌。
- Terraform 安装在您的本地计算机上,并使用 DigitalOcean 提供程序设置了一个项目。 完成 How To Use Terraform with DigitalOcean 教程的 Step 1 和 Step 2,并确保将项目文件夹命名为
terraform-outputs
,而不是loadbalance
。 在 Step 2 期间,不要包含pvt_key
变量和 SSH 密钥资源。 - 熟悉 HCL 数据类型和循环。 有关详细信息,请参阅 如何使用 Terraform 变量、依赖项和条件 教程提高灵活性。
注意: 本教程专门用 Terraform 1.0.2
测试过。
定义输出
在本节中,您将声明一个 Droplet,将其部署到云中,并通过定义一个显示 Droplet 的 IP 地址的输出来了解输出。
从您作为先决条件创建的 terraform-outputs
目录中,创建并打开 droplets.tf
文件进行编辑:
nano droplets.tf
添加以下 Droplet 资源和输出定义:
terraform-outputs/droplets.tf
resource "digitalocean_droplet" "web" { image = "ubuntu-20-04-x64" name = "test-droplet" region = "fra1" size = "s-1vcpu-1gb" } output "droplet_ip_address" { value = digitalocean_droplet.web.ipv4_address }
您首先声明一个名为 web
的 Droplet 资源。 它在云中的实际名称将是 test-droplet
,在 fra1
区域中,运行 Ubuntu 20.04。
然后,声明一个名为 droplet_ip_address
的输出。 在 Terraform 中,输出用于导出和显示内部和计算值以及有关资源的信息。 在这里,您将接受要输出的数据的 value
参数设置为声明的 Droplet 的 IP 地址。 在声明时,它是未知的,但一旦部署了 Droplet,它将变得可用。 每次部署后都会显示和访问输出。
保存并关闭文件,然后通过运行以下命令部署项目:
terraform apply -var "do_token=${DO_PAT}"
出现提示时输入 yes
应用。 输出的结尾将与此类似:
Output... digitalocean_droplet.web: Creating... ... digitalocean_droplet.web: Creation complete after 32s [id=207631771] Apply complete! Resources: 1 added, 0 changed, 0 destroyed. Outputs: droplet_ip_address = ip_address
突出显示的 IP 地址属于您新部署的 Droplet。 当所有资源属性都可用时,应用项目会将资源部署到云并在最后显示输出。 如果没有 droplet_ip_address
输出,Terraform 将不会显示有关 Droplet 的更多信息,除了它已部署。
也可以使用 output
命令显示输出:
terraform output
输出将列出项目中的所有 outputs
:
Outputdroplet_ip_address = ip_address
您还可以通过将其指定为参数来按名称查询特定输出:
terraform output output_name
对于 droplet_ip_address
,输出将仅包含 IP 地址:
Outputip_address
除了指定强制的 value
外,输出还有一些可选参数:
description
:嵌入详细说明输出内容的简短文档。depends_on
:每个资源上可用的元参数,允许您明确指定输出依赖于 Terraform 在规划期间无法自动推断的资源。sensitive
:接受一个布尔值,如果设置为true
,则可以防止在部署后显示输出的内容。
当 Terraform 部署的日志将公开可用时,sensitive
参数很有用,但输出内容应保持隐藏。 您现在将其添加到您的 Droplet 资源定义中。
打开 droplets.tf
进行编辑并添加突出显示的行:
terraform-outputs/droplets.tf
resource "digitalocean_droplet" "web" { image = "ubuntu-20-04-x64" name = "test-droplet" region = "fra1" size = "s-1vcpu-1gb" } output "droplet_ip_address" { value = digitalocean_droplet.web.ipv4_address sensitive = true }
完成后保存并关闭文件。 通过运行再次部署项目:
terraform apply -var "do_token=${DO_PAT}"
出现提示时输入 yes
。 您会看到输出已被编辑:
Output... Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: droplet_ip_address = <sensitive>
即使它被标记为 sensitive
,输出及其内容仍然可以通过其他渠道获得,例如查看 Terraform 状态或直接查询输出。
在下一步中,您将创建一个不同的 Droplet 和输出结构,因此通过运行以下命令销毁当前部署的结构:
terraform destroy -var "do_token=${DO_PAT}"
最后的输出将是:
Output... Destroy complete! Resources: 1 destroyed.
您已声明并部署了一个 Droplet,并创建了一个显示其 IP 地址的输出。 您现在将了解如何使用输出来显示更复杂的结构,例如列表和地图。
输出复杂结构
在本节中,您将使用 count
关键字从同一定义中部署多个 Droplet,并以各种格式输出它们的 IP 地址。
使用 for
循环
您需要修改 Droplet 资源定义,因此打开它进行编辑:
nano droplets.tf
将其修改为如下所示:
terraform-outputs/droplets.tf
resource "digitalocean_droplet" "web" { count = 3 image = "ubuntu-20-04-x64" name = "test-droplet-${count.index}" region = "fra1" size = "s-1vcpu-1gb" }
您已指定应使用 count
键创建三个 Droplet,并将当前索引添加到 Droplet 名称,以便您稍后能够辨别它们。 删除下面的现有输出。 完成后,保存并关闭文件。
通过运行应用代码:
terraform apply -var "do_token=${DO_PAT}"
Terraform 将计划创建三个编号的 Droplet,称为 test-droplet-0
、test-droplet-1
和 test-droplet-2
。 提示完成该过程时输入 yes
。 最后您将看到以下输出:
Output... Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
这意味着所有三个 Droplet 都已成功部署,并且有关它们的所有信息都存储在项目状态中。
访问其资源属性的最简单方法是使用输出,但为每个 Droplet 创建一个是不可扩展的。 解决方案是使用 for
循环遍历 Droplet 列表并收集它们的属性,或者使用 splat 表达式(您将在本步骤后面了解)。
您将首先定义一个输出,该输出将输出三个 Droplet 的 IP 地址,并与它们的名称配对。 打开droplets.tf
进行编辑:
nano droplets.tf
添加以下行:
terraform-outputs/droplets.tf
resource "digitalocean_droplet" "web" { count = 3 image = "ubuntu-20-04-x64" name = "test-droplet-${count.index}" region = "fra1" size = "s-1vcpu-1gb" } output "droplet_ip_addresses" { value = { for droplet in digitalocean_droplet.web: droplet.name => droplet.ipv4_address } }
droplet_ip_addresses
的输出值是使用 for
循环构造的。 因为它被大括号包围,所以结果类型将是一个映射。 该循环遍历 Droplets 列表,并为每个实例将其名称与其 IP 地址配对,并将其附加到结果映射中。
保存并关闭文件,然后再次应用项目:
terraform apply -var "do_token=${DO_PAT}"
出现提示时输入yes
,最后会收到输出内容:
OutputApply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: droplet_ip_addresses = { "test-droplet-0" = "ip_address" "test-droplet-1" = "ip_address" "test-droplet-2" = "ip_address" }
droplet_ip_addresses
输出详细说明了三个部署的 Droplet 的 IP 地址。
使用 Terraform output
命令,您可以使用其命令参数以 JSON 格式获取输出内容:
terraform output -json droplet_ip_addresses
结果将类似于以下内容:
Output{"test-droplet-0":"ip_address","test-droplet-1":"ip_address","test-droplet-2":"ip_address"}
JSON 解析在许多编程语言中被广泛使用和支持。 这样,您可以以编程方式解析有关已部署 Droplet 资源的信息。
使用 Splat 表达式
Splat 表达式提供了一种紧凑的方式来迭代列表的所有元素,并从每个元素中收集属性的内容,从而生成一个列表。 将提取三个已部署 Droplet 的 IP 地址的 splat 表达式将具有以下语法:
digitalocean_droplet.web[*].ipv4_address
[*]
符号遍历其左侧的列表,并且对于每个元素,获取其右侧指定的属性的内容。 如果左边的引用本身不是一个列表,它将被转换为它将成为唯一元素的列表。
您可以打开 droplets.tf
进行编辑并修改以下行来实现:
terraform-outputs/droplets.tf
resource "digitalocean_droplet" "web" { count = 3 image = "ubuntu-20-04-x64" name = "test-droplet-${count.index}" region = "fra1" size = "s-1vcpu-1gb" } output "droplet_ip_addresses" { value = digitalocean_droplet.web[*].ipv4_address }
保存文件后,通过运行以下命令应用项目:
terraform apply -var "do_token=${DO_PAT}"
您将收到现在是一个列表的输出,其中仅包含 Droplet 的 IP 地址:
Output... Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: droplet_ip_addresses = [ "ip_address", "ip_address", "ip_address", ]
要以 JSON 格式接收输出,请运行以下命令:
terraform output -json droplet_ip_addresses
输出将是一个数组:
Output["ip_address","ip_address","ip_address"]
您已将输出与 splat 表达式和 for
循环一起使用来导出已部署 Droplet 的 IP 地址。 您还收到了 JSON 格式的输出内容,现在您将使用 jq
(一种根据给定表达式动态过滤 JSON 的工具)来解析它们。
使用 jq
解析输出
在此步骤中,您将安装并学习 jq
的基础知识,这是一种用于处理 JSON 文档的工具。 您将使用它来解析 Terraform 项目的输出。
如果您使用的是 Ubuntu,请运行以下命令来安装 jq
:
sudo snap install jq
在 macOS 上,您可以使用 Homebrew 来安装它:
brew install jq
jq
将提供的处理表达式应用于给定的输入,可以通过管道输入。 jq
中最简单的任务是漂亮地打印输入:
terraform output -json droplet_ip_addresses | jq '.'
传入身份运算符 (.
) 意味着从输入解析的整个 JSON 文档应该不加修改地输出:
Output[ "first_ip_address", "second_ip_address", "third_ip_address" ]
您可以使用数组括号表示法仅请求第二个 IP 地址,从零开始计数:
terraform output -json droplet_ip_addresses | jq '.[1]'
输出将是:
Output"second_ip_address"
要使处理结果成为数组,请将表达式括在括号中:
terraform output -json droplet_ip_addresses | jq '[.[1]]'
你会得到一个漂亮的打印 JSON 数组:
Output[ "second_ip_address" ]
您可以通过在括号内指定索引范围来检索部分数组而不是单个元素:
terraform output -json droplet_ip_addresses | jq '.[0:2]'
输出将是:
Output[ "first_ip_address", "second_ip_address" ]
范围 0:2
返回前两个元素 - 范围的上半部分 (2
) 不包括在内,因此只有位于 0
和 1
位置的元素被获取。
您现在可以通过运行以下命令来销毁已部署的资源:
terraform destroy -var "do_token=${DO_PAT}"
在这一步中,您已安装 jq
并使用它来解析和操作 Terraform 项目的输出,该项目部署了三个 Droplet。
结论
您已经了解了 Terraform 输出,使用它们来显示有关已部署资源的详细信息并导出数据结构以供以后进行外部处理。 您还使用输出来显示单个资源的属性,以及显示构建的地图和包含资源属性的列表。
更多jq
特性详情,请访问官方文档。
本教程是 如何使用 Terraform 管理基础架构系列的一部分。 该系列涵盖了许多 Terraform 主题,从首次安装 Terraform 到管理复杂的项目。