Ansible Basics 05: Playbooks

Ansible playbooks are the core components of Ansible. Playbooks are written in YAML format and describe a set of tasks that need to be executed on the managed systems. A playbook consists of one or more plays, and each play defines a set of tasks to be performed on a group of hosts. Tasks are the individual actions or commands that Ansible should execute, such as installing packages, copying files, or restarting services. Tasks call out to the programmed code units called modules.

The basic components of a playbook

Here’s the basic structure of an Ansible playbook:

---
- name: Example Playbook
  hosts: target_hosts

  tasks:
    - name: Task 1
      <module_name>:  # appropriate Ansible module
        <module_parameters>: <value>

    - name: Task 2
      <module_name>:
        <module_parameters>: <value>

Let’s break it down:

  • name: The name is a human-readable description of what the playbook does. It’s optional but recommended for clarity.
  • hosts: This section specifies the target hosts or groups of hosts where the tasks defined in the playbook will be executed. Hosts can be defined either as individual hostnames or IP addresses, or as groups defined in the Ansible inventory file. Patterns can be used here.
  • tasks: Tasks define the actions that Ansible should perform on the target hosts. Each task typically corresponds to a specific module, which carries out a particular programmed action on the target system. Tasks are executed sequentially, in the order they are defined in the playbook (from top to bottom). The modules are part of different collections.

These are the essential components of an Ansible playbook.

Additional playbook components

Additional playbook components can be:

  • vars: Playbooks can include variable definitions that can be used throughout the playbook. Variables can be defined inline or in separate variable files, and they provide flexibility and reusability.
  • become: Indicates whether to execute tasks with escalated privileges (sudo or another method).
  • handlers: Handlers are similar to tasks but are only executed if triggered by another task. They are typically used to restart services or perform other actions in response to changes made by tasks. Handlers are defined separately from tasks and referenced using the notify directive.
  • roles: Playbooks can organize tasks into reusable units called roles. Roles encapsulate all the necessary tasks, variables, and other files needed to perform a specific function or role within the infrastructure. They promote modularity, reusability, and maintainability of Ansible code.

Ansible playbooks allow you to define the desired state of your infrastructure and automate complex tasks across multiple servers.

Running Ansible playbooks

For the sake of simplicity let’s use the following inventory file as reference for this section:

[deb]
192.168.1.91
192.168.1.92

[rpm]
192.168.1.93

The inventory file contains two groups (deb, rpm) and three hosts.

Your very first Ansible playbook file, let’s call it playbook.yaml looks like this:

- name: My first Ansible play
  hosts: all    # Targets the "all" group
  tasks:
    - name: Checking availability with ping
      ansible.builtin.ping:

The play targets the all host group.

To run the playbook, you have to use the ansible-playbook command. It takes similar arguments as the ansible command which you used for Ad-Hoc commands. You can read more info about the command options and arguments using the --help option.

Run the playbook with the ansible-playbook command, use the -i option for providing it an inventory file and use the playbook file as the last argument:

ansible-playbook -i inventory playbook.yaml

The output of an ansible-playbook run will contain the following elements:

1: PLAY [My first Ansible play]
2: TASK [Gathering Facts]
3: 192.168.1.91: ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
  1. The name of the play.
  2. Tasks running sequentially (there can be triggers, so called “handlers” here too).
  3. The “Play Recap” will show the results of the play.

A playbook file can contain multiple plays, both targeting different hosts or groups.

- name: My first Ansible play
  hosts: all    # Targets the "all" group
  tasks:
    - name: Checking availability with ping
      ansible.builtin.ping:

- name: My second play
  hosts: deb    # Targets the "deb" group
  tasks:
    - name: Random command as root
      ansible.builtin.command: 'uname'
      become: true

The playbook above contains two plays, the “My first Ansible play” and the “My second play“. The first play targets the all host group, the second one targets only the deb group.

Targeting hosts and groups with the --limit option

The playbook’s host directive targets a set of managed hosts or groups from the inventory.

Using the ansible-playbook command it will run on the hosts or groups from the hosts directive.

It is possible to narrow down the targeted hosts or groups using the --limit option of the ansible-playbook command.

To check and validate the targeted hosts or groups of an Ansible playbook use the --list-hosts option. This will NOT run the plays in the playbook, this only prints out the targeted systems.

ansible-playbook -i inventory playbook.yaml --list-hosts

playbook: playbook.yaml

  play #1 (all): My first Ansible playbook      TAGS: []
    pattern: ['all']
    hosts (3):
      192.168.1.91
      192.168.1.92
      192.168.1.93

  play #2 (deb): My second playbook     TAGS: []
    pattern: ['deb']
    hosts (2):
      192.168.1.91
      192.168.1.92

Limiting the playbook run only for the rpm group will work like this:

ansible-playbook -i inventory playbook.yaml --limit rpm --list-hosts

playbook: playbook.yaml

  play #1 (all): My first Ansible playbook      TAGS: []
    pattern: ['all']
    hosts (1):
      192.168.1.93

  play #2 (deb): My second playbook     TAGS: []
    pattern: ['deb']
    hosts (0):

The first play targets the all host group, the rpm group is part of it so there is a targeted host.

The second play targets only the deb group, there are no rpm group member machines in it.

With some creativity you can create a useful combination of inventories, hosts and groups with it. My experience is that it is not worth it making the inventories overly complex.

It is a clever idea to plan in advance and to avoid mis-targeting hosts during playbook runs. Multiple small inventory files and playbooks work better than an over-complicated monster.

Summary

As you can see playbooks are the essential core parts of Ansible. They are the blueprints of different operations to be executed on hosts and groups.

Playbooks run tasks from top to bottom with the ansible-playbook command. Tasks load Ansible modules to do the actual operations.

You can target less hosts from the hosts directive of the playbook with the --limit option.

This information is enough to get you started writing basic playbooks.

If you want to discuss the topic with other technology-minded people, join my Discord: https://discord.gg/YbSYGsQYES

Now we have an IRC channel as well: irc.libera.chat / #tomsitcafe

Leave a comment