7 Ansible Playbook Examples for Beginners

Ansible Playbooks Example

Ansible Playbooks are the heart of Ansible automation. They provide a simple way to define automation workflows using YAML. Playbooks consist of instructions (tasks) that Ansible executes on remote machines. They are easy to read and manage, making them ideal for automating IT processes such as configuration management, software deployment, and task execution.

In this guide, you’ll learn how to create, manage, and optimize Ansible Playbooks with examples.

What is an Ansible Playbook?

An Ansible playbook is a YAML file that defines tasks to run on one or more remote hosts. These tasks are grouped into plays and executed in order.

Key Components of Playbooks:

  • Hosts: These define the target machines on which the tasks are executed. The hosts field specifies which group or machine to apply the playbook to.
  • Tasks: These are the actual steps executed by Ansible, such as installing software or restarting services.
  • Handlers: Special tasks triggered when a change occurs, such as restarting a service after a configuration update.
  • Variables: Dynamic values used in playbooks to make tasks reusable across multiple environments.

Writing Your First Ansible Playbook

Let’s start with a simple playbook to install NGINX on an Ubuntu server.

1. Create an inventory file inventory.yml:

[webservers]
server1 ansible_host=192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa

2. Now create a playbook nginx_install.yml:

---
- name: Install NGINX on web server
  hosts: webservers
  become: yes
  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes

    - name: Install NGINX
      apt:
        name: nginx
        state: present

3. Run the playbook:

 # ansible-playbook -i inventory.yml nginx_install.yml

Using Loops and Conditional in Playbooks

You can use loops to repeat tasks, and conditionals to execute tasks only when certain conditions are met.

Here is a simple playbook that uses a loop to install multiple packages on target servers.

---
- name: Install multiple packages
  hosts: webservers
  tasks:
    - name: Install necessary packages
      apt:
        name: "{{ item }}"
        state: present
      loop:
        - nginx
        - curl
        - git

You can also use when conditional in playbooks to install packages based on operating systems.

The following playbook installs the Nginx package only if the target host runs a Debian-based operating system.

- name: Install NGINX only if the host is Ubuntu
  apt:
    name: nginx
    state: present
  when: ansible_facts['os_family'] == "Debian"

Dynamic Task Execution with include_tasks

include_tasks allows you to include a separate task file dynamically. It’s useful when you need flexibility, such as including tasks conditionally or within a loop.

Example: Include Task Files Conditionally

Here, we will conditionally include different task files based on the operating system.

Main Playbook (site.yml):

---
- name: Configure Web Servers
  hosts: webservers
  tasks:
    - name: Include tasks for Debian
      include_tasks: debian.yml
      when: ansible_facts['os_family'] == "Debian"

    - name: Include tasks for RedHat
      include_tasks: redhat.yml
      when: ansible_facts['os_family'] == "RedHat"

Debian Task File (debian.yml):

---
- name: Install NGINX on Debian
  apt:
    name: nginx
    state: present

RedHat Task File (redhat.yml):

---
- name: Install NGINX on RedHat
  yum:
    name: nginx
    state: present

Static Task Inclusion with import_tasks

import_tasks is processed when the playbook starts, so it is static and executed unconditionally. It’s better for simpler scenarios where tasks don’t need to be dynamically included.

Import Task Files for Standard Tasks

In this example, we split common tasks into separate files and use import_tasks to include them.

Main Playbook (site.yml):

---
- name: Common Server Configuration
  hosts: all
  tasks:
    - name: Import common tasks
      import_tasks: common_tasks.yml

Common Task File (common_tasks.yml):

---
- name: Update package cache
  apt:
    update_cache: yes

- name: Ensure NGINX is installed
  apt:
    name: nginx
    state: present

Reusing Tasks Across Playbooks

You can reuse the same set of tasks across multiple playbooks. This is useful for defining common actions, like setting up users or configuring security settings.

Reusing Tasks Across Playbooks

First Playbook (playbook1.yml):

---
- name: Web Server Setup
  hosts: webservers
  tasks:
    - import_tasks: setup_users.yml

Second Playbook (playbook2.yml):

---
- name: Database Server Setup
  hosts: dbservers
  tasks:
    - import_tasks: setup_users.yml

Task File (setup_users.yml):

---
- name: Create user John
  user:
    name: john
    state: present

- name: Add John to sudo group
  user:
    name: john
    groups: sudo
    append: yes

Now, both playbook1.yml and playbook2.yml can reuse the setup_users.yml task file.

Using Variables and Facts in Playbooks

Ansible allows you to define variables using YAML syntax. Variables allow you to define values that can be reused across tasks, which helps avoid hardcoding values in multiple places. This improves playbook maintainability.

Ansible facts automatically gather data about the target hosts, such as OS, IP address, or hardware details. You can use facts to make decisions dynamically during playbook execution,.

Let’s look at an optimized playbook that installs different web servers (nginx or httpd) based on the host’s operating system. For flexibility, we’ll combine variables and Ansible facts.

- name: Install web server based on OS
  hosts: all
  vars:
    web_package_debian: nginx
    web_package_redhat: httpd
  tasks:
    - name: Install web server on Debian-based systems
      apt:
        name: "{{ web_package_debian }}"
        state: present
      when: ansible_facts['os_family'] == "Debian"

    - name: Install web server on RedHat-based systems
      yum:
        name: "{{ web_package_redhat }}"
        state: present
      when: ansible_facts['os_family'] == "RedHat"

Ansible Playbook Options with Examples

When running a playbook, you can use several command-line options to control how the playbook executes. Understanding these options will help you customize playbook execution for different environments and scenarios.

Below are some frequently used options in the playbook.

1. Using –check Mode (Dry Run)

The –check option runs the playbook in “dry run” mode. It simulates the changes without applying them, allowing you to test the playbook’s logic and see what would change.

 # ansible-playbook playbook.yml --check

Use this mode when you want to validate the playbook without making changes to the target system.

2. Using –diff for Configuration File Changes

The –diff option shows the differences between files before and after the playbook is applied. This is useful when you’re managing configuration files.

 # ansible-playbook playbook.yml --diff

Use this when working with configuration files to see exactly what changes will be made.

3. Using –verbose for Detailed Output

Ansible provides verbosity levels through the -v, -vv, -vvv, or -vvvv flags. The more vs you use, the more detailed the output becomes. For example:

 # ansible-playbook playbook.yml -vvv

Use this when you want to see detailed logs of each step in the playbook’s execution.

4. Using the debug Module

The debug module helps to print the value of variables or other information during playbook execution. This is useful for troubleshooting and ensuring that variables are set correctly.

- name: Debug variable value
  hosts: all
  tasks:
    - name: Print OS family
      debug:
        var: ansible_facts['os_family']

    - name: Print a custom message
      debug:
        msg: "Running on {{ inventory_hostname }} which is part of {{ ansible_facts['os_family'] }}"

5. Using –start-at-task to Resume from a Specific Task

If a playbook fails or you want to test specific tasks, you can use the –start-at-task option to begin playbook execution from a particular task without starting from the beginning.

 # ansible-playbook playbook.yml --start-at-task="Install NGINX"

Use this to save time when debugging a specific part of the playbook.

6. Validate Playbooks with ansible-lint

ansible-lint is a tool that checks your playbooks for best practices and potential issues. It helps ensure that your playbook follows coding standards and doesn’t have syntax or logic errors.

First, install ansible-lint:

 # pip install ansible-lint

Then, run the linter:

 # ansible-lint playbook.yml

Use Ansible-Lint regularly to validate your playbooks for common errors and best practices.

7. Using –limit to Limit Target Hosts

The -l option limits the playbook execution to specific hosts or groups.

Example:

 # ansible-playbook playbook.yml -l webservers

This command limits the playbook execution to hosts in the webservers group.

8. Using –inventory to Specify the Inventory File

By default, Ansible uses the inventory file specified in the default configuration. You can override it using the -i option.

Example:

 # ansible-playbook my_playbook.yml -i /path/to/inventory.ini

This command specifies a custom inventory file for the playbook.

9. Using –ask-become-pass to Prompt for Sudo Password

If your playbook requires sudo privileges, you can use –ask-become-pass to prompt for the password.

Example:

 # ansible-playbook playbook.yml --ask-become-pass

This command prompts you to enter the sudo password for tasks that require elevated privileges.

Conclusion

Ansible playbooks give you full control over your automation—from package installation to service management and OS-specific behavior.

✅ Start small with a basic playbook, and scale up using loops, variables, conditionals, and task includes.

🔁 Reuse your playbooks and validate your logic with ansible-lint and --check mode.

FAQs

1. Can I use conditionals in an Ansible Playbook?

Yes, conditionals can be applied using the when clause to run tasks only when specific conditions are met.

2. What is the purpose of the hosts keyword in playbook?

The hosts keyword specifies the target group of hosts on which the playbook tasks will be executed.

3. How do you handle errors in Ansible Playbooks?

You can handle errors using the ignore_errors directive or by using block and rescue sections for more advanced error handling.

4. What is the use of the become directive in Ansible Playbooks?

The become directive is used to escalate privileges, allowing tasks to run as a different user, such as root, when necessary.

About Hitesh Jethva

Experienced Technical writer, DevOps professional with a demonstrated history of working in the information technology and services industry. Skilled in Game server hosting, AWS, Jenkins, Ansible, Docker, Kubernetes, Web server, Security, Proxy, Iptables, Linux System Administration, Domain Name System (DNS), and Technical Writing.

View all posts by Hitesh Jethva