由于您展示了cloud-config 模板,我假设您正在为启动时运行cloud-init 的AMI 准备user_data。这意味着这可能更像是一个 cloud-init 问题而不是 Terraform 问题,但我知道您还想知道如何将特定于 cloud-init 的答案转换为可行的 Terraform 配置。
User-data Formats 文档描述了格式化 user_data 以供 cloud-init 使用的各种可能方式。您在问题中提到了多部分 MIME,如果您希望 cloud-init 分别解释两个有效负载,而不是作为单个工件,这可能是一个可行的答案。 cloud-init 文档讨论了工具 make-mime,但 Terraform 的等价物是 the cloudinit_config data source 属于 the hashicorp/cloudinit provider:
variable "extra_cloudinit" {
type = object({
content_type = string
content = string
})
# This makes the variable optional to set,
# and var.extra_cloudinit will be null if not set.
default = null
}
data "cloudinit_config" "user_data" {
# set "count" to be whatever your aws_instance count is set to
count = ...
part {
content_type = "text/cloud-config"
content = templatefile(
"${path.module}/user_data.tp",
{
hostname = upper("${local.prefix}${count.index + 1}")
domain = local.domain
}
)
}
dynamic "part" {
# If var.extra_cloud_init is null then this
# will produce a zero-element list, or otherwise
# it'll produce a one-element list.
for_each = var.extra_cloudinit[*]
content {
content_type = part.value.content_type
content = part.value.content
# NOTE: should probably also set merge_type
# here to tell cloud-init how to merge these
# two:
# https://cloudinit.readthedocs.io/en/latest/topics/merging.html
}
}
}
resource "aws_instance" "example" {
count = length(data.cloudinit_config.user_data)
# ...
user_data = data.cloudinit_config.user_data[count.index].rendered
}
如果您希望额外的 cloud-init 配置总是以额外的 cloud-config YAML 值的形式出现,那么另一种方法是在 Terraform 中将两个数据结构合并在一起,然后 yamlencode 合并结果:
variable "extra_cloudinit" {
type = any
# This makes the variable optional to set,
# and var.extra_cloudinit will be null if not set.
default = {}
validation {
condition = can(merge(var.extra_cloudinit, {}))
error_message = "Must be an object to merge with the built-in cloud-init settings."
}
}
locals {
cloudinit_config = merge(
var.extra_cloudinit,
{
repo_update = true
repo_upgrade = "all"
# etc, etc
},
)
}
resource "aws_instance" "example" {
count = length(data.cloudinit_config.user_data)
# ...
user_data = <<EOT
#!cloud-config
${yamlencode(local.cloudinit_config)}
EOT
}
这种方法的一个缺点是 Terraform 的 merge 函数始终只是浅合并,而 cloud-init 本身具有 various other merging options。但是,一个优点是生成的单个 YAML 文档通常比多部分 MIME 有效负载更简单,因此可能更容易检查 terraform plan 输出中的正确性。