跳至主要内容

供应器

您可以使用供应器来模拟本地机器或远程机器上的特定操作,以便为服务准备服务器或其他基础设施对象。

供应器是最后的手段

OpenTofu 包含供应器的概念,这是一种务实的措施,因为我们知道总有一些行为无法在 OpenTofu 的声明式模型中直接表示。

但是,它们也为 OpenTofu 的使用带来了相当大的复杂性和不确定性。首先,OpenTofu 无法将供应器的操作建模为计划的一部分,因为它们原则上可以执行任何操作。其次,成功使用供应器需要协调比 OpenTofu 使用通常需要的更多细节:对服务器的直接网络访问,向登录发出 OpenTofu 凭据,确保安装所有必要的外部软件等等。

以下部分描述了一些可以使用供应器原则上解决,但也可以使用更好的解决方案的情况。我们不建议在以下部分描述的任何用例中使用供应器。

即使您的特定用例没有在以下部分中描述,我们仍然建议首先尝试使用其他技术来解决它,并且仅在没有其他选择时才使用供应器。

将数据传递到虚拟机和其他计算资源

在部署虚拟机或其他类似的计算资源时,我们通常需要传入有关其他相关基础设施的数据,服务器上的软件需要这些数据才能完成其工作。

通过 SSH 或 WinRM 与远程服务器交互的各种供应器可能用于通过登录服务器并直接提供这些数据来传递这些数据,但大多数云计算平台提供机制在创建实例时传递数据,以便数据在系统启动时立即可用。例如

许多官方 Linux 发行版磁盘镜像包含名为 cloud-init 的软件,它可以自动以各种方式处理通过上述方式传递的数据,允许您在引导过程中立即运行任意脚本并进行基本系统配置,无需通过 SSH 访问机器。

如果您正在构建自定义机器镜像,您可以通过上述方式以对您的应用程序有意义的方式使用“用户数据”或“元数据”,方法是参考您的供应商文档以了解如何在运行时访问数据。

如果您打算在云提供商中使用任何机制来自动启动和销毁一组服务器,则此方法是必需的,因为在这种情况下,单个服务器将在 OpenTofu 不在的情况下无人值守地启动以对其进行配置。

即使您直接使用 OpenTofu 部署单个服务器,以这种方式传递数据也将允许更快的启动时间并简化部署,从而避免 OpenTofu 直接访问新服务器的网络以及提供远程访问凭据的需要。

使用 cloud-config 配置文件

您可以在 OpenTofu 配置中添加 cloudinit_config 数据源,并指定您要作为 text/cloud-config 内容配置的文件。cloudinit_config 数据源渲染用于 cloud-init 的多部分 MIME 配置。使用 write_files 块以 YAML 编码的配置形式将文件传递到 content 字段中。

在以下示例中,my_cloud_config 数据源指定了一个名为 cloud.conftext/cloud-config MIME 部分。part.content 字段设置为 yamlencode,它将 write_files JSON 对象编码为 YAML,以便系统可以配置引用的文件。

代码块
data "cloudinit_config" "my_cloud_config" {
gzip = false
base64_encode = false

part {
content_type = "text/cloud-config"
filename = "cloud.conf"
content = yamlencode(
{
"write_files" : [
{
"path" : "/etc/foo.conf",
"content" : "foo contents",
},
{
"path" : "/etc/bar.conf",
"content" : file("bar.conf"),
},
{
"path" : "/etc/baz.conf",
"content" : templatefile("baz.tpl.conf", { SOME_VAR = "qux" }),
},
],
}
)
}
}

运行配置管理软件

为了方便那些被迫使用通用操作系统发行版镜像的用户,OpenTofu 包含许多针对启动特定配置管理产品的专用配置器。

我们强烈建议不要使用这些配置器,而是在自定义镜像构建过程中运行系统配置步骤。例如,HashiCorp Packer 提供了类似的配置管理配置器,并且可以在单独的构建过程中运行它们的安装步骤,然后创建一个系统磁盘镜像,您可以多次部署该镜像。

如果您使用的是具有集中式服务器组件的配置管理软件,您需要将注册步骤延迟到最终系统从您的自定义镜像引导后。为此,请使用上述机制之一将必要的信息传递到每个实例中,以便它可以在引导后立即向配置管理服务器注册,而无需接受来自 OpenTofu 通过 SSH 或 WinRM 的命令。

一流的提供程序功能可能可用

从技术上讲,可以使用 local-exec 配置器运行目标系统的 CLI 来创建、更新或以其他方式与该系统中的远程对象交互。

如果您尝试使用远程系统的新功能,而该功能尚未在其提供程序中得到支持,这可能是唯一的选择。但是,如果存在您打算使用的功能的提供程序支持,请优先使用该提供程序功能而不是配置器,以便 OpenTofu 可以完全了解对象并适当地管理对它的持续更改。

即使您需要的功能今天在提供程序中不可用,我们建议将 local-exec 使用视为临时解决方法,并还将在相关提供程序的存储库中打开一个问题,以讨论添加一流的提供程序支持。提供程序开发团队通常会根据兴趣优先考虑功能,因此打开一个问题是记录您对该功能的兴趣的一种方式。

配置器用于在本地或远程机器上执行脚本,作为资源创建或销毁的一部分。配置器可用于引导资源、清理销毁前的内容、运行配置管理等。

如何使用配置器

如果您确定配置器是解决问题后考虑了上面部分中的建议的最佳方法,您可以在计算实例的 resource 块中添加一个 provisioner 块。

代码块
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
command = "echo The server's IP address is ${self.private_ip}"
}
}

local-exec 配置器不需要其他配置,但大多数其他配置器必须通过 SSH 或 WinRM 连接到远程系统。您必须包含 一个 connection,以便 OpenTofu 知道如何与服务器通信。

OpenTofu 包含几个内置配置器。您也可以使用第三方配置器作为插件,方法是将它们放置在 %APPDATA%\terraform.d\plugins~/.terraform.d/plugins$XDG_DATA_HOME/opentofu/plugins 或 OpenTofu 二进制文件安装的同一个目录中。但是,我们不建议使用除内置的 filelocal-execremote-exec 配置器以外的任何配置器。

所有配置器都支持 whenon_failure 元参数,它们在下面描述(见 销毁时配置器失败行为)。

self 对象

provisioner 块中的表达式不能通过名称引用其父资源。相反,它们可以使用特殊的 self 对象。

self 对象表示配置器的父资源,并具有该资源的所有属性。例如,使用 self.public_ip 引用 aws_instancepublic_ip 属性。

在 CLI 输出中抑制配置器日志

provisioner 块的配置可以使用敏感值,例如 sensitive 变量sensitive 输出值。在这种情况下,配置器的所有日志输出都会被自动抑制,以防止显示敏感值。

创建时配置器

默认情况下,配置器在它们定义的资源被创建时运行。创建时配置器仅在创建期间运行,而不是在更新或任何其他生命周期期间运行。它们旨在作为执行系统引导的一种手段。

如果创建时配置器失败,该资源将被标记为已污染。已污染的资源将在下一次 tofu apply 时计划销毁和重新创建。OpenTofu 这样做是因为失败的配置器可能会使资源处于半配置状态。由于 OpenTofu 不能推理配置器所做的操作,确保资源正确创建的唯一方法是重新创建它。这就是污染。

您可以通过设置 on_failure 属性来更改此行为,该属性将在下面详细介绍。

销毁时配置器

如果指定了 when = destroy,则配置器将在定义它的资源销毁时运行。

代码块
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
when = destroy
command = "echo 'Destroy-time provisioner'"
}
}

销毁配置器在资源被销毁之前运行。如果它们失败,OpenTofu 将报错并在下一次 tofu apply 时再次运行配置器。由于这种行为,应注意销毁配置器在多次运行时是安全的。

销毁时配置器只能在资源被销毁时保留在配置中才能运行。如果从配置中完全删除了包含销毁时配置器的资源块,则其配置器配置将与之一起删除,因此销毁配置器不会运行。要解决此问题,可以使用多步骤过程来安全地删除具有销毁时配置器的资源

  • 更新资源配置以包含 count = 0
  • 应用配置以销毁资源的任何现有实例,包括运行销毁配置器。
  • 从配置中完全删除资源块及其 provisioner 块。
  • 再次应用,此时不应该采取任何进一步的措施,因为资源已经被销毁。

由于这种限制,您应该谨慎使用销毁时配置器。

多个配置器

可以在资源中指定多个配置器。多个配置器按它们在配置文件中定义的顺序执行。

您还可以混合使用创建和销毁配置器。只有对给定操作有效的配置器才会运行。这些有效的配置器将按它们在配置文件中定义的顺序运行。

多个配置器的示例

代码块
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
command = "echo first"
}

provisioner "local-exec" {
command = "echo second"
}
}

失败行为

默认情况下,失败的配置器也会导致 OpenTofu apply 本身失败。on_failure 设置可用于更改此行为。允许的值是

  • continue - 忽略错误并继续创建或销毁。

  • fail - 抛出错误并停止应用(默认行为)。如果这是一个创建配置器,则污染资源。

示例

代码块
resource "aws_instance" "web" {
# ...

provisioner "local-exec" {
command = "echo The server's IP address is ${self.private_ip}"
on_failure = continue
}
}