Terraform で Azure 仮想マシンのカスタムスクリプトを書く


はじめに

Azure には、Linux 等の仮想マシンを構築する際に特権ユーザーで初期スクリプト(カスタムスクリプト)を実行する仕組みがあります。
Terraform では azurerm_virtual_machine_extension でカスタムスクリプトを設定できます。
azurerm_virtual_machine_extension の書き方に難儀したので、記録しておきます。

Linux の場合

azurerm_virtual_machine_extension で module があるディレクトリの直下に作成した .sh のプレースホルダーを変換しながらに読み込みます。

main.tf
resource "azurerm_virtual_machine_extension" "custom" {
    name                 = "CustomScript"
    virtual_machine_id   = azurerm_linux_virtual_machine.vm.id
    publisher            = "Microsoft.Azure.Extensions"
    type                 = "CustomScript"
    type_handler_version = "2.0"

    settings = <<-SETTINGS
        {"script": "${base64encode(templatefile("${path.module}/customscript.sh", {
            data_disk_lun_01 = azurerm_virtual_machine_data_disk_attachment.vmdda01.lun
            data_disk_lun_02 = azurerm_virtual_machine_data_disk_attachment.vmdda02.lun
        }))}"}
    SETTINGS
}

.sh ではプレースホルダーを ${変数名} の形式で書きます。なお、.sh 内の変数は、${変数名} を使うとプレースホルダーと勘違いされてエラーになるため、$変数名 で参照します。

${path.module}/customscript.sh
DIR_DATADRIVE=/datadrive01
DISKNAME=/dev/$(dmesg | grep SCSI | grep 3:0:0:${data_disk_lun_01} | sed s/^.*\\[//g | sed s/\\].*//g)
sudo mkfs.ext4 $DISKNAME
partprobe $DISKNAME
sudo mkdir $DIR_DATADRIVE
sudo mount $DISKNAME $DIR_DATADRIVE

Windows の場合

Windows の場合、PowerShell でカスタムスクリプトを書きます。Windows には、スクリプトをそのまま渡すのではなく、実行コマンドを渡します。実行コマンドがやや複雑なので、プレースホルダーの変換は template_file に外出ししています。

main.tf
data "template_file" "customscript" {
    template = file("${path.module}/customscript.ps1")
    vars = {
        proxy_server = var.vm_setting.proxy.server
        proxy_port   = var.vm_setting.proxy.port
    }
}

resource "azurerm_virtual_machine_extension" "custom" {
    virtual_machine_id   = azurerm_windows_virtual_machine.vm.id
    name                 = "CustomScript"
    publisher            = "Microsoft.Compute"
    type                 = "CustomScriptExtension"
    type_handler_version = "1.10"

    protected_settings = <<SETTINGS
        {
            "commandToExecute": "powershell -command \"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${base64encode(data.template_file.customscript.rendered)}')) | Out-File -filepath customscript.ps1\" && powershell -ExecutionPolicy Unrestricted -File customscript.ps1"
        }
    SETTINGS
}