问题描述
我有一个像这样创建的谷歌存储桶对象(通过 terraform):
resource "google_storage_bucket_object" "my_post_startup_script" {
name = "my-script.sh"
source = "${path.module}/my-script.sh"
bucket = my_bucket
}
但是在那个脚本里面是我想要创建变量的东西。
所以说 my-script.sh 看起来像:
#!/bin/bash
echo "hello ${name}"
有没有办法让我传入一个变量以便进行插值,以便上传的脚本实际上说“你好约翰”
这可能需要一些中间步骤来创建一个带有变量插值的文件,然后我可以将其作为 google_storage_bucket_object 的源传入 - 但不确定如何完成。
解决方法
按照您目前编写的方式,读取文件 my-script.sh
的是 Google 提供程序本身,因此到那时进行任何进一步的 Terraform 模板处理为时已晚;模板处理是 Terraform 语言本身的一部分,在将配置传递给提供程序之前发生。
然而,google_storage_bucket_object
也有一个替代参数 content
,它允许您将所需的内容直接传递给提供者,而无需提供者从文件本身读取它。以最简单的形式,允许您将常量值发送到提供程序中,而无需先将它们写入磁盘:
resource "google_storage_bucket_object" "my_post_startup_script" {
name = "my-script.sh"
bucket = my_bucket
content = "Hello world!"
}
然而,该 content
参数可以采用任何返回字符串的有效 Terraform 语言表达式,其中一个示例是对 templatefile
的调用,它是一个询问 Terraform 本身(核心运行时,而不是提供者)从磁盘读取文件并将其内容解释为 string template。
把这两件事放在一起,你可以做到:
resource "google_storage_bucket_object" "my_post_startup_script" {
name = "my-script.sh"
bucket = my_bucket
content = templatefile("${path.module}/my-script.sh",{
name = var.example_name
})
}
对于您在此处分享的简单示例,无论是 Terraform 本身还是最终从磁盘读取文件的 Google Cloud Platform 提供商都没有太大区别,但可能存在一些实际差异在其他情况下很重要:
- Terraform 字符串始终是 Unicode 字符序列而不是原始字节,因此使用
content
传递值要求内容是 Unicode 字符串,并且提供程序将在保存之前将其编码为 UTF-8。另一方面,如果您使用source
,提供程序将完全按原样获取文件中的原始字节并上传它们,因此您可以上传其他字符编码的文本或上传不根本没有文字。 - 因为它现在是由呈现发送给提供程序的模板产生的字符串,而不仅仅是文件名,所以您将看到内容本身显示在带有
content
的 Terraform 计划输出中,而使用 {{1 }} 您以前只会看到文件名。在许多情况下,人们认为这是使用source
的优势而不是劣势,但是如果内容特别大(因此使计划输出很长)或者如果它包含不适合在控制台输出中显示的内容。 - Terraform 资源配置的大小存在实际限制,这取决于提供程序协议、SDK 和系统可用内存等各种技术细节,因此仅适合使用
content
用于相对较小的对象,例如脚本和其他小型配置文件。
如果您的用例包括处理聚集在一个子目录中的大量模板文件,您可能会发现 the Terraform module hashicorp/dir/template
很有用。它封装了 content
和 templatefile
函数调用,以准备一次上传的多个文件,并以 you can pass conveniently to a google_storage_bucket_object
resource using for_each
的方式返回它们。