Pregunta:
¿Alguien ha utilizado con éxito terraform + extra_config + imágenes en la nube de Ubuntu para interactuar con Cloud Init, proporcionando metadatos/datos de usuario? Espero que esto interactúe con DataSourceVMware, pero no puedo estar seguro en este momento.
Lo que he estado haciendo:
Estoy usando Terraform para implementar imágenes en la nube de Ubuntu en VMware vSphere 7. Ha sido bastante fácil usar las propiedades de 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"))
}
}
Pero cualquier intento de utilizar extra_config ha fracasado. Me gustaría poder proporcionar guestinfo.metadata y guestinfo.userdata. Pero actualmente, mis pruebas con metadatos (que se ven a continuación) parecieron fallar porque el nombre de host no está configurado en la 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"
}
Puedo ver la entrada del registro de vSphere para demostrar que se envió extra_config:
config.extraConfig("guestinfo.metadata"): (key = "guestinfo.metadata", value = "H4sIAAAAAAAA/2SOTUvGMBCE74H8h/De11dPQsSDHz14qIK ... snipped
Referencias:
- 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
Detalles de la versión:
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
Respuesta1
El problema es que cloud-init tiene, de forma predeterminada, el proveedor de fuente de datos OVF invocado antes de la nueva fuente de datos VMware (a partir de cloud-init 21.3). Terraform proporciona datos que le gustan al proveedor de fuentes de datos OVF y, por lo tanto, procesa la información. Eso explica por qué los "datos de usuario" de vApp Properties aceptan el archivo cloud-config.
La solución es eliminar el proveedor de fuente de datos OVF de cloud-init:
- [Navegador web[ Descargar OVA: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
- [VC UI] Implemente desde OVF, acepte los valores predeterminados (excepto el aprovisionamiento de disco, use Thin Provisioning).
- [VC UI] Editar configuración/Opciones de VM/Opciones de arranque/Retraso de arranque = 2000 ms.
- [IU de VC] Abra la consola de VM.
- [Consola de VM] Encienda la VM.
- [Consola VM] Mantenga presionada la tecla Mayús en la pantalla del BIOS (para forzar a GRUB a mostrar el menú).
- [Consola VM] Seleccione Opciones avanzadas para Ubuntu.
- [Consola VM] Seleccione la última versión del kernel con "(modo de recuperación)" al final.
- [Consola VM] Seleccione "raíz / Colocar en el indicador de shell raíz"
- [Consola VM] Presione Enter para mantenimiento
- [Consola VM] # dpkg-reconfigure cloud-init
- [Consola VM] Deseleccione todo excepto VMware y Ninguno
- [Consola VM] # limpieza de inicio de nube
- [Consola VM] # apagado -h ahora
- [VC UI] Editar configuración/Opciones de VM/Opciones de arranque/Retraso de arranque = 0 ms.
- [VC UI] Convertir a plantilla
Respuesta2
Haciendo lo mismo con los OVA en la nube de Ubuntu y encontré una pequeña solución para esto. No es ideal, ya que implica un reinicio, lo que significa que necesita un local-exec
aprovisionador para detectar cuándo finaliza la instancia, pero funciona.
Supongamos que tiene dos archivos yaml que está utilizando para datos de usuario: el primero que está pasando con las propiedades de vApp denominadas vapp-userdata.yaml
y luego el segundo que está pasando para la fuente de datos de VMware denominadaguest-userdata.yaml
Algo como esto en 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"
}
Tiene vapp-userdata.yaml
una write_file
acción que sobrescribe las definiciones de fuentes de datos actuales y las elimina OVF
cuando ya ha llegado a ese punto.
write_files:
- path: /etc/cloud/cloud.cfg.d/90_dpkg.cfg
owner: root:root
permissions: "0644"
content: |
datasource_list: [ VMware, None ]
Luego, en la parte inferior, termine con un reinicio.
power_state:
timeout: 600
mode: reboot
Cuando la máquina virtual se reinicie después de ese último comando, leerá la VMware
fuente de datos como se define en la nueva configuración de inicio de nube y procesará su información guest-userdata.yaml
y, metadata.yaml
si la ha definido, también.
En cuanto a detectar cuándo está terminado, todavía estoy tratando de encontrar la mejor manera de hacerlo. La manera más fácil es comenzar nc -l 12345
al final guest-userdata.yaml
y tener un aprovisionador local que continúe cuando pueda conectarse tcp/12345
, pero eso lo deja con un oyente de netcat abierto tcp/12345
que no es ideal.
Si encuentras una mejor manera, responde :)
Editar
Definitivamente habrá una mejor manera de hacer esto, pero...
En el fondo deguest-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
Luego como aprovisionador al final de su .tf
archivo
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"
}