Trim Your Playbooks.

Reading Time: 4 minutes

In the previous blog, We went through the basics of creating a simple playbook. Now we’re presented with the following scenario:

You are assigned the task to write a playbook which should carry out 10 tasks in order. There’s also a possibility that we have to re-use some of them in later playbooks.

The moment this problem is presented you think of the most luxurious thing which is done with two fingers: Copy & Paste.

When you mention reusability to a developer his/her ears will perk up. If you understand reusability, you will know beforehand, that this developer isn’t going to talk about copy & paste. So, Is it possible to have that reusability in playbooks? Can we write a short playbook?


Creating a playbook is easy because of YAML but for a reusable playbook, you have only the writer to thank. What tires the person most is not the content, it is the scrolling. Roles reduce scrolling for humans and deliver just what you want to do.

A role, If we look for a layman definition, is a part played by a person in a story. It gives a person a limited amount of work to do and makes the job more manageable. We can do the same with Ansible. What we will do is create a simple role and include that role in the playbook. It seems easy and it really is so.

Roles, as in Ansible, are ways of automatically loading certain vars_files, tasks, and handlers based on a known file structure.


For elucidating this concept, we will create a playbook for pulling a simple static site from docker and then run that site through port mapping.



Step 1: Creating a Role.

Let’s first create a role named static-site. We will do so by using the ansible-galaxy command.

>ansible-galaxy init static-site

This command will create a folder called static-site. Whose directory structure will be as follows:

├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
 └── main.yml

Each sub-directory created has the following semantics attached to them:

  • tasks– contain the main list of tasks to be executed by the role.
  • handlers– contain handlers, which may be used for this role or even anywhere outside this role.
  • defaults– contains default variables for the role.
  • vars– contains other variables for the role.
  • files– contains files which can be deployed via this role.
  • templates– contains templates which can be deployed via this role.`
  • meta– defines some metadata for this role.

So, if we execute the role inside a playbook, the flow of the role will be as follows:

  1. Previous tasks defined in the play.
  2. Any handlers triggered so far will be run.
  3. Any role dependencies defined in the roles meta/main.yml will be run first then the role executes itself.
  4. Post tasks after the role.

Step 2: Specifying task to the role.

Now our role has been set up and now we have to give it a set of tasks. So we will do the following things with this role:

  1. Install Docker, if not already present.
  2. Pull an image of static-site.
  3. Run the dock container on port 8080 through port mapping.

Go to the tasks/main.yml. Specify the steps as follows:

# tasks file for static-site
#step 2.1
 - name: check if the docker is present
 yum: name=docker state=latest

We have used the yum module to install the latest version of the docker engine. This step will be skipped if the latest version is already installed.

#step 2.2
- name: start docker
 service: name=docker state=running

service module here is used to run the Docker engine. We require a docker engine to run before we can pull the image from the docker repo.
status is the only thing which ensures that you docker is running and docker engine is latest in step 2.1

#step 2.3
 - name: pull the docker image
 command: docker pull dockersamples/static-site

command tag is used to execute the command on remote machine’s shell. The step works like an update for the image if the image is already present.

#step 2.4
- name: run the docker image
command: docker run -d -p 8080:80 -t dockersamples/static-site

In this command, we will map default port of the container to the port 8080 to the ec2 of AWS instance.

Step 3: Creating a playbook.

In this step, now we will create a playbook in the parent directory of the role we created previously.

We will just have to use the following lines in the playbook:

.... # hosts definition
   become: yes
.... # other tasks
     - static-site 
   #specify the location of the folder on your machine.
...# more roles or tasks

roles tag is used here which looks for the specified role. Another thing to notice is the become tag having the value true. This allows the docker to be run with root permissions because on the EC2 instance the docker can only run with root privileges.

Step – 4: Login to the EC2 instance.

Using the either of the commands connect to the instance/s.

>ssh `username`@`local IPv4 address`


>ssh -i `location of .pem file` `username`@`local IPv4 address`

Keep yourself logged into monitor the execution of the playbook.

Step – 4: Executing the playbook.

Let’s execute the playbook we have created using the following command:

>ansible-playbook your-playbook-name.yaml

Now after the execution has finished, You can check for the total effects the playbook has had on the remote instance. Using following docker commands on the console of the remote EC2 instance.

Check version fo the docker engine

>sudo docker -v

Check if the image has been pulled.

>sudo docker images -a

Check container execution.

>sudo docker ps -a

I hope you find this blog interesting.


Repository: Ansible Example

Written by 

Software Consultant