Ansible: Getting Started

What is Ansible?

Ansible was originally written by Michael DeHaan in Python with its first release on February 20, 2012. It was later acquired by Red Hat. Ansible is an open source configuration management and orchestration utility. It helps to automate deployment or softwares and configurations of multiple remote hosts. Instead of writing custom, unmanaged, long and individual bash scripts, system administrators can write playbooks in Ansible. Ansible is also supported by DevOps tools, such as Vagrant and Jenkins.

  • Playbook is a YAML (YAML Ain't Markup Language) file which consists a list of Plays.
  • A Play in a playbook is a list of Tasks.
  • A Task in a play contains Modules and its arguments.
  • Where as Module are the ones that do the actual work in ansible.

How Ansible Works?

The greatest benefit of Ansible that I see is, unlike Puppet it is agent less. The only requirement on remote host (know as Managed Host) is Python 2.4 or later. If you are running less than Python 2.5 on the remotes, you will also need python-simplejson. Ansible is installed on a central host (know as Control Host) where Playbooks are created. Playbooks are pushed to Managed Host thru SSH as a Python code and executed locally on Managed Host.

Installing Ansible

Ansible needs to be installed on control node. As of now control node is not supported on Windows. It is available via Yum(Red Hat), Apt (Debian), Portage (Gentoo), pkg (FreeBSD), OpenCSW (Solaris), Pacman (Arch Linux), Pip and can be installed from Source as well. Python 2.6 or 2.7 is required on Control Node. Python3 not yet supported just like many other Python apps :).

Red Hat based Distributions

Ansible on Red Hat based distributions like RHEL, CentOS, Fedora is available through EPEL repo.

Debian Based Distributions

[root@debian ~]# apt-get update
[root@debian ~]# apt-get install -y ansible

Testing Your Installation

[root@centos ~]# ansible --version
ansible 2.1.1.0  
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
[root@centos ~]# ansible localhost -m ping --connection=local 
localhost | SUCCESS => {  
    "changed": false, 
    "ping": "pong"
}
[root@centos ~]# 

ansible --version displays the ansible version and the ansible configuration file its referring to. ansible localhost -m ping --connection=local will run a ansible module ping on localhost using connection as local instead of ssh which is default. Receiving a SUCCESS and a "pong" in reply says that ansible was able to connect to localhost successfully. We will discuss more about modules later.

Ansible Configuration

Default ansible configuration file is located as /etc/ansible/ansible.cfg. If ansible finds a .ansible.cfg in users home directory, options in that config file will override the one in default config file.

[root@centos ~]# ansible --version
ansible 2.1.1.0  
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
[root@centos ~]# touch ~/.ansible.cfg
[root@centos ~]# ansible --version
ansible 2.1.1.0  
  config file = /root/.ansible.cfg
  configured module search path = Default w/o overrides
[root@centos ~]# 

If ansible finds ansible.cfg file in your current working directory, option within that file will take precedence over the above two. Below example shows that.

[root@centos ~]# mkdir Test
[root@centos ~]# cd Test
[root@centos Test]# touch ansible.cfg
[root@centos Test]# ansible --version
ansible 2.1.1.0  
  config file = /root/Test/ansible.cfg
  configured module search path = Default w/o overrides
[root@centos Test]# 

Or, if you have your config file at some other location and want ansible to point to it, $ANSIBLE_CONFIG bash environment variable will help you do that. And that takes precedence over all others.

[root@centos Test]# touch /var/tmp/myansible.cfg
[root@centos Test]# export ANSIBLE_CONFIG=/var/tmp/myansible.cfg
[root@centos Test]# ansible --version
ansible 2.1.1.0  
  config file = /var/tmp/myansible.cfg
  configured module search path = Default w/o overrides
[root@centos Test]# 

Inventory

If Ansible modules are the tools in your workshop, playbooks are your instruction manuals, and your inventory of hosts are your raw material.

Ansible’s inventory file is a list of your managed hosts. It can contain hostnames, ipaddresses, hostpaterns using regular expressions. It also contains groups of hosts and group of groups. Default inventory location is /etc/ansible/hosts. You can specify a different inventory file using the -i <path> option on the command line. Inventory file can also contain host and group variables which can later be used in playbooks.

Modules

Ansible ships with a hundreds of modules that can be executed directly on remote hosts using ad-hoc commands or through Playbooks.

You can also write your own modules. These modules can control system resources, like services, packages, or files (almost anything that you would like to manage), or handle executing system commands.

ansible-doc -l would give you a list of all modules with a short description piped to less.

ansible-doc <module_name> will show detailed information about the usage of module, including snippets and some examples which can be used in playbooks and ad-hoc commands.

Running Ad-Hoc Commands

True power of Ansible lies in playbooks. Why would you use ad-hoc tasks versus playbooks? Ad-hoc command is a quick way executing your modules on remote hosts without saving them for later use. For example, if you want to poweroff all or a group of servers on weekend.

ansible <HOST-PATTERN> -m <MODULE_NAME> -a <MODULE_ARGS>

[root@centos ~]# ansible all -m command -a "/usr/sbin/poweroff" -i myinventory

Some more examples will help you understand power of ad-hoc commands

Will execute hostname command on all hosts in your inventory

[root@centos ~]# ansible all -m command -a hostname 
localhost | SUCCESS | rc=0 >>  
centos

192.168.56.1 | SUCCESS | rc=0 >>  
Swapnils-MacBook-Pro.local  

Using YUM module, will install the latest version of docker on host named centos, if already install will make sure its latest.

[root@centos ~]# ansible centos -m yum -a 'name=docker state=latest'
centos | SUCCESS => {  
    "changed": false, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "All packages providing docker are up to date", 
        ""
    ]
}

Using service module, will started docker service and also enable it to start on system boot

[root@centos ~]# ansible centos -m service -a 'name=docker state=started enabled=yes'
centos | SUCCESS => {  
    "changed": true, 
    "enabled": true, 
    "name": "docker", 
    "state": "started"
}

Lets put it in a Playbook

We use this modules to create 2 tasks in a play. So, our playbook looks like below.

Lets execute it.

Please note, ansible playbooks are written as YAML, and YAML is very sensitive to spaces and indentation. Do not use tabs. putting the below line in your ~/.vimrc will help.

set nu  
set ai  
set softtabstop=2  
set expandtab  

Thats it for now. Next, I will go deeper into playbooks. Till then enjoy ansibling :)


Like it? Click here to Tweet your feedback

Swapnil Jain

RHCA Level X, RHCI ♦ Solution Architect ♦ DevOps Trainer & Consultant