PowerShell: Cara menggunakan Packer untuk membuat gambar komputer virtual di Azure

Berlaku untuk: ✔️ Mesin virtual Windows

Setiap mesin virtual (VM) di Azure dibuat dari gambar yang menentukan distribusi Windows dan versi OS. Citra dapat mencakup konfigurasi dan aplikasi yang telah dipasang sebelumnya. Azure Marketplace menyediakan banyak gambar pihak pertama dan ketiga untuk lingkungan OS dan aplikasi yang paling umum, atau Anda dapat membuat gambar kustom Anda sendiri yang disesuaikan dengan kebutuhan Anda. Artikel ini menjelaskan cara menggunakan alat open-source Packer untuk menentukan dan menyusun gambar kustom di Azure.

Artikel ini terakhir diuji pada 8/5/2020 menggunakan Packer versi 1.8.1.

Catatan

Azure sekarang memiliki layanan, Azure Image Builder, untuk menentukan dan membuat citra kustom Anda sendiri. Azure Image Builder dibangun di Packer, sehingga Anda bahkan dapat menggunakan skrip provisioner shell Packer yang sudah ada dengannya. Untuk mulai menggunakan Azure Image Builder, lihat Membuat Windows VM dengan Azure Image Builder.

Membuat grup sumber daya Azure

Selama proses pembangunan, Packer membuat sumber daya Azure sementara saat membangun VM sumber. Untuk mengambil VM sumber tersebut untuk digunakan sebagai citra, Anda harus menentukan grup sumber daya. Output dari proses pembangunan Packer disimpan dalam grup sumber daya ini.

Buat grup sumber daya dengan New-AzResourceGroup. Contoh berikut menampilkan cara membuat grup sumber daya bernama myPackerGroup di lokasi eastus:

$rgName = "myPackerGroup"
$location = "East US"
New-AzResourceGroup -Name $rgName -Location $location

Membuat info masuk Azure

Packer mengautentikasi dengan Azure menggunakan perwakilan layanan. Perwakilan layanan Azure adalah identitas keamanan yang dapat Anda gunakan dengan aplikasi, layanan, dan alat automasi seperti Packer. Anda mengontrol dan menentukan izin tentang operasi apa yang dapat dilakukan perwakilan layanan di Azure.

Buat prinsipal layanan dengan New-AzADServicePrincipal. Nilai untuk kebutuhan -DisplayName menjadi unik; ganti dengan nilai Anda sendiri sesuai kebutuhan.

$sp = New-AzADServicePrincipal -DisplayName "PackerPrincipal" -role Contributor -scope /subscriptions/yyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyy
$plainPassword = (New-AzADSpCredential -ObjectId $sp.Id).SecretText

Kemudian keluarkan password dan ID aplikasi.

$plainPassword
$sp.AppId

Untuk mengautentikasi ke Azure, Anda juga perlu mendapatkan penyewa Azure dan ID langganan dengan Get-AzSubscription:

$subName = "mySubscriptionName"
$sub = Get-AzSubscription -SubscriptionName $subName

Menentukan templat Packer

Untuk membuat citra, Anda membuat templat sebagai file JSON. Dalam templat, Anda menentukan penyusun dan provisioner yang melakukan proses pembangunan yang sebenarnya. Packer memiliki builder untuk Azure yang memungkinkan Anda menentukan sumber daya Azure, seperti kredensial utama layanan yang dibuat pada langkah sebelumnya.

Buat file bernama windows.json dan tempelkan konten berikut. Masukkan nilai Anda sendiri untuk hal berikut ini:

Parameter Tempat mendapatkan
client_id Lihat ID prinsipal layanan dengan $sp.AppId
client_secret Lihat kata sandi yang dibuat otomatis dengan $plainPassword
tenant_id Output dari perintah $sub.TenantId
subscription_id Output dari perintah $sub.SubscriptionId
managed_image_resource_group_name Nama grup sumber daya yang Anda buat di langkah pertama
managed_image_name Nama untuk citra disk terkelola yang dibuat
{
  "builders": [{
    "type": "azure-arm",

    "client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
    "client_secret": "ppppppp-pppp-pppp-pppp-ppppppppppp",
    "tenant_id": "zzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
    "subscription_id": "yyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyy",

    "managed_image_resource_group_name": "myPackerGroup",
    "managed_image_name": "myPackerImage",

    "os_type": "Windows",
    "image_publisher": "MicrosoftWindowsServer",
    "image_offer": "WindowsServer",
    "image_sku": "2016-Datacenter",

    "communicator": "winrm",
    "winrm_use_ssl": true,
    "winrm_insecure": true,
    "winrm_timeout": "5m",
    "winrm_username": "packer",

    "azure_tags": {
        "dept": "Engineering",
        "task": "Image deployment"
    },

    "build_resource_group_name": "myPackerGroup",
    "vm_size": "Standard_D2_v2"
  }],
  "provisioners": [{
    "type": "powershell",
    "inline": [
      "Add-WindowsFeature Web-Server",
      "while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
      "while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }",
      "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit",
      "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10  } else { break } }"
    ]
  }]
}

Anda juga dapat membuat file bernama windows.pkr.hcl dan menempelkan konten berikut dengan nilai Anda sendiri seperti yang digunakan untuk tabel parameter di atas.

source "azure-arm" "autogenerated_1" {
  azure_tags = {
    dept = "Engineering"
    task = "Image deployment"
  }
  build_resource_group_name         = "myPackerGroup"
  client_id                         = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
  client_secret                     = "ppppppp-pppp-pppp-pppp-ppppppppppp"
  communicator                      = "winrm"
  image_offer                       = "WindowsServer"
  image_publisher                   = "MicrosoftWindowsServer"
  image_sku                         = "2016-Datacenter"
  managed_image_name                = "myPackerImage"
  managed_image_resource_group_name = "myPackerGroup"
  os_type                           = "Windows"
  subscription_id                   = "yyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyy"
  tenant_id                         = "zzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz"
  vm_size                           = "Standard_D2_v2"
  winrm_insecure                    = true
  winrm_timeout                     = "5m"
  winrm_use_ssl                     = true
  winrm_username                    = "packer"
}

build {
  sources = ["source.azure-arm.autogenerated_1"]

  provisioner "powershell" {
    inline = ["Add-WindowsFeature Web-Server", "while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", "while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit", "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10  } else { break } }"]
  }

}

Templat ini membangun VM Windows Server 2016, menginstal IIS, kemudian menggeneralisasi VM dengan Sysprep. Penginstalan IIS memperlihatkan bagaimana Anda bisa menggunakan penyedia PowerShell untuk menjalankan perintah tambahan. Gambar Packer akhir kemudian menyertakan penginstalan dan konfigurasi perangkat lunak yang diperlukan.

Agen Tamu Windows berpartisipasi dalam proses Sysprep. Agen harus sepenuhnya diinstal sebelum VM dapat diproses sysprep. Untuk memastikan bahwa ini benar, semua layanan agen harus berjalan sebelum Anda menjalankan sysprep.exe. Cuplikan JSON sebelumnya menunjukkan salah satu cara untuk melakukan ini di penyedia PowerShell. Cuplikan ini diperlukan hanya jika VM dikonfigurasi untuk menginstal agen, yang merupakan default.

Membangun citra Packer

Jika Anda belum memasang Packer di komputer lokal Anda, ikuti instruksi penginstalan Packer.

Buat gambar dengan membuka perintah cmd dan tentukan file template Packer Anda sebagai berikut:

packer build windows.json

Anda juga dapat membuat gambar dengan menentukan file windows.pkr.hcl sebagai berikut:

packer build windows.pkr.hcl

Contoh output dari perintah sebelumnya adalah sebagai berikut:

azure-arm output will be in this color.

==> azure-arm: Running builder ...
    azure-arm: Creating Azure Resource Manager (ARM) client ...
==> azure-arm: Creating resource group ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> Location          : ‘East US’
==> azure-arm:  -> Tags              :
==> azure-arm:  ->> task : Image deployment
==> azure-arm:  ->> dept : Engineering
==> azure-arm: Validating deployment template ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> DeploymentName    : ‘pkrdppq0mthtbtt’
==> azure-arm: Deploying deployment template ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> DeploymentName    : ‘pkrdppq0mthtbtt’
==> azure-arm: Getting the certificate’s URL ...
==> azure-arm:  -> Key Vault Name        : ‘pkrkvpq0mthtbtt’
==> azure-arm:  -> Key Vault Secret Name : ‘packerKeyVaultSecret’
==> azure-arm:  -> Certificate URL       : ‘https://pkrkvpq0mthtbtt.vault.azure.net/secrets/packerKeyVaultSecret/8c7bd823e4fa44e1abb747636128adbb'
==> azure-arm: Setting the certificate’s URL ...
==> azure-arm: Validating deployment template ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> DeploymentName    : ‘pkrdppq0mthtbtt’
==> azure-arm: Deploying deployment template ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> DeploymentName    : ‘pkrdppq0mthtbtt’
==> azure-arm: Getting the VM’s IP address ...
==> azure-arm:  -> ResourceGroupName   : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> PublicIPAddressName : ‘packerPublicIP’
==> azure-arm:  -> NicName             : ‘packerNic’
==> azure-arm:  -> Network Connection  : ‘PublicEndpoint’
==> azure-arm:  -> IP Address          : ‘40.76.55.35’
==> azure-arm: Waiting for WinRM to become available...
==> azure-arm: Connected to WinRM!
==> azure-arm: Provisioning with Powershell...
==> azure-arm: Provisioning with shell script: /var/folders/h1/ymh5bdx15wgdn5hvgj1wc0zh0000gn/T/packer-powershell-provisioner902510110
    azure-arm: #< CLIXML
    azure-arm:
    azure-arm: Success Restart Needed Exit Code      Feature Result
    azure-arm: ------- -------------- ---------      --------------
    azure-arm: True    No             Success        {Common HTTP Features, Default Document, D...
    azure-arm: <Objs Version=“1.1.0.1” xmlns=“http://schemas.microsoft.com/powershell/2004/04"><Obj S=“progress” RefId=“0"><TN RefId=“0”><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N=“SourceId”>1</I64><PR N=“Record”><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
==> azure-arm: Querying the machine’s properties ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> ComputeName       : ‘pkrvmpq0mthtbtt’
==> azure-arm:  -> Managed OS Disk   : ‘/subscriptions/guid/resourceGroups/packer-Resource-Group-pq0mthtbtt/providers/Microsoft.Compute/disks/osdisk’
==> azure-arm: Powering off machine ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> ComputeName       : ‘pkrvmpq0mthtbtt’
==> azure-arm: Capturing image ...
==> azure-arm:  -> Compute ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm:  -> Compute Name              : ‘pkrvmpq0mthtbtt’
==> azure-arm:  -> Compute Location          : ‘East US’
==> azure-arm:  -> Image ResourceGroupName   : ‘myResourceGroup’
==> azure-arm:  -> Image Name                : ‘myPackerImage’
==> azure-arm:  -> Image Location            : ‘eastus’
==> azure-arm: Deleting resource group ...
==> azure-arm:  -> ResourceGroupName : ‘packer-Resource-Group-pq0mthtbtt’
==> azure-arm: Deleting the temporary OS disk ...
==> azure-arm:  -> OS Disk : skipping, managed disk was used...
Build ‘azure-arm’ finished.

==> Builds finished. The artifacts of successful builds are:
--> azure-arm: Azure.ResourceManagement.VMImage:

ManagedImageResourceGroupName: myResourceGroup
ManagedImageName: myPackerImage
ManagedImageLocation: eastus

Dibutuhkan beberapa menit bagi Packer untuk membangun VM, menjalankan provisioner, dan membersihkan penyebaran.

Membuat VM dari gambar Packer

Anda sekarang dapat membuat VM dari Gambar Anda dengan New-AzVM. Sumber daya jaringan pendukung akan dibuat jika belum tersedia. Ketika diminta, masukkan nama pengguna dan kata sandi administratif yang akan dibuat pada VM. Berikut contoh membuat komputer virtual dengan bernama myVm dari myPackerImage:

New-AzVm `
    -ResourceGroupName $rgName `
    -Name "myVM" `
    -Location $location `
    -VirtualNetworkName "myVnet" `
    -SubnetName "mySubnet" `
    -SecurityGroupName "myNetworkSecurityGroup" `
    -PublicIpAddressName "myPublicIpAddress" `
    -OpenPorts 80 `
    -Image "myPackerImage"

Jika Anda ingin membuat VM di grup atau wilayah sumber daya yang berbeda dari citra Packer Anda, tentukan ID citra alih-alih nama citra. Anda dapat memperoleh ID gambar dengan Get-AzImage.

Dibutuhkan beberapa menit untuk membuat VM dari gambar Packer Anda.

Menguji VM dan webserver

Dapatkan alamat IP publik VM Anda dengan Get-AzPublicIPAddress. Contoh berikut memperoleh alamat IP untuk myPublicIP yang dibuat sebelumnya:

Get-AzPublicIPAddress `
    -ResourceGroupName $rgName `
    -Name "myPublicIPAddress" | select "IpAddress"

Untuk melihat VM Anda, yang menyertakan instalasi IIS dari penyedia Packer, dalam tindakan, masukkan alamat IP publik ke browser web.

Situs default IIS

Langkah berikutnya

Anda juga dapat menggunakan skrip provisioner Packer yang ada dengan Azure Image Builder.