Terraform + Cloud-Init через extra_config и DataSourceVMware

Terraform + Cloud-Init через extra_config и DataSourceVMware

Вопрос:

Кто-нибудь успешно использовал terraform + extra_config + облачные образы Ubuntu для взаимодействия с Cloud Init, предоставляя метаданные/пользовательские данные? Надеюсь, это будет взаимодействовать с DataSourceVMware, но на данном этапе не уверен.

Чем я занимаюсь:

Я использую Terraform для развертывания облачных образов Ubuntu на VMware vSphere 7. Использовать свойства 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. Но в настоящее время мои тесты с метаданными (см. ниже) оказались неудачными, поскольку имя хоста не задано в виртуальной машине:

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 по умолчанию вызывает поставщика источника данных OVF до нового источника данных VMware (начиная с cloud-init 21.3). Terraform предоставляет данные, которые нравятся поставщику источника данных OVF, и поэтому он обрабатывает эту информацию. Это объясняет, почему vApp Properties "user-data" принимает cloud-config.

Решение — удалить поставщик источника данных OVF из cloud-init:

  1. [Веб-браузер[ Загрузить OVA: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
  2. [VC UI] Развертывание из OVF, принятие значений по умолчанию (за исключением выделения ресурсов на диске, использование тонкого выделения ресурсов).
  3. [VC UI] Изменить настройки / Параметры виртуальной машины / Параметры загрузки / Задержка загрузки = 2000 мс.
  4. [VC UI] Откройте консоль виртуальной машины.
  5. [Консоль виртуальной машины] Включите виртуальную машину.
  6. [Консоль виртуальной машины] Удерживайте клавишу Shift на экране BIOS (чтобы заставить GRUB отобразить меню).
  7. [Консоль виртуальной машины] Выберите Дополнительные параметры для Ubuntu.
  8. [Консоль виртуальной машины] Выберите последнюю версию ядра с «(recovery mode)» в конце.
  9. [Консоль виртуальной машины] Выберите «root / Перейти в командную строку root»
  10. [Консоль виртуальной машины] Нажмите Enter для обслуживания
  11. [Консоль виртуальной машины] # dpkg-reconfigure cloud-init
  12. [VM Console] Отмените выбор всего, кроме VMware и None.
  13. [Консоль виртуальной машины] # cloud-init clean
  14. [Консоль виртуальной машины] # shutdown -h now
  15. [VC UI] Изменить настройки / Параметры виртуальной машины / Параметры загрузки / Задержка загрузки = 0 мс.
  16. [VC UI] Преобразовать в шаблон

решение2

Делаю то же самое с OVA-файлами облака Ubuntu, и я нашел небольшой обходной путь. Это не идеально, так как это подразумевает перезагрузку, то есть вам нужен поставщик, 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"
  }

Связанный контент