使用Terraform时,如何自动生成inputs.tf和outputs.tf变量



注意:请参阅下面的####更新###部分。我对这个问题进行了大量修改,以明确我想要实现的目标,但将其作为附录添加,而不是重写这个问题

随着我的基础设施的发展,现在无法手动在variables.tf文件中添加输入变量,然后将这些值同步到outputs.tf文件的输出变量。它不仅占用了很多不必要的时间,而且可能花了更多的时间回去修复terraform validate告诉我的那些我因人为错误而错过的东西。当构建/使用其参数添加了一个要管理的附加层的模块时,尤其如此。

必须有更好的方法吗?以下是我想要实现的目标

假设我正在创建一个Azure AKS Kubernetes集群。Terraform资源是azurerm_kubernetes_cluster.

创建基本安装只需要8个参数,但几乎还有250个额外的参数。它们都有默认值。根据文档页面,他们也已经有了精彩的描述。(我厌倦了复制粘贴到我的variables { description = "this"}块中。)

这些信息在文档中。terraform plan还了解每一个额外的项目,因为它当然会出现在申请前计划中。(应用后已知)表示它是可选的,但将具有默认值。

在我的梦想世界里,我会运行这个假设的命令序列:

  • terraform plan
  • terraform document&lt-在这里,它自动生成每个参数作为变量块并将其插入variables.tf。它还自动生成每个可能的output "out_putable" {}块并将它插入outputs.tf
  • terraform apply -update-inputs -update-outputs&lt-在这里,所有可选的(应用后已知的)现在都是已知的,它应该相应地自动更新variables.tf和outputs.tf。添加-update-modules标志可以让它处理通过使用模块引入的附加层

这感觉像是以前解决过的问题。在我编写一个自定义工具来解析Terraform web文档和terraform show的输出之前,是否已经有了这样的方法?Terraform文档是我为README.md找到的最接近解决方案。如果它能满足我的需求,我还没有弄清楚。

我如何将这一切自动化?

############更新##########

当谈到Terraform在一个组织中的演变时,这篇文章和视频非常到位。我的组织处于模式3后期和模式5早期之间。当我们分解我们的";Terralith";团队之间存在不一致(模式、命名约定、变量和参数选择等)。这些开始导致CI/CD中的错误,迫使票证审查过程减慢速度。

所有资源都有必需参数和可选参数。但在我的组织中,例如,我们需要额外的可选参数

场景:日本的开发人员A创建了一个资源,忘记了一两个可选变量,或者给它们命名了一些模糊的东西,等等。美国的开发人员B被阻止,直到他们可以召集并讨论。考虑到时区、语言差异、机票审查,这一期现在推迟了一周或更长时间。

我需要自动化这一点,并创建精确的一致性,这样开发人员A一开始就完全符合开发人员B的期望;以及CI/CD测试所期望的内容——如果愿意的话,将初始过程模板化。换句话说,我需要去除手动创建main.tfvariables.tfoutputs.tf等的人为因素。

以下是如何实现这一目标的想法:

  • 使用Golang通过查询API自动生成文件如何查询API以获取特定资源的所有required参数的列表

我发现我可以查询提供商信息,但找不到检索资源信息的信息。我的想法是,当开发人员想要创建一个新资源时,他会运行go或typescript来生成清单文件以及预期的命名约定,并用每个人都期望的数据填充main.tf、variables.tf、outputs.tf等。我正在寻找类似curl registry.terraform.io/providers/hashicorp/azurerm/v2.99/resource_group?required=yes的形式。这应该会向我显示所有必需的参数,以及我可以直接从API使用的描述和其他信息。

  • 使用CDKTF从JSON生成HCL manifest.tf文件如何使用CDKTF生成HCL.tf文件?CDKTF正是我想要的——除了相反。HCL与JSON无缝兼容。运行cdktf synth创建./out/cdk.tf.out我太接近了如何将该文件转换为main.tf

这里的目标是拥有一个主文件,所有未来的清单文件都是从该主文件派生的。无论我们使用azurerm_kubernetes_cluster1次还是1000次,我确信每个参数、每个变量名、每个期望的输出都是完全相同的。如果在我们想要的结构中需要一个机会,它将在JSON级别进行更新,CI/CD可以确保这些更改在其使用的实例中传播。

我知道我可以使用cdk.out.tf文件作为模块的替代品,但我不希望我的团队成员必须学习typescript或如何读取json。如果我能创建一个模板化的JSON文件,其中包含我希望用户从中开始的内容,如果他们能运行一些像cdktf convert cdk.tf.out --HCL output-file.tf这样的命令,那么我就实现了我的目标。

如果cdktf synth可以创建一个HCL JSON文件,而cdktf convert可以获取一个manifest.tf文件并将其转换为HCL JSON,难道不能做完全相反的事情吗?将HCL JSON文件转换为人类可读的、声明性的、manifest.tf文件?

也许可以这样想。如果要允许Terraform进入模块注册表,它有一个模块所需的文件结构。我正试图为我们组织使用的每种资源创建一个类似的所需结构,无论何时何地使用。

如果您的目标是从资源类型模式中派生输入变量和输出值,那么Terraform可以为您提供这样做的信息。

在已经使用要使用其资源类型的提供程序的配置的工作目录中,运行以下命令:

terraform providers schema -json

结果包含当前配置的提供程序中可用的所有资源类型的JSON描述,以及每种资源类型的关于其属性的元数据,包括每种资源的类型约束信息和描述。

根据这些信息,您可以生成所需的任何其他文件。


请注意,如果您打算构建导出特定资源类型的整个表面积(所有输入和输出)的模块,Terraform文档明确建议不要这样做,建议直接使用资源类型,因为这样的模块通常不会提供足够的好处来超过它所暗示的额外复杂性和维护开销:

原则上,资源和其他构造的任何组合都可以分解为一个模块,但过度使用模块会使您的整体Terraform配置更难理解和维护,因此我们建议进行适度调整。

一个好的模块应该通过描述体系结构中的一个新概念来提高抽象级别,该概念是根据提供者提供的资源类型构建的。

例如,aws_instance和aws_elb都是属于aws提供者的资源类型。您可以使用一个模块来表示更高层次的概念";在AWS中运行的HashiCorp Consul集群";其恰好是从这些和其他AWS提供商资源构建的。

我们不建议编写仅是单个其他资源类型的精简包装器的模块。如果您很难找到与模块中的主要资源类型不同的模块名称,这可能表明您的模块没有创建任何新的抽象,因此模块增加了不必要的复杂性。只需直接在调用模块中使用资源类型即可。

我也有同样的问题,并开发了一个小的bash脚本来创建基于模块代码的输出定义

该代码要求hcedit工具从hcl代码中提取块

#!/usr/bin/env bash
set -o pipefail
_hcledit=$(which hcledit)

for tf_file in $(ls *.tf); do
cat $tf_file | $_hcledit block list | while read line; do
block_type="${line%%.*}"
line="${line#*.}"
case $block_type in
locals|output|variable|data) continue; break ;;
module)
output_name=$line 
output_description="Module '$output_name' attributes"
output_value="$block_type.$output_name"
;;
resource)
label_kind="${line%.*}"
label_name="${line#*.}"
output_name="${label_kind}_${label_name//[-]/_}"
output_description="Resource '$label_kind.$label_name' attributes"
output_value="$label_kind.$label_name"
;;
esac

cat <<-EOT
output "$output_name" {
description = "$output_description"
value       = $output_value
}
EOT
done
done

最新更新