Configuring Ansible
In a previous article, I covered Red Hat Ansible basics and installed Ansible, creating one control node named RHEL8
and four managed nodes (node1
, node2
, node3
, and node4
), all running Red Hat Enterprise Linux. Now, for Ansible to communicate with a managed node, you need to configure the control node and the managed nodes with a user account, and give that user account privilege escalation to run commands without having to enter a password.
Add a user account to all managed nodes (node1
, node2
, node3
, and node4
) and the control node (RHEL8
). To keep things simple in this example, I will create an ansible
user account, add the ansible
user to the wheel
group, and then configure SSH authentication.
User accounts
When configuring a new user account (in this case, the ansible
user), create the account across all nodes:
[kc@RHEL8 ~]$ sudo useradd ansible
Then add the ansible
user to the wheel
group:
[kc@RHEL8 ~]$ sudo usermod -aG wheel ansible
Set a password for the ansible
user so you can log in as that user:
[kc@RHEL8 ~]$ sudo passwd ansible
Changing password for user ansible.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
Next, configure the ansible
user for passwordless privilege escalation using the /etc/sudoers
file:
%wheel ALL=(ALL) NOPASSWD: ALL
Once you create the new ansible
user on all managed and control nodes, generate an SSH key on the control node and then copy the SSH public key to all managed nodes. In this example, I use the defaults while configuring SSH:
[kc@RHEL8 ~]$ sudo su - ansible
[ansible@RHEL8 ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ansible/.ssh/id_rsa):
Created directory '/home/ansible/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ansible/.ssh/id_rsa.
Your public key has been saved in /home/ansible/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:saD6SI4u47J50N5UmV2UfpZcXhbW6UzhrDH4ksr2z4w ansible@RHEL8
The key's randomart image is:
+---[RSA 2048]----+
| ... +=|
| o . =o+|
| .+.o o *+= |
| .+..o. B =o |
| . .. S = o |
|. ... . . . |
| ooo + |
|+=oo. . . + |
|O*o . E.+ |
+----[SHA256]-----+
Now, copy the SSH public key to all managed nodes, which lets the ansible
user log into all managed hosts without having to enter a password:
[ansible@RHEL8 ~]$ ssh-copy-id ansible@node1.example.com
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ansible/.ssh/id_rsa.pub"
The authenticity of host 'node1.example.com (3.15.137.216)' can't be established.
ECDSA key fingerprint is SHA256:SJMRfA1B8NDEA9BwxE6aiPs30YGS+Sp1eBRtocyK5sY.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
ansible@node1.example.com's password:
Number of key(s) added: 1
Now try logging into the machine with SSH: 'ansible@node1.example.com'"
and check to make sure that only the key(s) you wanted are added.
[ansible@RHEL8 ~]$
Configuration files
The default Ansible configuration file is located under /etc/ansible/ansible.cfg
. Most of Ansible’s settings can be modified using this configuration file to meet the needs of your environment, but the default configurations should satisfy most use cases. Regardless, it is worth knowing where Ansible searches for configuration files.
Ansible searches for configuration files in the following order, processing the first file it finds and ignoring the rest:
$ANSIBLE_CONFIG
if the environment variable is set.ansible.cfg
if it’s in the current directory.~/.ansible.cfg
if it’s in the user’s home directory./etc/ansible/ansible.cfg
, the default config file.
The default inventory file is found inside /etc/ansible/hosts
, but this location can be changed in the configuration file. You can also specify which inventory file to use with the -i
switch.
Your inventory file looks like this:
[nodes]
node1.example.com
node2.example.com
node3.example.com
node4.example.com
[webservers]
node2.example.com
node3.example.com
It is recommended that you specify different host files for various projects.
Ansible ad-hoc commands
An ad-hoc command is a command that you might issue to perform a quick task, but will not use in the immediate future. To appreciate Ansible ad-hoc commands and to help you use Ansible more efficiently, look at some essential Ansible command-line options:
Option | Description |
-b , --become |
Run command with privileges (doesn’t prompt for password). |
-m |
Provide module name to use. |
-a , --args |
Insert module arguments. |
-u |
Connect as different user. |
-h , --help |
Display help content. |
-v , --verbose |
Run commands in verbose mode. |
The complete list of Ansible command-line options can be found here. Now, have a look at some examples.
Checking connectivity with ad-hoc commands
To check connectivity to managed hosts using the ping
module:
[ansible@RHEL8 ~]$ ansible all -m ping
In the above command, all
specifies that Ansible should run this command on all hosts. Here is the response to that command:
[ansible@RHEL8 ~]$ ansible all -m ping
node2.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node1.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node3.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
node4.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[ansible@RHEL8 ~]$
Managing packages with ad-hoc commands
Using Ansible’s ad-hoc commands, you can also install software packages to your managed hosts. All you need to issue is a one-liner to install a single package to a group of managed hosts.
Install the Apache httpd
server on your webservers
managed hosts' group:
[ansible@RHEL8 ~]$ ansible webservers -m yum -a "name=httpd state=present" -b
Managing services with ad-hoc commands
Since you successfully installed Apache’s httpd
server in the last step, see how you can use Ansible’s ad-hoc commands to start and enable the httpd
service, so your Apache httpd
web server is up and running.
In order to enable a service, issue:
[ansible@RHEL8 ~]$ ansible webservers -b -m service -a "name=httpd enabled=yes"
To start, restart, and stop a service, change the value of the state argument to started
to start the service, restarted
to restart a service, and stopped
to stop a service:
[ansible@RHEL8 ~]$ ansible webservers -b -m service -a "name=httpd state=started"
Ansible ad-hoc commands are excellent and suitable for running a single task. A full list of modules can be found here.
Playbooks
Ansible playbooks are a powerful way of using Ansible. Unlike Ansible ad-hoc commands, Ansible playbooks can be saved and reused.
Playbooks are defined in YAML Ain’t Markup Language (YAML). Each playbook is comprised of one or more plays. The goal of plays is to map a group of hosts to tasks. Each play consists of one or more tasks, and these tasks are executed one at a time.
Here is a simple Ansible httpd.yaml
playbook to install Apache’s httpd
server on the webservers
group:
---
- hosts: webservers
remote_user: ansible
tasks:
- name: Ensure apache is installed and updated
yum:
name: httpd
state: latest
become: yes
In order to run this Ansible playbook, issue the following command in the format:
[ansible@RHEL8 ~]$ ansible-playbook -i <hostfile> <playbook.yaml>
Since you're using the default hosts file (/etc/ansible/hosts
), you can ignore -i
flag and just issue the command in the format:
[ansible@RHEL8 ~]$ ansible-playbook <playbook.yaml>
So, for this example:
[ansible@RHEL8 ~]$ ansible-playbook httpd.yaml
PLAY [webservers] *************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************
ok: [node2.example.com]
ok: [node3.example.com]
TASK [Ensure apache is installed and updated] *********************************************************************
changed: [node2.example.com]
changed: [node3.example.com]
PLAY RECAP ********************************************************************************************************
node2.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node3.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[ansible@RHEL8 ~]$
Playbooks are powerful when you need to run multiple tasks on different groups of managed hosts. To demonstrate how you can use more than ad-hoc commands, use a playbook to:
- Install the
httpd
server. - Enable and start the
httpd
service in yourwebservers
managed hosts' group. - Install
git
onall
managed hosts.
The playbook may look something like this:
---
- hosts: webservers
remote_user: ansible
become: yes
tasks:
- name: Installing apache
yum:
name: httpd
state: latest
- name: Enabling httpd service
service:
name: httpd
enabled: yes
notify:
- name: restart httpd
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
- hosts: all
remote_user: ansible
become: yes
tasks:
- name: Installing git
yum:
name: git
state: latest
In the above example, you performed two plays in one playbook. Read more about Ansible playbooks here.
Conclusion
Ansible is simple, easy to set up, and powerful. Ansible is agentless, which makes it easy for a sysadmin to get started with automation and spend less time configuring. With this tool, every sysadmin—irrespective of their experience level—can begin automating their infrastructure in just a few hours, if not minutes. The ease-of-use and robust toolset makes Ansible a highly desirable automation platform to learn.
Keerthi Chinthaguntla
Keerthi is aspiring Cloud, DevOps engineer, he has been working with Windows and Linux systems. He believes in continuous learning (CL) and continuous sharing (CS), on his way building his very own CL CS pipeline. When he is not playing in the CLI, you will find him playing Cricket. More about me