Linux
Implement Ansible Playbooks RHCE EX294 Exam Part 03
In the previous chapter, we made an introduction to Ansible and looked at the fundamental topics. These included creating an Ansible inventory, managing configuration files, and running ad hoc commands on managed hosts. In this chapter, we dive deeper and touch base on how to implement Ansible playbooks to automate tasks on manage remote hosts.
At the end of this chapter, you will have a firm grasp of Ansible Playbooks and be able to write your own playbooks and execute them using the ansible-playbook
command.
ANSIBLE PLAYBOOKS AND AD HOC COMMANDS
Sure, you can use ad hoc commands to run commands on a set or multiple remote hosts and achieve the expected results. However, the true power of Ansible lies in learning how to implement Ansible playbooks in order to execute complex tasks on remote targets.
What is a playbook?
A Playbook is a text file in YAML format that contains one or more plays to be executed on managed hosts. It is usually saved in a .yml
format.
A play is an ordered set of tasks which are to be executed on remote hosts defined in the inventory file. A task is an operation to be carried out. A playbook file can be made of one or multiple plays.
FORMATTING AN ANSIBLE PLAYBOOK FILE
To get a better understanding of Ansible playbooks, we will preview an ad hoc command from the previous chapter. The ad hoc command creates a new user winnie
on the remote host.
1 |
$ ansible -m user -a 'name=winnie uid=1002 state:present' 173.82.104.69 |
The ad hoc command can be rewritten in a playbook file as a single task as shown below:
1 2 3 4 5 6 7 8 9 10 |
--- - name: Configure a new user on remote host hosts: 173.82.104.69 tasks: - name: Create a new user with UID 1002 user: name: winnie uid: 1002 state: present |
Structure of a playbook
From the example above, a playbook file begins with the dashes ( — ). A play comprises key-value pairs. Keys within the same play should have a similar indentation. In this playbook example, we have 3 keys: name, hosts, and tasks.
The very first line begins with a dash and space. This indicates the name of the play The name attribute is the first item on the list and takes an arbitrary string as a label. This is basically an identification that specifies what the play does. While optional, the name key comes recommended for clarity purposes.
Next online is the ‘hosts’ key. As you might have guessed, the ‘hosts’ key defines the targets against which the playbook will run. The ‘hosts‘ attribute can take an IP address(es), domain name, or host groups in the inventory.
Lastly, we have the ‘tasks‘ key that specifies the tasks to be executed in order in a play. The task at hand uses the user module to create a new user on the remote host with the name winnie
and uid 1002
.
The task in this play has 2 keys:
- Name: This documents the name of the task, and takes a string value. It is recommended to name your tasks for documentation purposes.
- User: This is the module used to run the tasks. Its arguments are passed as key-value pairs which are children of the module. The arguments, in this case, are name, uid, and state.
Indentations in Playbooks
As you might have noted, a playbook consists of indentations to structure its data. Although there are no strict rules on the spacing, a few basic rules apply:
- Elements in the same list must have the same indentation.
- Children items must be indented more than their parents. Feel free to add more blank lines for better readability.
For indentation, only use the spacebar key on the keyboard and not the TAB key. A play comprises key-value pairs. Keys within the same play should have a similar indentation.
RUNNING PLAYBOOKS
Let’s now switch gears and see how you can run Ansible Playbooks. To run playbooks, the ansible-playbook command is used in the syntax shown
1 |
# ansible-playbook playbook-file.yml |
The example below shows an example of a playbook file – install_apache.yml
which installs the Apache2 web server on a remote host with the IP 173.82.104.69
1 2 3 4 5 6 7 8 9 |
--- - name: play to setup web server hosts: 173.82.104.69 tasks: - name: Install Apache web server apt: name: apache2 state: present |
To execute the playbook, run the command:
1 |
# ansible-playbook install_apache.yml |
Here’s the output of executing the playbook file.
Let’s briefly discuss the output:
The name of the play is the first to be displayed when the playbook is run. The ‘Gathering Facts‘ task is a unique task that is run by the setup module as it gathers information also note that the remote host is indicated as ‘changed‘ implying that the operation was a success. This is further evidenced by the ‘PLAY RECAP’ that indicates ok=2 and changed=1
Syntax verification
It’s always recommended to check your playbook and ensure that the syntax is correct and that there are no errors. To achieve this, use the --syntax-check
option as shown.
1 |
$ ansible-playbook --syntax-check install_apache.yml |
If there are no syntax errors, only the playbook file name will be printed as shown.
However, if the syntax check fails, an error will be printed on the terminal as shown.
Perform a dry run
A dry run simulates the actual playbook execution but does not execute the playbook. It gives you a glance at how the playbook file will run and the changes that will happen during playbook execution. To perform a dry run, use the -C option as shown:
1 |
$ ansible-playbook -C install_apache.yml |
Increase verbosity
By default, the ansible-playbook command does not print out detailed task execution when running a playbook file. The ansible-playbook -v
option provides additional information up to 4 levels during playbook execution.
OPTION | DESCRIPTION |
-v | Displays location of the Ansible configuration file in use. |
-vv | Prints out both the location of the Ansible configuration file and task results. |
-vvv | Includes information about connections to managed hosts. |
-vvvv | Includes additional verbosity such as scripts being executed, users connecting to managed hosts to execute scripts and so much more. |
IMPLEMENTING MULTIPLE PLAYS
A playbook can consist of multiple plays, not just one. Recall that a play is a collection of tasks to be executed. Each play can apply tasks to different managed hosts. Multiple plays come in handy in a complex deployment involving multiple tasks which need to be carried out on various hosts.
Writing a playbook with multiple plays is quite a simple and straightforward process. In the example below, we have 2 plays. The first installs Apache web server on a host whose IP is 173.82.56.50 while the second play instalsl the Mariadb database server on the host whose IP is 173.82.201.202.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
--- - name: play to setup web server hosts: 173.82.56.50 tasks: - name: Install Apache web server on CentOS 8 yum: name: httpd state: present - name: play to install mariadb hosts: 173.82.201.202 tasks: - name: Install Mariadb database server yum: name: mariadb state: latest |
REMOTE USERS AND PRIVILEGE ESCALATION IN PLAYS
Other than what is specified in the default configuration file, Ansible Plays can include different remote users or privilege escalation settings for a play. These are defined in the play itself at the same level as the hosts or tasks keywords.
You can define the user that is executing the tasks in a playbook using the remote_user keyword. This keyword also overrrides the user specified in the Ansible configuration file.
1 |
<strong>remote_user: user</strong> |
Additionally, if privilege escalation is enabled, then keywords such as become_user become relevant.
PRIVILEGE ESCALATION ATTRIBUTES
We have tackled privilege escalation parameters before. In plays, you can use the boolean become parameter to either enable or disable privilege escalation. It can take either a Yes or No value as shown:
1 |
become: true |
When privilege escalation is enabled, then the become_method keyword comes in handy and is used to define the privilege escalation method to be used during a specific play. For instance, sudo is used for privilege escalation in our example below.
1 |
become_method: sudo |
Also, if privilege escalation is defined, then the become_user can also be used to specify the user for privileges escalation in a specific play
1 |
become_user: privileged user |
FINDING MODULES FOR TASKS
As you implement Ansible playbooks, playing around with modules becomes routine task. Ansible ships with a wealth of modules that can be used in a myriad of applications including modules for use in cloud platforms such as AWS and Azure. In the previous chapter we had an overview of Ansible modules and how they are used.
Let’s do some recap. You can list all the modules in Ansible, use the ansible-doc command. To view more information, append the -l flag to list module names and a summary of their functions.
1 |
$ ansible-doc -l |
To display a particular module and its functions, use the ansible-doc module-name command. For example, to find out more information about the apt module, the command will be:
1 |
$ ansible-doc apt |
The -s option give more insights into how a module can be used with ansible.
1 |
$ ansible-doc -s apt |
PLAYBOOK SYNTAX VARIATIONS
Lastly , let’s have a look at some of the syntax variations in Ansible YAML format.
Comments
Comments are lines of text that describe what a play or a task is all about. They start with a hash sign and are not executed at runtime.
1 |
# This is a comment |
If there is content to the left of the comment, precede the number
symbol with a space.
1 |
remoteuser: user # This is also a YAML comment |
YAML Strings
It’s not necesary to enclose strings in quotation marks even where there are spaces contained in the string. If you insist, you can enclose them in single or double quotation marks.
1 2 3 4 5 |
An example of a string 'Yet another string' "Now you get the picture" |
YAML Lists
Lists can be written in a normal single-dash style as shown:
1 2 3 4 |
hosts: - server1 - server2 - server3 |
Also, you can have the items in an inline format enclosed in square brackets as shown:
1 |
hosts: [server1, server2, server3] |
However, this should be avoided as it makes it harder to read.
YAML dictionaries
Dictionaries are key-value pairs that take the following format.
1 2 |
name: httpd state: present |
They can also be written in an inline-block format a shown, but this is quite clumsy and not recommended as you implement playbooks in Ansible.
1 |
{name:httpd , state:present} |
Playbook shorthand
In some cases, some playbooks use the shorthand method of defining tasks by placing the key-value pairs on the same line as the module name:
1 2 3 |
- tasks: name: Install Apache web server service: name=httpd enabled=true state=started |
While the playbook will run without any issues, this shorthand form is generally discouraged as it is hard to read and follow through.
Stacking the task’s keyword vertically is highly encouraged as it makes it easier to follow along as shown.
1 2 3 4 5 6 |
- tasks: name: Install Apache web server service: name:httpd enabled:true state:started |
And that’s it for this Chapter. We hope you gained valuable insights on how to implement Ansible Playbooks. We will come back with the next article soon.
-
DevOps55 years ago
Saltstack Tutorial for beginners [2023]
-
DevOps55 years ago
How to build a Docker cron job Container easily [2023]
-
Linux55 years ago
mail Command in Linux/Unix with 10+ Examples [2023]
-
DevOps55 years ago
Docker ADD vs COPY vs VOLUME – [2023]
-
DevOps55 years ago
How to setup Pritunl VPN on AWS to Access Servers
-
Linux55 years ago
Grep Command In Unix/Linux with 25+ Examples [2023]
-
Linux55 years ago
How To setup Django with Postgres, Nginx, and Gunicorn on Ubuntu 20.04
-
Linux55 years ago
Find command in Unix/Linux with 30+ Examples [2023]