How to Install and Configure Ansible on Ubuntu 22.04

Ansible is a very popular configuration management tool designed to streamline the process of controlling a large number of servers. It can automate the process of setting up new servers and installing applications with a single command or file. You can control as many servers and run processes on them simultaneously from a single node. Ansible doesn't require any special software required to be installed on the server nodes and can control them over SSH.

In this guide, we will learn how to install and configure Ansible on an Ubuntu 22.04 server.

Prerequisites

  • Two or more server systems running Ubuntu 22.04 with OpenSSH server installed.
  • Both the server and nodes are accessible via public IP addresses.
  • A non-root user with sudo privileges is set up on the Ansible server and a root user with a password is set up on the Ansible clients.

Step 1 - Install Ansible

We will use Ansible's official repository to install its latest version. Add Ansible's official repository to the server.

$ sudo add-apt-repository ppa:ansible/ansible

Fortunately, Ubuntu ships with Ansible 2.9 which is what we will install. Run the following command to install Ansible.

$ sudo apt install ansible -y

Test your installation by running the following command.

$ ansible --version
ansible [core 2.13.3rc1]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/navjot/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/navjot/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.4 (main, Jun 29 2022, 12:14:53) [GCC 11.2.0]
  jinja version = 3.0.3
  libyaml = True

Install and activate the python3-argcomplete package to set up Ansible bash completion support.

$ sudo apt install python3-argcomplete
$ sudo activate-global-python-argcomplete3

You can now press the Tab key to get a list of options for the bash shell.

Step 2 - Setting up Inventory File

To be able to connect to multiple hosts, you need a file that will record the details of the nodes. This file is called the Inventory file.

Depending on how many servers you want to control, Ansible's Inventory file also allows you to arrange them in groups and subgroups. You can also set custom variables applicable to select hosts or groups which can be further used while passing on the instructions.

Ansible ships with a default Inventory file available at /etc/ansible/hosts. Open it with the Nano editor.

$ sudo nano /etc/ansible/hosts

Paste the following code at the bottom of the file.

[servers]
server1 ansible_host=203.0.113.111
server2 ansible_host=203.0.113.112
server3 ansible_host=203.0.113.113

[all:vars]
ansible_python_interpreter=/usr/bin/python3

The servers section defines the list of nodes you want to connect to. You can create as many groups to arrange servers in multiple groups.

The all:vars group sets the ansible_python_interpreter parameter on all the hosts in the inventory. It makes sure that Ansible uses Python 3 executable instead of Python 2 which has been removed from recent Ubuntu versions.

When you’re finished, save the file by pressing Ctrl + X and entering Y when prompted to confirm your changes.

Note: You can also create your Inventory file in any location of your choice which you can then pass off by using the -i parameter while running Ansible commands.

You can check your inventory list by the following command.

$ ansible-inventory --list -y
all:
  children:
    servers:
      hosts:
        server1:
          ansible_host: 203.0.113.111
          ansible_python_interpreter: /usr/bin/python3
        server2:
          ansible_host: 203.0.113.112
          ansible_python_interpreter: /usr/bin/python3
        server3:
          ansible_host: 203.0.113.113
          ansible_python_interpreter: /usr/bin/python3
    ungrouped: {}

Organizing Servers into Groups and Subgroups

This is a useful tip if you have a lot of servers with some servers performing specific functions. For example, you can use this method to group web servers and database servers separately. You can even make a host part of multiple groups. To achieve that, your inventory file should look something like the following.

[webservers]
203.0.113.111
203.0.113.112

[dbservers]
203.0.113.113
server_hostname

[development]
203.0.113.111
203.0.113.113

[production]
203.0.113.112
server_hostname

Step 3 - Set up SSH Keys

For Ansible to be able to connect to the servers, you must configure SSH keys between your Ansible server and hosts specified in the inventory file. This will work only if the Ansible clients don't have a public key enabled and have a root account enabled with a password.

Use the following steps to create and set up an SSH key for Ansible and its nodes.

Create the key for Ansible.

$ ssh-keygen -t rsa -b 4096 -C "Ansible key"

Copy the public key to your accounts on the remote servers. For this, we will use the ssh-copy-id command.

$ ssh-copy-id -i $HOME/.ssh/id_rsa.pub [email protected]
$ ssh-copy-id -i $HOME/.ssh/id_rsa.pub [email protected]
$ ssh-copy-id -i $HOME/.ssh/id_rsa.pub [email protected]

That's all. Now Ansible should be able to talk to your servers.

Setup SSH Keys on Nodes with existing Public Key

If the clients already have public keys enabled, then you will have to follow certain extra steps. For that, you need to create a new user accessible only by Ansible on every node server. That user will have sudo privileges accessible without a password and can be accessed only from your ansible server.

To create a ansible user, run the following command.

$ sudo adduser ansible

Choose a strong password and leave all the other fields empty.

Now, configure password-less sudo access to this user through the following command.

$ echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible

Now, that you have the new user added and configured, you can copy the SSH key from your ansible server to the node server using the following command.

$ ssh-copy-id [email protected]

You will be prompted a password for the ansible user. Enter it and the SSH key will be copied.

Next, disable the password-based login for the ansible user on the node server.

$ sudo usermod -L ansible

Now, your node server is only accessible from the Ansible server since only that server has the public key for it and you can't use it with sudo privileges on the node server directly since password login is disabled.

You will have to repeat these steps for each node server. Also, replace the root user with the ansible user in this tutorial.

Step 4 - Test Connection

After setting up the inventory file and SSH keys, we should check if Ansible can connect to the servers.

Type the following command to check the connection. This command will test the connection to all the servers from the inventory file.

$ ansible all -m ping -u root

This command uses Ansible's ping module to run a connectivity test on all the servers. You should get an output like the following.

server1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
server2 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
server3 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

If this is the first time you are using Ansible, you will be asked to confirm the authenticity of all the servers. When prompted, type yes and press ENTER to confirm.

Step 5 - Run Some basic commands

Let us run some basic commands on the servers using Ansible. To run any command on the server, the following format is used.

$ ansible all -a "command" -u <username>

Check Disk Usage

First, let us check disk usage on all our servers.

$ ansible all -a "df -h" -u root
server1 | CHANGED | rc=0 >>
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           198M  972K  197M   1% /run
/dev/sda2        50G  3.9G   44G   9% /
tmpfs           989M     0  989M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           198M  4.0K  198M   1% /run/user/1000

server2 | CHANGED | rc=0 >>
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           198M  922K  197M   1% /run
/dev/sda2        50G  4.9G   43G  10% /
tmpfs           989M     0  989M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           198M  4.0K  198M   1% /run/user/1000

Target Individual Hosts and Groups

Until now, we were running commands on all remote servers at once. But that is not always the case. To run a command on just one server, you should use the following format.

$ ansible server1 -a "uptime" -u root
server1 | CHANGED | rc=0 >>
 21:38:26 up 11 min,  2 users,  load average: 0.00, 0.20, 0.19

The above command checks the uptime on server1 from the inventory group.

You can also target multiple servers using the following format.

$ ansible server1:server2 -m ping -u root

You can also target groups or subgroups from the inventory file directly.

$ ansible groupname -m ping -u <username>

Update all servers

For this tutorial, we are assuming all the remote servers are running Debian or Ubuntu OS.

Run the following command to update the software on all your servers.

$ ansible all -m apt -a "update_cache=yes upgrade=yes" -u root

The -m parameter defines the module for Ansible to run. The -a parameter refers to the arguments or commands for the associated module. Here, we are using the apt module of Ansible to update servers just like we used the ping module in our last example. The update_cache updates the APT cache on the server and upgrade=yes tells Ansible to run the apt upgrade command.

If you are using the ansible user as documented above, you need to modify the ansible command to run with elevated sudo privileges.

$ ansible server2 -m apt -a "update_cache=yes upgrade=yes" -K -b -u ansible

Here, -K asks for a privilege escalation password. -b runs the ansible operation with become which allows you to be another user. Both variables combined allow ansible to run with elevated sudo privileges. You will need to use this for all commands which require sudo privileges.

Sometimes, some of these update commands may require a reboot so run the following command to reboot all your servers.

$ ansible all -a "reboot" -u root

These were just some of the basic commands you can run using Ansible.

Step 6 - Introduction to Playbooks

The above commands allow you to run one-off tasks but if you want to set up multiple servers or run the same sequence of commands on multiple servers, you need to set up playbooks. Playbooks are files written in YAML and contain instructions to automate a sequence of tasks for setting up applications and services.

We will now create a playbook to install Nginx and set up an HTML page on the Ansible node. Create a directory for Ansible in your home directory.

$ mkdir ~/ansible

Create and open the playbook file for editing.

$ cd ~/ansible
$ nano testplaybook.yml

Playbooks use the YAML format to define one or more plays. A play is a set of ordered tasks arranged in a way to automate a process. The plays are defined as a YAML list.

The first step to define a play is to determine which hosts are the target using the hosts: all directive. The become directive is used to indicate that the following tasks must be executed by a super user.

We will define three tasks: one to add a user, one to upgrade all the packages, and the last one to install the Nginx server. The vars section of the playbook is used to define custom variables. We define two variables, one for the user we need to add, and the second one to define the state of the package we need to install. To use the variable, we need to enclose the variable name between double curly brackets.

The ansible.builtin.user module is used to add a new user with sudo privileges. To add the user, we are using the name, password and the group variables. The group variable is set to sudo to give superuser permissions to the user. You can't put the plaintext-password in the playbook file, therefore, we will add an SHA hashed secret. We will use the mkpasswd utility for that. To install it, run the following command to install the whois package.

$ sudo apt install whois

Generate the hashed password. You will be asked for the usual password and will be given a hashed string for it. Note down the hashed key to be used in the playbook file.

$ mkpasswd --method=sha-512
Password:
$6$dGbprm2oVqClDDDh$Epk6r5eXYkYBaQpQpP.H7VCdz0g9Aj0aO8hjy/WXq4WmfQ7GvQP2/cl/cNhd7.LRFuCKix9uCF2t8X5/Pv0Lk1

The update_cache directive is to update the system's repository list just like the apt update command and the upgrade: dist directive tells Ansible to perform the system upgrade. The third task is self-explanatory which installs the latest version of the Nginx server.

Based on the information we discussed, paste the following code into the file. Paste the hashed key you got as the value for the password variable.

---
- name: Test playbook
  hosts: all
  become: true
  vars:
      state: latest
      user: navjot
  tasks:
  - name: Add the user {{ user }}
    ansible.builtin.user:
      name: "{{ user }}"
      password: '$6$dGbprm2oVqClDDDh$Epk6r5eXYkYBaQpQpP.H7VCdz0g9Aj0aO8hjy/WXq4WmfQ7GvQP2/cl/cNhd7.LRFuCKix9uCF2t8X5/Pv0Lk1'
      group: sudo
  - name: Upgrade all apt packages
    apt:
      update_cache: yes
      upgrade: dist
  - name: Install the {{ state }} of package "nginx"
    apt:
      name: "nginx"
      state: "{{ state }}"

Save the file by pressing Ctrl + X and entering Y when prompted to confirm your changes.

To execute the playbook, run the following command. The --ask-become-pass flag will ask for your root password to perform an elevated operation.

$ ansible-playbook testplaybook.yml --ask-become-pass

You will get the following output.

BECOME password:

PLAY [Test playbook] ***************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
ok: [server1]
ok: [server2]
ok: [server3]

TASK [Add the user casablanca] *****************************************************************************************
changed: [server3]
changed: [server2]
changed: [server1]

TASK [Upgrade all apt packages] ****************************************************************************************
changed: [server1]
changed: [server2]
changed: [server3]

TASK [Install the latest of package "nginx"] ***************************************************************************
changed: [server3]
changed: [server2]
changed: [server1]

PLAY RECAP *************************************************************************************************************
server1                    : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
server2                    : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
server3                    : ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

This confirms that your playbook ran successfully.

If you are using a custom inventory file, you need to include the location of the file in the command as follows.

$ ansible-playbook -i /etc/ansible/custominventory testplaybook.yml --ask-become-pass 

Conclusion

That wraps up our tutorial on installing and configuring Ansible on Ubuntu 22.04 server. If you have any questions, post them in the comments below.

Share this page:

Suggested articles

0 Comment(s)

Add comment