如何从 Terraform 中的文件加载输入数据?

Zha*_* Yi 15 terraform

aws_cloudwatch_event_target在 terraform 中定义了一个从cloudwatch. 该input字段是事件参数,例如:

resource "aws_cloudwatch_event_target" "data" {
  rule      = "${aws_cloudwatch_event_rule.scheduler.name}"
  target_id = "finance_producer_cloudwatch"
  arn       = "${aws_lambda_function.finance_data_producer.arn}"
  input     = "{\"test\": [\"111\"]}"
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何input从外部文件加载json 数据。

Mar*_*ins 49

这里的答案取决于几个不同的问题:

  • 该文件是配置的静态部分,与.tf文件一起签入版本控制,还是作为应用过程的一部分动态生成?
  • 您是要按字面意思使用文件内容,还是需要从 Terraform 配置中的其他地方将值替换到其中?

这两个问题形成了四个不同答案的矩阵:

             |  Literal Content            Include Values from Elsewhere
-------------|----------------------------------------------------------
Static File  |  file(...) function         templatefile(...) function
Dynamic File |  local_file data source     template_file data source
Run Code Online (Sandbox Code Playgroud)

我将在下面更详细地描述这四个选项中的每一个。

所有这些示例中的一个共同主题是对 的引用path.module,它计算当前模块的加载路径。另一种思考方式是它是包含当前.tf文件的目录。允许访问其他目录中的文件,但在大多数情况下,通过将数据文件和配置文件放在一起来保持模块中的内容自包含是合适的。

Terraform 字符串是 unicode 字符序列,因此 Terraform 只能读取包含有效 UTF-8 编码文本的文件。对于 JSON,这没问题,但对于其他通常可能不是 UTF-8 编码的文件格式,请记住这一点。

file功能

file函数从磁盘读取文件的文字内容,作为对配置的初始评估的一部分。该文件的内容被视为用于验证目的的文字字符串值,因此该文件必须作为配置的静态部分存在于磁盘上(通常在您的版本控制中),而不是动态生成期间terraform apply

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = file("${path.module}/input.json")
}
Run Code Online (Sandbox Code Playgroud)

这是最常见和最简单的选项。如果该file功能足以满足您的需求,那么它是用作默认选择的最佳选择。

templatefile功能

templatefile函数函数类似file,但它不只是按字面意思返回文件内容,而是将文件内容解析为字符串模板,然后使用第二个参数中给出的一组局部变量对其进行评估。如果您需要从 Terraform 配置中的其他地方传递一些数据,这将非常有用,如下例所示:

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = templatefile("${path.module}/input.json.tmpl", {
    instance_id = aws_instance.example.id
  })
}
Run Code Online (Sandbox Code Playgroud)

input.json.tmpl你可以使用Terraform模板语法替代变量值:

{"instance_id":${jsonencode(instance_id)}}
Run Code Online (Sandbox Code Playgroud)

在整个结果是 JSON 的情况下,我建议只使用 生成整个结果jsonencode,因为这样您就可以让 Terraform 担心 JSON 转义等问题,只需用 Terraform 的对象语法编写数据结构:

${jsonencode({
  instance_id = instance_id
})}
Run Code Online (Sandbox Code Playgroud)

与 一样file,因为templatefile是一个函数,它在配置的初始解码期间被评估,并且其结果被验证为文字值。因此,模板文件也必须是作为配置的一部分分发的静态文件,而不是动态生成的文件。

local_file数据源

数据源是读取现有对象或计算结果的特殊资源类型,而不是创建和管理新对象。因为它们是资源,所以它们可以参与依赖关系图,从而可以使用由相同 Terraform 配置中的其他资源在terraform apply.

所述local_file数据源属于所述local提供者和本质上是数据源的等效的file功能。

在以下示例中,我将var.input_file用作对由相同配置中的其他资源创建的文件路径的任何引用的占位符。在实际示例中,这很可能是对资源属性的直接引用。

data "local_file" "input" {
  filename = var.input_file
}

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = data.local_file.input.content
}
Run Code Online (Sandbox Code Playgroud)

template_file数据源

所述template_file数据源是数据源的等效的templatefile功能。它的用法类似于在local_file这种情况下我们通过将其作为静态文件读取来填充模板本身,使用file函数或local_file如上所述取决于模板是在静态文件中还是动态生成的文件中,但如果它是一个我们更喜欢使用该templatefile函数的静态文件,因此我们将在local_file此处使用数据源:

data "local_file" "input_template" {
  filename = var.input_template_file
}

data "template_file" "input" {
  template = data.local_file.input_template.content
  vars = {
    instance_id = aws_instance.example.id
  }
}

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = data.template_file.input.rendered
}
Run Code Online (Sandbox Code Playgroud)

templatefile函数是在 Terraform 0.12.0 中添加的,因此您可能会在其他地方看到使用template_file数据源渲染静态模板文件的示例。这是一个旧模式,现在在 Terraform 0.12 中已弃用,因为该templatefile函数在大多数情况下提供了更直接和可读的配置。

在一个怪癖template_file,而不是数据源templatefile功能是数据源所属template提供者,而不是对terraform核心,所以它的模板功能,可在这将取决于其提供的版本被安装,而不是哪一个版本的Terraform CLI 已安装。该template供应商可能落后Terraform核心滞后无论在哪个模板语言功能都可用,这是另一个原因更喜欢templatefile功能在可能的情况。

其他可能性

这个问题特别是关于从文件中读取数据,但为了完整起见,我还想指出,对于小型 JSON 有效负载,有时最好将它们作为 Terraform 数据结构直接内联在配置中,并使用 转换为 JSON jsonencode,如下所示:

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = jsonencode({
    instance_id = aws_instance.example.id
  })
}
Run Code Online (Sandbox Code Playgroud)

将数据结构内联编写为 Terraform 表达式意味着未来的读者可以直接看到将发送的内容,而无需参考单独的文件。但是,如果数据结构非常大且复杂,那么内联包含它会损害整体可读性,因为它可能压倒同一文件中的其他配置。

因此,选择哪个选项在很大程度上取决于具体情况,但始终值得考虑单独文件的间接性是否是可读性的最佳选择。

Terraform 也有一个yamlencode函数(在撰写本文时是实验性的),它可以对 YAML 格式的数据结构执行类似的操作,直接在.tf文件内部或在外部模板中的插值序列中。