通过 extra_config 和 DataSourceVMware 进行 Terraform + Cloud-Init

通过 extra_config 和 DataSourceVMware 进行 Terraform + Cloud-Init

问题:

是否有人成功使用 terraform + extra_config + Ubuntu 云镜像与 Cloud Init 交互,提供元数据/用户数据?我希望这将与 DataSourceVMware 交互,但目前还不能确定。

我一直在做的事情:

我正在使用 Terraform 在 VMware vSphere 7 上部署 Ubuntu 云映像。使用 vApp 属性非常简单:

... below code snipped from resource "vsphere_virtual_machine" "vm" { }

vapp {
    properties = {
        hostname = var.vm_Name_Lower
        instance-id = var.vm_Name_Lower
        user-data = base64encode(file("${path.module}/userdata.yml"))
    }
}

但任何使用 extra_config 的尝试都失败了。我希望能够提供 guestinfo.metadata 和 guestinfo.userdata。但目前,我对元数据的测试(如下所示)似乎失败了,因为 VM 中未设置主机名:

data "cloudinit_config" "metadata" {
    gzip = true
    base64_encode = true
    part {
        content_type = "text/cloud-config"
        content = <<-EOF
            local-hostname: testvm
            instance-id: testvm
        EOF
    }
}

... below code snipped from resource "vsphere_virtual_machine" "vm" { }

extra_config = {
    "guestinfo.metadata" = data.cloudinit_config.metadata.rendered
    "guestinfo.metadata.encoding" = "gzip+base64"
}

我可以看到 vSphere 日志条目来证明 extra_config 已发送:

config.extraConfig("guestinfo.metadata"): (key = "guestinfo.metadata", value = "H4sIAAAAAAAA/2SOTUvGMBCE74H8h/De11dPQsSDHz14qIK ... snipped

参考:

版本详细信息:

Client system (on which terraform is run): Ubuntu 20.04.3 LTS
ESXi: 7.0.2 / Build: 18538813
vCenter Server: 7.0.2 / Build: 18455184
Cloud Image: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
Terraform v1.0.7
on linux_amd64
provider registry.terraform.io/hashicorp/template v2.2.0
provider registry.terraform.io/hashicorp/vsphere v1.24.3

答案1

问题在于,cloud-init 默认在新的 VMware 数据源之前调用 OVF 数据源提供程序(从 cloud-init 21.3 开始)。Terraform 提供 OVF 数据源提供程序喜欢的数据,因此它会处理这些信息。这解释了为什么 vApp Properties“user-data”接受 cloud-config。

解决方案是从 cloud-init 中删除 OVF 数据源提供程序:

  1. [Web 浏览器[ 下载 OVA:https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
  2. [VC UI] 从 OVF 部署,接受默认值(磁盘配置除外,使用精简配置)。
  3. [VC UI] 编辑设置/VM 选项/启动选项/启动延迟 = 2000ms。
  4. [VC UI] 打开 VM 控制台。
  5. [虚拟机控制台] 启动虚拟机。
  6. [VM 控制台] 在 BIOS 屏幕上按住 Shift(强制 GRUB 显示菜单)。
  7. [VM 控制台] 选择 Ubuntu 的高级选项。
  8. [VM 控制台] 选择末尾带有“(恢复模式)”的最新内核版本。
  9. [VM 控制台] 选择“root / Drop to root shell prompt”
  10. [VM Console] 按 Enter 进行维护
  11. [VM 控制台]# dpkg-reconfigure cloud-init
  12. [VM 控制台] 取消选择除 VMware 和 None 之外的所有内容
  13. [虚拟机控制台]# cloud-init clean
  14. [虚拟机控制台]#shutdown -h now
  15. [VC UI] 编辑设置/VM 选项/启动选项/启动延迟 = 0ms。
  16. [VC UI] 转换为模板

答案2

对 Ubuntu 云 OVA 执行同样的操作,我发现了一些解决方法。这不是理想的方法,因为它需要重新启动,这意味着您需要一个local-exec配置程序来检测实例何时真正完成,但它确实有效。

假设您有两个用于用户数据的 yaml 文件 - 第一个文件与名为 vApp Properties 的文件一起传递vapp-userdata.yaml,第二个文件与名为 VMware 数据源的文件一起传递guest-userdata.yaml

Terraform 中类似这样的情况

  vapp {
    properties = {
      user-data = base64encode(data.template_file.vapp_userdata[count.index].rendered)
    }
  }

  extra_config = {
    "guestinfo.metadata"          = base64encode(data.template_file.guest-metadata[count.index].rendered)
    "guestinfo.metadata.encoding" = "base64"
    "guestinfo.userdata"          = base64encode(data.template_file.userdata.rendered)
    "guestinfo.userdata.encoding" = "base64"
  }

在您的vapp-userdata.yaml操作中write_file,覆盖当前的数据源定义并将其删除,OVF因为您已经到达了这一点。

write_files:
  - path: /etc/cloud/cloud.cfg.d/90_dpkg.cfg
    owner: root:root
    permissions: "0644"
    content: |
      datasource_list: [ VMware, None ]

然后在底部完成重新启动

power_state:
  timeout: 600
  mode: reboot

当虚拟机在执行最后一条命令后重新启动时,它将读取VMware新 cloud-init 配置中定义的数据源,并且如果您也定义了数据源,它将处理您的数据guest-userdata.yaml源。metadata.yaml

至于检测何时完成,我仍在尝试找出最佳方法。简单的方法是从nc -l 12345的末尾开始guest-userdata.yaml,并有一个本地配置程序,当它可以连接到 时继续进行tcp/12345,但这会让您打开一个 netcat 侦听器,tcp/12345这并不理想。

如果你找到更好的方法,请回复:)

编辑

绝对会有更好的方法来做到这一点,但是......

在底部guest-userdata.yaml

runcmd:
  - mkdir -p /mnt/sharedfolder
  - sysctl -w vm.overcommit_memory=1
  - sysctl -w kernel.panic=10
  - sysctl -w kernel.panic_on_oops=1
  - curl https://releases.rancher.com/install-docker/${docker_version}.sh | sh
  - usermod -aG docker ubuntu
  - nc -l 1234 & ncpid=$!  #start nc and get PID
  - sleep 20
  - kill $ncpid #kill PID once Terraform has had time to connect

.tf然后作为文件末尾的提供者

  provisioner "local-exec" {
    # Wait for cloud-init userdata cmds
    # Netcat: z (scan port only), w1 (wait 1 second)
    command = "count=0; until $(nc -zw1 ${self.default_ip_address} 1234); do sleep 1; count=`expr $count + 1`; done"
  }

相关内容