Tutorial: Create a VM or virtual machine scale set from the Azure Shared Image Gallery using Ansible
Important
Ansible 2.9 (or later) is required to run the sample playbooks in this article.
Shared Image Gallery is a service that allows you to manage, share, and organize custom-managed images easily. This feature is beneficial for scenarios where many images are maintained and shared. Custom images can be shared across subscriptions and between Microsoft Entra tenants. Images can also be replicated to multiple regions for quicker deployment scaling.
In this article, you learn how to:
- Create a generalized VM and custom image
- Create a Shared Image Gallery
- Create a shared image and image version
- Create a VM using the generalized image
- Create a virtual machine scale set using the generalized image
- Get information about your Shared Image Gallery, image and version.
Prerequisites
- Azure subscription: If you don't have an Azure subscription, create a free account before you begin.
Install Ansible: Do one of the following options:
- Install and configure Ansible on a Linux virtual machine
- Configure Azure Cloud Shell and - if you don't have access to a Linux virtual machine - create a virtual machine with Ansible.
Get the sample playbooks
There are two ways to get the complete set of sample playbooks:
- Download the SIG folder and save it to your local machine.
- Create a new file for each section and copy the sample playbook in it.
The vars.yml
file contains the variables used by all sample playbooks for this tutorial. You can edit the file to provide unique names and values.
The first sample playbook 00-prerequisites.yml
creates what's necessary to complete this tutorial:
- A resource group, which is a logical container in which Azure resources are deployed and managed.
- A virtual network; subnet; public IP address and network interface card for the VM.
- A source Virtual Machine, which is used for creating the generalized image.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Create resource group if doesn't exist
azure_rm_resourcegroup:
name: "{{ resource_group }}"
location: "{{ location }}"
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: "{{ resource_group }}"
name: "{{ virtual_network_name }}"
address_prefixes: "10.0.0.0/16"
- name: Add subnet
azure_rm_subnet:
resource_group: "{{ resource_group }}"
name: "{{ subnet_name }}"
address_prefix: "10.0.1.0/24"
virtual_network: "{{ virtual_network_name }}"
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: "{{ resource_group }}"
allocation_method: Static
name: "{{ ip_name }}"
- name: Create virtual network interface cards for VM A and B
azure_rm_networkinterface:
resource_group: "{{ resource_group }}"
name: "{{ network_interface_name }}"
virtual_network: "{{ virtual_network_name }}"
subnet: "{{ subnet_name }}"
- name: Create VM
azure_rm_virtualmachine:
resource_group: "{{ resource_group }}"
name: "{{ source_vm_name }}"
admin_username: testuser
admin_password: "Password1234!"
vm_size: Standard_B1ms
network_interfaces: "{{ network_interface_name }}"
image:
offer: UbuntuServer
publisher: Canonical
sku: 16.04-LTS
version: latest
Run the playbook using ansible-playbook
ansible-playbook 00-prerequisites.yml
In the Azure portal, check the resource group you specified in vars.yml
to see the new virtual machine and various resources you created.
Generalize the VM and create a custom image
The next playbook, 01a-create-generalized-image.yml
, generalizes the source VM created in previous step and then create a custom image based on it.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Generalize VM
azure_rm_virtualmachine:
resource_group: "{{ resource_group }}"
name: "{{ source_vm_name }}"
generalized: yes
- name: Create custom image
azure_rm_image:
resource_group: "{{ resource_group }}"
name: "{{ image_name }}"
source: "{{ source_vm_name }}"
Run the playbook using ansible-playbook
ansible-playbook 01a-create-generalized-image.yml
Check your resource group and make sure testimagea
shows up.
Create the Shared Image Gallery
The image gallery is the repository for sharing and managing images. The sample playbook code in 02-create-shared-image-gallery.yml
creates a Shared Image Gallery in your resource group.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Create shared image gallery
azure_rm_gallery:
resource_group: "{{ resource_group }}"
name: "{{ shared_gallery_name }}"
location: "{{ location }}"
description: This is the gallery description.
Run the playbook using ansible-playbook
ansible-playbook 02-create-shared-image-gallery.yml
You now see a new gallery, myGallery
, in your resource group.
Create a shared image and image version
The next playbook, 03a-create-shared-image-generalized.yml
creates an image definition and an image version.
Image definitions include the image type (Windows or Linux), release notes, and minimum and maximum memory requirements. Image version is the version of the image. Gallery, image definition, and image version help you organize images in logical groups.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Create shared image
azure_rm_galleryimage:
resource_group: "{{ resource_group }}"
gallery_name: "{{ shared_gallery_name }}"
name: "{{ shared_image_name }}"
location: "{{ location }}"
os_type: linux
os_state: generalized
identifier:
publisher: myPublisherName
offer: myOfferName
sku: mySkuName
description: Image description
- name: Create or update a simple gallery image version.
azure_rm_galleryimageversion:
resource_group: "{{ resource_group }}"
gallery_name: "{{ shared_gallery_name }}"
gallery_image_name: "{{ shared_image_name }}"
name: "{{ shared_image_version }}"
location: "{{ location }}"
publishing_profile:
end_of_life_date: "2020-10-01t00:00:00+00:00"
exclude_from_latest: yes
replica_count: 3
storage_account_type: Standard_LRS
target_regions:
- name: West US
regional_replica_count: 1
- name: East US
regional_replica_count: 2
storage_account_type: Standard_ZRS
managed_image:
name: "{{ image_name }}"
resource_group: "{{ resource_group }}"
register: output
- debug:
var: output
Run the playbook using ansible-playbook
ansible-playbook 03a-create-shared-image-generalized.yml
Your resource group now have an image definition and an image version for your gallery.
Create a VM based on the generalized image
Finally, run 04a-create-vm-using-generalized-image.yml
to create a VM based on the generalized image you created in previous step.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Create VM using shared image
azure_rm_virtualmachine:
resource_group: "{{ resource_group }}"
name: "{{ vm_name }}"
vm_size: Standard_DS1_v2
admin_username: adminUser
admin_password: PassWord01
managed_disk_type: Standard_LRS
image:
id: "/subscriptions/{{ lookup('env', 'AZURE_SUBSCRIPTION_ID') }}/resourceGroups/{{ resource_group }}/providers/Microsoft.Compute/galleries/{{ shared_gallery_name }}/images/{{ shared_image_name }}/versions/{{ shared_image_version }}"
Run the playbook using ansible-playbook
ansible-playbook 04a-create-vm-using-generalized-image.yml
Create a virtual machine scale sets based on the generalized image
You can also create a virtual machine scale set based on the generalized image. Run 05a-create-vmss-using-generalized-image.yml
to do so.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Create a virtual machine scale set using a shared image
azure_rm_virtualmachinescaleset:
resource_group: "{{ resource_group }}"
name: "{{ vmss_name }}"
vm_size: Standard_DS1_v2
admin_username: adminUser
admin_password: PassWord01
capacity: 2
virtual_network_name: "{{ virtual_network_name }}"
upgrade_policy: Manual
subnet_name: "{{ subnet_name }}"
managed_disk_type: Standard_LRS
image:
id: "/subscriptions/{{ lookup('env', 'AZURE_SUBSCRIPTION_ID') }}/resourceGroups/{{ resource_group }}/providers/Microsoft.Compute/galleries/{{ shared_gallery_name }}/images/{{ shared_image_name }}/versions/{{ shared_image_version }}"
Run the playbook using ansible-playbook
ansible-playbook 05a-create-vmss-using-generalized-image.yml
Get information about the gallery
You can get information about the gallery, image definition, and version by running 06-get-info.yml
.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Get Shared Image Gallery information
azure_rm_gallery_info:
resource_group: "{{ resource_group }}"
name: "{{ shared_gallery_name }}"
- name: Get shared image information
azure_rm_galleryimage_info:
resource_group: "{{ resource_group }}"
gallery_name: "{{ shared_gallery_name }}"
name: "{{ shared_image_name }}"
- name: Get Shared Image Gallery image version information
azure_rm_galleryimageversion_info:
resource_group: "{{ resource_group }}"
gallery_name: "{{ shared_gallery_name }}"
gallery_image_name: "{{ shared_image_name }}"
name: "{{ shared_image_version }}"
Run the playbook using ansible-playbook
ansible-playbook 06-get-info.yml
Delete the shared image
To delete the gallery resources, refer to sample playbook 07-delete-gallery.yml
. Delete resources in reverse order. Start by deleting the image version. After you delete all of the image versions, you can delete the image definition. After you delete all image definitions, you can delete the gallery.
- hosts: localhost
connection: local
vars_files:
- ./vars.yml
tasks:
- name: Delete gallery image version.
azure_rm_galleryimageversion:
resource_group: "{{ resource_group }}"
gallery_name: "{{ shared_gallery_name }}"
gallery_image_name: "{{ shared_image_name }}"
name: "{{ shared_image_version }}"
state: absent
- name: Delete gallery image
azure_rm_galleryimage:
resource_group: "{{ resource_group }}"
gallery_name: "{{ shared_gallery_name }}"
name: "{{ shared_image_name }}"
state: absent
- name: Delete a simple gallery.
azure_rm_gallery:
resource_group: "{{ resource_group }}"
name: "{{ shared_gallery_name }}"
state: absent
Run the playbook using ansible-playbook
ansible-playbook 07-delete-gallery.yml
Clean up resources
Save the following code as
delete_rg.yml
.--- - hosts: localhost tasks: - name: Deleting resource group - "{{ name }}" azure_rm_resourcegroup: name: "{{ name }}" state: absent register: rg - debug: var: rg
Run the playbook using the ansible-playbook command. Replace the placeholder with the name of the resource group to be deleted. All resources within the resource group will be deleted.
ansible-playbook delete_rg.yml --extra-vars "name=<resource_group>"
Key points:
- Because of the
register
variable anddebug
section of the playbook, the results display when the command finishes.
- Because of the