Terraform + Cloud-Init(extra_config および DataSourceVMware 経由)

Terraform + Cloud-Init(extra_config および DataSourceVMware 経由)

質問:

terraform + extra_config + Ubuntu クラウド イメージを使用して Cloud Init とインターフェースし、メタデータ/ユーザー データを提供することに成功した人はいますか? これが DataSourceVMware と相互作用することを期待していますが、現段階では確信がありません。

私がやってきたこと:

私は Terraform を使用して VMware vSphere 7 に Ubuntu クラウド イメージをデプロイしています。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 の両方を提供できるようにしたいのですが、現時点では、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"
}

extra_config が送信されたことを証明する vSphere ログ エントリを確認できます。

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 がデフォルトで、新しい VMware データソース (cloud-init 21.3 以降) の前に OVF データソース プロバイダーを呼び出すことです。Terraform は OVF データソース プロバイダーが好むデータを提供しているため、その情報を処理します。これが、vApp プロパティの「user-data」が cloud-config を受け入れる理由です。

解決策は、cloud-init から OVF データソース プロバイダーを削除することです。

  1. [Web ブラウザ[ OVA をダウンロード: https://cloud-images.ubuntu.com/impish/current/impish-server-cloudimg-amd64.ova
  2. [VC UI] OVF からデプロイし、デフォルトを受け入れます (ディスク プロビジョニングを除き、シン プロビジョニングを使用します)。
  3. [VC UI] 設定の編集 / VM オプション / 起動オプション / 起動遅延 = 2000 ミリ秒。
  4. [VC UI] VM コンソールを開きます。
  5. [VM コンソール] VM の電源をオンにします。
  6. [VM コンソール] BIOS 画面で Shift キーを押し続けます (GRUB にメニューを強制的に表示させるため)。
  7. [VM コンソール] Ubuntu の詳細オプションを選択します。
  8. [VM コンソール] 最後に「(リカバリ モード)」が付いた最新のカーネル バージョンを選択します。
  9. [VMコンソール] 「ルート/ルートシェルプロンプトにドロップ」を選択
  10. [VMコンソール] メンテナンスのためにEnterキーを押してください
  11. [VM コンソール] # dpkg-reconfigure cloud-init
  12. [VMコンソール] VMwareとNone以外の選択をすべて解除します
  13. [VM コンソール] # cloud-init clean
  14. [VMコンソール] # シャットダウン -h now
  15. [VC UI] 設定の編集 / VM オプション / 起動オプション / 起動遅延 = 0 ミリ秒。
  16. [VC UI] テンプレートに変換

答え2

Ubuntu クラウド OVA でも同じことを行ってみたところ、ちょっとした回避策が見つかりました。再起動が必要なので理想的とは言えません。つまり、local-execインスタンスが実際に終了したかどうかを検出するにはプロビジョナーが必要ですが、うまくいきます。

ユーザーデータに使用している2つのyamlファイルがあるとします。1つ目はvAppプロパティに渡しvapp-userdata.yaml、2つ目は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_fileOVF

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

最後のコマンドの後に VM が再起動すると、新しい cloud-init 構成で定義されているデータ ソースが読み込まれ、定義済みの場合は処理VMwareされます。guest-userdata.yamlmetadata.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"
  }

関連情報