Kahibaro
Discord Login Register

Playbooks and inventories

Understanding Ansible Playbooks

Ansible playbooks are YAML files that describe what you want done on which machines, and in what order. They are the core of how you use Ansible beyond one-off ansible ad‑hoc commands.

A playbook is made of one or more plays. Each play maps:

At a high level:

Basic Playbook Structure

The minimal structure:

Example: simple webserver setup


- name: Install and start Nginx
  hosts: webservers
  become: true
  tasks:
    - name: Install nginx package
      ansible.builtin.package:
        name: nginx
        state: present
    - name: Ensure nginx is running and enabled
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

Key points:

Multiple Plays in a Single Playbook

You can have multiple plays in one playbook, targeting different host groups or doing different stages.

Example: configure database and web servers in one run:


- name: Configure database servers
  hosts: db
  become: true
  tasks:
    - name: Install PostgreSQL
      ansible.builtin.package:
        name: postgresql
        state: present
- name: Configure web servers
  hosts: web
  become: true
  tasks:
    - name: Install application dependencies
      ansible.builtin.package:
        name:
          - python3
          - python3-venv
        state: present

Plays run top to bottom; each play loops over its target hosts.

Tasks and Modules

A task calls a module with parameters. Tasks are executed in order.

Common points:

Example:

- name: Copy application config
  ansible.builtin.copy:
    src: files/app.conf
    dest: /etc/myapp/app.conf
    owner: root
    group: root
    mode: "0644"

Tasks are idempotent when modules are written correctly: running the same playbook again should not keep changing the system.

Using Variables in Playbooks

Variables make playbooks reusable and flexible.

Defining Variables in Plays

You can define variables in a play using vars:

- name: Configure app
  hosts: web
  become: true
  vars:
    app_port: 8080
    app_user: myapp
  tasks:
    - name: Ensure app user exists
      ansible.builtin.user:
        name: "{{ app_user }}"
        system: true
    - name: Configure firewall
      ansible.posix.firewalld:
        port: "{{ app_port }}/tcp"
        permanent: true
        state: enabled

Note:

Including Variable Files

Instead of putting many variables inside a play, you can use vars_files:

- name: Configure app from variable file
  hosts: web
  become: true
  vars_files:
    - vars/app.yml
  tasks:
    - name: Debug app settings
      ansible.builtin.debug:
        var: app_port

Where vars/app.yml might look like:


app_port: 8080
app_env: production

Conditionals and When Clauses

Playbooks often need to do something only if a condition is met. Use when.

Example: run a task only on Debian-based systems:

- name: Install httpd or apache2 depending on OS
  hosts: web
  become: true
  tasks:
    - name: Install Apache on Debian/Ubuntu
      ansible.builtin.package:
        name: apache2
        state: present
      when: ansible_os_family == "Debian"
    - name: Install httpd on RedHat family
      ansible.builtin.package:
        name: httpd
        state: present
      when: ansible_os_family == "RedHat"

Conditions can use facts (like ansible_os_family), variables, or registered results.

Loops in Playbooks

Loops let you repeat a task over a list of items.

Example: install several packages:

- name: Install multiple packages
  ansible.builtin.package:
    name: "{{ item }}"
    state: present
  loop:
    - git
    - curl
    - vim

Or with dictionaries:

- name: Create multiple users
  ansible.builtin.user:
    name: "{{ item.name }}"
    shell: "{{ item.shell }}"
  loop:
    - { name: "alice", shell: "/bin/bash" }
    - { name: "bob",   shell: "/bin/zsh" }

Handlers and Notifications

Handlers are tasks that run only when notified, usually to restart services after changes.

Example:

- name: Webserver configuration
  hosts: web
  become: true
  tasks:
    - name: Deploy nginx config
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart nginx
  handlers:
    - name: Restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted

Notes:

Roles in Playbooks (High-Level Usage)

The concept of roles themselves belongs in more detail elsewhere, but for playbooks you need to know how to use them.

To apply roles in a play:

- name: Apply common configuration
  hosts: all
  become: true
  roles:
    - common
    - users
    - nginx

Roles help split big playbooks into reusable components.

Understanding Ansible Inventories

The inventory tells Ansible which hosts exist and how to connect to them. Playbooks reference hostnames or groups from the inventory via the hosts field.

An inventory can be:

Here we focus on static inventories and how playbooks use them.

Basic INI-Style Inventory

The simplest static inventory format is INI-style.

Example inventory.ini:

[web]
web1.example.com
web2.example.com
[db]
db1.example.com
[allservers:children]
web
db

Group names are in []. Hosts under them are listed line-by-line.

You can then run:

ansible-playbook -i inventory.ini site.yml

And in your playbook:

- name: Configure web servers
  hosts: web
  ...

Host Variables and Group Variables

You can define variables in the inventory itself.

Example with host-specific variables:

[web]
web1 ansible_host=10.0.0.11 ansible_user=ubuntu
web2 ansible_host=10.0.0.12 ansible_user=ubuntu
[db]
db1 ansible_host=10.0.0.21 ansible_user=postgres

Here:

Group variables in the same file:

[web]
web1
web2
[web:vars]
http_port=80
max_clients=200

All hosts in web now have http_port and max_clients defined.

Inventory Directory Layout: `group_vars` and `host_vars`

A more scalable way to manage variables is using group_vars and host_vars directories, usually next to your playbook.

Typical layout:

project/
  inventory.ini
  group_vars/
    all.yml
    web.yml
    db.yml
  host_vars/
    web1.yml
    web2.yml
  site.yml

Examples:

group_vars/all.yml (applies to every host):


ansible_user: ubuntu
timezone: UTC

group_vars/web.yml (applies to the web group):


http_port: 80
app_env: production

host_vars/web1.yml (applies only to web1):


app_env: staging

Variable precedence rules are detailed in Ansible docs, but in short, host_vars override group_vars, and closer definitions override more global ones.

YAML-Style Inventory

You can also write the inventory itself in YAML.

Example inventory.yml:


all:
  children:
    web:
      hosts:
        web1:
          ansible_host: 10.0.0.11
        web2:
          ansible_host: 10.0.0.12
    db:
      hosts:
        db1:
          ansible_host: 10.0.0.21
  vars:
    ansible_user: ubuntu

Use it with:

ansible-playbook -i inventory.yml site.yml

This style is more structured, which can be helpful in complex setups.

Host Patterns in Playbooks

The hosts field in a play uses patterns to select hosts from the inventory.

Some useful patterns:

Example:

- name: Apply base configuration to all but database servers
  hosts: all:!db
  become: true
  roles:
    - common

Putting It Together: Playbooks + Inventories

A small complete example, referencing both playbook and inventory concepts.

inventory.ini:

[web]
web1 ansible_host=10.0.0.11 ansible_user=ubuntu
web2 ansible_host=10.0.0.12 ansible_user=ubuntu
[db]
db1 ansible_host=10.0.0.21 ansible_user=postgres
[all:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa

group_vars/web.yml:


nginx_listen_port: 8080

site.yml playbook:


- name: Configure web servers
  hosts: web
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.package:
        name: nginx
        state: present
    - name: Configure nginx port
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart nginx
  handlers:
    - name: Restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted
- name: Configure database servers
  hosts: db
  become: true
  tasks:
    - name: Install PostgreSQL
      ansible.builtin.package:
        name: postgresql
        state: present

Run:

ansible-playbook -i inventory.ini site.yml

Here you can see:

This combination—clear inventories plus structured playbooks—is the core workflow of Ansible-based configuration management.

Views: 22

Comments

Please login to add a comment.

Don't have an account? Register now!