问题:
是否有人成功使用 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
参考:
- https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/cloudinit_config
- https://github.com/vmware-archive/cloud-init-vmware-guestinfo
- https://grantorchard.com/terraform-vsphere-cloud-init/
- https://github.com/rgl/terraform-vsphere-ubuntu-example/blob/master/main.tf
版本详细信息:
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 数据源提供程序:
- [Web 浏览器[ 下载 OVA:https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
- [VC UI] 从 OVF 部署,接受默认值(磁盘配置除外,使用精简配置)。
- [VC UI] 编辑设置/VM 选项/启动选项/启动延迟 = 2000ms。
- [VC UI] 打开 VM 控制台。
- [虚拟机控制台] 启动虚拟机。
- [VM 控制台] 在 BIOS 屏幕上按住 Shift(强制 GRUB 显示菜单)。
- [VM 控制台] 选择 Ubuntu 的高级选项。
- [VM 控制台] 选择末尾带有“(恢复模式)”的最新内核版本。
- [VM 控制台] 选择“root / Drop to root shell prompt”
- [VM Console] 按 Enter 进行维护
- [VM 控制台]# dpkg-reconfigure cloud-init
- [VM 控制台] 取消选择除 VMware 和 None 之外的所有内容
- [虚拟机控制台]# cloud-init clean
- [虚拟机控制台]#shutdown -h now
- [VC UI] 编辑设置/VM 选项/启动选项/启动延迟 = 0ms。
- [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"
}