Pergunta:
Alguém usou com sucesso imagens de nuvem terraform + extra_config + Ubuntu para fazer interface com Cloud Init, fornecendo metadados/dados de usuário? Espero que isso interaja com o DataSourceVMware, mas não posso ter certeza neste estágio.
O que tenho feito:
Estou usando o Terraform para implantar imagens de nuvem Ubuntu no VMware vSphere 7. Tem sido fácil usar as propriedades do 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"))
}
}
Mas qualquer tentativa de usar extra_config falhou. Eu gostaria de poder fornecer guestinfo.metadata e guestinfo.userdata. Mas atualmente, meus testes com metadados (vistos abaixo) parecem falhar porque o nome do host não está definido na 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"
}
Posso ver a entrada de log do vSphere para provar que o extra_config foi enviado:
config.extraConfig("guestinfo.metadata"): (key = "guestinfo.metadata", value = "H4sIAAAAAAAA/2SOTUvGMBCE74H8h/De11dPQsSDHz14qIK ... snipped
Referências:
- 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
Detalhes da versão:
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
Responder1
O problema é que o cloud-init tem, por padrão, o provedor de fonte de dados OVF invocado antes da nova fonte de dados VMware (a partir do cloud-init 21.3). O Terraform fornece dados que o provedor de fonte de dados OVF gosta e, portanto, processa as informações. Isso explica por que os "dados do usuário" das propriedades do vApp aceitam a configuração da nuvem.
A solução é remover o provedor de fonte de dados OVF do cloud-init:
- [Navegador da Web[Baixar OVA: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
- [VC UI] Implante a partir do OVF, aceite padrões (exceto provisionamento de disco, use Thin Provisioning).
- [VC UI] Editar configurações / Opções de VM / Opções de inicialização / Atraso de inicialização = 2.000 ms.
- [VC UI] Abra o console da VM.
- [Console VM] Ligue a VM.
- [VM Console] Segure Shift na tela do BIOS (para forçar o GRUB a exibir o menu).
- [Console VM] Selecione Opções Avançadas para Ubuntu.
- [VM Console] Selecione a versão mais recente do kernel com "(modo de recuperação)" no final.
- [Console VM] Selecione "root / Drop to root shell prompt"
- [VM Console] Pressione Enter para manutenção
- [Console VM] # dpkg-reconfigure cloud-init
- [VM Console] Desmarque tudo, exceto VMware e Nenhum
- [Console VM] # limpeza de inicialização na nuvem
- [Console VM] # shutdown -h agora
- [VC UI] Editar configurações / Opções de VM / Opções de inicialização / Atraso de inicialização = 0 ms.
- [VC UI] Converter em modelo
Responder2
Fazendo o mesmo com os OVAs da nuvem do Ubuntu e encontrei uma pequena solução alternativa para isso. Não é o ideal, pois envolve uma reinicialização, o que significa que você precisa de um local-exec
provisionador para detectar quando a instância realmente foi concluída, mas funciona.
Digamos que você tenha dois arquivos yaml que está usando para userdata - o primeiro que você está passando com as propriedades do vApp nomeadas vapp-userdata.yaml
e o segundo que você está passando para a fonte de dados VMware chamadaguest-userdata.yaml
Algo assim no 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"
}
Você vapp-userdata.yaml
tem uma write_file
ação que substitui as definições atuais da fonte de dados e as remove OVF
quando você já atingiu esse ponto.
write_files:
- path: /etc/cloud/cloud.cfg.d/90_dpkg.cfg
owner: root:root
permissions: "0644"
content: |
datasource_list: [ VMware, None ]
Então, na parte inferior, termine com uma reinicialização
power_state:
timeout: 600
mode: reboot
Quando a VM for reinicializada após o último comando, ela lerá a VMware
fonte de dados conforme definido na nova configuração do cloud-init e processará sua guest-userdata.yaml
e metadata.yaml
se você também tiver definido isso.
Quanto a detectar quando terminar, ainda estou tentando descobrir a melhor maneira de fazer isso. A maneira mais fácil é começar nc -l 12345
no final guest-userdata.yaml
e ter um provisionador local que prossiga quando puder se conectar a tcp/12345
, mas isso deixa você com um ouvinte netcat aberto, tcp/12345
o que não é o ideal.
Se você encontrar uma maneira melhor, responda :)
Editar
Com certeza haverá uma maneira melhor de fazer isso, mas ...
No fundo doguest-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
Então, como provisionador no final do seu .tf
arquivo
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"
}