Terraform + Cloud-Init über extra_config & DataSourceVMware

Terraform + Cloud-Init über extra_config & DataSourceVMware

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:

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:

  1. [Webbrowser[ OVA herunterladen: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
  2. [VC-Benutzeroberfläche] Von OVF bereitstellen, Standardeinstellungen akzeptieren (außer bei der Datenträgerbereitstellung, Thin Provisioning verwenden).
  3. [VC UI] Einstellungen bearbeiten / VM-Optionen / Startoptionen / Startverzögerung = 2000 ms.
  4. [VC UI] VM-Konsole öffnen.
  5. [VM-Konsole] VM einschalten.
  6. [VM-Konsole] Halten Sie die Umschalttaste auf dem BIOS-Bildschirm gedrückt (um GRUB zur Anzeige des Menüs zu zwingen).
  7. [VM-Konsole] Wählen Sie Erweiterte Optionen für Ubuntu.
  8. [VM-Konsole] Wählen Sie die neueste Kernel-Version mit „(Wiederherstellungsmodus)“ am Ende.
  9. [VM-Konsole] Wählen Sie „root / Zur Root-Shell-Eingabeaufforderung wechseln“
  10. [VM-Konsole] Drücken Sie die Eingabetaste für die Wartung
  11. [VM-Konsole] # dpkg-reconfigure cloud-init
  12. [VM-Konsole] Deaktivieren Sie alles außer VMware und Keine
  13. [VM-Konsole] # cloud-init clean
  14. [VM-Konsole] # shutdown -h jetzt
  15. [VC UI] Einstellungen bearbeiten / VM-Optionen / Startoptionen / Startverzögerung = 0 ms.
  16. [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-execProvisioner, 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.yamlund 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.yamlverfügen über eine write_fileAktion, die die aktuellen Datenquellendefinitionen überschreibt und entfernt, OVFda 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 VMwareDatenquelle wie in der neuen Cloud-Init-Konfiguration definiert ein und verarbeitet Ihr „ guest-userdata.yamlund“, metadata.yamlwenn 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 12345am Ende von zu beginnen guest-userdata.yamlund 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/12345was 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 .tfDatei

  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"
  }

verwandte Informationen