Frage:
Hat jemand erfolgreich Terraform + Extra_Config + Ubuntu-Cloud-Images verwendet, um eine Schnittstelle zu Cloud Init herzustellen und Metadaten/Benutzerdaten bereitzustellen? Ich hoffe, dass dies mit DataSourceVMware interagiert, kann es aber zu diesem Zeitpunkt noch nicht sicher sagen.
Was ich gemacht habe:
Ich verwende Terraform, um Ubuntu-Cloud-Images auf VMware vSphere 7 bereitzustellen. Die Verwendung von vApp-Eigenschaften ist recht einfach:
... 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"))
}
}
Aber jeder Versuch, extra_config zu verwenden, ist fehlgeschlagen. Ich möchte sowohl guestinfo.metadata als auch guestinfo.userdata bereitstellen können. Aber derzeit scheinen meine Tests mit Metadaten (siehe unten) fehlzuschlagen, da der Hostname in der VM nicht festgelegt ist:
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"
}
Ich kann den vSphere-Protokolleintrag sehen, der beweist, dass die extra_config gesendet wurde:
config.extraConfig("guestinfo.metadata"): (key = "guestinfo.metadata", value = "H4sIAAAAAAAA/2SOTUvGMBCE74H8h/De11dPQsSDHz14qIK ... snipped
Verweise:
- 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
Versionsdetails:
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
Antwort1
Das Problem besteht darin, dass Cloud-Init standardmäßig den OVF-Datenquellenanbieter vor der neuen VMware-Datenquelle aufgerufen hat (ab Cloud-Init 21.3). Terraform stellt Daten bereit, die dem OVF-Datenquellenanbieter gefallen, und verarbeitet daher die Informationen. Das erklärt, warum die vApp-Eigenschaften „Benutzerdaten“ die Cloud-Konfiguration akzeptieren.
Die Lösung besteht darin, den OVF-Datenquellenanbieter aus Cloud-Init zu entfernen:
- [Webbrowser[ OVA herunterladen: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
- [VC-Benutzeroberfläche] Von OVF bereitstellen, Standardeinstellungen akzeptieren (außer bei der Datenträgerbereitstellung, Thin Provisioning verwenden).
- [VC UI] Einstellungen bearbeiten / VM-Optionen / Startoptionen / Startverzögerung = 2000 ms.
- [VC UI] VM-Konsole öffnen.
- [VM-Konsole] VM einschalten.
- [VM-Konsole] Halten Sie die Umschalttaste auf dem BIOS-Bildschirm gedrückt (um GRUB zur Anzeige des Menüs zu zwingen).
- [VM-Konsole] Wählen Sie Erweiterte Optionen für Ubuntu.
- [VM-Konsole] Wählen Sie die neueste Kernel-Version mit „(Wiederherstellungsmodus)“ am Ende.
- [VM-Konsole] Wählen Sie „root / Zur Root-Shell-Eingabeaufforderung wechseln“
- [VM-Konsole] Drücken Sie die Eingabetaste für die Wartung
- [VM-Konsole] # dpkg-reconfigure cloud-init
- [VM-Konsole] Deaktivieren Sie alles außer VMware und Keine
- [VM-Konsole] # cloud-init clean
- [VM-Konsole] # shutdown -h jetzt
- [VC UI] Einstellungen bearbeiten / VM-Optionen / Startoptionen / Startverzögerung = 0 ms.
- [VC UI] In Vorlage konvertieren
Antwort2
Ich habe dasselbe mit den Ubuntu-Cloud-OVAs gemacht und einen kleinen Workaround dafür gefunden. Das ist nicht ideal, da es einen Neustart erfordert, d. h. Sie benötigen einen local-exec
Provisioner, der erkennt, wann die Instanz tatsächlich fertig ist, aber es funktioniert.
Angenommen, Sie haben zwei YAML-Dateien, die Sie für Benutzerdaten verwenden - die erste übergeben Sie mit vApp-Eigenschaften namens vapp-userdata.yaml
und die zweite übergeben Sie für die VMware-Datenquelle namensguest-userdata.yaml
So etwas in 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"
}
Sie vapp-userdata.yaml
verfügen über eine write_file
Aktion, die die aktuellen Datenquellendefinitionen überschreibt und entfernt, OVF
da Sie diesen Punkt bereits erreicht haben.
write_files:
- path: /etc/cloud/cloud.cfg.d/90_dpkg.cfg
owner: root:root
permissions: "0644"
content: |
datasource_list: [ VMware, None ]
Anschließend unten mit einem Neustart abschließen
power_state:
timeout: 600
mode: reboot
Wenn die VM nach dem letzten Befehl neu startet, liest sie die VMware
Datenquelle wie in der neuen Cloud-Init-Konfiguration definiert ein und verarbeitet Ihr „ guest-userdata.yaml
und“, metadata.yaml
wenn Sie das auch definiert haben.
Was die Erkennung des Abschlusses angeht, versuche ich immer noch, den besten Weg dafür zu finden. Der einfache Weg ist, nc -l 12345
am Ende von zu beginnen guest-userdata.yaml
und einen lokalen Provisioner zu haben, der fortfährt, wenn er eine Verbindung zu herstellen kann tcp/12345
. Dadurch bleibt jedoch ein Netcat-Listener auf geöffnet, tcp/12345
was nicht gerade ideal ist.
Wenn Sie einen besseren Weg finden, antworten Sie :)
Bearbeiten
Es gibt sicherlich eine bessere Möglichkeit, dies zu tun, aber ...
Am Ende vonguest-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
Dann als Provisioner am Ende Ihrer .tf
Datei
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"
}