Ansible

Photo by Growtika on Unsplash

Ansible

What is Ansible?

Ansible is simply an open-source IT engine that automates application deployment, intra-service orchestration, cloud provisioning and many other IT tools.

Suppose an organization has hundreds of systems and given one or even a small team of people the responsibility to configure all the systems making their work tough and repetitive. Also, manual work is prone to errors. Comes into picture Ansible, which can automate the configuration of all the systems.

Ansible does so in different ways:

  1. Execute tasks from your machine instead of SSH into all remote servers.

  2. Configuration/Installation/Deployment steps in a single YAML file instead of manual and shell scripts.

  3. Re-use the same file multiple times for different environments.

  4. More reliable and less likely for errors.

Ansible is Agentless

Normally when you want to use some tool on a machine you need to go to that machine and install an agent for that tool. However, to use Ansible you don't have to install anything on the target servers, you just install it on your control machine which could be even your laptop. And that machine can now manage all target machines remotely.

Agentless means that you don't need to install any additional software on the target machines to be able to work with Ansible.

Ansible uses YAML, which is also the reason why it became so popular. So it doesn't require learning any special language.

One of the major disadvantages of most other orchestration tools is that you are required to configure an agent on the target systems before you can invoke any kind of automation.

Ansible Modules

Ansible works with modules. Modules are small programs that do the actual work.

Modules get pushed to the target server by the control machine.

They do their job on the target server like installing an application, stopping a process, applying firewall rules, etc.

Modules are very granular. One module does one small specific task.

Ansible has hundreds of modules and each executes a specific task. You can see the whole list of Ansible modules in the official documentation.

Ansible Playbooks

Ansible playbooks are Ansible's orchestration language. It is in playbooks where we define what we want Ansible to do. It is a set of instructions you provide Ansible.

For example, it can be as simple as running a series of commands on different servers in a sequence and restarting those servers in a particular order or it could be as complex as deploying hundreds of VMs in a public and private cloud infrastructure.

A playbook is a single YAML file containing a set of plays. A play defines a set of activities to be run on a single or a group of hosts.

A task is a single action to be performed on a host. The different actions run by tasks are called modules.

The playbook is a list of dictionaries in YAML terms. Each play is a dictionary and has a set of properties called name, hosts, and tasks. The host parameter indicates which hosts you want these operations to run on.

Here is an example of an Ansible Playbook.

---
  - name: Playbook
    hosts: webservers
    tasks:
      - name: ensure apache is at the latest version
        yum:
          name: httpd
          state: latest
      - name: ensure apache is running
        service:
          name: httpd
          state: started

Ansible Inventory

Ansible can work with one or multiple systems in your infrastructure at the same time. To work with multiple servers, Ansible needs to establish connectivity to those servers. This is done using SSH for Linux and PowerShell remoting for windows. That's what makes Ansible agentless.

Now, information about the target systems is stored in an inventory file. If you don’t create a new inventory file, Ansible uses the default inventory file located at /etc/ansible/host location.

The inventory file is in an INI-like format. It's simply several servers listed one after the other. You can also group different servers.

In inventory files, we have different parameters.

  1. Ansible_host is an inventory parameter used to specify the FQDN or IP Address of a server.

  2. Ansible_connection is what defines how Ansible connects to the target server.

  3. Ansible_port defines which port to connect to.

  4. Ansible_user defines the user used to make remote connections.

  5. Ansible_ssh_pass defines the SSH password for Linux.

Here is an example of Ansible inventory.

[webservers]  
foo.example.com  
bar.example.com  

[dbservers]  
one.example.com  
two.example.com  
three.example.com

Ansible Variables

Variables in Ansible store information that varies with each host.

To add a variable we could simply add a vars directive followed by variables in a key-value pair format.

vars:
   dns_server: 10.1.250.10

We can also have variables defined in a separate file dedicated for variables.

So how do we use variables? Here is an example.

-
   name: Add DNS server to resolv.conf
   hosts: localhost
   vars:
       dns_server: 10.1.250.10
   tasks: 
       - lineinfile:
             path: /etc/resolv.conf
             line: 'nameserver {{ dns_server }}'

Remember that this format we are using to use variables in playbooks is called Jinja2 Templating.

While using variables with Jinja2 Templating, remember to enclose them within quotes. However, if the variable is in between sentences then that is not required.

Ansible Conditionals

We could use the when conditional statement to specify a condition for each task. Only if the condition is true, that task will run.

Here is an example.

- name: Install NGINX
  hosts: all
  tasks:
   - name: Install NGINX on Debian
    apt:
      name: nginx
       state: present
    when:
           ansible_os_family == "Debian"
  - name: Install NGINX on Redhat
    yum:
      name: nginx
       state: present
    when:
           ansible_os_family == "RedHat"

Make sure to use the == sign when checking equality in a conditional statement.

You may use an OR operator to specify either of the two conditions.

AND operator must satisfy both conditions.

You may use conditionals in a loop as well. Here is an example.

- name: Install Softwares
  hosts: all
  vars:
     packages:
         - name: nginx
          required: True
         - name: apache
          required : False
  tasks:
   - name: Install "{{ item.name }}" on Debian
     apt:
       name: "{{ item.name }}"
       state: present
     when: item. required == True
     loop: "{{ packages }}"

Ansible Loops

Look at this example where we are creating an Ansible Playbook to create users in a system using the user module. The user module helps you create users on the target systems.

-
   name: Create users
   hosts: localhost
   tasks:
     - user: name=Virat   state=present

Here we have created just one user. What if we want to create multiple users?

One way to do this would be to duplicate the lines as many times as required.

-
   name: Create users
   hosts: localhost
   tasks:
     - user: name=Virat       state=present
     - user: name=Sachin      state=present
     - user: name=Rohit       state=present
     - user: name=Hardik      state=present
     - user: name=Rishabh     state=present
     - user: name=Rahul       state=present

But this is not an efficient way. A better way to do this would be to have a single task loop over all the users. Here comes into the picture Loops.

Loop is a looping directive that executes the same task a multiple number of times. Each time it runs, it stores the value of each item in the loop in a variable. Consider this example.

-
   name: Create users
   hosts: localhost
   tasks:
     - user: name='{{ item }}'  state=present
       loop:
         - Virat 
         - Sachin
         - Rohit
         - Hardik
         - Rishabh
         - Rahul

So, that was my blog on Ansible. You can check out the official documentation to learn more about it.

Connect with me on Twitter