Come usare Packer per creare immagini di macchine virtuali di Windows in AzureHow to use Packer to create Windows virtual machine images in Azure

Ogni macchina virtuale (VM, Virtual Machine) in Azure viene creata a partire da un'immagine che ne definisce la distribuzione di Windows e la versione del sistema operativo.Each virtual machine (VM) in Azure is created from an image that defines the Windows distribution and OS version. Le immagini possono includere applicazioni e configurazioni preinstallate.Images can include pre-installed applications and configurations. In Microsoft Azure Marketplace sono disponibili molte prime immagini e immagini di terze parti per i sistemi operativi e gli ambienti applicativi più diffusi. In alternativa, è possibile creare immagini personalizzate su misura per le proprie esigenze.The Azure Marketplace provides many first and third-party images for most common OS' and application environments, or you can create your own custom images tailored to your needs. Questo articolo illustra in dettaglio come definire e compilare immagini personalizzate in Azure tramite lo strumento open source Packer.This article details how to use the open source tool Packer to define and build custom images in Azure.

Creare un gruppo di risorse di AzureCreate Azure resource group

Durante il processo di compilazione della macchina virtuale di origine Packer crea risorse di Azure temporanee.During the build process, Packer creates temporary Azure resources as it builds the source VM. Per acquisire la macchina virtuale di origine per usarla come immagine, è necessario definire un gruppo di risorse,To capture that source VM for use as an image, you must define a resource group. nel quale verrà archiviato l'output del processo di compilazione di Packer.The output from the Packer build process is stored in this resource group.

Creare un gruppo di risorse con New-AzureRmResourceGroup.Create a resource group with New-AzureRmResourceGroup. L'esempio seguente crea un gruppo di risorse denominato myResourceGroup nella posizione eastus:The following example creates a resource group named myResourceGroup in the eastus location:

$rgName = "myResourceGroup"
$location = "East US"
New-AzureRmResourceGroup -Name $rgName -Location $location

Creare credenziali di AzureCreate Azure credentials

Per eseguire l'autenticazione con Azure, Packer usa un'entità servizio.Packer authenticates with Azure using a service principal. Un'entità servizio di Azure è un'identità di sicurezza che è possibile usare con le app, con i servizi e con strumenti di automazione come Packer.An Azure service principal is a security identity that you can use with apps, services, and automation tools like Packer. Le autorizzazioni per le operazioni che l'entità servizio può eseguire in Azure vengono controllate e definite dall'utente.You control and define the permissions as to what operations the service principal can perform in Azure.

Creare un'entità servizio con New-AzureRmADServicePrincipal e assegnare le autorizzazioni per consentire all'entità servizio di creare e gestire risorse con New-AzureRmRoleAssignment:Create a service principal with New-AzureRmADServicePrincipal and assign permissions for the service principal to create and manage resources with New-AzureRmRoleAssignment:

$sp = New-AzureRmADServicePrincipal -DisplayName "Azure Packer IKF" -Password "P@ssw0rd!"
Sleep 20
New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $sp.ApplicationId

Per eseguire l'autenticazione in Azure è anche necessario ottenere l'ID del tenant e l'ID della sottoscrizione di Azure con Get-AzureRmSubscription:To authenticate to Azure, you also need to obtain your Azure tenant and subscription IDs with Get-AzureRmSubscription:

$sub = Get-AzureRmSubscription
$sub.TenantId
$sub.SubscriptionId

Questi due ID verranno usati nel passaggio successivo.You use these two IDs in the next step.

Definire un modello di PackerDefine Packer template

Per compilare immagini, è necessario creare un modello come file JSON.To build images, you create a template as a JSON file. Nel modello si definiscono i compilatori e gli strumenti di provisioning che eseguono il processo di compilazione effettivo.In the template, you define builders and provisioners that carry out the actual build process. Packer è dotato di uno strumento di provisioning per Azure che consente di definire risorse di Azure, ad esempio le credenziali delle entità servizio create nel passaggio precedente.Packer has a provisioner for Azure that allows you to define Azure resources, such as the service principal credentials created in the preceding step.

Creare un file con nome windows.json e incollare al suo interno il contenuto seguente.Create a file named windows.json and paste the following content. Immettere valori personalizzati per i parametri seguenti:Enter your own values for the following:

ParametroParameter OrigineWhere to obtain
client_idclient_id ID entità servizio di visualizzazione con $sp.applicationIdView service principal ID with $sp.applicationId
client_secretclient_secret Password specificata in$securePasswordPassword you specified in $securePassword
tenant_idtenant_id Output del comando $sub.TenantIdOutput from $sub.TenantId command
subscription_idsubscription_id Output del comando $sub.SubscriptionIdOutput from $sub.SubscriptionId command
object_idobject_id ID oggetto entità servizio di visualizzazione con $sp.IdView service principal object ID with $sp.Id
managed_image_resource_group_namemanaged_image_resource_group_name Nome del gruppo di risorse creato nel primo passaggioName of resource group you created in the first step
managed_image_namemanaged_image_name Nome per l'immagine del disco gestito che viene creataName for the managed disk image that is created
{
  "builders": [{
    "type": "azure-arm",

    "client_id": "0831b578-8ab6-40b9-a581-9a880a94aab1",
    "client_secret": "P@ssw0rd!",
    "tenant_id": "72f988bf-86f1-41af-91ab-2d7cd011db47",
    "subscription_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx",
    "object_id": "a7dfb070-0d5b-47ac-b9a5-cf214fff0ae2",

    "managed_image_resource_group_name": "myResourceGroup",
    "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": "3m",
    "winrm_username": "packer",

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

    "location": "East US",
    "vm_size": "Standard_DS2_v2"
  }],
  "provisioners": [{
    "type": "powershell",
    "inline": [
      "Add-WindowsFeature Web-Server",
      "if( Test-Path $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml ){ rm $Env:SystemRoot\\windows\\system32\\Sysprep\\unattend.xml -Force}",
      "& $Env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /shutdown /quiet"
    ]
  }]
}

Questo modello compila una macchina virtuale di Windows Server 2016, installa IIS e quindi generalizza la macchina virtuale con Sysprep.This template builds a Windows Server 2016 VM, installs IIS, then generalizes the VM with Sysprep.

Compilare l'immagine in PackerBuild Packer image

Se Packer non è installato nel computer locale, seguire le istruzioni di installazione di Packer.If you don't already have Packer installed on your local machine, follow the Packer installation instructions.

Compilare l'immagine specificando il file del modello di Packer come segue:Build the image by specifying your Packer template file as follows:

./packer build windows.json

Ecco un esempio di output dei comandi precedenti:An example of the output from the preceding commands is as follows:

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

Packer impiega alcuni minuti per compilare la macchina virtuale, eseguire gli strumenti di provisioning e pulire la distribuzione.It takes a few minutes for Packer to build the VM, run the provisioners, and clean up the deployment.

Creare una macchina virtuale da un'immagine di AzureCreate VM from Azure Image

Impostare nome utente e password dell'amministratore delle macchine virtuali con il comando Get-Credential.Set an administrator username and password for the VMs with Get-Credential.

$cred = Get-Credential

È ora possibile creare una macchina virtuale dall'immagine con New-AzureRmVM.You can now create a VM from your Image with New-AzureRmVM. L'esempio seguente crea una macchina virtuale denominata myVM da myPackerImage.The following example creates a VM named myVM from myPackerImage.

# Create a subnet configuration
$subnetConfig = New-AzureRmVirtualNetworkSubnetConfig `
    -Name mySubnet `
    -AddressPrefix 192.168.1.0/24

# Create a virtual network
$vnet = New-AzureRmVirtualNetwork `
    -ResourceGroupName $rgName `
    -Location $location `
    -Name myVnet `
    -AddressPrefix 192.168.0.0/16 `
    -Subnet $subnetConfig

# Create a public IP address and specify a DNS name
$publicIP = New-AzureRmPublicIpAddress `
    -ResourceGroupName $rgName `
    -Location $location `
    -AllocationMethod "Static" `
    -IdleTimeoutInMinutes 4 `
    -Name "myPublicIP"

# Create an inbound network security group rule for port 80
$nsgRuleWeb = New-AzureRmNetworkSecurityRuleConfig `
    -Name myNetworkSecurityGroupRuleWWW  `
    -Protocol Tcp `
    -Direction Inbound `
    -Priority 1001 `
    -SourceAddressPrefix * `
    -SourcePortRange * `
    -DestinationAddressPrefix * `
    -DestinationPortRange 80 `
    -Access Allow

# Create a network security group
$nsg = New-AzureRmNetworkSecurityGroup `
    -ResourceGroupName $rgName `
    -Location $location `
    -Name myNetworkSecurityGroup `
    -SecurityRules $nsgRuleWeb

# Create a virtual network card and associate with public IP address and NSG
$nic = New-AzureRmNetworkInterface `
    -Name myNic `
    -ResourceGroupName $rgName `
    -Location $location `
    -SubnetId $vnet.Subnets[0].Id `
    -PublicIpAddressId $publicIP.Id `
    -NetworkSecurityGroupId $nsg.Id

# Define the image created by Packer
$image = Get-AzureRMImage -ImageName myPackerImage -ResourceGroupName $rgName

# Create a virtual machine configuration
$vmConfig = New-AzureRmVMConfig -VMName myVM -VMSize Standard_DS2 | `
Set-AzureRmVMOperatingSystem -Windows -ComputerName myVM -Credential $cred | `
Set-AzureRmVMSourceImage -Id $image.Id | `
Add-AzureRmVMNetworkInterface -Id $nic.Id

New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vmConfig

La creazione della macchina virtuale richiede alcuni minuti.It takes a few minutes to create the VM.

Testare la macchina virtuale e IISTest VM and IIS

Ottenere l'indirizzo IP pubblico della macchina virtuale con il comando Get-AzureRmPublicIPAddress.Obtain the public IP address of your VM with Get-AzureRmPublicIPAddress. L'esempio seguente ottiene l'indirizzo IP per myPublicIP creato in precedenza:The following example obtains the IP address for myPublicIP created earlier:

Get-AzureRmPublicIPAddress `
    -ResourceGroupName $rgName `
    -Name "myPublicIP" | select "IpAddress"

Sarà quindi possibile immettere l'indirizzo IP pubblico in un Web browser.You can then enter the public IP address in to a web browser.

Sito IIS predefinito

Passaggi successiviNext steps

In questo esempio Packer è stato usato per creare un'immagine di macchina virtuale con IIS già installato.In this example, you used Packer to create a VM image with IIS already installed. È possibile usare questa immagine di macchina virtuale insieme a flussi di lavoro di distribuzione esistenti, ad esempio per distribuire app in macchine virtuali create dall'immagine con Team Services, Ansible, Chef o Puppet.You can use this VM image alongside existing deployment workflows, such as to deploy your app to VMs created from the Image with Team Services, Ansible, Chef, or Puppet.

Per altri modelli di Packer di esempio per distribuzioni di Windows di altro tipo, vedere questo repository di GitHub.For additional example Packer templates for other Windows distros, see this GitHub repo.