Ansible is a configuration management tool used to control and apply configuration changes to infrastructure. However, before you can apply changes to the infrastructure it first has to exist. Ansible has several Azure modules that allow you to deploy resources in Azure. This tutorial will walk you through deploying a Windows virtual machine to Azure using an Ansible playbook. By the end of the tutorial you'll understand how to use several of the Azure Ansible modules to deploy workloads to Azure.
Prerequisites
In order to follow along in this tutorial you'll need the following:
-
Ansible installed
-
ansible[azure]
pip packaged installed
-
- Connection to Azure from Ansible setup
Table Of Contents
Azure Ansible Modules
Creating a virtual machine in Azure requires several different Azure resources; a resource group, virtual network, subnet, public ip address, network security group, network interface card, and the virtual machine itself. Each of these Azure resources can be managed and modified using an Ansible module. These Ansible modules allow you to codify your infrastructure in yaml files in the form of Ansible playbooks. Below is a list of the Ansible modules that are used throughout this tutorial. However, many more Ansible modules exist and can be found in Ansible's module index.
Ansible modules required to deploy an Azure virtual machine
- azure_rm_resourcegroup
- azure_rm_virtualnetwork
- azure_rm_subnet
- azure_rm_publicipaddress
- azure_rm_securitygroup
- azure_rm_networkinterface
- azure_rm_virtualmachine
Playbook Contents
Create a Resource Group
Azure resource groups are used to logically group related resources. Resource groups help organize your cloud environment and can also be used to grant access to specific workloads within the resource group. They are also required when creating other Azure resources. Such as virtual networks. Another benefit of resource groups is easy cleanup. When you delete a resource group everything inside of it is deleted with it.
In order to create an Azure resource group with Ansible use the azure_rm_resourcegroup
module. It requires two parameters; name
and location
. The name parameter will become the name of the resource group and the location is the Azure region the resource group is placed in. Placing a resource group in one region does not mean you can only use that region for other Azure resources inside the resource group. It is simply where the metadata of the resource group is located.
- name: Create resource group
azure_rm_resourcegroup:
name: ansible-rg
location: eastus
Create a Virtual Network
Virtual networks allow you to build out your private network within Azure. Virtual networks are used to connect resources running within an Azure data center. Even though they are virtual and exist out of reach to you. The same networking principals apply. The virtual network requires two main parts; address space and a subnet or subnets.
In order to deploy the virtual network in Azure with Ansible you'll need use two Ansible modules; azure_rm_virtualnetwork
and azure_rm_subnet
. The subnet module depends on the network module and for that reason the network module will be defined first. Ansible is procedural and the order of the tasks is very important.
The task Create virtual network
requires three parameters; resource_group
, name
, and address_prefixes
. The resource_group is the name given to the previous tasks which created the resource group. vNet
is the name given to the virtual network resource and will be used when creating the subnet. Address prefixes of 10.0.0.0/16
defines the address space of the virtual network.
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: ansible-rg
name: vNet
address_prefixes: "10.0.0.0/16"
Add subnet
is the next tasks which is used to add a subnet range to the virtual network. A subnet is a logical subdivision of an IP network and in this example it is used to carve out a section of IP addresses for web machines within that network. The task uses the azure_rm_subnet
Ansible module. The subnet is given the name of webSubnet
followed by the address prefix of the subnet 10.0.1.0/24
and it specifies the virtual network where the subnet will be created which is vNet
.
- name: Add subnet
azure_rm_subnet:
resource_group: ansible-rg
name: webSubnet
address_prefix: "10.0.1.0/24"
virtual_network: vNet
Create a Public Ip
While the virtual network created previously will assign a private Ip address to the virtual machine the Public Ip address assigns a public Ip address to the virtual machine. Without a Public Ip address you won't be able to communicate with the virtual machine without a VPN or other means. To create an Azure Public Ip address resource using Ansible, you'll use the azure_rm_publicipaddress
module.
In order to create an Azure Public Ip address you'll need to define the following parameters; resource group, allocation method, and name. Specifying the resource group of ansible-rg places the public ip address in the same location as the rest of the resources already created. Allocation method determines when the Ip address is assigned to the resource and when the Ip address is released. There are two options for allocation method, static and dynamic and the resource SKU determines which of these you can choose. To learn more about these options check out IP address types and allocation methods in Azure. The name of the resource is webPublicIP
.
Perhaps you want to return the public Ip address assigned right after the resource is created. You can accomplish this by using an Ansible command called register. Register allows you to populate variables based on the output of Ansible tasks. In this example the output of the task Create public IP address is assigned to a variable named output_ip_address_
. Registering the variable does not output the information. Which is what the debug command does within the Output public IP
task. Because output from tasks are in JSON you can parse the results to display what you want. In this example the variable output_ip_address is parsed to display only the ip address and nothing else.
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: ansible-rg
allocation_method: Static
name: webPublicIP
register: output_ip_address
- name: Output public IP
debug:
msg: "The public IP is {{ output_ip_address.state.ip_address }}"
Create Network Security Group
Azure Network Security Groups are what filter network traffic based on a set of rules that are defined. You can think of them as being similar to a network firewall. Without a network security group allowing traffic in, you will not be able to connect to your virtual machine within Azure. For that reason it is necessary to use the azure_rm_securitygroup
module to create one and also define some rules allowing traffic in.
In this example you'll want to connect to the virtual machine using three different protocols; RDP, HTTP, HTTPS, and WimRM. Each of these uses different inbound ports to communicate. RDP uses 3389, HTTP uses 80, HTTPS uses 443, and WinRM uses 5985 and 5986. Each of these protocols will require a set of rules associated with the network security group allowing inbound traffic in. To create an Azure network security group you only need two pieces of information. The resource group to associate it with and the name of the network security group. However, you'll need more information to create rules associated with it.
It is a common practice to create one rule per protocol. In this example, you'll create three rules. When creating the rules each one requires you specify a name, protocol, destination port range, access, priority, and direction.
- name: Create Network Security Group
azure_rm_securitygroup:
resource_group: ansible-rg
name: networkSecurityGroup
rules:
- name: 'allow_rdp'
protocol: Tcp
destination_port_range: 3389
access: Allow
priority: 1001
direction: Inbound
- name: 'allow_web_traffic'
protocol: Tcp
destination_port_range:
- 80
- 443
access: Allow
priority: 1002
direction: Inbound
- name: 'allow_powershell_remoting'
protocol: Tcp
destination_port_range:
- 5985
- 5986
Create a Virtual Network Interface Card
Every computer virtual or not requires some form of network interface card to communicate with computers outside of itself. That is where the Azure virtual network interface card comes in. Previous to this you've created several virtual networking components; a virtual network, subnet, a public ip address, and a network security group. All of these resources will be assigned to a virtual network interface card giving the Azure virtual machine private and public network access.
The Ansible module to create an Azure virtual network interface is azure_rm_networkinterface
. In order to properly configure the interface you must associate it with a virtual network, subnet, network security group, and to access the virtual machine from the internet a public Ip address.
- name: Create a network interface
azure_rm_networkinterface:
name: webNic
resource_group: ansible-rg
virtual_network: vNet
subnet_name: webSubnet
security_group: networkSecurityGroup
ip_configurations:
- name: default
public_ip_address_name: webPublicIP
primary: True
Create a Virtual Machine
Everything to this point as prepared the Azure environment for you to deploy the virtual machine. You have a lot of options when it comes to deploying a virtual machine in Azure. However, in this tutorial you'll be deploying a Standard DS1 v2 Windows Server 2019 virtual machine. The Ansible module used to deploy Azure virtual machines is azure_rm_virtualmachine
.
As with every Azure resource you've created so far the virtual machine requires a resource group and a name. The name will be used for the Azure resource and the virtual machine's hostname. The vm_size
uses Azure a Standard_DS1_v2 instance. You can learn more about Azure's instance sizes here. Windows virtual machines also require a user name and password be specified when you create the virtual machine. admin_username
is set to azureuser and will be the local user account you'll login with. admin_password
is set to "{{ password }}"
which is an Ansible variable. To avoid having the password stored in clear text, you'll prompt for that input in the next section.
webNic
is the only network interface you'll need to define at this time. It will connect the virtual machine to the private and public Ip addresses you defined when creating the network resources. os_type
defines which Operating System will be used by the virtual machine. Setting this to Windows
changes the behavior of the default parameters passed in to the task. image
has several sub parameters that define the image used to build the virtual machine. When choosing an image you must specify; the offer (WindowsServer), the publisher (MicrosoftWindowsServer), sku (2019-Datacenter), and version (latest).
- name: Create VM
azure_rm_virtualmachine:
resource_group: ansible-rg
name: winWeb01
vm_size: Standard_DS1_v2
admin_username: azureuser
admin_password: "{{ password }}"
network_interfaces: webNic
os_type: Windows
image:
offer: WindowsServer
publisher: MicrosoftWindowsServer
sku: 2019-Datacenter
version: latest
Deploy an Azure Windows Virtual Machine
Throughout this tutorial you've seen snippets of Ansible tasks. When putting those tasks into a playbook you have to add a few additional sections. hosts
is used to define which target the playbook will be executed against. Setting this to localhost will run the playbook on the Ansible server itself.
var_prompts
is used to prompt for Ansible variables when the playbook is executed. It's a simple choice for populating variables that contain sensitive information that you do not want to store in the playbook file. You'll use it to prompt for and populate the password used by the task creating the virtual machine.
tasks
define the sequential tasks that are executed to complete the playbook. The order of these tasks is very important. For example, the task creating the resource group must be at the top. Without the resource group all the tasks after it will fail because the resource group does not exist yet.
Because the tasks used in this playbook create Azure resources a connection from Ansible to Azure must be establish before you can execute the playbook. You have several options available to connect Ansible to Azure. You can define environment variables or create an Ansible credential file. Both options are explained in dept in Connecting to Azure with Ansible
Connecting to Azure with Ansible
Josh Duffney for CloudSkills.io ・ Dec 18 '19
#deployWindowsAzureVirtualMachine.yaml
---
- hosts: localhost
connection: local
vars_prompt:
- name: password
prompt: "Enter local administrator password"
tasks:
- name: Create resource group
azure_rm_resourcegroup:
name: ansible-rg
location: eastus
- name: Create virtual network
azure_rm_virtualnetwork:
resource_group: ansible-rg
name: vNet
address_prefixes: "10.0.0.0/16"
- name: Add subnet
azure_rm_subnet:
resource_group: ansible-rg
name: webSubnet
address_prefix: "10.0.1.0/24"
virtual_network: vNet
- name: Create public IP address
azure_rm_publicipaddress:
resource_group: ansible-rg
allocation_method: Static
name: webPublicIP
register: output_ip_address
- name: Output public IP
debug:
msg: "The public IP is {{ output_ip_address.state.ip_address }}"
- name: Create Network Security Group
azure_rm_securitygroup:
resource_group: ansible-rg
name: networkSecurityGroup
rules:
- name: 'allow_rdp'
protocol: Tcp
destination_port_range: 3389
access: Allow
priority: 1001
direction: Inbound
- name: 'allow_web_traffic'
protocol: Tcp
destination_port_range:
- 80
- 443
access: Allow
priority: 1002
direction: Inbound
- name: 'allow_powershell_remoting'
protocol: Tcp
destination_port_range:
- 5985
- 5986
access: Allow
priority: 1003
direction: Inbound
- name: Create a network interface
azure_rm_networkinterface:
name: webNic
resource_group: ansible-rg
virtual_network: vNet
subnet_name: webSubnet
security_group: networkSecurityGroup
ip_configurations:
- name: default
public_ip_address_name: webPublicIP
primary: True
- name: Create VM
azure_rm_virtualmachine:
resource_group: ansible-rg
name: winWeb01
vm_size: Standard_DS1_v2
admin_username: azureuser
admin_password: "{{ password }}"
network_interfaces: webNic
os_type: Windows
image:
offer: WindowsServer
publisher: MicrosoftWindowsServer
sku: 2019-Datacenter
version: latest
ansible-playbook
is the Ansible command used to execute playbooks. Because the playbook is targeting localhost, the Ansible server itself no inventory or host file is required. All that is required is the name of the playbook to be executed. Save the above playbook as deployWindowsAzureVirtualMachine.yaml
and run the following command to deploy your Windows virtual machine to Azure!
ansible-playbook deployWindowsAzureVirtualMachine.yaml
Modified recording, actual run time 5 minutes
Conclusion
You've now deployed a Windows virtual machine to Azure! At this point you might be wondering what the benefit of using Ansible is over creating the resources in the Azure portal or by using a PowerShell script. The benefits of using Ansible are;
- codified infrastructure
- idempotent automation
- configuration management
If you had used the portal you'd have a difficult time recreating the environment exactly the way it was before. If you had scripted the creation of all these resources you wouldn't be able to run that same script over and over without a lot of modification and error handling. That is where the idempotent nature of Ansible is extremely valuable.
Top comments (3)
Nice article Josh! I am assuming this playbook is run from the azure cloud console? Right? If I needed to run it from my Laptop with ansible installed, what would I need to change to connect to azure cloud shell remotely and run this playbook? Sorry if I have misunderstood anything.
That's a great question Umar. This tutorial is from the context of an Ansible environment that doesn't use the CloudShell. The workflow laid out in this blog post is for Ansible that is installed on a virtual machine or running inside of a container with Ansible installed. If you're using CloudShell it's even easier because Azure automatically authenciates for you in the CloudShell. Here's more information on using the CloudShell with Ansible. I hope that answers you're question thanks for the comment! If you have more questions please let me know. :)
docs.microsoft.com/en-us/azure/ans...
Thank you! I will have a look