cloud-init - 我正在尝试通过 cloud init 通过用户数据将文件复制到 Windows EC2 实例

cloud-init - I am trying to copy files to Windows EC2 instance through cloud init by passing it through user data

我正在尝试通过用户数据通过云初始化将文件复制到 Windows EC2 实例,云初始化模板运行,它创建了一个文件夹但不复制文件,你能帮我理解吗我在我的代码中做错了什么。

此代码通过自动缩放组的启动配置传递

data template_cloudinit_config ebs_snapshot_scripts {
  gzip          = false
  base64_encode = false

  part {
    content_type = "text/cloud-config"
    content      = <<EOF
<powershell>
$path = "C:\aws"
If(!(test-path $path))
{
      New-Item -ItemType Directory -Force -Path $path
}
</powershell>

write_files:
   -  content: |
     ${file("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/1-start-ebs-snapshot.ps1")}
       path: C:\aws-start-ebs-snapshot.ps1
       permissions: '0744'
   -   content: |
     ${file("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/2-run-backup.cmd")}
       path: C:\aws-run-backup.cmd
       permissions: '0744'
   -   content: |
     ${file("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/3-ebs-snapshot.ps1")}
       path: C:\aws-ebs-snapshot.ps1
       permissions: '0744'
EOF
  }
}

您当前的方法涉及使用 Terraform 模板语言通过将字符串连接在一起来生成 YAML,其中一些字符串是来自外部文件的多行字符串,并且由于 YAML 是一个空格,因此要正确执行总是非常复杂-敏感语言。

我有两个想法可以使这更容易。您可以同时执行这两项操作,尽管执行其中一项也可能奏效。


第一个想法是遵循 Terraform 的 templatefile 函数文档中的 the recommendations about generating JSON and YAML。尽管您的模板是内联的而不是在单独的文件中,但您可以在此处应用类似的原则让 Terraform 本身负责生成有效的 YAML,然后您只需担心使输入数据结构成为正确的形状即可:

  part {
    content_type = "text/cloud-config"

    # JSON is a subset of YAML, so cloud-init should
    # still accept this even though it's jsonencode.
    content = jsonencode({
      write_files = [
        {
          content     = file("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/1-start-ebs-snapshot.ps1")
          path        = "C:\aws\1-start-ebs-snapshot.ps1"
          permissions = "0744"
        },
        {
          content     = file("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/2-run-backup.cmd")
          path        = "C:\aws\2-run-backup.cmd"
          permissions = "0744"
        },
        {
          content     = file("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/3-ebs-snapshot.ps1")
          path        = "C:\aws\3-ebs-snapshot.ps1"
          permissions = "0744"
        },
      ]
    })
  }

jsonencode and yamlencodeTerraform 函数知道如何自动转义换行符和其他特殊字符,因此您只需将文件内容作为属性包含在对象中,Terraform 会自动将其编码为有效的字符串文字.


第二种思路是使用base64编码,而不是直接编码。如果将附加的 属性 encoding 设置为 b64,Cloud-init 允许将文件内容作为 base64 传递。然后,您可以使用 Terraform's filebase64 function 将文件内容直接读入 base64 字符串,然后您可以将其包含到 YAML 中,而无需任何特殊引号或转义。

使用 base64 还意味着放置在远程系统上的文件应该与 Terraform 模块中磁盘上的文件逐字节相同,而通过在 YAML 字符串中使用 file 则有行尾和其他空格可能会在此过程中被更改。

另一方面,使用 base64 的一个缺点是文件内容无法在 terraform plan 输出中直接读取,因此计划不会像使用 base64 那样清晰只是简单的 YAML 字符串编码。


您可以通过使用 filebase64 函数作为第一个示例中 jsonencode 参数的一部分,将这两种想法结合在一起:

        # ...
        {
          encoding    = "b64"
          content     = filebase64("${path.module}/../../../../scripts/aws-ebs-snapshot-ps/1-start-ebs-snapshot.ps1")
          path        = "C:\aws\1-start-ebs-snapshot.ps1"
          permissions = "0744"
        },
        # ...

cloud-init 只能可靠 writes files,所以你必须为他们提供内容。我建议将您的文件存储在 S3 中(例如)并在启动时拉取它们。

抱歉传入 MS-Linux 混淆示例。

使用相同的write files写一个简短的脚本,例如

#!/bin/bash
wget something.ps1
wget something-else.ps2

然后使用 runcmd/bootcmd 运行 文件:

bootcmd:
  - ./something.ps1
  - ./something-else.ps2

工作完成,w/oencoding/character-escaping头疼。