How to setup Ansible in Ubuntu? In this tutorial, we are going to learn how to install and setup Ansible on Ubuntu 20.04/Ubuntu 22.04. Ansible is a simple agentless IT automation tool. It handles configuration management, application deployment, cloud provisioning, ad-hoc task execution, network automation, and multi-node orchestration over the SSH protocol. Ansible makes complex changes like zero-downtime rolling updates with load balancers easy.
Installing Ansible on Ubuntu 20.04/Ubuntu 22.04
Since Ansible is used to manage remote hosts via SSH protocol, the node on which you install Ansible, becomes the control node
and the node which you will manage using Ansible is called managed hosts
.
Run System Update
Before you can proceed, ensure that your system package cache is up-to-date;
sudo apt update
Install Ansible on Ubuntu 20.04/Ubuntu 22.04
There different methods you can use to install Ansible on Ubuntu 20.04/Ubuntu 22.04 systems;
Install Ansbile using PIP on Ubuntu
To install Ansbile using Python PIP command, proceed as follows;
Ensure that PIP is available on the system;
python3 -m pip -V
Such an output should be printed if PIP is available;
pip 22.3.1 from /usr/local/lib/python3.8/dist-packages/pip (python 3.8)
If PIP is available, then you can proceed to install Ansible.
Otherwise, install PIP before you can proceed;
apt install python3-pip
If PIP is already installed, you might want to upgrade it;
python3 -m pip install --upgrade pip
With PIP being available on the system, you can install Ansbile for the current user only by running the command below;
python3 -m pip install --user ansible
All the Ansible binaries are installed in ‘$HOME/.local/bin
‘ which is not on PATH.
You can add this path to PATH environment variable temporarily using;
export PATH=$PATH:~/.local/bin
Or load it when you start your shell (if using bash);
echo "export PATH=$PATH:~/.local/bin" >> ~/.bashrc
source ~/.bashrc
Or, you simply install Ansible for system wide users using the command below;
sudo python3 -m pip install ansible
Check Ansible version;
ansible --version
ansible [core 2.14.2]
config file = None
configured module search path = ['/home/kifarunix/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/kifarunix/.local/lib/python3.10/site-packages/ansible
ansible collection location = /home/kifarunix/.ansible/collections:/usr/share/ansible/collections
executable location = /home/kifarunix/.local/bin/ansible
python version = 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] (/usr/bin/python3)
jinja version = 3.0.3
libyaml = True
Install Ansible using APT Package Manager
Ubuntu default repos provides Ansible packages. However, such packages may not be up-to-date.
To check available versions of the Ansible package, run the command below;
sudo apt-cache policy ansible
Sample output from Ubuntu 20.04;
ansible:
Installed: (none)
Candidate: 2.9.6+dfsg-1
Version table:
2.9.6+dfsg-1 500
500 http://us.archive.ubuntu.com/ubuntu focal/universe amd64 Packages
You can as well install Ansible PPA repos that will also provide latest Ansible packages;
apt -y install software-properties-common
sudo apt-add-repository ppa:ansible/ansible --yes
You can then install Ansible by executing the command below;
sudo apt install ansible
Once the installation is done, you can check the version of install Ansible as follows;
ansible --version
Setting up Ansible on Control Node
Now that Ansible is installed on an Ubuntu 20.04/Ubuntu 22.04 control node, it is time to set it up to enable you automate deployment of your tasks on the managed remote hosts via SSH protocol.
Setup Ansible Inventory
An Ansible inventory is a file that list or defines the hosts to be managed via Ansible. /etc/ansible/hosts
is the default Ansible inventory file. It is also possible to define a custom file as your Ansible inventory file. When you use a non-default inventory file, you have to specify the path to it with -i <path>
option while running ansible.
An inventory file can also be used to store variable values that relate to a specific host or group in inventory.
In the inventory file:
- you can specify the details of the hosts using resolvable hostnames or IP addresses,
- A group of hosts are delimited by
[header]
elements - A hostname/IP address can be a member of multiple groups
See examples below to create a hosts file with ungrouped hosts, grouped hosts and a range of hosts.
In this tutorial, I will create my inventory in my home directory.
mkdir $HOME/ansible
vim $HOME/ansible/hosts
NOTE: Any individual host, (Ungrouped hosts),should be specified before any group headers.
# Ungrouped list of hosts
server01.kifarunix-demo.com
192.168.58.5
# Range of hosts
192.168.56.[111:112]
[webapps]
app[01:04].kifarunix-demo.com
# Grouped Hosts
[database]
db[01:03].kifarunix-demo.com
db05.kifarunix-demo.com
db07.kifarunix-demo.com
Save and exit the file.
You can list the hosts in your inventory using the ansible-inventory
command. For example, to display the contents of our hosts list above in YAML format;
ansible-inventory -i $HOME/ansible/hosts --list -y
all:
children:
database:
hosts:
db01.kifarunix-demo.com: {}
db02.kifarunix-demo.com: {}
db03.kifarunix-demo.com: {}
db05.kifarunix-demo.com: {}
db07.kifarunix-demo.com: {}
ungrouped:
hosts:
192.168.56.111: {}
192.168.56.112: {}
192.168.58.5: {}
server01.kifarunix-demo.com: {}
webapps:
hosts:
app01.kifarunix-demo.com: {}
app02.kifarunix-demo.com: {}
app03.kifarunix-demo.com: {}
app04.kifarunix-demo.com: {
Read more on how to build ansible inventory.
Setting up Ansible SSH key authentication
Generate SSH Keys
Use of passwordless SSH key authentication is one of the common methods that by default Ansible uses for managing remote hosts. Therefore, you need to generate passwordless SSH key and copy the keys to the remote hosts your want to manage with Ansible.
ssh-keygen
For passwordless SSH key generation, simply press ENTER for empty password.
Generating public/private rsa key pair.
Enter file in which to save the key (/home/koromicha/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/koromicha/.ssh/id_rsa
Your public key has been saved in /home/koromicha/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:Ba9LyP0epsCPIVN5nvIVT9zgnLCRL1P/dmgiAvWjbMc koromicha@koromicha
The key's randomart image is:
+---[RSA 3072]----+
| . |
| o . |
| . * o |
| . = + X = |
| * S B B o |
| o * * B o |
| o = O E o o +|
| o O B o o ..|
| . + . |
+----[SHA256]-----+
Read more about other connection methods on Ansible connection plugins page.
Copy the keys to remote hosts
Next, copy the keys to the remote hosts. Use a remote user with sudo rights.
for i in 192.168.58.5 192.168.56.111 192.168.56.112; do ssh-copy-id -o StrictHostKeyChecking=no johndoe@$i; done
In this demo, we will be using a user with passwordless sudo rights. To enable a user to run commands with sudo without being prompted for password, run the command below on the remote hosts being managed.
echo "johndoe ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/johndoe
Read more on Ansible privileges escalation page.
Test Ansible Connection to Remote Hosts
Ansible uses ping module to verify the reachability to the remote hosts defined on the inventory file. Below is our test inventory;
ansible-inventory -i $HOME/ansible/demo --list -y
all:
children:
centos:
hosts:
192.168.56.111: {}
192.168.56.112: {}
ungrouped: {}
To test the connection, as user johndoe
, whose keys we copied above;
ansible -i $HOME/ansible/demo -m ping -u johndoe all
192.168.56.111 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
192.168.56.112 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
Both 192.168.56.111 and 192.168.56.112 are CentOS 8 servers.
Running Ansible ad-hoc commands
If you have tasks that you would rarely repeat, ad-hoc commands come in so handy. With ad-hoc commands, you can manage user accounts, services, packages, run ad-hoc system commands like check free RAM, gather system facts.
To see a few examples, check if the remote systems have internet connectivity using ping command;
ansible -i $HOME/ansible/demo -a "ping 8.8.8.8 -c 3" all -u johndoe
To check free memory;
ansible -i $HOME/ansible/demo -a "free -h" all -u johndoe
192.168.56.112 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 818Mi 234Mi 196Mi 10Mi 387Mi 444Mi
Swap: 819Mi 0B 819Mi
192.168.56.111 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 818Mi 230Mi 214Mi 10Mi 373Mi 452Mi
Swap: 819Mi 0B 819Mi
To install a package, for example a vim editor, as user johndoe
with sudo rights (--become
);
ansible -i $HOME/ansible/demo -m apt -m yum -a "name=vim state=present" all -u johndoe --become
Read more about ad-hoc commands on Introduction to ad-hoc commands.
Using Ansible Playbooks
Playbooks are Ansible’s configuration, deployment, and orchestration language. They define roles and tasks (a set of steps to take to set up a specific process) to be executed on the remote hosts.
In this demo, we will cover two simple examples of playbooks;
So before we can proceed, create Ansible roles directory. Ansible Roles defines a collections of variables, tasks, files, templates and any other ansible artefacts.
For our example, we will have two roles, useraccount
and apache
, for defining what user account to create and the package to be installed.
Below is our simple sample Roles directory structure;
myplaybooks
site.yml
roles/
useraccounts
tasks/
main.yml
webserver/
tasks/
main.yml
To create the relevant directories as per above structure;
mkdir -p myplaybooks/roles/{useraccounts/tasks,webserver/tasks}
Create master playbook, site.yml to define values that will be applicable to all other tasks;
vim myplaybooks/site.yml
---
#
# A common Playbook to Create a user accounts.
#
- hosts: all
remote_user: johndoe
become: yes
roles:
- useraccounts
- webserver
Ansible Playbook to Create User Account
The playbook for creating user account is as per my roles directory structure above. So create a file in which you will define particulars of a user to be created.
vim myplaybooks/roles/useraccounts/tasks/main.yml
---
#
# Create a user account
#
- name: Add User Jane Doe to the system
user:
name: janedoe
password: "{{ 'strongpassword' | password_hash('sha512') }}"
groups: wheel
shell: /bin/bash
comment: Jane Doe
expires: 1584993090
Ansible Playbook to Install Apache Web server
Similarly, create task file for installing Apache web server on Ubuntu 20.04 and CentOS 8 systems;
vim myplaybooks/roles/webserver/tasks/main.yml
---
#
# Install Apache Web server on CentOS 8
#
- name: Install Apache on CentOS 8
yum:
name: httpd
update_cache: yes
state: latest
To list master Ansible Playbook tasks;
ansible-playbook myplaybooks/site.yml --list-tasks -i demo
playbook: myplaybooks/site.yml
play #1 (all): all TAGS: []
tasks:
useraccounts : Add User Jane Doe to the system TAGS: []
webserver : Install Apache on CentOS 8 TAGS: []
Running Ansible Playbook Dry Run checks
To check your playbook without making any changes on the remote host, use the --check
option.
ansible-playbook myplaybooks/site.yml --check -i $HOME/ansible/demo
PLAY [all] *****************************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [192.168.56.112]
ok: [192.168.56.111]
TASK [useraccounts : Add User Jane Doe to the system] **********************************************************************************************************************
changed: [192.168.56.112]
changed: [192.168.56.111]
TASK [webserver : Install Apache on CentOS 8] ******************************************************************************************************************************
changed: [192.168.56.111]
changed: [192.168.56.112]
PLAY RECAP *****************************************************************************************************************************************************************
192.168.56.111 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.56.112 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Executing Ansible Playbook
Once you have verified that there is not error with the checks above, proceed to execute the playbook;
ansible-playbook myplaybooks/site.yml -i $HOME/ansible/demo
PLAY [all] *****************************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [192.168.56.112]
ok: [192.168.56.111]
TASK [useraccounts : Add User Jane Doe to the system] **********************************************************************************************************************
changed: [192.168.56.111]
changed: [192.168.56.112]
TASK [webserver : Install Apache on CentOS 8] ******************************************************************************************************************************
changed: [192.168.56.111]
changed: [192.168.56.112]
PLAY RECAP *****************************************************************************************************************************************************************
192.168.56.111 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.56.112 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verify User Account Creation and Package installed using Ansible
You can create yet another master playbook to verify if user account for janedoe is created as well as checking is Apache is installed by checking its service if available. Both of these can be checked using Ansible getent module.
vim myplaybooks/check.yml
---
- hosts: centos
remote_user: johndoe
become: yes
gather_facts: no # or it will fail on the setup step
tasks:
- name: Check if user Jane Doe (janedoe) is created.
getent:
database: passwd
key: janedoe
- name: Check if Apache service exists.
getent:
database: services
key: http
Execute the playbook;
ansible-playbook myplaybooks/check.yml -i $HOME/ansible/demo
PLAY [centos] **************************************************************************************************************************************************************
TASK [Check if user Jane Doe (janedoe) is created.] ************************************************************************************************************************
ok: [192.168.56.112]
ok: [192.168.56.111]
TASK [Check if Apache service exists.] *************************************************************************************************************************************
ok: [192.168.56.112]
ok: [192.168.56.111]
PLAY RECAP *****************************************************************************************************************************************************************
192.168.56.111 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.56.112 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
And there you go.
That marks the end of our tutorial on how to install and setup Ansible on Ubuntu 20.04. We hope this was informative. Enjoy.
Further Reading
Other Tutorials
Install and Deploy Kubernetes Cluster on Ubuntu 20.04