---
title: "How to Build (And Actually Understand) a Solid Ansible Playbook"
description: "Learn how to build and get your head over how a solid Ansible playbook works through an Ansible playbook example in this step-by-step tutorial!"
canonical: "https://adamtheautomator.com/ansible-playbook-example/"
---

# How to Build (And Actually Understand) a Solid Ansible Playbook

> Learn how to build and get your head over how a solid Ansible playbook works through an Ansible playbook example in this step-by-step tutorial!

Source: https://adamtheautomator.com/ansible-playbook-example/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![How to Build (And Actually Understand) a Solid Ansible Playbook](https://adamtheautomator.com/wp-content/uploads/2022/02/How-to-Build-And-Actually-Understand-a-Solid-Ansible-Playbook.jpg)

# How to Build (And Actually Understand) a Solid Ansible Playbook

[![](https://secure.gravatar.com/avatar/2beb65fca997135120ed98dc6a2e57dcdf1a7d7d2f5ff687b5d91dc7ccd7a6b5?s=192&d=mm&r=g)Sagar](https://adamtheautomator.com/author/shanky-mendiratta/)16 February 20229 min. read

Categories: [DevOps](/category/devops/)

Tags:[Ansible](/tag/ansible/)

Table of Contents

*   [Prerequisites](#prerequisites)
*   [Declaring a Basic Ansible Playbook](#declaring-a-basic-ansible-playbook)
*   [Preventing Ansible Playbook from Stopping Executing Tasks](#preventing-ansible-playbook-from-stopping-executing-tasks)
*   [Defining Ansible Role Tomcat for an Ansible Playbook](#defining-ansible-role-tomcat-for-an-ansible-playbook)
*   [Building an Ansible Playbook](#building-an-ansible-playbook)
*   [Deploying an Ansible Playbook with the tomcat Ansible Role](#deploying-an-ansible-playbook-with-the-tomcat-ansible-role)
*   [Verifying the Tomcat Service Works on a Remote Machine](#verifying-the-tomcat-service-works-on-a-remote-machine)
*   [Conclusion](#conclusion)

Are you new to Ansible and struggling to create your first [Ansible Playbook](https://docs.ansible.com/ansible/latest/user_guide/playbooks.html)? Going through an [Ansible playbook](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html) example would be an excellent start to get your head over how an Ansible playbook works. Lucky for you, this tutorial has got you covered.

In this tutorial, you’ll learn how to build and create Ansible playbooks for service deployment while understanding the breakdown of what makes an Ansible playbook as a whole.

Without further delay, read on and start building!

## Prerequisites

This tutorial comprises step-by-step instructions. If you’d like to follow along, be sure you have the following in place:

*   An [Ansible controller host](https://docs.ansible.com/ansible/latest/installation_guide/index.html) – This tutorial uses [Ansible v2.11.7](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) on an Ubuntu 20.04.3 LTS machine.

Related:[How to Setup Ansible (Ubuntu, RHEL, CentOS, macOS)](https://adamtheautomator.com/install-ansible/)

*   A remote Linux computer to test the tomcat installation – This tutorial uses Ubuntu 20.04.3 LTS as the remote node.
    
*   An [inventory file](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html) and one or more hosts configured to run Ansible commands and playbooks. The remote Linux computer is called _myserver,_ and this tutorial uses an inventory group called _web_.
    
*   Python v3.6 or later installed both on your Ansible controller host and the remote node machine – This tutorial uses Python v3.9 on an Ubuntu machine.
    

Related:[How Do You Install Python 3.6?](https://adamtheautomator.com/install-python-36/)

## Declaring a Basic **Ansible Playbook**

Ansible playbooks let you deploy complex applications, offer reusable configuration management, multi-machine deployments, and perform multiple tasks on repetition. Ansible playbooks are written in YAML format containing multiple tasks and executed in sequential order.

To better understand how an Ansible playbook works, you’ll declare an Ansible playbook to install Apache on your remote node.

1\. Log in to the Ansible Controller host using your favorite SSH client.

2\. Next, create a file named _apache.yml_ in your home directory with your preferred text editor. Populate the file with the below content (playbook), which starts and enables the Apache service.

The code below deploys the Ansible task to install Apache to the destination server address (`web`) with the remote user (`ubuntu`).

```yaml
# Playbook apache.yml
---
- name: Installing Apache service 
  hosts: my_app_servers                                  # Define all the hosts
  remote_user: ubuntu                                    # Remote_user is ubuntu
  # Defining the Ansible task
  tasks:                                                 
  - name: Install the Latest Apache
    apt:
      name: httpd
      state: latest
```

3\. Run the below [`ansible-playbook`](https://docs.ansible.com/ansible/latest/cli/ansible-playbook.html) command to verify the playbook (`apache.yml`) to catch syntax errors (`--syntax-check`) and other problems.

> _Remember always to do this syntax check before you run your Ansible playbook. Doing so lets you avoid accidentally messing things up with your project._

```bash
ansible-playbook apache.yml --syntax-check
```

As you can see below, there are no errors displayed, which confirms that the Ansible playbook (apache.yml) has no syntax issues and can be executed safely.

![Verifying Syntax Errors in Ansible Playbook (apache.yml)](https://devopsdatacenter.files.wordpress.com/2021/02/image-95.png?w=552)

Verifying Syntax Errors in Ansible Playbook (apache.yml)

4\. Finally, run the command below to execute the Ansible playbook (`apache.yml`).

```bash
ansible-playbook apache.yml
```

If you see an OK status that specifies the Ansible task doesn’t need to perform any work. But if you get the changed status, the task is executed successfully on the remote node.

![Executing the Ansible Playbook](https://adamtheautomator.com/wp-content/uploads/2022/02/image-195.png)

Executing the Ansible Playbook

## Preventing Ansible Playbook from Stopping Executing Tasks

Previously you learned how to create a basic Ansible playbook. But while you execute the playbook, Ansible may receive a [non-zero return code](https://bobcares.com/blog/non-zero-return-code-ansible/) from a command. Or a failure from a module stopping the playbook from executing further.

To prevent the failures of stopping other tasks from executing, consider using the [error handling](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html) feature in the Ansible playbook. Error handling allows you to operate even when any task fails using [rescue and always functions](https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html#handling-errors-with-blocks) and the output you want.

Create a new playbook named _main.yml_ and copy/paste the below code. The below Ansible Playbook performs various tasks while handling failed tasks with the Ansible built-in debug module (`[ansible.builtin.debug](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html))`

```yaml
---
- name: update web servers
# Testing the Ansible Playbook on your local machine
  hosts: localhost
  remote_user: ubuntu
  tasks:
  - name: Ansible block to perform error handling 
    block:
 
      - name: Ansible task prints a message I execute normally
        ansible.builtin.debug:
          msg: 'I execute normally'
 
      - name: Ansible task will fail
        ansible.builtin.command: /bin/false
 
      - name: Ansible task will not proceed due to the previous task failing
        ansible.builtin.debug:
          msg: 'I never execute, '
 
    rescue:
      - name: Ansible task Print when errors
        ansible.builtin.debug:
          msg: 'I caught an error, can do stuff here to fix it
 
    always:
      - name: Ansible task will always get executed
        ansible.builtin.debug:
          msg: 'This executes always'
```

Now, run the below command to execute the playbook (`main.yml`)

```bash
ansible-playbook main.yml
```

Below, you’ll notice that rescue functions in the Ansible block allowed Ansible tasks to continue and run, while other tasks terminated as they failed:

*   The first task executed, printing a message that says **I execute normally**.
*   The second task fails as the command specified is incorrect (`ansible.builtin.command: /bin/false`).
*   The third task won’t proceed because the second task failed.
*   The fourth and fifth tasks always run as they contain rescue and always functions.

![Executing the main.yml Playbook](https://adamtheautomator.com/wp-content/uploads/2022/02/image-196.png)

Executing the _main.yml_ Playbook

## Defining Ansible Role Tomcat for an Ansible Playbook

At this point, you now have a basic understanding of how to build Ansible playbooks to execute simple tasks. But when you need to perform a lot of deployment work or multiple tasks that can repeat many times over, then consider using [Ansible roles](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html).

Using Ansible roles is good practice because the content in roles can be reused and shared with others. You’ll see how Ansible roles work in action by creating an Ansible-playbook to deploy Apache Tomcat service on your remote node. But first, you’ll create an Ansible role folder.

1\. Open the terminal in your Ansible controller host, then run the following commands to create a directory called _~/ansible\_playbook\_demo_ and switch to that directory. This directory will contain the [playbook](https://www.redhat.com/en/topics/automation/what-is-an-ansible-playbook#:~:text=An%20Ansible%C2%AE%20playbook%20is,make%20up%20an%20Ansible%20inventory.\)) and all the required configuration files you’ll need to deploy Apache Tomcat.

```bash
mkdir ~/ansible_playbook_demo
cd ~/ansible_playbook_demo
```

2\. Next, run the command below to create another directory named _roles_ inside the _~/ansible\_playbook\_demo_ directory, and switch to that directory.

The _~/ansible\_playbook\_demo/roles_ directory will contain the Tomcat role you need to deploy.

> _By default, Ansible looks for roles in two locations in a directory called roles/ within the directory where playbook resides or in the /etc/Ansible/roles. If you wish to store roles at different paths, [declare the paths using the `- role:` parameter in the playbook](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html)._

```bash
mkdir -p roles && cd roles
```

3\. Finally, run the command below to create the folders required by the tomcat role.

The `p` flag tells the `mkdir` command to create the parent directory (`tomcat`) and the folders such as _tasks_, _handlers_, _defaults_, _vars_, and _templates_. Each of these folders is common for every Ansible role and will eventually contain a _main.yml_ file to deploy the Tomcat role.

> _You can create the role with any name within the roles directory._

```bash
# task directory - contains the list of tasks that a role needs to execute
# handlers directory - is like normal tasks in an Ansible playbook. 
	# but they run only if the task contains a “notify” directive. 
# library directory - store any plugins or modules such as Python
# files directory - copy any files from the Ansible controller host to other nodes
# vars directory - contains all the variables you need to use in the main.yml file
# defaults directory - stores the variables that required by the role to execute
# templates - is a file that contains all your configuration parameters, 
	# but the dynamic values are given as variables in the Ansible  
mkdir -p tomcat/{tasks, handlers, defaults, vars, templates}
```

4\. Finally, run the `tree` command below to verify all required folders in the roles directory.

```bash
tree
```

At this point, you should have the file structure shown below.

![Verifying the files and directories under the roles folder](https://adamtheautomator.com/wp-content/uploads/2022/02/image-197.png)

Verifying the files and directories under the _roles_ folder

## Building an Ansible Playbook

Now that you have set up the Ansible role _tomcat_ folder, you’ll add a _main.yml_ files inside each subdirectory of the _~/ansible\_playbook\_demo/roles/tomcat/_ directory.

Ansible playbook automatically picks the values from the correct file (_main.yml_) from the relevant folder and deploys the Apache Tomcat on the remote node.

1\. Open your favorite text editor, and create a file named _main.yml_ in the _tasks_ directory.

Populate the file with the below content (playbook), which starts and enables the Tomcat service.

```yaml
---
# Installing the Java (Open Jdk) 
- name: Install Java 1.8
  apt: name=openjdk-8-jdk

# Adding the group tomcat
- name: add group "tomcat"
  group: name=tomcat

# Adding the user tomcat along with Ansible When condition
- name: add user "tomcat"
  user: name=tomcat group=tomcat home=/usr/share/tomcat createhome=no
  become: True
  become_method: sudo
  when: ansible_os_family == "Debian"

# Downloading the tomcat package using the Ansible variables
- name: Download Tomcat
  get_url: 
     url:  "{{ tomcat_download_url }}"
     dest: "{{ tomcat_download_location }}"

# Creating the tomcat directory
- name: Create a tomcat directory
  file:
    path: /usr/share/tomcat
    state: directory
    owner: tomcat
    group: tomcat

# Extracting the tomcat archive 
- name: Extract tomcat archive
  unarchive:
    src: "{{ tomcat_download_location }}"
    dest: /usr/share/tomcat
    owner: tomcat
    group: tomcat
    remote_src: yes
    extra_opts: "--strip-components=1"
    creates: /usr/share/tomcat/bin

# Copying the Ansible Jinja template (tomcat.service.j2) file to the destination node
- name: Copy tomcat service file
  template:
    src: templates/tomcat.service.j2
    dest: /etc/systemd/system/tomcat.service
  

# Starting and Enabling the tomcat service on the destination node.
- name: Start and enable tomcat
  service:
    daemon_reload: yes
    name: tomcat
    state: started
    enabled: yes
  when: ansible_service_mgr == "systemd"
```

Related:[How to Work with Ansible When and Other Conditionals](https://adamtheautomator.com/ansible-when/)

2\. Next, create another file named _main.yml_ in the _vars_ directory and copy/paste the below code.

The code below contains the variables tomcat\_download\_url and tomcat\_download\_location. These variables are set with assigned values that the Ansible role picks from the _main.yml_ file in the _tasks_ directory while running the playbook.

```yaml
tomcat_download_url: https://dlcdn.apache.org/tomcat/tomcat-10/v10.0.14/bin/apache-tomcat-10.0.14.tar.gz
tomcat_download_location: /tmp/apache-tomcat-10.0.14.tar.gz
```

3\. Lastly, create a template file named _tomcat.service.j2_ in the _templates_ directory and populate with the below code.

Below is the _tomcat.service.j2_ template that Ansible renders when you execute the playbook. Ansible then copies the data from this template to the destination node in the _/etc/systemd/system/tomcat.service_ directory.

```bash
# Unit defines the name of the service you need to deploy, which is Tomcat. 
[Unit]
Description=Tomcat
After=network.target

# Service section allows you to define the type of service.
# Forking allows you to start the tomcat service as a system start-up 
# and keeps the service running in the background.
[Service]
Type=forking

User=tomcat
Group=tomcat

# Environment contains the list of environment variables, such as 
# JAVA_HOME, etc., that Tomcat requires to run.

Environment=JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
Environment=CATALINA_HOME=/usr/share/tomcat
Environment=CATALINA_BASE=/usr/share/tomcat
Environment=CATALINA_PID=/usr/share/tomcat/temp/tomcat.pid

ExecStart=/usr/share/tomcat/bin/startup.sh
ExecStop=/usr/share/tomcat/bin/shutdown.sh

# Install section defines if the specified Unit is enabled or disabled
# WantedBY automatically starts the Tomcat at boot up.
[Install]
	WantedBy=multi-user.target
```

## Deploying an Ansible Playbook with the `tomcat` Ansible Role

You’ve managed to set up and configure the Ansible role file structure and files/folder within the Tomcat Ansible role. But unless you run the playbook, the role you created is not doing anything, so you’ll quickly deploy the Ansible role using the Ansible playbook.

Create a YML file with a name you prefer, and copy/paste the below code. For this example, the file is named _~/ansible\_playbook\_demo/tomcat-setup.yml._

The code below deploys the Ansible role (tomcat) that you configured in the “Defining Ansible Role Tomcat for an Ansible Playbook” section to the destination server address (web). Notice you deploy the Ansible role with the remote user (ubuntu) with admin access.

> _You can use roles in_ [three ways](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#using-roles)_:_ [play level](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#using-roles-at-the-play-level) _with the roles option,_ [tasks level](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#including-roles-dynamic-reuse) _with_ [include\_role](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#including-roles-dynamic-reuse)_, and_ [import\_role](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#importing-roles-static-reuse) _options._

```bash
- name: Tomcat deployment playbook
  hosts: web
  remote_user: ubuntu
  roles:
    - tomcat
```

> _Validating the Ansible playbook using the [`--check`](https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html#using-check-mode) flag with the `ansible-playbook` command shown below is a good practice before actually executing the playbook. The `--check` flag tells Ansible to perform a simulation without running the playbook._  
> ansible-playbook tomcat-setup.yml –check

Now, run the below command to execute the playbook

```bash
ansible-playbook tomcat-setup.yml
```

![Deploying the Ansible Playbook with the Tomcat Ansible Role](https://adamtheautomator.com/wp-content/uploads/2022/02/image-211.png)

Deploying the Ansible Playbook with the Tomcat Ansible Role

## Verifying the Tomcat Service Works on a Remote Machine

You’ve executed your Ansible playbook and deployed Apache Tomcat on the remote machine. So the next step is to test if the Tomcat service is running successfully. You’ll verify the Tomcat service’s status and see if you can access the Apache Tomcat landing page.

Open the terminal in the remote node, and execute the below command to verify the Tomcat service. The `tomcat` command will provide the `status` of the Tomcat service.

```bash
service tomcat status
```

Below, you can see that status shows Tomcat service is running.

![Verifying the Tomcat service on the remote machine](https://adamtheautomator.com/wp-content/uploads/2022/02/image-198.png)

Verifying the Tomcat service on the remote machine

Now, run the `curl` command below to access Apache Tomcat’s landing page (`localhost:8080`).

```bash
curl localhost:8080
```

Notice an output of an HTML code below, which indicates you’ve accessed Apache Tomcat’s landing page. This output confirms that your Ansible playbook works perfectly in deploying Apache Tomcat service.

![Verifying the Tomcat service landing page on the remote machine](https://adamtheautomator.com/wp-content/uploads/2022/02/image-199.png)

Verifying the Tomcat service landing page on the remote machine

## Conclusion

In this tutorial, you’ve taken advantage to learn how to build a rock-solid Ansible playbook using various Ansible features such as Ansible role, variables, and so on. Using the same Ansible playbook you built, you also learned to deploy Apache tomcat.

Now that you have sound knowledge of the Ansible playbook, which application do you plan to deploy with Ansible playbooks? Or perhaps learn how to [leverage Ansible variables in roles and playbooks](https://adamtheautomator.com/ansible-variables/)?

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fansible-playbook-example%2F&text=How%20to%20Build%20\(And%20Actually%20Understand\)%20a%20Solid%20Ansible%20Playbook)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fansible-playbook-example%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fansible-playbook-example%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2021/04/A-Step-by-Step-Guide-to-Getting-Started-with-Ansible-on-Windows.jpg)

### [Mastering Ansible on Windows: Your Go-To Expert Guide](/ansible-on-windows/)

Ansible on Windows made simple. A complete guide to hassle-free installation and configuration, perfect for users seeking quick and effective mastery.

![](https://adamtheautomator.com/wp-content/uploads/2022/10/How-to-Manage-Python-Libraries-with-Ansible-Pip.jpg)

### [How to Manage Python Libraries with Ansible Pip](/ansible-pip/)

Learn how to effectively manage Python libraries with the Ansible Pip module and take control of your Python dependencies!

![](https://adamtheautomator.com/wp-content/uploads/2022/06/Highly-Effective-Automation-with-Ansible-AWX.jpg)

### [Highly Effective Automation with Ansible AWX](/ansible-awx/)

Learn how Ansible AWX can take your Ansible playbooks to the next level and automate all the things with this ATA Learning tutorial!

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
