Featured image of post Your very first VM in Azure… deployed with Ansible, of course!

Your very first VM in Azure… deployed with Ansible, of course!

Ecrit par ~ zwindler ~

Haven’t you already wrote an article about Ansible and VM provisioning?

You might have read already a few articles on Ansible on this blog. I really like Ansible. I already wrote a few articles on this topic, even a few in english, and there are a few playbooks on my Github account if you want to check it out.

[French readers]Au cas où vous l’auriez manqué, la version française de cet article est disponible ici[/French readers]

One of the articles that you like the most, especially my english speaking viewers, is the one about deploying virtual machines on VMware vSphere platform. But now that I have moved on past VMware and started working on cloud providers (mostly the big ones, AWS, GCP and Azure), I felt it was time to share my automation playbooks about that also ;)

As you might have guessed, Ansible and cloud providers teams have been working hard to provide integrations. You can have a look at the BIG list of modules for cloud integrations only!

That’s especially true for Azure and Microsoft teams, which are relatively available and that provide regular updates (this is going to be the topic of another article, #teasing).


Now that I introduced the subject, let’s deploy a VM on Azure. Yay!

Good news is that’s it’s almost the same thing as deploying a VM in vSphere. We have prerequisites, parameters to fill in and pouf, a VM appears.

Bad news is that prerequisites are going to be a little bit more tedious to install/configure, but worry not, I’ll give you all the steps ;)

There are two guides giving us info on how to configure our workstation to start working with Azure:


On a mint/debian/ubuntu, get the necessary python modules :

apt install python-pip ansible
pip install setuptools wheel 
pip install ansible[azure]


To deploy a VM in Azure, you need… an Azure account!

Thanks, captain obvious.

Ok, so assuming you don’t have one, you have to know that you can get a 200$ free credit. To open the account, simply go to this page

The only two issues with this is that this credit expires after 30 days (while AWS of GCP gives 365 days!) and that you need a credit card. I know that having to register a credit card can be a little frightening.

If you read all the informations, they claim that it’s only to avoid bots and that they won’t get money from it. If you consume all you credit or move past the 30 days, the account will be locked. Personnaly it worked great indeed and I didn’t lost a cent, but you shouldn’t believe me and be careful to avoid a bad surprise I case it dooesn’t work as well for you.

Once we have our account, we have to configure our workstation. The easiest way to do this is to use az cli for linux (but then you need to install it). You can also configure the files by hand (following the guides I gave previously).

az login
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code CCHMTROLL to authenticate.

After that, you should have a .azure in your homedir

ll .azure
total 8
drwxrwxrwx 1 zwindler zwindler  512 Aug  4 17:00 ./
drwxr-xr-x 1 zwindler zwindler  512 Aug  4 16:56 ../
-rw------- 1 zwindler zwindler 7124 Aug  4 17:00 accessTokens.json
-rw-rw-rw- 1 zwindler zwindler    5 Aug  4 16:56 az.json
-rw-rw-rw- 1 zwindler zwindler    5 Aug  4 16:56 az.sess
-rw-rw-rw- 1 zwindler zwindler  333 Aug  4 17:00 azureProfile.json
-rw-rw-rw- 1 zwindler zwindler   66 Aug  4 17:00 clouds.config
-rw------- 1 zwindler zwindler   27 Aug  4 16:56 config

Soooo… we deploy this VM or not?

Yeah, now that our workstation is configured, this becomes easy again!

The Azure module to create a VM in a playbook is azure_rm_virtualmachine. Documentation can be found here https://docs.ansible.com/ansible/latest/modules/azure_rm_virtualmachine_module.html#azure-rm-virtualmachine-module

Here’s one of the examples given in the documentation:

- name: Create a VM with managed disk
    resource_group: Testing
    name: testvm001
    vm_size: Standard_D4
    managed_disk_type: Standard_LRS
    admin_username: adminUser
      - path: /home/adminUser/.ssh/authorized_keys
        key_data: < insert your ssh public key here... >
      offer: CoreOS
      publisher: CoreOS
      sku: Stable
      version: latest

Most of the options given here are a strict minimum. There are many many more. I’ll explain a little what’s what:

On azure, there are multiple logic entities to segment resources between each other. Subscription is the highest level of segmentation (mostly used for multitenancy, environment segregation or billing) and resources groups. You can have multiple subscription in a same account, and many resource groups in a single subscription.

The name of the resource we are going to deploy.

Now we enter inside the topic. This is a size of the VM (in terms of vCPUs and GB of RAM) we are going to give our VM. A guide of the available size can be found here => https://docs.microsoft.com/fr-fr/azure/virtual-machines/windows/sizes-general


The type of the virtual disk we are going to create at the same time. Basically, will your disk be on full SSD disk array or not. You won’t find much information on exactly how your data is stored aside from SLAs (availability and performance).

For example, we know that a Premium disk of 128 GB will have a performance threshold of 500 IOPS and 100 MB/s. If you add just one GB (from 129 GB to 256), you’ll get 1100 IOPS and 125 Mo/s. Don’t expect to swindle Azure by have the performance of a 256 GB disk for the price of 128+1 GB, because a the moment you move past 128 GB, you’ll pay for a 256 GB (even if you ask only for 129, and even if you only you 10 GB).

admin_username & ssh_public_keys

Self explainatory.


On Azure, you can access preconfigured images:

If we want a Ubuntu 16.04:

      offer: UbuntuServer 
      publisher: Canonical 
      sku: '16.04.0-LTS'
      version: latest

If we want a CentOS 7.4 :

      offer: CentOS
      publisher: OpenLogic
      sku: '7.4'
      version: latest


Ok, I gave you a little piece of YAML and I explained it to you. That’s nice, but you want more. Can we have more, you ask?

Of course, you can!

In fact, you need more to have a working VM. In Azure, as we are not in our own datacenter where everything has been previously set up from network to hypervisors, we need more objects (resources) than just a VM.

I already told you about it, we first need a resource group, in which we’ll put our VM. But, we also need a virtual network interface that we will attach to the VM. This vNIC will have to have a public IP address if we are going to connect on it. Also, we will need a virtual network for the vNIC, and maybe add some basic firewalling rules.

We could do all this by hand… :(

Or… we could automated it all with an Ansible playbook !!!

- name: "Create Azure resources"
  connection: local
  hosts: all
    - name: "location"
      prompt: "Choose region to deploy VMs"
      private: no
      default: "westeurope"
    - name: "project_prefix"
      prompt: "Choose a prefix for all the resources"
      private: no
      default: "test"
    - name: "instances_number"
      prompt: "Choose a number of virtual machines to create"
      private: no
      default: 1
    - name: "vm_size"
      prompt: "Choose a size for azure virtual machines"
      private: no
      default: "Standard_B2s"
    - name: "managed_disk_type"
      prompt: "Choose a type for azure virtual disks"
      private: no
      default: "Standard_LRS"
    - name: "admin_username"
      prompt: "Choose an admin username"
      private: no
      default: "zwindler"
    - name: "admin_pub_path"
      prompt: "Where can I find the admin public key ?"
      private: no
      default: "~/.ssh/id_rsa.pub"
    - name: "local_ip"
      prompt: "your local IP address (skip if you don't want to add 22 port to NSG)"
      private: no
      default: "skip"
    - name: "virtualnetwork_cidr"
      prompt: "Give a network CIDR for virtual network (large)"
      private: no
      default: ""
    - name: "subnet_cidr"
      prompt: "Give a subnet of that network"
      private: no
      default: ""
    - resourcegroup_name: "{{project_prefix}}-rg"
    - availabilityset_name: "{{project_prefix}}-avset"
    - virtualnetwork_name: "{{project_prefix}}-vnet"
    - subnet_name: "{{project_prefix}}-subnet"
    - securitygroup_name: "{{project_prefix}}-nsg"
    - vm_root_name: "{{project_prefix}}-vm"
    - public_ip_name: "{{project_prefix}}-ip"
    - nic_root_name: "{{project_prefix}}-nic"
    - name: "Create {{project_prefix}}-rg Resource Group"
        name: "{{resourcegroup_name}}"
        location: "{{location}}"

    - name: "Create {{availabilityset_name}} Availability Set"
        name: "{{availabilityset_name}}"
        location: "{{location}}"
        resource_group: "{{resourcegroup_name}}"
        sku: Aligned

    - name: "Create {{virtualnetwork_name}} Virtual Network"
        name: "{{virtualnetwork_name}}"
        resource_group: "{{resourcegroup_name}}"
          - "{{virtualnetwork_cidr}}"

    - name: "create {{subnet_name}} Subnet in {{virtualnetwork_name}} for VMs"
        name: "{{subnet_name}}"
        virtual_network_name: "{{virtualnetwork_name}}"
        resource_group: "{{resourcegroup_name}}"
        address_prefix_cidr: "{{subnet_cidr}}"
      register: subnet

    - name: "Create {{securitygroup_name}} security rules (if local IP address was given)"
        name: "{{securitygroup_name}}"
        resource_group: "{{resourcegroup_name}}"
        purge_rules: yes
          - name: 'AllowSSHFromYourOwnInternetIP'
            protocol: 'Tcp'
            source_address_prefix: "{{local_ip}}"
            destination_port_range: 22
            access: Allow
            priority: 1000
            direction: Inbound
      when: local_ip | ipaddr

    - name: "Create a {{nic_root_name}}X network interface for each VM"
        name: "{{nic_root_name}}{{item}}"
        resource_group: "{{resourcegroup_name}}"
        virtual_network: "{{virtualnetwork_name}}"
        subnet_name: "{{subnet_name}}"
        security_group: "{{securitygroup_name}}"
          - name: "ipconfig"
            public_ip_address_name: "{{public_ip_name}}"
            primary: True
      with_sequence: count="{{instances_number}}"

    - name: "Create {{vm_root_name}}X VM with existing NIC"
        resource_group: "{{resourcegroup_name}}"
        name: "{{vm_root_name}}{{item}}"
        vm_size: "{{vm_size}}"
        managed_disk_type: "{{managed_disk_type}}"
        admin_username: "{{admin_username}}"
        availability_set: "{{availabilityset_name}}"
        ssh_password_enabled: false
          - path: "/home/{{admin_username}}/.ssh/authorized_keys"
            key_data: "{{lookup('file', '{{admin_pub_path}}') }}"
        network_interface_names: "{{nic_root_name}}{{item}}"
          offer: UbuntuServer
          publisher: Canonical
          sku: '16.04.0-LTS'
          version: latest
      with_sequence: count="{{instances_number}}"

For those of you that want to be spare the copy paste, this playbook can also be found on this Github repository

You only have to run it:

pip install --user netaddr
echo localhost > hosts
ansible-playbook -i hosts azure-deploy.yml
TASK [Create test-vmX VM with existing NIC] *****************************************
changed: [localhost] => (item=1)

PLAY RECAP **************************************************************************
localhost                  : ok=1    changed=7    unreachable=0    failed=0

Final words

Where are we now?

Now, we have a playbook, deploying VMs on Azure, but not only!

These machines are preinstalled with a Linux OS, preconfigured with your own SSH key and user. Only your local IP address can access it through SSH, all the VMs are in a single private virtual network; All the VMs are spread evenly accross Azure hypervisors to avoid SPOF by adding the VMs in an AVSET (availability set).

All of this could have been done by someone else by hand, with a little time. But not you. You, you used this playbook to do it all with only one command ;)

Aren’t you badass?

Généré avec Hugo
Thème Stack conçu par Jimmy