Building Ansible Playbooks Step-by-Step

Update 2019: We’ve recently developed a Learning Path, Introduction to Ansible, which will help you to get you started using Ansible to automate common IT tasks, you will learn about Configuration Management and you’ll be able to practice your knowledge on Ansible through a series of hands-on labs. Guy Hummel, our expert cloud trainer, has recently written an introductory post on What is Ansible?.


Learn to build Ansible playbooks with our guide, one step at a time

In our previous posts, we introduced Ansible fundamentals and dived deeper into Ansible playbooks. Now let’s learn to create an Ansible playbook step by step. Working with a playbook, we’ll go from deploying a simple HTML website to a complete LAMP stack.

Deploying Simple HTML Page

To deploy a simple HTML page, we need to ensure that apache is installed and configured on our host machine. So, therefore, in this section we will:

  • install Apache
  • start the Apache service
  • deploy a static webpage with images – This static webpage will leverage Ansible templates where it will display the text “Thank you for reading this post. My IP Address is <ip-address-of-instance>” and cloudacademy logo. To fetch the IP address of the host, it will rely on Ansible Fact
  • restart Apache once the deployment is over

Before we move forward, let’s have a look at the high-level structure of this simple Ansible playbook.

site.yml – starting point of our ansible playbook
hosts – carrying hosts information
roles/ - defining what each type of server has to perform
       webservers/
              tasks/ - tasks performed on webservers
                     main.yml
              handlers/ - running tasks under particular events
                     main.yml
              templates/ - configuration files which can reference variables
                     index.html.j2
              files/ - files to be copied to webservers
                     cloud.png

Let’s go through the configuration file line by line and see how configuration works.
hosts – points to Ansible hosts. Here’s a possible syntax:

[webservers]
10.0.0.156

site.yml – the starting point for executing our Ansible playbook. Includes information about hosts and roles associated with them.

---
- name: install and configure webservers
hosts: webservers
remote_user: ec2-user
sudo: yes
roles:
   - webservers

If we want to log into our host machines using a different username and with sudo privileges, we need to use the “remote_user” and “sudo: yes” parameter in our site.yml file. There can be additional parameters too, but they’re not needed right now. Here, we have also defined roles granted to hosts in the [webservers] group.

main.yml (Tasks) – This configuration file defines tasks to be executed on hosts that have webservers roles granted. It looks like:

---
# This task installs and enables apache on webservers
- name: ensure apache is installed
yum: pkg=httpd state=latest
- name: ensure apache is running
service: name=httpd state=running enabled=yes
- name: copy files to document root
copy: src=cloud.png dest=/var/www/html/cloud.png
- name: copy application code to document root
template: src=index.html.j2 dest=/var/www/html/index.html
notify: restart apache

Since YAML files are so intuitive, we can easily see that this will install and run Apache on host instances and copy certain files and templates to the host’s document root.
main.yml (handlers) – This configuration file defines the action to be performed only upon notification of tasks or state changes. In main.yml (tasks), we defined notify: restart apache handler which will restart Apache once the files and templates are copied to hosts.

---
- name: restart apache
service: name=httpd state=restarted

index.html.j2 (template) – a file you can deploy on hosts. However, template files also include some reference variables which are pulled from variables defined as part of an Ansible playbook or facts gathered from the hosts. Our index.html.j2 file looks like a regular html webpage with a referenced variable.

<html>
<head>
    <title>CloudAcademy Ansible Demo</title>
</head>
<body>
    <h1>
        Thank you for reading this post.
        My IP Address is {{ ansible_eth0.ipv4.address }}
    </h1>
    <br/><br/><br/>
    <p>
        <img src="cloud.png" alt="CloudAcademy Logo"/>
    </p>
</body>
</html>

We have declared a reference variable “{{ ansible_eth0.ipv4.address }}” which will print the IP address of the host on which this Ansible playbook is executed.
cloud.png (files) – The regular image file to be copied to hosts.

Once we have all the files created and present, we can execute an ansible-playbook command and configure our hosts.

build# ansible-playbook site.yml -i hosts
PLAY [install and configure webservers] ***************************************
GATHERING FACTS ***************************************************************
ok: [10.0.0.156]
TASK: [webservers | ensure apache is installed] *******************************
changed: [10.0.0.156]
TASK: [webservers | ensure apache is running] *********************************
changed: [10.0.0.156]
TASK: [webservers | copy files to document root] ******************************
changed: [10.0.0.156]
TASK: [webservers | copy application code to document root] *******************
changed: [10.0.0.156]
NOTIFIED: [webservers | restart apache] ***************************************
changed: [10.0.0.156]
PLAY RECAP ********************************************************************
10.0.0.156                 : ok=6   changed=5   unreachable=0   failed=0

That’s it. We have installed Apache and deployed our webpage using host-based files. On browsing our host’s IP address, we will see our static webpage with the referenced variables value defined.

Deploying a PHP webpage configured to work with a MySQL database

So until now, we’ve installed and started Apache, deployed a static webpage, and restarted Apache using handlers. Now we will upgrade the functionality of our existing Ansible playbook by adding additional features. Specifically, we’ll:

  • install PHP and related packages
  • install MySQL server
  • create databases in MySQL server
  • grant privileges to databases
  • deploy a PHP web page which will list the names of all the databases in our MySQL server and print certain facts about our host.

This will modify the structure of our existing Ansible playbook:

site.yml – starting point of our ansible playbook
hosts – carrying hosts information
group_vars
       all – carrying variables for groups
roles/ - defining what each type of server has to perform
       webservers/
              tasks/ - tasks performed on webservers
                     main.yml
              handlers/ - running tasks under particular events
                     main.yml
              templates/ - configuration files which can reference variables
                     index.php.j2
              files/ - files to be copied to webservers
                     cloud.png
       dbservers
              tasks/
                     main.yml

all (group_vars) : contains group-specific variables. Currently, we have only one group i.e., all.

dbuser: ansible
dbpassword: 12345

hosts : We have to update our hosts file if the webserver and database server is configured on the same host.

[all]
10.0.0.156

site.yml : Once we have updated our hosts file with a new group “all”, we have to update our site.yml file which will grant the webserver and dbserver role to the “all” host group.

---
- name: install and configure webservers
hosts: all
remote_user: ec2-user
sudo: yes
roles:
   - webservers
   - dbservers

main.yml (tasks for webservers): This YAML file will now install additional PHP related packages.

---
# These task installs and enables apache on webservers
- name: ensure apache,php related packages are installed
yum: name={{ item }} state=present
with_items:
   - httpd
   - php
   - php-mysql
- name: ensure apache is running
service: name=httpd state=running enabled=yes
- name: copy files to document root
copy: src=cloud.png dest=/var/www/html/cloud.png
- name: copy application code to document root
template: src=index.php.j2 dest=/var/www/html/index.php
notify: restart apache

index.php.j2 (templates): Instead of an HTML file, we’ve moved to index.php which includes application code to print names of all databases and other operating systems related information:

<html>
<head>
       <title>CloudAcademy Ansible Demo</title>
</head>
<body>
    <h3>
        Thank you for reading this post. My IP Address is {{ ansible_eth0.ipv4.address }}.
        This is {{ ansible_system }} OS with {{ ansible_userspace_architecture }} architecture
    </h3>
    <p>
        <strong>List of Databases:</strong> <br/>
    <?php
    //Spoiler: don't do this at home!
    $dbobj = mysql_connect('{{ ansible_lo.ipv4.address }}', '{{ dbuser }}', '{{ dbpassword }}');
    if (!$dbobj) { die('Could not connect: ' . mysql_error()); }
    $result = mysql_query("SHOW DATABASES");
    while ($res = mysql_fetch_assoc($result)){
        echo $res['Database'] . "<br/>";
    }
    ?>
    </p>
    <br/>
    <p><img src="cloud.png" alt="CloudAcademy Logo"></p>
</body>
</html>

main.yml (tasks for dbservers) : This configuration file will install the MySQL-server, and MySQL python packages, create databases and create database users.

---
# These task installs and enables apache on webservers
- name: ensure mysql is installed
yum: name={{ item }} state=present
with_items:
   - mysql-server
   - MySQL-python
- name: ensure mysql is running
service: name=mysqld state=running enabled=yes
- name: create application database
mysql_db: name={{ item }} state=present
with_items:
   - ansible_db01
   - ansible_db02
- name: create application user
mysql_user: name={{ dbuser }} password={{ dbpassword }} priv=*.*:ALL state=present

That’s it. Our Ansible playbook to deploy a LAMP stack is now ready. We built up a playbook that will install Apache, PHP, MySQL-server, create a MySQL user and databases and deploy our application code which prints information about Ansible’s host and list of databases.

To execute this Ansible playbook on the host, we will use the ansible-playbook command:

#ansible-playbook site.yml -i hosts
PLAY [install and configure webservers] ***************************************
GATHERING FACTS ***************************************************************
ok: [10.0.0.156]
TASK: [webservers | ensure apache,php related packages are installed] *********
changed: [10.0.0.156] => (item=httpd,php,php-mysql)
TASK: [webservers | ensure apache is running] *********************************
changed: [10.0.0.156]
TASK: [webservers | copy files to document root] ******************************
changed: [10.0.0.156]
TASK: [webservers | copy application code to document root] *******************
changed: [10.0.0.156]
TASK: [dbservers | ensure mysql is installed] *********************************
changed: [10.0.0.156] => (item=mysql-server,MySQL-python)
TASK: [dbservers | ensure mysql is running] ***********************************
changed: [10.0.0.156]
TASK: [dbservers | create application database] *******************************
changed: [10.0.0.156] => (item=ansible_db01)
changed: [10.0.0.156] => (item=ansible_db02)
TASK: [dbservers | create application user] ***********************************
changed: [10.0.0.156]
NOTIFIED: [webservers | restart apache] ***************************************
changed: [10.0.0.156]
PLAY RECAP *******************************************************************
10.0.0.156                 : ok=10   changed=9   unreachable=0   failed=0

Browsing to our host IP address will display:
Screenshot 2015-01-25 01.00.06
There’s lots more to learn about Ansible in future posts!

Avatar

Written by

Sanket Dangi

Head of Managed Services at REAN Cloud. Before joining REAN Cloud, I was CEO and Founder of StraightArc Solutions which was later acquired by REAN Cloud. I started my career working on cloud computing. Loves to talk about DevOps, System Administration, Scalability, High Availability, Disaster Recovery and Cloud Security. Apart from work, I love to meet people, travel and watch sports.


Related Posts

Avatar
Adam Hawkins
— July 9, 2019

Top 20 Open Source Tools for DevOps Success

Open source tools perform a very specific task, and the source code is openly published for use or modification free of charge. I've written about DevOps multiple times on this blog. I reiterate the point that DevOps is not about specific tools. It's a philosophy for building and improv...

Read more
  • Ansible
  • Chef
  • configuration management
  • DevOps
  • devops tools
  • Docker
  • infrastructure-as-code
  • Kubernetes
  • telemetry
Avatar
Guy Hummel
— March 4, 2019

What is Ansible?

What is Ansible? Ansible is an open-source IT automation engine, which can remove drudgery from your work life, and will also dramatically improve the scalability, consistency, and reliability of your IT environment. We'll start to explore how to automate repetitive system administratio...

Read more
  • Ansible
  • Cloud Computing
Stefano Bellasio
Stefano Bellasio
— July 7, 2016

4 New Webinars for July 2016: Ansible, AWS Lambda, A/B Testing Algorithms in the Cloud, and Office Hours

Hello! This is Stefano. It's been a while since my last post on our blog. I've been busy working with our great team at Cloud Academy, but I would like to use this article today to talk about something we've been really enjoying these last few months: doing cloud training webinars with ...

Read more
  • Ansible
  • AWS
Avatar
Maxime Thoonsen
— March 3, 2016

Deploy Web Applications on IaaS with Ansible

This article explains how to easily deploy a web application on IaaS platforms using Ansible. We'll see the big picture and then study the case of deploying a Symfony application. What is Ansible? Ansible is an automation framework written in Python. An Ansible script is basically a l...

Read more
  • Ansible
  • AWS
Avatar
Chandan Patra
— October 21, 2015

Ansible and AWS: Cloud IT Automation Management

With things moving a bit more slowly through the holiday season, we’re going to re-run some of our most popular posts from 2015. Enjoy! The kinds of virtual infrastructures that define the cloud computing ecosystem demand a high level of automation. As the number of virtual servers use...

Read more
  • Ansible
  • AWS
  • Azure
Avatar
David Clinton
— January 26, 2015

Cloud Technology and Security Alert News Digest – Issue #10

Update 2019: We've been busy working on some great training content around security, check out the Cloud Academy library to prepare on all-things cloud security. Welcome to the Cloud Technology and Security Alert News Digest. This week we've got word of some big platform changes ...

Read more
  • Ansible
  • Azure
  • Chef
  • Containers
  • Security
Avatar
Sanket Dangi
— January 12, 2015

Going Deeper into Ansible Playbooks

Update 2019: We've recently developed a Learning Path, Introduction to Ansible, which will help you to get you started using Ansible to automate common IT tasks, you will learn about Configuration Management and you'll be able to practice your knowledge on Ansible through a series of ha...

Read more
  • Ansible
  • Cloud Computing
Avatar
Sanket Dangi
— December 29, 2014

Get Started with Ansible on the Cloud

Update 2019: We've recently developed a Learning Path, Introduction to Ansible, which will help you to get you started using Ansible to automate common IT tasks, you will learn about Configuration Management and you'll be able to practice your knowledge on Ansible through a series of ha...

Read more
  • Ansible
  • AWS