Ansible Basics

Ayush Goyal


  • There is a critical openssl update that needs to be quickly deployed on all your 100 servers.
  • easy if you try???
  • You have to setup mysql master-slave on 10 servers(1 master, 9 slaves).
  • isn't hard to do???
  • Your servers have reached there resource limit and you quickly need to add 10 more servers to meet the demand.
  • You may say I am a dreamer. But I am not the only one.

What is ansible and why use it?

A simple configuration management and orchestration tool.

  • To have a adaptable and reproducible configuration managing thousands of servers.
  • It is designed for cloud. Works out of the box with Amazon web services.
  • Easily extendable, many times without requiring to patch core software.
  • Its build on top of python, yaml and ssh. Doesn't require much setup to start using.
  • Its declarative and idempotent.

Installing ansible on mac

brew install python
easy_install pip
pip install -Iv ansible==1.7.2

Quickly setup a test vagrant

  • Create a folder for your development environment

    mkdir testansible
    cd testansible
  • Initialize Vagrant with the box you just imported

    vagrant init ubuntu-12.04
  • Uncomment the private network line in Vagrantfile and change the ip "private_network", ip: ""
  • Start Vagrant Instance

    vagrant up

Key Ansible Concepts

Inventory file

  • Ansible works through an inventory file to know which hosts it can connect to
  • Inventory can be either static or dynamic
  • Today we will deal with just static inventory file.
  • In production, we use dynamic inventory which uses cloud apis

An example Static Inventory

Ansible static inventory uses INI-like format.

  • It looks something like this

    mail.example.coma          ;<~host
    [dbservers]                ;<~group   id=10    ;<~host_vars   id=11    ;<~host_vars
    [webservers:vars]          ; group_vars
  • A host in ansible jargon is a single target, which you can connect to and deploy on. You can define hosts using ranges (ranges are inclusive)
  • You can organise hosts in a group to target multiple hosts simultaneously.
  • host_vars have variables associated with a host, which you can use to manage your config. These variables/facts can either be fetched from a central inventory db or can be defined.
  • group_vars are variables for an entire group. These can be fetched from inventory

Our own inventory file

Add this in hosts file inside the testansible folder

server ansible_ssh_host= ansible_ssh_user=vagrant ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key

[localhost] ansible_connection=local ec2_tag_Name=localhost

Run ad-hoc command using ansible

Now you have inventory, you can execute your own ad-hoc commands

  • Run this on terminal:

    ansible -i hosts server -m shell -a "uptime"
  • Lets target a group this time

    ansible -i hosts servers -m ping
  • Let's fetch and use a hostvar this time

    ansible -i hosts localhost -m shell -a "echo {{ec2_tag_Name}}"

Ansible Modules

Ansible modules is a logical unit in ansible, which when specified with required parameters, can perform certain action.


  • shell: run adhoc shell commands
  • ping: module to test connectivity to host
  • copy: module to copy file from localhost to remote server
  • ec2: launch an ec2 instance

Ansible Playbooks

Ansible playbooks is the language of ansible. It allows you to design plans for orchestration, config management, deployment.

  • It's just a yaml file and has a very minimal syntax.
  • A simple playbook file looks like this. This one has a single play. Let's create a playbook.yml file in our testansible dir:

    - name: playbook to setup apache
      hosts: server
      sudo: yes
      - name: ensure apache is at the latest version
        apt: name=apache2 state=latest update_cache=yes
      - name: ensure apache is running
        service: name=apache2 state=started
  • We can execute a playbook on a host like this:

    ansible-playbook -i hosts playbook.yml

Ansible Playbook: An extended example

- name: playbook to setup apache
  hosts: server
  sudo: yes
    http_port: 80
    - vars_files/apache.yml
    - name: ensure apache is at the latest version
      apt: name=apache2 state=latest update_cache=yes
      tags: install_apache
    - name: copy apache conf
      template: src=site.conf.j2 dest=/etc/apache2/sites-enabled/site.conf mode=0640 owner=apache group=apache
      notify: restart apache
    - name: ensure apache is running
      service: name=apache2 state=started
    - name: restart apache
      service: name=apache2 state=restarted
  • tasks are collection of steps to be executed one after another
  • handlers are tasks which run only when triggered.
  • vars are various variables in a playbook, used for templates etc. They can be passed at runtime to modify behaviour
  • vars_files are collection of vars, stored in seperate yaml files
  • tags are identifier for tasks. You can skip or run a task by using ansible-playbook cli options.

Ansible Playbook: Roles

Roles are abstracted logical grouping of tasks, handlers and vars.

- name: playbook to setup apache
  hosts: server
  sudo: yes
    - apache
  • Roles can be created in a roles directory relative to your playbook path
  • Roles directory structure looks something like this

    $ tree roles/apache
    ├── defaults
    │   └── main.yml
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── tasks
    │   └── main.yml
    ├── files
    │   └── apache2.conf
    ├── templates
    │   └── site.conf.j2
    └── vars
        └── main.yml

A simple apache role

  • create roles directory inside your testansible

    mkdir -p roles/apache/{defaults,tasks,handlers,templates}
  • add this to roles/apache/defaults/main.yml

    http_name: john lennon
  • add this to roles/apache/tasks/main.yml

    - name: ensure apache is at the latest version
      apt: name=apache2 state=latest update_cache=yes
    - name: copy test html page
      template: src=test.html.j2 dest=/var/www/test.html mode=0644 owner=root group=root
      notify: restart apache
    - name: ensure apache is running
      service: name=apache2 state=started
  • add this to roles/apache/handlers/main.yml

    - name: restart apache
      service: name=apache2 state=restarted
  • add this to roles/apache/templates/test.html.j2

         <title>{{http_name}}'s Page</title>
        <p>This is {{http_name}}'s webpage</p>
  • Once you have setup all your create a apache.yml playbook in your testansible directory

    - name: playbook to setup apache
      hosts: server
      sudo: yes
        - apache
  • Execute your playbook using:

    ansible-playbook -i hosts apache.yml -e "http_name=ayush"


Extras: Ansible Doc

You can lookup documentation for modules using ansible-doc utility

  • list all modules

    ansible-doc -l
  • check documentation of a module using:

    ansible-doc apt

Extras: Loops and conditionals in ansible

Although not hard to do and explain, loops and conditionals can be setup in ansible playbooks using with_items and when keywords Checkout reference for ansible documentation link for it.

Extras: YAML and jinja

  • Ansible uses yaml and jinja for its language syntax.
  • Variables in playbook use jinja syntax. Templates also use jinja
  • A good understanding of yaml and jinja is required to understand ansible really well.
  • Checkout documentation resources on yaml and jinja at the end.

Extras: Ansible Vault

You can have encrypted vars files. There is a utility ansible-vault to encrypt a vars files

  • If you encrypt vars files using ansible-vault, you need to provide the password when running playbook using ansible-playbook
  • This is useful when you have publicly accesible library and you want to keep your parameters secret.
  • Refer to links in references for more info

Extras: Vagrant Ansible Provisioner

Vagrant has an ansible provisioner facility, which can generate the ansible inventory file and run playbook with just vagrant up

  • It requires some configuration to be done in Vagrantfile
  • Looks something like this:

    config.vm.provision "ansible" do |ansible|
      ansible.playbook = "playbook.yml"
      ansible.tags = "logrotate"
      ansible.groups = {
        "group1" => ["machine1"],
        "group2" => ["machine2", "machine3"],
        "all_groups:children" => ["group1", "group2", "group3"],
        "group1:vars" => { "variable1" => 9, "variable2" => "example" }

What's next

World Peace. Maybe?


  • Create a new vagrant machine
  • Write an ansible playbook which when executed:
    • setup nginx, along with config to render php pages
    • copy an html page in nginx document root which renders the current time
    • This setup should work without manually doing anything just by running the playbook.
  • Bonus task: set it up so that all of this gets done with just vagrant up after destroying the old machine
Made with