What is Ansible, Why do we use Ansible, Ansible Terminologies

Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.

Ansible’s main goals are simplicity and ease-of-use. It also has a strong focus on security and reliability, featuring a minimum of moving parts, usage of OpenSSH for transport (with other transports and pull modes as alternatives), and a language that is designed around auditability by humans–even those not familiar with the program.

Ansible manages machines in an agent-less manner. There is never a question of how to upgrade remote daemons or the problem of not being able to manage systems because daemons are uninstalled. Because OpenSSH is one of the most peer-reviewed open source components, security exposure is greatly reduced. Ansible is decentralized–it relies on your existing OS credentials to control access to remote machines. If needed, Ansible can easily connect with Kerberos, LDAP, and other centralized authentication management systems.

Ansible releases a new major release of Ansible approximately every two months. The core application evolves somewhat conservatively, valuing simplicity in language design and setup. However, the community around new modules and plugins being developed and contributed moves very quickly, adding many new modules in each release.

Few Advantages of Ansible

  1. Ansible is free and open source.
  2. Agentless. Unlike other tools, ansible doesnt require a master client model. which means, no agent to be installed at the client.
  3. So how does it work? Ansible uses SSH for the operations on the existing network.
  4. System requirement is very low.
  5. Developed in Python. Python is that it is inbuilt into most Unix and Linux deployments nowadays, so getting up and running is quicker.
  6. lightweight and quick deployment. Of-course its lightweight and its very fast to deployment, because it uses the SSH, doesn’t have master client communication compare to other tools.
  7. Ansible uses YAML Syntax in configuration files.
  8. Larger community. Ansible has a large and engaged community of users who can help answer your questions.

Ansible Terminologies

Before playing with ansible, we should have knowledge of its terminologies to understand the functionality.

Playbooks

Playbooks are expressed in YAML format and have a minimum of syntax, Playbooks are the language by which Ansible configures, administers, deploys systems, automate tasks and orchestrates.

Task

Playbooks exist to run tasks. Tasks combine an action with a name and optionally some other keywords (like looping directives). Handlers are also tasks, but they are a special kind of task that do not run unless they are notified by name when a task reports an underlying change on a remote system.

Action

An action is a part of a task that specifies which of the modules to run and which arguments to pass to that module. Each task can have only one action, but it may also have other parameters.

Facts

Facts are simply things that are discovered about remote nodes. While they can be used in playbooks and templates just like variables, facts are things that are inferred, rather than set. Facts are automatically discovered by Ansible when running plays by executing the internal setup module on the remote nodes. You never have to call the setup module explicitly, it just runs, but it can be disabled to save time if it is not needed or you can tell ansible to collect only a subset of the full facts via the gather_subset: option. For the convenience of users who are switching from other configuration management systems, the fact module will also pull in facts from the ohai and facter tools if they are installed. These are fact libraries from Chef and Puppet, respectively. (These may also be disabled via gather_subset:)

Host

A host is simply a remote machine that Ansible manages. They can have individual variables assigned to them, and can also be organized in groups. All hosts have a name they can be reached at (which is either an IP address or a domain name) and, optionally, a port number, if they are not to be accessed on the default SSH port.

Group

A group consists of several hosts assigned to a pool that can be conveniently targeted together, as well as given variables that they share in common.

Handlers

Handlers are just like regular tasks in an Ansible playbook but are only run if the Task contains a notify directive and also indicates that it changed something. For example, if a config file is changed, then the task referencing the config file templating operation may notify a service restart handler. This means services can be bounced only if they need to be restarted. Handlers can be used for things other than service restarts, but service restarts are the most common usage.

Ad Hoc

Refers to running Ansible to perform some quick command, using /usr/bin/ansible, rather than the orchestration language, which is /usr/bin/ansible-playbook. An example of an ad hoc command might be rebooting 50 machines in your infrastructure. Anything you can do ad hoc can be accomplished by writing a playbook and playbooks can also glue lots of other operations together.

Inventory

A file (by default, Ansible uses a simple INI format) that describes Hosts and Groups in Ansible. Inventory can also be provided via an Inventory Script (sometimes called an “External Inventory Script”). So you can define all your hosts in a single file as a Inventory either in the hostname format, ip address or fqdn.

Modules

Modules are the units of work that Ansible ships out to remote machines. Modules are kicked off by either /usr/bin/ansible or /usr/bin/ansible-playbook (where multiple tasks use lots of different modules in conjunction). Modules can be implemented in any language, including Perl, Bash, or Ruby – but can leverage some useful communal library code if written in Python. Modules just have to return JSON. Once modules are executed on remote machines, they are removed, so no long running daemons are used. Ansible refers to the collection of available modules as a library.

Library

A collection of modules made available to /usr/bin/ansible or an Ansible playbook.

Notify

The act of a task registering a change event and informing a handler task that another action needs to be run at the end of the play. If a handler is notified by multiple tasks, it will still be run only once. Handlers are run in the order they are listed, not in the order that they are notified.

Orchestration

Many software automation systems use this word to mean different things. Ansible uses it as a conductor would conduct an orchestra. A datacenter or cloud architecture is full of many systems, playing many parts – web servers, database servers, maybe load balancers, monitoring systems, continuous integration systems, etc. In performing any process, it is necessary to touch systems in particular orders, often to simulate rolling updates or to deploy software correctly. Some system may perform some steps, then others, then previous systems already processed may need to perform more steps. Along the way, emails may need to be sent or web services contacted. Ansible orchestration is all about modeling that kind of process.

Push Mode

Push mode is the default mode of Ansible. In fact, it’s not really a mode at all – it’s just how Ansible works when you aren’t thinking about it. Push mode allows Ansible to be fine-grained and conduct nodes through complex orchestration processes without waiting for them to check in.

Pull Mode

By default, Ansible runs in push mode, which allows it very fine-grained control over when it talks to each system. Pull mode is provided for when you would rather have nodes check in every N minutes on a particular schedule. It uses a program called ansible-pull and can also be set up (or reconfigured) using a push-mode playbook. Most Ansible users use push mode, but pull mode is included for variety and the sake of having choices.

Roles

Roles are units of organization in Ansible. Assigning a role to a group of hosts (or a set of groups, or host patterns, etc.) implies that they should implement a specific behavior. A role may include applying certain variable values, certain tasks, and certain handlers – or just one or more of these things. Because of the file structure associated with a role, roles become redistributable units that allow you to share behavior among playbooks – or even with other users.

Templates

Ansible can easily transfer files to remote systems but often it is desirable to substitute variables in other files. Variables may come from the inventory file, Host Vars, Group Vars, or Facts. Templates use the Jinja2 template engine and can also include logical constructs like loops and if statements.

When(Optional)

An optional conditional statement attached to a task that is used to determine if the task should run or not. If the expression following the when: keyword evaluates to false, the task will be ignored.

YAML

Ansible does not want to force people to write programming language code to automate infrastructure, so Ansible uses YAML to define playbook configuration languages and also variable files. YAML is nice because it has a minimum of syntax and is very clean and easy for people to skim. It is a good data format for configuration files and humans, but also machine readable. Ansible’s usage of YAML stemmed from Michael DeHaan’s first use of it inside of Cobbler around 2006. YAML is fairly popular in the dynamic language community and the format has libraries available for serialization in many languages (Python, Perl, Ruby, etc.).

Ansible Inventory. Target your Systems

Ansible is an automation tool which works for multiple systems in a infrastructure at the same time. So we should have system lists to manage it. we call that as a inventory. Ansible inventory file has the list of all managed host names one line per host. Inventory management is also important factor in Ansible.

oracle-server1.example.com
oracle-server2.example.com

Note : You can define your host names in ipaddress or hostname or fqdn.

By default, this ansible host inventory file is located under /etc/ansible/hosts. Hence if you run a Ansible Playbook or Ansible Ad-hoc commands, that will look the hosts groups under the default file. You can specify a different inventory file using the “-i " option on the command line as shown below.

ansible-playbook -i /root/database_servers install.yml

But remember, We must enable password less SSH authentication between ansible master server host and client hosts, else you would get an error as “Failed to connect to the host via ssh: Permission denied”. Make sure you configure Password-less Login with SSH Keys

Hosts Groups Declaration

You can declare the different groups in single host inventory file. For example, If you have database and web servers, then we can declare the list of server names under each groups.

[database-servers]
oracle-a.example.com
oracle-b.example.com
oracle-c.example.com
oracle-d.example.com
[webservers]
web1.example.com
web2.example.com
web3.example.com

Also, you can simplify the declaration more, if you have similar hostname starts with same characters.

[database-servers]
oracle-[a-d].example.com 
[webservers]
web[1-3].example.com

Either in alphabetic format or numeric format.

Note : A host can be in more than one group.

Inventory File Parameters

By default, Ansible works on SSH port number 22. if you have different port to connect the hosts, then define the hosts as below.

web1.example.com:4301

You can also define the connection type and also user depend on the target hosts:

[webservers]
web1.example.com     ansible_connection=ssh        ansible_user=mjohn
web2.example.com     ansible_connection=ssh        ansible_user=peter

As shown above, some of the ansible parameters mentioned below can be used on need and these are commonly used parameters. You can get more parameters from ansible.org.

Ansible Configuration File

Default Ansible Configuration file is /etc/ansible/ansible.cfg

[root@node1 ~]# vi /etc/ansible/ansible.cfg
# config file for ansible -- https://ansible.com/
# ===============================================
# nearly all parameters can be overridden in ansible-playbook
# or with command line flags. ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory or /etc/ansible/ansible.cfg, whichever it
# finds first
[defaults]
# some basic default values...
#inventory      = /etc/ansible/hosts
#library        = /usr/share/my_modules/
#module_utils   = /usr/share/my_module_utils/
#remote_tmp     = ~/.ansible/tmp
#local_tmp      = ~/.ansible/tmp
#forks          = 5
#poll_interval  = 15
#sudo_user      = root
#ask_sudo_pass = True
#ask_pass      = False
.
.
.
#..... more......

This ansible configuration file has many parameters like inventory file location, library location, modules and etc,. All these default values are commented. If you wanted to change the default behavior of any parameter, just uncomment and change the value.

Multiple Ansible configuration files

Ansible has the flexibility to have multiple configuration file. So changing the single configuration file for every time is not required depend on the environment.

Ansible will find the configuration file as below whichever it finds first

  1. Environment variable ANSIBLE_CONFIG set or not, (example: ANSIBLE_CONFIG=/root/ansible.cfg)
  2. Find ansible.cfg in the current working directory if Environment variable ANSIBLE_CONFIG not set. Hence you can create dedicated directory for different environments.
  3. Find ansible.cfg in the home directory if Environment variable ANSIBLE_CONFIG not set and no ansible.cfg file in the current working directory.
  4. Find /etc/ansible/ansible.cfg.

Ansible Adhoc command with examples

An Ansible ad-hoc commands can be used to do some quick task to perform some simple operations through the command line.

But real automation works using playbooks only. You may ask me if playbook is the real automation then Why do we use ad-hoc commands.

Answer is so simple, Every-time you may not needed to perform a big operations, Some time we are required to perform some simple tasks. So we don’t need to write a big playbooks. Also ad-hoc command is a easiest way to explore Ansible.

Assume that, you wanted to restart or power off all of your infrastructure servers or if you wanted to get an uptime of all servers or to get an kernel versions or os information something like a small and quick tasks. On that cases, you can use a ad-hoc commands instead of writing a playbooks. Playbooks can be used to do a many tasks.

For example, if you want to install http web server, you are required to perform some multiple tasks.

  1. Install a httpd package
  2. Configuring the webserver
  3. Starting and Enabling the httpd service.

For this kind of multiple task, you can write a playbook and execute it.

Syntax of ad-hoc command is

command hostgroup module/options[arguments]

Where
command is ansible
host group - It specifies on what machines, task to be performed
module or arguments - What actions to be performed.

Lets take an example. Assume that, you wanted to get a uptime of a list of hostgroup named “servers” as per specified in Ansible Inventory host file.

[root@localhost ~]# ansible servers -a "uptime"
node1 | SUCCESS | rc=0 >> 21:53:10 up 7 min,  2 users,  load average: 0.49, 0.35, 0.20
node2 | SUCCESS | rc=0 >> 21:53:10 up 7 min,  1 user,  load average: 0.01, 0.04, 0.05

Here we have used ‘-a’ option rather than using a direct modules. This would execute a command ‘uptime’ on hostgroup “servers” and will give you the output of uptime in the screen.

Let me now demonstrate you the use of module. Here I will use a module ping to check weather a server is alive.

[root@localhost ~]# ansible servers -m ping
node1 | SUCCESS => 
{    "changed": false,    
     "failed": false,    
     "ping": "pong" 
}

Here we have used a module “ping” with option “-m”.

Some commonly used modules are apt/yum, copy, ec2, file, service, template, and user.

To know the list of available modules in ansible, execute the command.

[root@localhost ~]# ansible-doc -l | more
apk                                                  Manages apk packages                                                                                            
apt                                                  Manages apt-packages                                                                                            
apt_key                                              Add or remove an apt key                                                                                        
apt_repository                                       Add and remove APT repositories                                                                                 
apt_rpm                                              apt_rpm package manager                                                                                         
archive                                              Creates a compressed archive of one or more files or trees                                                      
aruba_command                                        Run commands on remote devices running Aruba Mobility Controller                                                
aruba_config                                         Manage Aruba configuration sections                                                                             
asa_acl                                              Manage access-lists on a Cisco ASA                                    

Documentation for each module can be accessed from the command line with the ansible-doc tool. To know the required arguments and also to get a help of a particular module. Execute the below command.

[root@localhost ~]# ansible-doc modulename
Example 1: Using module, Create a user called “john” using a module “user”.
[root@localhost ~]# ansible servers -m user -a "name=john password=redhat"
node1 | SUCCESS => 
{   "changed": true,
    "comment": "",
    "createhome": true,
    "failed": false,
    "group": 1000,
    "home": "/home/john",
    "name": "john",
    "password": "NOT_LOGGING_PASSWORD",
    "shell": "/bin/bash",
    "state": "present",
    "system": false,
    "uid": 1000
}

Where,
-m is a option to use a module
user is a module name to manage the user accounts
-a is options to pass the arguments “name=john password=redhat

Above command will create a user call “john” in all the servers mentioned in Ansible Inventory file.

Example 2: Without using a module “yum”, install a httpd package.
[root@localhost ~]# ansible all -a "yum -y install httpd"

Where, -a is a option to pass the argument. If no module is specified, then it consider that as a comand and execute at the client servers.

Example 3: Using a module “yum’, install a httpd package.
[root@localhost ~]# ansible all -m yum -a "name=httpd state=present"

That’s all about the basics of Ansible Ad-hoc command how to use. This would help you when we write playbook.

Ansible Playbook. What is that?

Ansible playbooks are a way to send commands to remote computers in a scripted way. Instead of using Ansible commands individually to remotely configure computers from the command line, you can configure entire complex environments by passing a script to one or more systems.

Ansible playbooks are written in the YAML data serialization format. If you don’t know what a data serialization format is, think of it as a way to translate a programmatic data structure (lists, arrays, dictionaries, etc) into a format that can be easily stored to disk. The file can then be used to recreate the structure at a later point. JSON is another popular data serialization format, but YAML is much easier to read.

Each playbook contains one or more plays, which map hosts to a certain function. Ansible does this through something called tasks, which are basically module calls.

How to create an Ansible Playbook?

Create a playbook with a file name, not necessary to have the filename with any extension. but create with extension with “.yml” else you wont find the difference of normal text file and a playbook.

The file starts with: - - -

[root@ansiblenode ~]# vi install.yml
---
- hosts: all
  sudo: true
  vars:
     packages: [ 'vim', 'git', 'curl' ]
  tasks:
  - name: Install Package
    apt: name="{ item }" state=latest
    with_items: packages

- hosts: all
  tasks:
     - name: Install httpd Package
       apt: name=httpd state=latest

This is a requirement for YAML to interpret the file as a proper document. YAML allows multiple “documents” to exist in one file, each separated by “- - -”, but Ansible only wants one per file, so this should only be present at the top of the file.

YAML is very sensitive

We should be more cautious with the spaces while writing a ansible playbook. Tabs are not allowed here. Character should start exactly or after the previous parameter starts and it should looks like a statement as shown in the above examples.

Basically Playbooks consists of three sections:

  1. Host declaration : It defines that on which server groups playbook should run based on the ansible inventory file.
  2. Variable declaration (optional): Declare variables for your Playbook.
  3. Action / Tasks Declaration : You specify the list of tasks to be carried out.

Lets say configuring a basic Apache Web-server and the following tasks are required.

  1. Installing a httpd packages
  2. Configuring the httpd service
  3. Starting and Enabling httpd service

So lets create the playbook with the above tasks.

[root@ansiblenode ~]# vi install.yml
---
- hosts: all
  tasks:
  - name: Install httpd Package
    yum: name=httpd state=latest
  - name: Copy httpd configuration file
    copy: src=/data/httpd.original dest=/etc/httpd/conf/httpd.conf
  - name: Start and Enable httpd service
    service: name=httpd state=restarted enabled=yes

Let’s do syntax check to ensure there is no syntax error using below command.

[root@ansiblenode ~]# ansible-playbook install.yml --syntax-check
playbook: install.yml

Run a playbook and configure the httpd service.

[root@ansiblenode ~]# ansible-playbook install.yml
PLAY [all] *****************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************
ok: [server1]
TASK [Install httpd Package] ***********************************************************************************
changed: [server1]
TASK [Copy httpd configuration file] ***************************************************************************
ok: [server1]
TASK [Start and Enable httpd service] **************************************************************************
changed: [server1]
PLAY RECAP *****************************************************************************************************
server1                    : ok=4    changed=2    unreachable=0    failed=0

Variable Declarations

Instead of creating 10 tasks for installing 10 different packages, you can create a single task by using variables in a same playbook as below,

vars:
     package: vim,yum-utils
tasks:
     - name: Install Package
       yum: name='{ package }' state=latest

Notify and Handlers in Ansible Playbook

[root@ansiblenode ~]# vi install.yml
---
- hosts: all
  tasks:
  - name: Install httpd Package
    yum: name=httpd state=latest
  - name: Copy httpd configuration file
    copy: src=/data/httpd.original dest=/etc/httpd/conf/httpd.conf
    notify:
    - restart apache
  - name: Start and Enable httpd service
    service: name=httpd state=restarted enabled=yes
  handlers:
  - name: restart apache
    service: name=httpd state=restarted

The “notify” item contains a list with one item, which is called “restart apache”. This is not an internal Ansible command, it is a reference to a handler, which can perform certain functions when it is called from within a task. We will define the “restart apache” handler below the playbook.

The “handlers” section exists at the same level as the “hosts” and “tasks”. Handlers are just like tasks, but they only run when they have been told by a task that changes have occurred on the client system.

Ansible Roles for Creating Clean Code

  1. Ansible roles consists of many playbooks, which is similar to modules in puppet and cook books in chef.
  2. Roles allow you to create very minimal playbooks that then look to a directory structure to determine the actual configuration steps they need to perform.
  3. Roles are set of tasks and additional files which allow you to break up the configurations.
  4. An Easy way to share your Ansible Code.
  5. Organizing things into roles also allows you to reuse common configuration steps between different types of servers.

Create a Role

To create a Ansible roles, use ansible-galaxy command which has the templates to create it. This will create it under the default directory /etc/ansible/roles and do the modifications else we need to create each directories and files manually.

[root@learnitguide ~]# ansible-galaxy init /etc/ansible/roles/apache --offline
- apache was created successfully

where,
ansible-galaxy is the command to create the roles using the templates,
init is to initialize the role,
apache is the name of role created at /etc/ansible/roles/ location,
offline is to create offline mode rather than getting from online repo of Ansible Galaxy.

List out the directory created under /etc/ansible/roles.

[root@learnitguide ~]# tree /etc/ansible/roles/apache/
/etc/ansible/roles/apache/
|-- README.md
|-- defaults
|   `-- main.yml
|-- files
|-- handlers
|   `-- main.yml
|-- meta
|   `-- main.yml
|-- tasks
|   `-- main.yml
|-- templates
|-- tests
|   |-- inventory
|   `-- test.yml
`-- vars
    `-- main.yml
8 directories, 8 files

We have got the clean directory structure. Each directory must contain a main.yml file, which contains the relevant content.

Directory Structure of Ansible Role

tasks - contains the main list of tasks to be executed by the role.
handlers - contains handlers, which may be used by this role or even anywhere outside this role.
defaults - default variables for the role.
vars - other variables for the role. Vars has the higher priority than defaults.
files - contains files required to transfer or deployed to the target machines via this role.
templates - contains templates which can be deployed via this role.
meta - defines some data / information about this role (author, dependency, versions, examples, etc)

I Believe you will now be in a good state to try out Ansible Roles yourself. Write up to me if you require any guidance. You can see these roles for reference Ex: nginx, docker, git; but I will suggest you to try out yourself & Make Mistakes!

Anyone who has never made a mistake has never tried anything new - Albert Einstein

Ansible Vault. Encrypt your Ansible Playbooks

Ansible Vault is a feature of ansible which allow us to protect the sensitive data with encryption in a playbooks such as data files, usernames, passwords, configurations. If any ansible playbook is encrypted, even a ansible administrator cannot read a playbook with any editors without providing a valid vault password. Its not publicly visible.

Encrypt a Playbook

To encrypt a Playbook, Use the option “encrypt” along with ansible-vault command. Enter the vault password twice you wish to set for the particular playbook users.yml, this password is only for this file.

[root@localhost ansible]# ansible-vault encrypt users.yml
New Vault password:
Confirm New Vault password:
Encryption successful

Now the playbook, “users.yml” is encrypted.

Now, if anyone try to open the protected file with any normal editors, they cannot be readable by the users. because its encrypted.

[root@localhost ansible]# cat users.yml
$ANSIBLE_VAULT;1.1;AES256
61663736643362356533646434663830356534646435373164626230633436396666646332393538
3333353735356363663237323034336465633939346536330a313435666439323936306435313830
33313736303432303463636137623064626238333434613037346538663332383663363431613465
3236633939613836360a323335303263626163303532626334663530316137636535313834613237

So Once any playbook is encrypted with ansible-vault command, you have to use the ansible vault command to manage the encrypted file as below.

Note : You can also encrypt your regular system files with Ansible Vault.

View Contents of Encrypted Playbook

Use the “view” option along with ansible-vault command and enter the vault password.

[root@localhost ansible]# ansible-vault view users.yml
Vault password:
---
- hosts: clients
  tasks:
  - name: Adding Users
    user:
     name: john

Edit the encrypted playbook file?

Use the “edit” option along with ansible-vault command and enter the vault password. This will use your default editor set in your user environment.

[root@localhost ansible]# ansible-vault edit users.yml
Vault password:

Once you have done the changes, save and exit from the file.

Run an encrypted Ansible playbook file?

If a playbook is encrypted, We cannot run a ansible-playbook as we do normally. Else you would get an error as below.

[root@localhost ansible]# ansible-playbook users.yml
ERROR! Attempting to decrypt but no vault secrets found

Instead, we can use use the argument “–ask-vault-pass” to provide the vault password or Save your vault password in a file and call the vault password file using the argument “–vault-password-file”.

1. Using the argument “–ask-vault-pass”
[root@localhost ansible]# ansible-playbook users.yml --ask-vault-pass
Vault password:

Enter the vault password when it prompts to run the ansible playbook.

2. Using the argument “–vault-password-file”

Before run, save your vault password in a file and run the playbook again.

[root@localhost ansible]# cat vault-passwd
redhat

Vault password is stored in a file called vault-passwd.

[root@localhost ansible]# ansible-playbook users.yml --vault-password-file /root/ansible/vault-passwd

This time vault password will be taken from the file you have provided, hence it wont prompt you to enter the vault passwd.

If you are not allowed to store the password in clear format, then use only “–ask-vault-pass” argument.

Congratulations! You have successfully completed this tutorial. I hope this has been a great journey for you; Off-Course HECTIC as it was for me, but believe me this is just a Start! Look forward to my other tutorials on some more interesting topics and don’t forget to subscribe to my feeds.
Write up to me with your comments!