Ansible with Task Automation Demo
Josephat Kene
Posted on May 20, 2024
Table of Content
- Introduction
- What is Ansible
- How Ansible Works
- Demo
- Solution
- Inventory
- Connecting to Slave Nodes
- Playbook
- Playbook Breakdown
- Updating Packages
- Installing Apache
- Starting Apache and Opening Port 80 in the CentOS System
- Running the Playbook
- Conclusion
Introduction
You got that lucky break and bagged an internship in cloud engineering. One of your duties is managing over 10 servers on the cloud, updating and upgrading the packages, and installing new applications on new servers.
You'll be wondering how to SSH into all the servers and run all those commands one after the other. That sounds like a lot. However, a way to automate that and make your life easy is by using Ansible.
What is Ansible?
Ansible is an open-source IT automation engine that automates provisioning, configuration management, application deployment, orchestration, and many other IT processes. It is free to use, and the project benefits from the experience and intelligence of its thousands of contributors.
So imagine you have many machines for different purposes and tasks and you have to manage all of them, Ansible is a super robot that helps you connect to those machines and you tell Ansible what you want it to do in all of those machines and it does it for you.
How Ansible works
Ansible needs a master node or controller that will be used to connect to all other nodes, machines, or servers to manage them.
It uses an Inventory file that stores the IP of all the machines it should connect to and perform tasks on.
It also needs a playbook which is a YAML file that tells ansible what it wants it to do and the tasks to perform on all other nodes or machines it is connected to.
Demo
To explain how Ansible works better, You will use a demonstration. In this demo, you are going to provision 3 Linux servers. Two will be Ubuntu and one will be CentOS. The Master node (controller) will be any of the Ubuntu servers and the slave node will be One Ubuntu server and the CentOS server.
You are going to run a playbook that installs Apache on the slave nodes. In the CentOS server, you will start the Apache and enable port 80 in the firewall.
Solution
First, you have to provision 3 virtual machines using Vagrant. An alternative is your AWS EC2.
In the master node, first, install ansible on your master node with the command:
sudo apt install ansible
Then create a directory with any name of your choice. This directory will house all the files and playbooks related to our Ansible project.
- Inventory
Now you have to create your Inventory file. An Inventory in Ansible contains the IP address or domain name of all the servers or slave nodes we want to manage with Ansible.
It can also contain some other data like groupings, group variables, and host variables (which we will address later for better understanding). The inventory file should be inside the directory we created.
To create an inventory file, run the command:
sudo vim inventory
The picture below is the inventory file with the IP addresses of both our slave nodes.
Remember that an inventory file can contain data like groupings? That means that we can group our slave nodes into whatever groups we want to put them in. The groups can be web servers, databases, or by their Linux distribution.
The picture below shows how to group the IP addresses of our slave nodes.
- Connecting to Slave nodes
For Ansible to be able to run tasks on your slave nodes with the playbook, it needs some form of connection to those slave nodes in your inventory.
The way to get that connection is to generate an SSH key on your master node or controller, copy the public keys, and paste them into the authorized keys of your slave nodes.
The command to generate the SSH key is:
ssh-keygen -t ed25519 -C "default"
The "ssh-keygen" is the command line utility for generating SSH keys, the "-t ed25519" specifies the type of key to create which is ed25519, the "-C "default" add a comment 'default' to key for information purposes.
The picture below is the result after creating the ssh key.
Do the same thing for the second one but this time the comment will be ansible and you will change the path to where the keys will to /home/vagrant/.ssh/ansible.pub
This is how your ansible key creation will look
For this article, please don't create a password when you create the SSH keys. To get the public key, navigate into /home/vagrant/.ssh/ the copy the keys of ansible.pub and id_ed25519.pub. Then paste it into the authorized key file in your slave nodes separately.
The default key is for you to be able to connect or SSH into your slave nodes from the controller and the Ansible key is the one Ansible will use to connect to the slave nodes.
To be sure your master node can connect to your slave nodes in your inventory, make sure your slave nodes are up and running then run the command in the directory that has your inventory:
ansible all --key-file ~/.ssh/ansible -i inventory -m ping
"ansible" is the command line tool. You are calling ansible.
"all" is specifying that the command should run against all the IP addresses or hosts in the inventory file.
"--key-file ~/.ssh/ansible" is telling ansible the particular SSH key to use for authentication. In the case the key located in (~/.ssh/ansible)
"-i inventory" is you specifying the inventory file that contains all the IP addresses of your slave nodes
"-m ping" specifies the ansible module to use. In this case 'ping' which just testing to check if the IPs in the Inventory are reachable.
- Playbook
A playbook in Ansible is like a blueprint of tasks you want to automate. These tasks are executed with little manual effort across all the hosts in your inventory. The playbook tells Ansible what to do and which device to do it in.
One or more tasks are combined to make a play and these tasks can be mapped to a specific host, a group of hosts, or all the hosts. A playbook can also include one or more plays. The tasks/plays are executed the way they are written.
Tasks are executed by Ansible modules. These modules contain some data that determines when and where a task is executed and the user that executes the tasks.
Now to open a playbook file, still inside the directory you created that your inventory is in, run the command:
sudo vim playbook.yml
The playbook for our demo is the code block below.
---
- hosts: all
become: true
pre_tasks:
- name: install updates (centOS)
tags: always
yum:
update_only: yes
update_cache: yes
when: ansible_os_family == 'RedHat'
- name: install updates (Ubuntu)
tags: always
apt:
upgrade: dist
update_cache: yes
when: ansible_os_family == 'Ubuntu'
#Installing apache for ubuntu and centos
- hosts: all
become: true
tasks:
- name: install apache for ubuntu server
tags: apache,apache2,ubuntu
apt:
name: apache2
state: latest
when: ansible_distribution == "Ubuntu"
- name: install Apache for CentOS server
tags: apache,centos,httpd
yum:
name: httpd
state: latest
when: ansible_distribution == "CentOS"
#Start and enable apache for CentOS
- name: start httpd (CentOS)
tags: apache,centos,httpd
service:
name: httpd
state: started
enabled: yes
when: ansible_distribution == "CentOS"
#Open port 80/tcp for CentOS
- name: Open port 80/tcp in firewalld
firewalld:
service: http
permanent: yes
state: enabled
when: ansible_distribution == "CentOS
notify: Reload firewalld
#Reload Firewall for CentOS
handlers:
- name: Reload firewalld
service:
name: firewalld
state: reloaded
when: ansible_distribution == "CentOS"
N.B You should note that when writing your ansible playbook, your indentation is very important. You miss a single line of indentation in a task or a play and that particular task or play won't run. Sometimes the entire playbook might not work.
- Component Breakdown
- Updating Package
---
- hosts: all
become: true
pre_tasks:
- name: install updates (centOS)
tags: always
yum:
update_only: yes
update_cache: yes
when: ansible_os_family == 'RedHat'
- name: install updates (Ubuntu)
tags: always
apt:
upgrade: dist
update_cache: yes
when: ansible_os_family == 'Ubuntu'
-
---
represents the beginning of a YAML file -
- hosts: all
specifies that the playbook should run on all hosts. You can also pick any specific host group.become: true
This ensures that all tasks are executed with sudo privileges. Although it is optional. Your plays can run without it. -
pre_tasks:
You can also use "tasks" here however, using pre_tasks means the tasks here are executed before any other tasks. The first part of the task here updates the packages for the CentOS servers and the second task does the same for the Ubuntu server -
name
This is the description of the tasks -
tags
when running an ansible playbook, you can specify a tag you want the playbook to run on, setting this tag to always makes sure these tasks run regardless of the tags specified when running the playbook. It is also optional. -
yum
andapt
These are modules used to manage packages in the RedHat and Debian-based systems.-
update_only
This ensures only updates are installed -
update_cache
This refreshes the package database cache -upgrade
Specifies the type of upgrade to perform. 'dist' in this case performs a full distribution upgrade.
-
when
This is a conditional statement in Ansible that states a task should run on Ubuntu or RedHat systems.
So the above Play is you going into that system to runsudo apt update
orsudo yum upgrade
as it is best practice to update your packages before any installation but this time you are doing it remotely with Ansible!Installing Apache
#Installing apache for ubuntu and centos
- hosts: all
become: true
tasks:
- name: install apache for ubuntu server
tags: apache,apache2,ubuntu
apt:
name: apache2
state: latest
when: ansible_distribution == "Ubuntu"
- name: install apache for CentOS server
tags: apache,centos,httpd
yum:
name: httpd
state: latest
when: ansible_distribution == "CentOS"
The code block above is the part of the playbook that installs Apache for both Ubuntu and CentOS systems.
Now if you had used 'tasks' instead of 'pre_tasks' you would not have to repeat the host
, become
, and tasks
parts. It will all be under the first one.
-
name
describes the name of the task -
tags
keywords to use in running a specific task by adding--tags "apache,ubuntu,httpd,apache2"
to the ansible command -
apt
andyum
These are modules used to manage Ubuntu and RedHat-based systems-
name
This is the name of the package to install. "apache2" for Ubuntu and "httpd" for centOS -
state
This ensures the package installed is up to date by setting it to "latest"
-
when
This is a conditional statement that makes sure the tasks run on Ubuntu or CentOS systems.
This play is you going into the slave nodes to run the commandsudo apt install apache2
orsudo yum install httpd
Starting Apache and Opening Port 80 in the CentOS System
#Start and enable apache for CentOS
- name: start httpd (CentOS)
tags: apache,centos,httpd
service:
name: httpd
state: started
enabled: yes
when: ansible_distribution == "CentOS"
#Open port 80/tcp for CentOS
- name: Open port 80/tcp in firewalld
firewalld:
service: http
permanent: yes
state: enabled
when: ansible_distribution == "CentOS
notify: Reload firewalld
#Reload Firewall for CentOS
handlers:
- name: Reload firewalld
service:
name: firewalld
state: reloaded
when: ansible_distribution == "CentOS"
These tasks configure Apache or httpd as it is called for the CentOS system.
Here, you are using a few different modules and their arguments. The new modules used are the service
module which manages the state of a service and firewalld
module which manages firewall settings.
The first task using the service module, starts the service (httpd) and enables it.
The second task using the firewalld module, enables the http service (which corresponds to port 80), makes the change permanent, and enables it.
It uses notify to alert the handler which is used in the third task that a change has been made. The handler will only run if the change was made.The third task introduces a new concept called "handlers". It is used to perform actions when notified of a task. It is mostly used to perform actions like restarting services or reloading configurations only when necessary.
In this case, from the arguments of the service module, it is used to reload the firewalld service.
You can also find out more about the ansible module with the ansible documentation
- Running the Playbook
Now that you understand what the entire playbook does, it's time to check if it works. The command to run an ansible playbook is:
ansible-playbook -i inventory playbook.yml
The "inventory" should be the name of your inventory file and the playbook.yml should be the name of your playbook file.
This command should be run inside the directory that has your playbook and inventory file
If your playbook runs successfully you should get this output
If you check the play recap at the bottom, you will see that no task failed for each of the slave nodes.
Now if you check the IP address of your slave nodes on your browser to be sure Apache was installed, you should get the Apache default page as shown in the pictures below
Apache default page for Ubuntu
Apache default page for CentOS
- Conclusion
In this article you have learned what Ansible is, how it works and a few concepts used like the playbook and inventory using a demo. You should also remember that indentations are important when writing your playbooks.
The playbook written in this article is not the best way to write a playbook as there are a few repetitions. We can consolidate it by using variables and Roles. Those will be discussed in the second part of this article!
Posted on May 20, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.