Ansible Basics

Introduction

  • Ansible is an IT automation tool. It can be used to deploy applications, configure services on multiple servers in less efforts.
  • It works agentless using SSH for connection.
  • Configuration files are written in YAML and file extension is yml
  • Ansible has controller machine in which Ansible is installed and all playbooks, required templates, files are stored.
  • Controller machine connect to client machines over ssh and run required commands.
  • Various Ansible modules are available such as user, file, filesystem, service, yum, apt etc.
  • Refer http://docs.ansible.com/ansible/index.html

Installation
On RedHat based system using yum:

$ yum install epel-release
$ yum install ansible

On Debian based systems using apt:

$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible

Configuration

  • Configuration files stored in /etc/ansible by default.
  • Main configuration file is /etc/ansible/ansible.cfg

For config file Ansible looks into

  1. First location for ansible.cfg is /etc/ansible/ansible.cfg
  2. Second location is Current directory / ansible.cfg
    So if we create directory name “config” in current directory. Then we need to export ANSIBLE_CONFIG settings.
    export ANSIBLE_CONFIG=/opt/ansible/neelesh/config/ansible.cfg
    Add above line to ~/.bashrc
  3. Third location is ~/.ansible.cfg
  • Hosts inventory is defined under /etc/ansible/hosts by default. However you can define custom host inventory in your ansible.cfg file.
    In ansible hosts file, need to add entries in below format:

     [group_name-1]
     ip_address or hostname
     [group_name-2]
     ip_address or hostname
     [group_name-3:children]
     group name-1
     group name-2
    

Note: We have created test-user user on all servers. test-user user has sudo privileges with NOPASSWD.
Basic Commands
List all hosts configured in hosts file.

 $ ansible all --list-hosts

List hosts which are member of group_name-1

 $ ansible group_name-1 --list-hosts

Pings all hosts which are mentioned in ansible hosts file

 $ ansible all -m ping -u test-user -k -s 

–> -k to ask for password. We can configure password less connection by doing key exchange.
-m for Ansible module.
-s to use sudo.

To get all facts about ansible clients.

$ ansible all -m setup -u test-user -k

To get facts in file use below command. You will get all facts inside ansible controller in ~/.ansible/tmp/facts/<IP of hadoop-servers>

 $ ansible all -m setup --tree ~/.ansible/tmp/facts -u test-user -k

To get only IPaddress facts using setup module

 $ ansible all -m setup -a 'filter=*ipv4*' -u test-user -k

Get Architecture details of Ansible clients using setup modules and arguments

 $ ansible all -m setup -a 'filter=ansible_arch*' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_domain*' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_fqdn' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_interfaces' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_kernel' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_memtotal_mb' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_proc*' -u test-user -k
 $ ansible all -m setup -a 'filter=ansible_virt*' -u test-user -k

Check if file is present

 $ ansible all -m file -a 'path=/etc/fstab' -u test-user -k

Create directory /tmp/etc

 $ ansible all -m file -a 'path=/tmp/etc state=directory \
 mode=0700 owner=root' -u test-user -k -s

Remove /tmp/etc

 $ ansible all -m command -a 'rm -rf /tmp/etc removes=/tmp/etc' \
 -s -u test-user -k

Install lynx browser in Redhat based linux

 $ ansible all -s -m yum -a 'pkg=lynx state=installed update_cache=true'

Writing basic Playbook
We define Ansible’s configuration, deployment, and orchestration in Playbooks. Playbooks are like cookbooks in Chef. They can describe a policy you want your remote systems to enforce, or a set of steps in a general IT process.
Playbooks are expressed in YAML format (see YAML Syntax) and have a minimum of syntax.
Each playbook is composed of one or more ‘plays’ in a list. It is possible to run certain steps on webservers and certain steps on application servers by grouping them.
We will write playbook which will install httpd, restart it and enable it at boot time.
It is recommended to start playbook with ‘—‘
It also recommended to use “SPACE” instead of “TAB”,
first.yml

 ---
 # My first playbook
 - hosts: group_name-1
   user: test-user
   become: yes
   become_method: sudo
   gather_facts: yes
   connection: ssh
   tasks:
    - name: Install HTTPD Server
      package: name=httpd state=latest
      notify: Restart HTTPD
   handlers:
    - name: Restart HTTPD
      service: name=httpd state=restarted enabled=yes

first.yml has 3 sections.

  • Host declaration
     - hosts: group_name-1
       user: test-user
       become: yes
       become_method: sudo
       gather_facts: yes
       connection: ssh
    
  • Tasks
     tasks:
     - name: Install HTTPD Server
       package: pkg=httpd state=latest
       notify: Restart HTTPD
    
  • Handlers
    handlers:
    - name: Restart HTTPD
      service: name=httpd state=restarted enabled=yes
    

All sections are self-explanatory.

  • Execute first.yml:
    $ ansible-playbook first.yml –k
    

    Notes:
    – In Ansible 2.0 for sudo privileges need to use

    become: yes
    become_method: sudo
    

    – In Ansible version prior to 2.0 need to use – sudo: yes

    – value of “notify” in tasks should be same as value of – name in handlers.

Using Roles
Roles are ways of automatically loading certain vars_files, tasks, and handlers for certain group of hosts. Eg. If we have web servers, application servers, db servers in our environment then we can have roles like
common – Common steps for all
web – For all web servers
db – For all db servers
Which organize our playbook appropriately.
Directory structure of role:
In ansible.cfg we can define path of roles to be stored using “roles_path = /path/to/roles/”
Inside roles directory there will be sub structure as below:
../roles/
———webserver/
———————– tasks
———————– files
———————– vars
———————– meta
———————– templates
../roles/
———dbserver/
…..

Ansible checks for “main.yml” in each subfolder inside roles, in above eg. tasks, files, vars, etc.

First.yml using roles:

--- # First.yml using role
- hosts: group_name-1
  user: test-user
  become: yes
  become_method: sudo
  gather_facts: yes
  connection: ssh
  roles:
   - webserver

../roles/webserver/tasks/main.yml

--- # tasks/main.yml
- name: Install HTTPD Server
  package: pkg=httpd state=latest
  notify: Restart HTTPD

../roles/webserver/handlers/main.yml

--- # tasks/main.yml
- name: Restart HTTPD
  service: name=httpd state=restarted enabled=yes

Now Just execute first.yml using steps given above.

Variables
We can define variables in playbook under “vars” and recall their values using {{…}}
There are 2 main type of variables system facts and user defined.
System facts we get from gathering facts and user defined variable has to declare in playbooks.

User Defined Variables
For eg. we can use variable in first.yml like below:

--- # first playbook using User defined variable
- hosts: group_name-1
  user: test-user
  become: yes
  become_method: sudo
  gather_facts: yes
  connection: ssh
  vars:
    pkg_name: httpd
    service_name: httpd
  tasks:
   - name: Install HTTPD Server
     package: pkg={{ pkg_name }} state=latest
     notify: Restart HTTPD
  handlers:
   - name: Restart HTTPD
     service: name={{ service_name }} state=restarted enabled=yes

If we are using roles then we can define all variables in ../roles/<role_name>/vars/main.yml
So in above example ../roles/<role_name>/vars/main.yml will look like:

--- # vars/main.yml
pkg_name: httpd
service_name: httpd

System Variables
We can use system variables for using system information like hostname, IPaddress, OS family, OS version etc. We get these values when enable “gather_facts” in playbook.
For eg. Suppose if we want to use FQDN of hosts in playbook, we can simply use {{ ansible_fqdn }} in our playbook.
We can use these variables in conditional statements as well. For eg. RedHat based system uses “httpd” as package name but Debian based system uses “apache2” as a package name. So if we want to install httpd on Redhat based systems and apache2 on debian based system then we can use conditional statement like below:

- name: Install HTTPD on CentOS
  yum: pkg= httpd state=latest
  when: ansible_os_family=="RedHat"
- name: Install HTTPD on Ubuntu
  apt: pkg= apache2 state=latest
  when: ansible_os_family=="Debian"

Loops
We also can define loops in our playbooks. If we want to install multiple packages we can use below loop

- name: Install multiple packages
  package: pkg={{ item }} state=latest
  with_items:
   - httpd
   - php

until loop
Below example will verify httpd service status and it will wait till it gets “active (running)” in status output.

- name: Installing Apache Web Server
  yum: pkg=httpd state=latest
- name: Verify Service Status
  shell: systemctl status httpd
  register: result
  until: result.stdout.find("active (running)") != 1
  retries: 4
  delay: 5
  debug: var=result

Templates
Ansible uses jinja2 templates Jinja is nothing but extension of python.
Here is just an example of how we can use templates in Ansible Playbooks.
First.yml will install HTTPD server. Now we want to change default http port to 8989 instead of 80.
Here are the steps:
– copy default httpd.conf inside “templates” directory as httpd.conf.j2
– In ../roles/webserver/templates/httpd.conf.j2 just change “Listen 80” to “Listen {{ my_http_port }} “
– In ../roles/webserver/vars/main.yml
my_http_port: 8989
– In tasks/main.yml

--- # tasks/main.yml
- name: Install HTTPD Server
  package: pkg=httpd state=latest
  notify: Restart HTTPD
- name: Replace HTTPD.conf
  template: src=httpd.conf.j2
            dest=/etc/httpd/conf/httpd.conf
            owner=root group=root mode=0644
  notify: Restart HTTPD

In this example template module will copy templates/httpd.conf.j2 to /etc/httpd/conf/httpd.conf and also replace {{ my_http_port }} variable to its value.

Ansible is very powerful, robust and yet easy tool used for Deployment Automation and configuration management across massive infrastructure.
You can drop me your queries related to Ansible on ngurjar[at]neeleshgurjar[dot]co[dot]in[dot]

Neelesh Gurjar has written 122 articles

4 thoughts on “Ansible Basics

Leave a Reply