Core Basics of Ansible Playbook: From YAML Syntax and File Structure to Core Elements

Ansible Playbooks are written in YAML. They describe the entire process of automation in a human-readable language. This article will delve into the fundamental core of Playbooks, further mastering the clever uses of Ansible scripts.

YAML Syntax

1. Indentation Rules

<span>YAML</span> uses spaces for indentation to represent hierarchical relationships, which is its most basic syntax rule. It is important to note that: the Tab key cannot be used, only spaces should be used. This is because the display width of <span>Tab</span> may vary across different editors, leading to parsing errors in <span>yaml</span>.

---
- name: Correct play
  hosts: webservers   # Correct

- name: Incorrect play
   hosts: webservers  # Incorrect indentation

2. Key-Value Pairs

Key-value pairs are the basic building blocks of YAML, formatted as <span>key: value</span>. There must be a space after the colon, followed by the value.

name: Install nginx  # Correct
name:Install nginx   # Incorrect

3. Lists (Arrays)

Format: Use a hyphen <span>- </span>(followed by a space) to indicate list items. All list items must have the same indentation.

fruits:
  - Apple
  - Orange
  - Banana

Inline Format: You can also use square brackets <span>[]</span> for inline representation, suitable for shorter lists.<span>fruits: [Apple, Orange, Banana]</span>

4. Dictionaries

Format: Use indentation to represent multiple key-value pairs in a dictionary. In simple terms, it is a collection of key-value pairs.

user:
  name: xiaoyv
  uid: 1001
  shell: /bin/bash

Inline Format: Use curly braces <span>{}</span> for inline representation.<span>user: {name: john, uid: 1000, shell: /bin/bash}</span>

5. Strings

Strings usually do not require quotes, but if the string contains special characters (such as <span>:</span>,<span>{</span>,<span>}</span>,<span>[</span>,<span>]</span>,<span>,</span>,<span>&</span>,<span>*</span>,<span>#</span>,<span>?</span>,<span>|</span>,<span>-</span>,<span><</span>,<span>></span>,<span>=</span>,<span>!</span>,<span>%</span>,<span>@</span>,<span>\</span>), they must be enclosed in single quotes <span>'</span> or double quotes <span>"</span>.

A small detail:

  • Single quotes <span>'</span>: Strong strings, any special characters inside will be escaped as ordinary characters. For example:<span>path: '/usr/local/bin’</span>
  • Double quotes <span>"</span>: Weak strings, support escaping using <span>\</span>. For example:<span>msg: "This is a line.\nThis is another line."
    </span>

Multi-line Strings:

  1. <span>|</span>: Preserves line breaks. Suitable for writing configuration file blocks.
  2. <span>></span>: Collapses line breaks into spaces but preserves empty lines between paragraphs. Suitable for writing long commands or descriptions.
# Output will preserve line breaks and indentation.
content: |
  server {
    listen 80;
    server_name example.com;
  }

# Parsed will become one line:
# yum clean all &amp;&amp; yum makecache
command: &gt;
  yum clean all 
  &amp;&amp; yum makecache

Playbook File Structure

A Playbook is like a blueprint for a project, defining which machines to execute tasks on, in what order, and what tasks need to be performed.

Basic Structure Example

---
# 1. Beginning of the script, YAML file identifier (optional but recommended)
- name: Description of the first Play         # 2. Define a Play
  hosts: group1                 # 3. Core element of the Play: target hosts
  vars:                         # 4. Core element of the Play: variables
    http_port: 80
  tasks:                         # 5. Core element of the Play: task list
    - name: Install nginx           # 6. A Task
      ansible.builtin.package:   # 7. Core of the Task: module and its parameters
        name: nginx
        state: present

- name: Description of the second Play         
  hosts: group2
  tasks:
    -...

Core Elements

The execution order of Playbook file elements is linear and top-down, with Ansible executing each Play in order. Within a Play, the execution order is: <span>Process hosts</span> -> <span>Gather facts</span> -> <span>Load vars</span> -> <span>Run tasks</span> -> <span>Run handlers</span>.

1. Play

A Play is a set of instructions in a Playbook targeting a specific group of hosts. A Playbook can contain multiple Plays. It includes the following core elements:

  • <span>hosts</span>: Target hosts/groups.
  • <span>name</span>: Description of the Play. This description will be output by Ansible during YAML execution.
  • <span>vars</span>/<span>vars_files</span>: Define variables or load variables from external files.
  • <span>vars_prompt</span>: Prompt the user for variable input at runtime.
  • <span>tasks</span>: Sequence of tasks to be executed. This is also the main body of the Play.
  • <span>handlers</span>: Operations notified by tasks. Commonly used for restarting services, reloading configurations, etc.
  • <span>roles</span>: Referenced roles. A way to organize tasks, variables, files, etc., grouping content by roles for reuse.
  • <span>gather_facts</span>: Boolean value, determining whether to collect information about target hosts (such as OS, IP, hostname, etc.) at the start of the Play.

2. Task

A Task is an operation that calls a module in Ansible. In simple terms, it is Ansible’s workshop.

Core Structure of a Task:

  • <span>- name: </span>: Description of the task. Each value of <span>- name</span> will be output in the execution log.
  • <span>module: parameter=value ...</span> : Module and parameters.
  • <span>when</span> : Conditional statement. The task will only execute if the condition is met.<span>when: ansible_os_family == "Debian"</span>
  • <span>loop</span> or <span>with_<lookup_plugin></span> : Loop statement. Used to repeatedly execute a module but pass different values.
- name: Add multiple users
  ansible.builtin.user:
    name: "{{ item }}"
    state: present
  loop:
    - db_user
    - web_user
    - app_user
  • <span>register</span> : Capture the output (return value) of a task and store it in a variable for use in subsequent tasks.
- name: Check the status of /etc/nginx/nginx.conf file
  ansible.builtin.stat:
    path: /etc/nginx/nginx.conf
  register: nginx_conf_result   # Assign the result returned by the module to {nginx_conf_result} variable

- name: Report status
  ansible.builtin.debug:
    msg: "Nginx configuration file exists!"
  when: nginx_conf_result.stat.exists     # Check if the file exists, if true execute debug module

3. Handler

A Handler is a special task that only executes when notified by other tasks, commonly used for service restarts and configuration reloads.

tasks:
  - name: Update nginx configuration
    ansible.builtin.template:
      src: nginx.conf.j2
      dest: /etc/nginx/conf/nginx.conf
    notify: Restart Nginx # Notify handler

handlers:
  - name: Restart Nginx
    ansible.builtin.service:
      name: nginx
      state: restarted

Small Reminder:

  • The notify statement triggers the name of the handler, not the task itself. The name of the handler must be unique.
  • Even if notified multiple times, it will only execute once, after all normal tasks are completed.

Logic of Ansible’s Operation

The execution order of Ansible is linear and top-down:

  1. Execute each Play in order
  2. Within a single Play:
  • Process <span>hosts</span><span> to determine target hosts</span>
  • Collect <span>gather_facts</span><span> (if set to true)</span>
  • Load <span>vars</span><span> variables</span>
  • Run <span>tasks</span>
  • Finally run notified <span>handlers</span>

Conclusion

Writing a playbook can be likened to a carefully choreographed performance. Mastering the standard YAML syntax, understanding the core elements of Playbooks, and the linear execution order will help you better navigate Ansible.

More valuable content will be continuously updated, feel free to like πŸ‘, bookmark πŸ’›, and share πŸ“€, thank you for your support!

Leave a Comment