问题描述
在使用 Terraform 时,有一个关于使用模板生成 cloud-init 文件的问题。Terraform 提供了一个函数 templatefile
,可以将 Terraform 本地或外部获取的变量应用于 Jinja2 模板。用户尝试根据 Terraform 文档中的示例,使用这些模板生成包含 Jinja2 的 cloud-init 文件。
用户的模板示例如下:
ssh_keys:
ecdsa_private: "${ssh_ecdsa_key_private}"
然后,用户在 Terraform 中设置这些变量:
data "template_file" "user_data" {
template = templatefile(
"cloud/cloud.cfg",
{
ssh_ecdsa_key_private = file("./ssh/acme-bitbucket-id_ecdsa")
}
)
}
然而,问题出现在 cloud-init 文件的 yaml 格式上。
用户遇到的错误消息大致如下:
in "<unicode string>", line 22, column 1: " ^could not find expected ':' in "<unicode string>", line 24, column 8: "-----BEGIN OPENSSH PRIVATE KEY----- ^"...
用户认为问题可能是文件的缩进格式不正确,导致 yaml 解析出错。
解决方案
以下是解决这个问题的几种方案,根据情况选择适合的方法。
方案1:使用 HDL 对象处理模板变量
在 Terraform 中,你可以将模板变量作为 HDL 对象(哈希、字典、列表等)进行处理,这有助于避免一些格式化问题。下面是一个示例:
data "template_file" "user_data" {
template = templatefile(
"cloud/cloud.cfg",
{
ssh_keys = {
ssh_ecdsa_key_private = file("./ssh/acme-bitbucket-id_ecdsa")
ssh_ecdsa_key_public = file("./ssh/acme-bitbucket-id_ecdsa.pub")
}
}
)
}
在这个示例中,我们将 ssh_keys
作为一个字典对象处理,其中包含私钥和公钥的文件内容。这样可以更好地维护格式。
方案2:使用 yamlencode 函数
Terraform 提供了 yamlencode
函数,可以将变量编码为 yaml 格式,确保生成的 cloud-init 文件保留正确的格式。以下是使用 yamlencode
函数的示例:
data "template_file" "user_data" {
template = templatefile(
"cloud/cloud.cfg",
{
ssh_keys = {
ssh_ecdsa_key_private = file("./ssh/acme-bitbucket-id_ecdsa")
}
}
)
}
resource "null_resource" "example" {
triggers = {
user_data = yamlencode(data.template_file.user_data.rendered)
}
}
在这个示例中,我们使用了一个 null_resource
来触发 yamlencode
函数并将生成的 yaml 内容存储在触发器中。这可以确保生成的 cloud-init 文件在 yaml 上下文中保持正确的格式。
请根据实际情况选择适合你需求的方案。如果你对 yaml 的格式有特殊要求,建议使用方案2,因为它可以更好地控制生成的文件格式。