Welcome to the Ansible Tutorials. The objective of these tutorials is to get in depth understanding of Ansible. In these tutorials, we will cover various Ansible functions with examples. The tutorial starts with overview of Ansible, Installation of Ansible.

In addition to these tutorials, we will also cover common issues, Interview questions and How To’s of Ansible.


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 manages machines in an agentless manner. 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 is open source software (GPLv3), and is developed by a large group of industry-experts from all over the world.

Anisible Architecture


Ansible runs on a central computer. Playbooks define configuration policy and orchestration workflows. Ansible then uses SSH to execute modules on remote machines without having to install any systems management software. Ansible comes with a large selection of modules for automating common tasks, and users can also write their own in their choice of favorite language. Inventory can be sourced from simple text files, the cloud, or configuration management databases (CMDBs). Results can be stored and processed into a variety of systems.

Configuration and Defaults

New in version 0.7+.

Ansible has an optional configuration file that can be used to tune settings and also eliminate the need to pass various command line flags. Ansible will look for the config file in the following order, using the first config file it finds present

-File specified by the ANSIBLE_CONFIG environment variable

-ansible.cfg in the current working directory. (version 0.8 and up)



For those running from source, a sample configuration file lives in the examples/ directory. The RPM will install configuration into /etc/ansible/ansible.cfg automatically.

Installation of Ansible

Configuration management systems are designed to make controlling large numbers of servers easy for administrators and operations teams. They allow you to control many different systems in an automated way from one central location.

Install ansible on a RHEL/CentOS Linux based system

$ sudo yum install ansible

Install ansible on a Debian/Ubuntu Linux based system

$ sudo apt-get install software-properties-common

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

$ sudo apt-get update

$ sudo apt-get install ansible

Install ansible using pip

The pip command is a tool for installing and managing Python packages, such as those found in the Python Package Index.

$ sudo pip install ansible

latest version of ansible using source code

$ cd ~

$ git clone git://github.com/ansible/ansible.git

$ cd ./ansible

$ source ./hacking/env-setup

When running ansible from a git checkout,  remember that you will need to setup your environment everytime you want to use it, or you can add it to your bash rc file.


$ echo "export ANSIBLE_HOSTS=~/ansible_hosts" >> ~/.bashrc

$ echo "source ~/ansible/hacking/env-setup" >> ~/.bashrc

The hosts file for ansible is basically a list of hosts that ansible is able to perform work on. By default ansible looks for the hosts file at /etc/ansible/hosts, but there are ways to override that which can be handy if you are working with multiple installs or have several different clients for whose datacenters you are responsible for.

$ ansible all -m shell -a "hostname" --ask-pass -i


The environment variable is $ANSIBLE_HOSTS, and can be set as follows:

$ export ANSIBLE_HOSTS=~/ansible_hosts

Once all requirements are installed and you have you hosts file setup you can give it a test run. For a quick test I put into the ansible hosts file as follow:

$ echo "" > ~/ansible_hosts

Now lets test with a quick ping:

$ ansible all -m ping

OR ask for the ssh password:

$ ansible all -m ping --ask-pass

it is highly recommended you setup keys for ansible to use but in the previous test we used --ask-pass, on some machines you will need to install sshpass or add a -c paramiko like so:

$ ansible all -m ping --ask-pass -c paramiko

Interested in mastering Ansible Training? 

Enroll now for FREE demo on Ansible Training.

Setup SSH Keys

-c and --ask-pass options:

Generating public/private rsa key pair.

Enter file in which to save the key (/home/mike/.ssh/id_rsa):

Enter passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved in /home/mike/.ssh/id_rsa.

Your public key has been saved in /home/mike/.ssh/id_rsa.pub.

The key fingerprint is:

94:a0:19:02:ba:25:23:7f:ee:6c:fb:e8:38:b4:f2:42 mike@ultrabook.linuxdork.com

The key's randomart image is:

+--[ RSA 2048]----+

|... . . |

|. . + . . |

|= . o o |

|.* . |

|. . . S |

| E.o |

|.. .. |

|o o+.. |

| +o+*o. |


$ ansible all -m copy -a "src=/home/mike/.ssh/id_rsa.pub

dest=/tmp/id_rsa.pub" --ask-pass -c paramiko

There are many ways to put this in place on the remote machine but since we are using ansible.


SSH password: | success >> {

"changed": true,

"dest": "/tmp/id_rsa.pub",

"gid": 100,

"group": "users",

"md5sum": "bafd3fce6b8a33cf1de415af432774b4",

"mode": "0644",

"owner": "mike",

"size": 410,

"src": "/home/mike/.ansible/tmp/ansible-tmp-1407008170.46-208759459189201/source",

"state": "file",

"uid": 1000


Add the public key in remote server, enter:

$ ansible all -m shell -a "cat /tmp/id_rsa.pub >>

/root/.ssh/authorized_keys" --ask-pass -c paramiko


SSH password: | FAILED | rc=1 >> /bin/sh: /root/.ssh/authorized_keys: Permission denied

To run things as root, so let's add a -u option:

$ ansible all -m shell -a "cat /tmp/id_rsa.pub >>

/root/.ssh/authorized_keys" --ask-pass -c paramiko -u root


SSH password: | success | rc=0 >>

File transfer using ansible

$ ansible all -m authorized_key -a "user=mike key='{{ lookup('file',

'/home/mike/.ssh/id_rsa.pub') }}'

path=/home/mike/.ssh/authorized_keys manage_dir=no" --ask-pass -c



SSH password: | success >> {

"changed": true,

"gid": 100,

"group": "users",

"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCq+Z8/usprXk0aCAPyP0TGylm2MKbmEsHePUOd7p5DO1QQTHak+9gwdoJJavy0yoUdi+C+autKjvuuS+vGb8+I+8mFNu5CvKiZzIpMjZvrZMhHRdNud7GuEanusTEJfi1pUd3NA2iXhl4a6S9a/4G2mKyf7QQSzI4Z5ddudUXd9yHmo9Yt48/ASOJLHIcYfSsswOm8ux1UnyeHqgpdIVONVFsKKuSNSvZBVl3bXzhkhjxz8RMiBGIubJDBuKwZqNSJkOlPWYN76btxMCDVm07O7vNChpf0cmWEfM3pXKPBq/UBxyG2MgoCGkIRGOtJ8UjC/daadBUuxg92/u01VNEB mike@ultrabook.linuxdork.com",

"key_options": null,

"keyfile": "/home/mike/.ssh/authorized_keys",

"manage_dir": false,

"mode": "0600",

"owner": "mike",

"path": "/home/mike/.ssh/authorized_keys",

"size": 410,

"state": "file",

"uid": 1000,

"unique": false,

"user": "mike"


The keys are in place lets try running an arbitrary command like hostname and hope we don’t get prompted for a password

$ ansible all -m shell -a "hostname" -u root

output: | success | rc=0 >>

Run commands as root and not be bothered by using a password we are in a good place to easily configure any and all hosts in the ansible hosts file. Let’s remove the key from /tmp:

$ ansible all -m file -a "dest=/tmp/id_rsa.pub state=absent" -u root

output | success >> { "changed": true, "path": "/tmp/id_rsa.pub", "state": "absent" }

$ ansible all -m zypper -a "name=apache2 state=latest" -u root

output | success >> {

"changed": false,


"apache2", "state": "latest" }

This brings me to the next point, something that makes ansible very flexible and gives more power to playbooks, many may have noticed the -m zypper in the previous commands. Now unless you use openSuse or Suse enterpise you may not be familiar with zypper, it is basically the equivalent of yum in the suse world. In all of the examples above I have only had one machine in my hosts file, and while everything but the last command should work on any standard *nix systems with standard ssh configs, this leads to a problem.

$ cat ~/ansible_hosts





Create some groups of servers, and give them some meaningful tags. Then we create a playbook that will do different things for the different kinds of servers. You might notice the similarity between the yaml data structures and the command line instructions we ran earlier. Basically the -m is a module, and -a is for module args. In the YAML representation you put the module then :, and finally the args.


- hosts: SUSEBased

remote_user: root


- zypper: name=apache2 state=latest

- hosts: RHELBased

remote_user: root


- yum: name=httpd state=latest

simple playbook, we can run it as follows:

$ ansible-playbook testPlaybook.yaml -f 10


PLAY [SUSEBased] **************************************************************


GATHERING FACTS ***************************************************************

ok: []


TASK: [zypper name=apache2 state=latest] **************************************

ok: []


PLAY [RHELBased] **************************************************************


GATHERING FACTS ***************************************************************

ok: []

ok: []


TASK: [yum name=httpd state=latest] *******************************************

changed: []

changed: []


PLAY RECAP ******************************************************************** : ok=2 changed=1 unreachable=0 failed=0 : ok=2 changed=1 unreachable=0 failed=0 : ok=2 changed=0 unreachable=0 failed=0

The -f is what lets ansible run on multiple hosts in parallel. Instead of using all, or a name of a host group, on the command line you can put this passwords for the ask-pass prompt into the playbook. While we no longer need the –ask-pass since we have ssh keys setup, it comes in handy when setting up new machines, and even new machines can run from a playbook. To demonstrate this lets convert our earlier key example into a playbook:



- hosts: SUSEBased

remote_user: mike

sudo: yes


- authorized_key: user=root key="{{ lookup('file', '/home/mike/.ssh/id_rsa.pub') }}" path=/root/.ssh/authorized_keys manage_dir=no

- hosts: RHELBased

remote_user: mdonlon

sudo: yes


- authorized_key: user=root key="{{ lookup('file', '/home/mike/.ssh/id_rsa.pub') }}" path=/r

Machines need to change over time, you don’t need to re-write a playbook every time a machine changes, just update the pertinent bits and commit the changes. Another benefit of this ties into what I said earlier about being able to manage the entire infrastructure from multiple places. You can easily git clone your playbook a new machine and be completely setup to manage everything in a repetitive manner.