如何使用Terraform输出管理基础设施数据

简介

Terraform 输出用于从项目状态中提取有关基础架构资源的信息。利用 Hashicorp 配置语言(HCL)的其他功能,Terraform 使用的这种语言,可以查询并将资源信息转换成更复杂的数据结构,例如列表和映射。输出功能在向外部软件提供信息以便其操作创建的基础架构资源时非常有用。

在本教程中,您将通过创建一个部署 Droplets 的简单基础架构来学习 Terraform 输出语法及其参数。您还将通过将它们转换为 JSON 来学习如何编程地解析输出。

先决条件

  • 一个 DigitalOcean 个人访问令牌,您可以通过 DigitalOcean 控制面板创建。您可以在 DigitalOcean 产品文档中找到创建个人访问令牌的说明,如何创建个人访问令牌
  • 请在您的本地机器上安装Terraform并使用DigitalOcean提供商设置一个项目。完成教程《如何使用Terraform与DigitalOcean》中的第1步第2步,并确保将项目文件夹命名为terraform-outputs,而不是loadbalance。在第第2步中,不要包含pvt_key变量和SSH密钥资源。
  • 熟悉HCL数据类型和循环。有关更多信息,请参阅教程《如何使用Terraform变量、依赖关系和条件性提高灵活性》。

注意: 本教程已特别针对Terraform 1.0.2进行测试。

定义输出

在本节中,您将声明一个Droplet,将其部署到云中,并通过定义一个显示Droplet IP地址的输出来了解输出。

作为先决条件,您已经创建了名为terraform-outputs的目录,请在该目录中创建并打开droplets.tf文件进行编辑:

  1. 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
}

您首先声明了一个Droplet资源,称为web。其实际名称在云中将是test-droplet,在区域fra1,运行Ubuntu 20.04。

然后,您声明了一个输出,名为droplet_ip_address。在Terraform中,输出用于导出和显示内部和计算的值和信息。在此处,您设置value参数,该参数接受要输出的数据。这里,您将设置为所声明的Droplet的IP地址。在声明时,它是未知的,但将在部署后变得可用。输出是在每次部署后显示的。

保存并关闭文件,然后使用以下命令部署项目:

  1. 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将在部署后仅显示资源的状态,而不会显示任何其他详细信息。

  1. terraform output

可以使用output命令显示所有outputs

Output
droplet_ip_address = ip_address

输出将列出项目中所有的outputs

  1. terraform output output_name

也可以通过指定名称来查询特定的输出:

Output
ip_address

对于droplet_ip_address,输出将只包含IP地址:除了必需的value参数外,输出还具有几个可选参数:

  • 描述:嵌入简短的文档,详细说明输出显示的内容。
  • depends_on:在每项资源中都可用的元参数,允许您明确指定 Terraform 在计划过程中无法自动推断依赖的资源。
  • sensitive:接受一个布尔值,如果设置为true,将防止在部署后显示输出内容。

sensitive参数在Terraform部署日志公开可用,但输出内容应保持隐藏时非常有用。现在您将它添加到您的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
}

完成编辑后保存并关闭文件。通过运行以下命令再次部署项目:

  1. 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和输出结构,因此通过运行以下命令销毁当前已部署的资源:

  1. terraform destroy -var "do_token=${DO_PAT}"

最后输出的结果将是:

Output
... Destroy complete! Resources: 1 destroyed.

您已经声明并部署了一个Droplet,并创建了一个显示其IP地址的输出。接下来,您将学习如何使用输出显示更复杂的结构,例如列表和映射。

输出复杂结构

在这一节中,您将使用count关键字从同一定义部署多个Droplets,并使用各种格式输出它们的IP地址。

使用for循环

首先,您需要修改Droplet资源定义,所以打开它进行编辑:

  1. 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"
}

您已经指定应该创建三个Droplets,并在Droplet名称中添加当前索引,以便稍后能够区分它们。删除下面的现有输出。完成后,保存并关闭文件。

现在运行以下代码:

  1. terraform apply -var "do_token=${DO_PAT}"

Terraform会计划创建这三个编号的Droplets,名为test-droplet-0test-droplet-1test-droplet-2。在提示时输入yes完成整个过程。最后,您将看到以下输出:

Output
... Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

这意味着所有三个Droplets都已成功部署,并且项目状态中存储了有关它们的所有信息。

要访问其资源属性,最简单的方法是使用输出。但是,为每个Droplet创建一个输出并不可扩展。解决方案是使用for循环遍历Droplets列表并收集它们的属性,或者使用展开表达式(您将在本步骤稍后学习)。

您首先定义一个输出,该输出将输出三个Droplet的IP地址,并与它们的名字配对。打开droplets.tf进行编辑:

  1. 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地址配对并添加到结果映射中。

保存并关闭文件,然后再次应用项目:

  1. terraform apply -var "do_token=${DO_PAT}"

当提示时输入yes,最后会收到输出内容:

Output
Apply 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格式获取输出的内容:

  1. 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表达式提供了一种紧凑的方式来遍历列表中的所有元素,并从每个元素中收集属性的内容,从而得到一个列表。一个提取部署的三台Droplets的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
}

保存文件后,通过运行以下命令应用项目:

  1. terraform apply -var "do_token=${DO_PAT}"

您将收到一个列表的输出,该输出只包含Droplets的IP地址:

Output
... Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: droplet_ip_addresses = [ "ip_address", "ip_address", "ip_address", ]

要获取JSON格式的输出,请运行以下命令:

  1. terraform output -json droplet_ip_addresses

输出将是一个单一的数组:

Output
["ip_address","ip_address","ip_address"]

您已经使用输出、Splat表达式和for循环导出了部署的Droplets的IP地址。您还收到了输出内容作为JSON,现在您将使用jq—一个根据给定表达式动态过滤JSON的工具—来解析它们。

使用`jq`解析输出

在这个步骤中,您将安装并学习`jq`这个工具的基础用法,它用于操作JSON文档。您将使用它来解析Terraform项目的输出。

如果您使用的是Ubuntu,请运行以下命令来安装`jq`:

  1. sudo snap install jq

在macOS上,您可以使用Homebrew来安装它:Homebrew

  1. brew install jq

jq对给定的输入应用提供的处理表达式,输入可以通过管道传输。在jq中最简单的任务是美化输入:

  1. terraform output -json droplet_ip_addresses | jq '.'

传入身份操作符(.)意味着应该输出整个从输入解析出的JSON文档,而不做任何修改:

Output
[ "first_ip_address", "second_ip_address", "third_ip_address" ]

您可以使用数组方括号表示法(从零开始计数)来请求第二个IP地址:

  1. terraform output -json droplet_ip_addresses | jq '.[1]'

输出将是:

Output
"second_ip_address"

为了使处理结果成为一个数组,请将表达式用方括号括起来:

  1. terraform output -json droplet_ip_addresses | jq '[.[1]]'

您将得到一个美化打印的JSON数组:

Output
[ "second_ip_address" ]

您可以通过指定索引范围来检索数组的部分,而不是单个元素:

  1. terraform output -json droplet_ip_addresses | jq '.[0:2]'

输出将是:

Output
[ "first_ip_address", "second_ip_address" ]

范围0:2返回第一个两个元素-范围的上限(2)不包括,所以只获取位置0和1的元素。

现在您可以运行以下命令销毁部署的资源:

  1. terraform destroy -var "do_token=${DO_PAT}"

在本步中,您已安装了jq并使用它来解析和操作您的Terraform项目的输出,该输出部署了三个Droplets。

结论

您已经学习了关于Terraform输出,使用它们显示有关部署的资源的详细信息,以及用于稍后外部处理的导出数据结构。您还使用了输出显示单个资源的属性,以及包含资源属性的地图和列表。

欲了解有关jq的更多信息,请参阅官方文档

本教程是《如何使用Terraform管理基础设施》系列的一部分。该系列涵盖了Terraform的多个主题,从首次安装Terraform到管理复杂项目。

Source:
https://www.digitalocean.com/community/tutorials/how-to-manage-infrastructure-data-with-terraform-outputs