Create a Linux image and distribute it to an Azure Compute Gallery

Applies to: ✔️ Linux VMs ✔️ Flexible scale sets

This article shows you how you can use the Azure Image Builder, and the Azure CLI, to create an image version in an Azure Compute Gallery (formerly known as Shared Image Gallery), then distribute the image globally. You can also do this using Azure PowerShell.

We'll be using a sample .json template to configure the image. The .json file we're using is here: helloImageTemplateforSIG.json.

To distribute the image to an Azure Compute Gallery, the template uses sharedImage as the value for the distribute section of the template.

Register the providers

To use Azure Image Builder, you need to register the feature.

Check your registration.

az provider show -n Microsoft.VirtualMachineImages | grep registrationState
az provider show -n Microsoft.KeyVault | grep registrationState
az provider show -n Microsoft.Compute | grep registrationState
az provider show -n Microsoft.Storage | grep registrationState
az provider show -n Microsoft.Network | grep registrationState
az provider show -n Microsoft.ContainerInstance | grep registrationState

If they don't say registered, run the following:

az provider register -n Microsoft.VirtualMachineImages
az provider register -n Microsoft.Compute
az provider register -n Microsoft.KeyVault
az provider register -n Microsoft.Storage
az provider register -n Microsoft.Network
az provider register -n Microsoft.ContainerInstance

Set variables and permissions

We'll be using some pieces of information repeatedly, so we'll create some variables to store that information.

Image Builder only supports creating custom images in the same Resource Group as the source managed image. Update the resource group name in this example to be the same resource group as your source managed image.

# Resource group name - we are using ibLinuxGalleryRG in this example
# Datacenter location - we are using West US 2 in this example
# Additional region to replicate the image to - we are using East US in this example
# name of the Azure Compute Gallery - in this example we are using myGallery
# name of the image definition to be created - in this example we are using myImageDef
# image distribution metadata reference name

Create a variable for your subscription ID.

subscriptionID=$(az account show --query id --output tsv)

Create the resource group.

az group create -n $sigResourceGroup -l $location

Create a user-assigned identity and set permissions on the resource group

Image Builder uses the user-identity provided to inject the image into the Azure Compute Gallery. In this example, you'll create an Azure role definition that has the granular actions to perform distributing the image to the gallery. The role definition will then be assigned to the user-identity.

# create user assigned identity for image builder to access the storage account where the script is located
identityName=aibBuiUserId$(date +'%s')
az identity create -g $sigResourceGroup -n $identityName

# get identity id
imgBuilderCliId=$(az identity show -g $sigResourceGroup -n $identityName --query clientId -o tsv)

# get the user identity URI, needed for the template

# this command will download an Azure role definition template, and update the template with the parameters specified earlier.
curl -o aibRoleImageCreation.json

imageRoleDefName="Azure Image Builder Image Def"$(date +'%s')

# update the definition
sed -i -e "s/<subscriptionID>/$subscriptionID/g" aibRoleImageCreation.json
sed -i -e "s/<rgName>/$sigResourceGroup/g" aibRoleImageCreation.json
sed -i -e "s/Azure Image Builder Service Image Creation Role/$imageRoleDefName/g" aibRoleImageCreation.json

# create role definitions
az role definition create --role-definition ./aibRoleImageCreation.json

# grant role definition to the user assigned identity
az role assignment create \
    --assignee $imgBuilderCliId \
    --role "$imageRoleDefName" \
    --scope /subscriptions/$subscriptionID/resourceGroups/$sigResourceGroup

To use Image Builder with an Azure Compute Gallery, you need to have an existing gallery and image definition. Image Builder won't create the gallery and image definition for you.

If you don't already have a gallery and image definition to use, start by creating them. First, create a gallery.

az sig create \
    -g $sigResourceGroup \
    --gallery-name $sigName

Then, create an image definition.

az sig image-definition create \
   -g $sigResourceGroup \
   --gallery-name $sigName \
   --gallery-image-definition $imageDefName \
   --publisher myIbPublisher \
   --offer myOffer \
   --sku 18.04-LTS \
   --os-type Linux

Download and configure the .json

Download the .json template and configure it with your variables.

curl -o helloImageTemplateforSIG.json
sed -i -e "s/<subscriptionID>/$subscriptionID/g" helloImageTemplateforSIG.json
sed -i -e "s/<rgName>/$sigResourceGroup/g" helloImageTemplateforSIG.json
sed -i -e "s/<imageDefName>/$imageDefName/g" helloImageTemplateforSIG.json
sed -i -e "s/<sharedImageGalName>/$sigName/g" helloImageTemplateforSIG.json
sed -i -e "s/<region1>/$location/g" helloImageTemplateforSIG.json
sed -i -e "s/<region2>/$additionalregion/g" helloImageTemplateforSIG.json
sed -i -e "s/<runOutputName>/$runOutputName/g" helloImageTemplateforSIG.json
sed -i -e "s%<imgBuilderId>%$imgBuilderId%g" helloImageTemplateforSIG.json

Create the image version

This next part will create the image version in the gallery.

Submit the image configuration to the Azure Image Builder service.

az resource create \
    --resource-group $sigResourceGroup \
    --properties @helloImageTemplateforSIG.json \
    --is-full-object \
    --resource-type Microsoft.VirtualMachineImages/imageTemplates \
    -n helloImageTemplateforSIG01

Start the image build.

az resource invoke-action \
     --resource-group $sigResourceGroup \
     --resource-type  Microsoft.VirtualMachineImages/imageTemplates \
     -n helloImageTemplateforSIG01 \
     --action Run

Creating the image and replicating it to both regions can take a while. Wait until this part is finished before moving on to creating a VM.

Create the VM

Create a VM from the image version that was created by Azure Image Builder.

az vm create \
  --resource-group $sigResourceGroup \
  --name myAibGalleryVM \
  --admin-username aibuser \
  --location $location \
  --image "/subscriptions/$subscriptionID/resourceGroups/$sigResourceGroup/providers/Microsoft.Compute/galleries/$sigName/images/$imageDefName/versions/latest" \

SSH into the VM.

ssh aibuser@<publicIpAddress>

You should see the image was customized with a Message of the Day as soon as your SSH connection is established!

**            This VM was built from the:            **
**      !! AZURE VM IMAGE BUILDER Custom Image !!    **
**         You have just been Customized :-)         **

Clean up resources

If you want to now try recustomizing the image version to create a new version of the same image, skip the next steps and go on to Use Azure Image Builder to create another image version.

This deletes the image that was created, along with all of the other resource files. Make sure you're finished with this deployment before deleting the resources.

When deleting gallery resources, you need delete all of the image versions before you can delete the image definition used to create them. To delete a gallery, you first need to have deleted all of the image definitions in the gallery.

Delete the image builder template.

az resource delete \
    --resource-group $sigResourceGroup \
    --resource-type Microsoft.VirtualMachineImages/imageTemplates \
    -n helloImageTemplateforSIG01

Delete permissions assignments, roles and identity

az role assignment delete \
    --assignee $imgBuilderCliId \
    --role "$imageRoleDefName" \
    --scope /subscriptions/$subscriptionID/resourceGroups/$sigResourceGroup

az role definition delete --name "$imageRoleDefName"

az identity delete --ids $imgBuilderId

Get the image version created by image builder, this always starts with 0., and then delete the image version

sigDefImgVersion=$(az sig image-version list \
   -g $sigResourceGroup \
   --gallery-name $sigName \
   --gallery-image-definition $imageDefName \
   --subscription $subscriptionID --query [].'name' -o json | grep 0. | tr -d '"')
az sig image-version delete \
   -g $sigResourceGroup \
   --gallery-image-version $sigDefImgVersion \
   --gallery-name $sigName \
   --gallery-image-definition $imageDefName \
   --subscription $subscriptionID

Delete the image definition.

az sig image-definition delete \
   -g $sigResourceGroup \
   --gallery-name $sigName \
   --gallery-image-definition $imageDefName \
   --subscription $subscriptionID

Delete the gallery.

az sig delete -r $sigName -g $sigResourceGroup

Delete the resource group.

az group delete -n $sigResourceGroup -y

Next steps

Learn more about Azure Compute Galleries.