从安装了cloud-init的 AMI 开始时(这在许多官方 Linux 发行版中很常见),我们可以使用 cloud-init 的write_files
模块将任意文件放入文件系统,只要它们足够小以适应论点以及user_data
所有其他cloud-init
数据。
与所有 cloud-init 模块一样,我们write_files
使用cloud-init 的基于 YAML 的配置格式进行配置,该格式以单独一行的特殊标记字符串开头#cloud-config
,然后是 YAML 数据结构。因为 JSON 是 YAML 的子集,所以我们可以使用 Terraformjsonencode
来生成有效值[1]。
locals {
cloud_config_config = <<-END
#cloud-config
${jsonencode({
write_files = [
{
path = "/etc/example.txt"
permissions = "0644"
owner = "root:root"
encoding = "b64"
content = filebase64("${path.module}/example.txt")
},
]
})}
END
}
当write_files
我们设置 时,模块可以接受 base64 格式的数据encoding = "b64"
,因此我们将它与 Terraform 的filebase64
函数结合使用以包含外部文件的内容。其他方法在这里也是可能的,例如使用 Terraform 模板动态生成字符串并将base64encode
其编码为文件内容。
如果您可以像上面一样在单个配置文件中表达您希望 cloud-init 执行的所有操作,那么您可以local.cloud_config_config
直接分配为您的 instance user_data
,并且 cloud-config 应该在系统启动时识别并处理它:
user_data = local.cloud_config_config
如果您需要将创建文件与其他一些操作(例如运行 shell 脚本)结合起来,您可以使用 cloud-init 的多部分存档格式来编码多个“文件”以供 cloud-init 处理。Terraform 有一个cloudinit
提供程序,其中包含一个数据源,用于轻松为 cloud-init 构建多部分存档:
data "cloudinit_config" "example" {
gzip = false
base64_encode = false
part {
content_type = "text/cloud-config"
filename = "cloud-config.yaml"
content = local.cloud_config_config
}
part {
content_type = "text/x-shellscript"
filename = "example.sh"
content = <<-EOF
#!/bin/bash
echo "Hello World"
EOT
}
}
此数据源将生成一个字符串,cloudinit_config.example.rendered
该字符串是适用user_data
于 cloud-init 的多部分存档:
user_data = cloudinit_config.example.rendered
EC2 规定最大用户数据大小为 64 KB,因此所有编码数据一起必须符合该限制。如果您需要放置接近或超过该限制的大文件,最好使用中间其他系统来传输该文件,例如让 Terraform 将文件写入 Amazon S3 存储桶并将软件放入您的实例使用实例配置文件凭据检索该数据。不过,对于用于系统配置的小数据文件来说,这应该不是必需的。
需要注意的是,从 Terraform 和 EC2 的角度来看,内容user_data
只是一个任意字符串。处理字符串的任何问题都必须在目标操作系统本身内进行调试,方法是读取 cloud-init 日志以查看它如何解释配置以及尝试采取这些操作时发生了什么。
[1]:我们也可能使用yamlencode
,但在我写这篇文章的时候,这个函数有一个警告,它的确切格式可能会在未来的 Terraform 版本中发生变化,这是不可取的,user_data
因为它会导致实例被替换。如果您将来阅读本文并且该警告不再出现在yamldecode
文档中,请考虑yamlencode
改用。