An introduction to Ansible: Install & Deployment.
It has been a while since I wrote about the IaaC tool; previously, I focused on the provisioning tool. Today, I’m going to show you how to effortlessly install a cutting-edge configuration management tool that will empower you to easily set up and manage remote servers like a pro! Yes, This tutorial is all about Ansible. Before we dive into the details let’s take a quick look at some of the prerequisites for the tutorial.
Requirements:
- Linux machines with root access.
- Azure subscription.
Note: You can use docker for Linux machines as well.
What you will learn 🤩:
- How to install and configure Ansible on the controller node.
- Writing inventory and playbooks.
- Installing packages on managed nodes.
- Deploying virtual machine on Azure using playbooks.
- Bonus commands.
Ansible needs 1 controller node and other managed nodes. I will be using WSL as a controller node & VMS in Azure as a managed node.
I have written a shell script to create virtual machines on Azure. This script will also automatically configure the public key of your local machine to the cloud instances. (Script execution may take time, Ignore all the warnings)
Note: If you are creating the machines on the portal via GUI then you need to add the public key of a local machine.
Let’s Start 😎:
Note: Perform all the steps on the local machine/controller node only.
Step 1: Run the following script to create multiple machines on the cloud.
(2 is recommended, 1 is enough as well 😅)
The script will show you the public addresses of the virtual machines on completion. We will be using these to test connections and include them in the inventory file later on.
group=ansibleNodesRG
size=$1
read -p "How many machines you want to create? = " instance
if [ -z $instance ] || [ $instance -eq 0 ]; then
echo "\nNo size is provided, Please specify the size and Try Again."
exit 1
fi
generate_keys() {
if [ -f ~/.ssh/id_rsa ]; then
echo "SSH keys already exist, Deleting...."
rm -rf ~/.ssh
fi
echo "\n Generating new ssh keys.\n"
yes "" | ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/id_rsa
}
generate_keys
echo "\nInitializing VM Creation Process.\n"
az group create -g $group -l centralindia 2> /dev/null
if [ $? -ne 0 ]; then
az group create -g group -l centralindia
fi
az network vnet create \
-n vm-net \
-g $group \
-l centralindia \
--address-prefixes '192.168.0.0/16' \
--subnet-name subnet \
--subnet-prefixes '192.168.0.0/24'
if [ -z $size ]; then
echo "\nNo size is provided, Using default size Standard_B1s for machine"
size=B1s
fi
vm_create() {
for i in $(seq 1 $instance);
do
az vm create \
-n Machine$i \
-g $group \
-l centralindia \
--size Standard_$size \
--image Ubuntu2204 \
--admin-username amitgujar \
--vnet-name vm-net \
--subnet subnet \
--public-ip-sku Standard \
--generate-ssh-keys \
--ssh-key-values ~/.ssh/id_rsa.pub
az vm open-port -g $group -n Machine$i --port 80
done
}
vm_create
update_vm() {
for i in $(seq 1 $instance);
do
az vm run-command invoke \
-g $group \
-n Machine$i \
--command-id RunShellScript \
--script "sudo apt update -y"
done
}
update_vm
vm_listIpAddress() {
for i in $(seq 1 $instance);
do
az vm list-ip-addresses \
-n Machine$i \
-g $group | grep ipAddress | cut -d':' -f2
done
}
vm_listIpAddress
Step 2: Install Ansible and Python3 on the local machine.
sudo apt install python3.10 -y
sudo apt-add-repository ppa:ansible/ansible
sudo apt update -y
sudo apt install ansible -y
Step 3: Verify the ansible installation.
Step 4: Verify the ssh connection of the cloud machines. Use the public IPs from Step 1.
We need to write our first inventory file. We can directly change the main inventory file located in /etc/ansible/hosts. However, it is a good practice to create a per-project inventory.
Inventory is a file that contains information about the management nodes that Ansible controls.
Step 5: Create the inventory file and add the following lines.
[azure]
ip address of the machine 1
ip address of the machine 2
[azure:vars]
ansible_user=amitgujar
ansible_python_interpreter=/usr/bin/python3
It’s time to test the connection of managed nodes and master node.
Step 6: Enter the following command.
ansible all -i inventory -m ping
(If you get the success message then a connection is successful)
After writing the inventory file, the next step is to create a playbook.
A playbook is a file containing a series of tasks to be executed on a remote server.
Step 7: Create the playbook.yaml file and add the following lines.
- name: Installing packages
hosts: azure
become: true
tasks:
- name: Installing nginx
ansible.builtin.package:
name: nginx
state: present
Step 8: Enter the following command to execute the playbook against the managed nodes.
ansible-playbook -i inventory playbook.yaml
To check if nginx is installed, use the curl command.
We have successfully installed the nginx package on the managed nodes. By using the same steps you can install different packages as well.
Deployment on Azure:
Step 1: Install Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
Step 2: Install pip3 & azure packages.
sudo apt install python3-pip
pip3 install -r /usr/lib/python3/dist-packages/ansible_collections/azure/azcollection/requirements-azure.txt
Step 3: Create the service principle for the subscription. Enter the following command.
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/<SUBSCRIPTION_ID>"
Note down the following details.
{
"appId": "xxxxxx-xxx-xxxx-xxxx-xxxxxxxxxx",
"displayName": "azure-cli-2023-xxxx",
"password": "xxxxxx~xxxxxx~xxxxx",
"tenant": "xxxxx-xxxx-xxxxx-xxxx-xxxxx"
}
Step 4: Add these details into the ~/.bashrc for the authentication.
export AZURE_SUBSCRIPTION_ID=<SUBSCRIPTION_ID>
export AZURE_CLIENT_ID=<CLIENT_ID>
export AZURE_SECRET=<CLIENT_SECRET>
export AZURE_TENANT=<TENANT_ID>
Restart the terminal instance.
Step 5: Create the playbook to deploy the resource group & virtual network on the Azure portal.
- name: Creation of virtual machine
hosts: localhost
vars:
resource_name: rg-ansiblemanaged
location: centralindia
virtual_network_name: vnet-ansiblemanaged
public_ip_name: pip_ansiblemanaged
nsg_name: nsg-ansiblemanaged
subnet_name: subnet-ansiblemanaged
nic_name: nic-ansiblemanaged
tasks:
# creating a resource group
- name: Creating a resource group
azure.azcollection.azure_rm_resourcegroup:
name: "{{ resource_name }}"
location: "{{ location }}"
# creating a virtual network
- name: Creating virtual network
azure.azcollection.azure_rm_virtualnetwork:
name: "{{ virtual_network_name }}"
resource_group: "{{ resource_name }}"
location: "{{ location }}"
address_prefixes_cidr:
- "10.0.0.0/16"
# creating a subnet
- name: Adding subnet
azure.azcollection.azure_rm_subnet:
name: "{{ subnet_name }}"
resource_group: "{{ resource_name }}"
virtual_network: "{{ virtual_network_name }}"
address_prefix_cidr: "10.0.1.0/24"
# creating a public ip
- name: Creating public ip
azure.azcollection.azure_rm_publicipaddress:
name: "{{ public_ip_name }}"
resource_group: "{{ resource_name }}"
allocation_method: Static
register: output_public_ip
# creating a network security group
- name: Creating NSG
azure.azcollection.azure_rm_securitygroup:
name: "{{ nsg_name }}"
resource_group: "{{ resource_name }}"
rules:
- name: 'Allow_SSH'
protocol: Tcp
destination_port_range: 22
access: Allow
priority: 100
direction: Inbound
- name: 'Allow_web_traffic'
protocol: Tcp
destination_port_range:
- 80
- 443
access: Allow
priority: 101
direction: Inbound
# creating a network interface
- name: Creating NIC with public ip
azure.azcollection.azure_rm_networkinterface:
name: "{{ nic_name }}"
resource_group: "{{ resource_name }}"
virtual_network: "{{ virtual_network_name }}"
subnet_name: "{{ subnet_name }}"
security_group: "{{ nsg_name }}"
ip_configurations:
- name: deafult
public_ip_address_name: "{{ public_ip_name }}"
primary: true
# creating virtual machines
- name: Finally creating a VM
azure.azcollection.azure_rm_virtualmachine:
name: vm-ansiblemanaged
resource_group: "{{ resource_name }}"
vm_size: Standard_B1s
admin_username: amit
ssh_password_enabled: false
ssh_public_keys:
- path: /home/amit/.ssh/authorized_keys
key_data: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
network_interfaces:
- name: "{{ nic_name }}"
image:
offer: 0001-com-ubuntu-server-jammy
publisher: Canonical
sku: '22_04-lts'
version: latest
# connection string
- name: Connect to machine using this string
ansible.builtin.debug:
msg: "ssh amit@{{ output_public_ip.state.ip_address }}"
Step 6: Execute the playbook on localhost
ansible-playbook vm_linux.yaml
Step 7: Check if the deployment is successful.
ssh amit@ip_address_displayed_in_terminal
Note: As you can notice we don’t need managed nodes for the resource group deployment, localhost is enough.
Bonus 😉:
Ad hoc commands :
Ad hoc commands are powerful single-line commands in Ansible. They are very useful to execute singular tasks on managed nodes.
Command 1: Harness the power of SCP to transfer files.
ansible azure -i inventory -m ansible.builtin.copy -a "src=/path of controller dest=/path to target machines"
Command 2: Changing file permissions on remote machines.
ansible azure -i inventory -m ansible.builtin.file -a "dest=/home/amitgujar/playbook.yaml mode=777"
Command 3: Checking os-release
ansible all -i inventory -a "cat /etc/os-release"
Wrapping up:
Today we have covered several concepts of Ansible including installation, configuration, playbooks, and inventory files. Working with deployment on Azure & some ad hoc commands.