Ansible environment

The Ansible development environment in Azure will comprise the following:

  • Windows Server 2019 virtual machine
  • Linux virtual machine running CentOS

Each virtual machine in Azure requires several Azure resources, and each of these resources is managed by different Ansible Modules.

Ansible Modules

The following are the required Azure resources and the corresponding Ansible Modules:

Azure Resource Azure Module
Resource Group azure_rm_resourcegroup
Virtual Network azure_rm_virtualnetwork
Subnet azure_rm_subnet
Public IP Address azure_rm_publicipaddress
Network Security Group azure_rm_securitygroup
Network Interface Card azure_rm_networkinterface
Custom Script Extension azure_rm_virtualmachineextension
Virtual Machine azure_rm_virtualmachine

Ansible codifies your infrastructure in YAML files called Ansible playbooks. You will use pre-written Ansible playbooks to deploy the Ansible development environment to Azure.

Resource Dependency
Several of the Azure resources depend on other resources. These dependencies mean that you have to run the playbooks in the right order.

Let’s start exploring the playbooks we will cover in this lesson one by one.

Create a resource group

First, you need to create a resource group. Review the playbook below:

---
- hosts: localhost
  connection: local
  
  tasks:
    - name: Create resource group
      azure_rm_resourcegroup:
        name: ansible
        location: eastus
Create a resource group

Ansible playbook

Ansible playbooks are written in YAML and have two main sections:

  • Hosts
  • Tasks

Hosts

Hosts determine which hosts are targeted by the playbook. Refer to Line 2-3 for hosts in the above playbook.

Tasks

Tasks define what Ansible will execute sequentially. From Line 5 onwards, you can observe all the tasks that Ansible will perform.

The azure_create_resource_group.yaml playbook has only one task, Create Resource Group. The task uses the azure_rm_resourcegroup Ansible module to deploy a resource group to Azure.

connection: local
Ansible uses SSH as the default connection. Adding connection: local under the hosts' section runs the tasks locally rather than connecting with SSH.

Execute the playbook by clicking on the Run button. The button runs the following command in the terminal:

Press + to interact
ansible-playbook azure_create_resource_group.yaml

Deploy a Windows virtual machine

We will require the following resources to deploy a virtual machine on Azure:

  • Virtual network
  • Subnet
  • Public IP address
  • Network Security Group
  • Network interface
  • Azure virtual machine

Review the playbook below and note the Ansible Modules required to deploy an Azure virtual machine:

---
- hosts: localhost
  connection: local

  tasks:

    - pause:
        prompt: "Enter password"
        echo: no
      when: password is undefined
      register: password_input

    - set_fact:
        password: "{{ password_input.user_input }}"
      when: password is undefined

    - set_fact:
        count: "{{ 100 | random }}"
      run_once: yes

    - name: Windows - Create virtual network
      azure_rm_virtualnetwork:
        resource_group: ansible
        name: vnet-winweb
        address_prefixes: "10.0.0.0/16"

    - name: Windows - Add subnet
      azure_rm_subnet:
        resource_group: ansible
        name: snet-winweb
        address_prefix: "10.0.1.0/24"
        virtual_network: vnet-winweb

    - name: Windows - Create public IP address
      azure_rm_publicipaddress:
        resource_group: ansible
        allocation_method: Static
        domain_name: "vm-winweb{{ count }}"
        name: pip-winweb
      register: output_ip_address

    - name: Output public IP
      debug:
        msg: "The public IP is {{ output_ip_address.state.ip_address }}"

    - name: Windows - Create Network Security Group
      azure_rm_securitygroup:
        resource_group: ansible
        name: nsg-winweb
        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: Windows - Create a network interface
      azure_rm_networkinterface:
        name: nic-winweb
        resource_group: ansible
        virtual_network: vnet-winweb
        subnet_name: snet-winweb
        security_group: nsg-winweb
        ip_configurations:
          - name: default
            public_ip_address_name: pip-winweb
            primary: True

    - name: Windows - Create VM
      azure_rm_virtualmachine:
        resource_group: ansible
        name: "vm-winweb{{ count }}" 
        vm_size: Standard_DS1_v2
        admin_username: ansible
        admin_password: "{{ password }}"
        network_interfaces: nic-winweb
        os_type: Windows
        image:
          offer: WindowsServer
          publisher: MicrosoftWindowsServer
          sku: 2019-Datacenter
          version: latest

    - name: Windows - create Azure vm extension to enable HTTPS WinRM listener
      azure_rm_virtualmachineextension:
        name: winrm-extension
        resource_group: ansible
        virtual_machine_name: "vm-winweb{{ count }}"
        publisher: Microsoft.Compute
        virtual_machine_extension_type: CustomScriptExtension
        type_handler_version: '1.10'
        settings: '{"fileUris": ["https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"],"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"}'
        auto_upgrade_minor_version: true

    - name: Windows - Get facts for one Public IP
      azure_rm_publicipaddress_info:
        resource_group: ansible
        name: pip-winweb
      register: publicipaddresses

    - name: Windows - set public ip address fact
      set_fact: publicipaddress="{{ publicipaddresses | json_query('publicipaddresses[0].ip_address')}}"

    - name: Windows - wait for the WinRM port to come online
      wait_for:
        port: 5986
        host: '{{ publicipaddress }}'
        timeout: 600
Create a Windows virtual machine

Execute the playbook by clicking on the Run button. The button runs the following command in the terminal:

Press + to interact
ansible-playbook azure_create_windows_vm.yaml

A prompt will display for the password. You can provide a password of your own choice. You will use this same password later to connect to the virtual machine.

pause Ansible Module
Pauses playbook execution for a set amount of time or until a prompt is acknowledged. Read more about the pause module.

Deploy a Linux virtual machine

Deploying a Linux virtual machine with Ansible is identical to that of a Windows virtual machine. Review the azure_create_linux_vm.yaml playbook below. It uses the same modules as before and only requires the arguments to be changed:

  • The ports allowed in the Network Security Group.
  • Image selected for the virtual machine.
---
- hosts: localhost
  connection: local

  tasks:
    - pause:
        prompt: "Enter password"
        echo: no
      when: password is undefined
      register: password_input

    - set_fact:
        password: "{{ password_input.user_input }}"
      when: password is undefined

    - set_fact:
        count: "{{ 100 | random }}"
      run_once: yes

    - name: 'Linux - Create virtual network'
      azure_rm_virtualnetwork:
        resource_group: ansible
        name: vnet-linux
        address_prefixes: "10.0.0.0/16"

    - name: 'Linux - Add subnet'
      azure_rm_subnet:
        resource_group: ansible
        name: snet-linux
        address_prefix: "10.0.1.0/24"
        virtual_network: vnet-linux

    - name: 'Linux - Create public IP address'
      azure_rm_publicipaddress:
        resource_group: ansible
        allocation_method: Static
        domain_name: "vm-linuxweb{{ count }}"
        name: pip-linux
      register: output_ip_address

    - name: Output public IP
      debug:
        msg: "The public IP is {{ output_ip_address.state.ip_address }}"

    - name: 'Linux - Create Network Security Group'
      azure_rm_securitygroup:
        resource_group: ansible
        name: nsg-linux
        rules:
          - name: SSH
            protocol: Tcp
            destination_port_range: 22
            access: Allow
            priority: 1001
            direction: Inbound
          - name: 'allow_web_traffic'
            protocol: Tcp
            destination_port_range:
              - 80
              - 443
            access: Allow
            priority: 1002
            direction: Inbound

    - name: 'Linux - Create virtual network interface card'
      azure_rm_networkinterface:
        resource_group: ansible
        name: nic-linux
        virtual_network: vnet-linux
        subnet: snet-linux
        security_group: nsg-linux
        ip_configurations:
          - name: linux-ipconfig
            public_ip_name: pip-linux
            primary: True

    - name: 'Linux - Create VM'
      azure_rm_virtualmachine:
        resource_group: ansible
        name: "vm-linuxweb{{ count }}"
        vm_size: Standard_DS1_v2
        admin_username: ansible
        admin_password: "{{ password }}"
        ssh_password_enabled: true
        network_interfaces: nic-linux
        #custom_data: "{{ lookup('file', 'cloud-init.yml') }}"
        image:
          offer: CentOS
          publisher: OpenLogic
          sku: '8.0'
          version: latest

    - name: Linux - update sudoers
      azure_rm_virtualmachineextension:
        name: update-sudoers
        resource_group: ansible
        virtual_machine_name: "vm-linuxweb{{ count }}"
        publisher: Microsoft.Azure.Extensions
        virtual_machine_extension_type: CustomScript
        type_handler_version: '2.0'
        settings: '{"fileUris": ["https://raw.githubusercontent.com/Duffney/becomeansible/master/chapter-03/azure/update-sudoers.sh"],"commandToExecute": "bash update-sudoers.sh"}'
        auto_upgrade_minor_version: true
Create a Linux virtual machine

Execute the playbook by clicking on the Run button. Once again, use the password of your own choice when prompted. The following command is executed when you click the Run button:

Press + to interact
ansible-playbook azure_create_linux_vm.yaml

Delete the environment

All the above infrastructure lies in the free tier. You will be using these resources in the upcoming lessons and chapters. In case you are going to visit the next lessons later, you can take down the resources to avoid any unexpected bills.

You can take these resources down by executing the playbook below.

Disclaimer: Run the playbook at your own risk!
It is highly recommended you use a development Azure subscription.

Review the playbook:

---
- hosts: localhost
  connection: local
  
  tasks:
    - name: delete resource group
      azure_rm_resourcegroup:
        name: ansible
        force_delete_nonempty: yes
        state: absent
Delete the Ansible environment

Execute the playbook by clicking on the Run button. It will execute the following command:

Press + to interact
ansible-playbook azure_delete_ansible_env.yaml

In this lesson, you were introduced to the Ansible playbooks and modules to create Linux and Windows virtual machines in Azure.


Download the Source Code
You can download the playbooks for this lesson from the Github repository, become Ansible.

Get hands-on with 1300+ tech skills courses.