Ansibel Playbook

Milan Neupane | Apr 17, 2025 min read

What is an Ansible Playbook?

An Ansible Playbook is a YAML file used to define and execute automation tasks on remote machines. It is the heart of Ansible configuration management, enabling infrastructure as code. Playbooks can describe a policy to be enforced or a set of steps in a general IT process.

Unlike scripts that run sequentially, Playbooks are declarative, meaning you define the desired state of your system rather than how to get there.


Structure of an Ansible Playbook

An Ansible Playbook is made up of:

  • Plays: Each play targets a group of hosts and defines a list of tasks to run.
  • Tasks: Each task executes a module with specific arguments.
  • Modules: Reusable Ansible code blocks like apt, copy, service, etc.
  • Variables: Used to store dynamic values.
  • Handlers: Special tasks triggered by notify from other tasks.
  • Roles: A way to organize playbooks into reusable components.

Example: A Basic Ansible Playbook

---
- name: Install Apache on web servers
  hosts: webservers
  become: yes

  vars:
    apache_package: apache2

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

    - name: Install Apache
      apt:
        name: "{{ apache_package }}"
        state: present

    - name: Ensure Apache is running
      service:
        name: "{{ apache_package }}"
        state: started
        enabled: yes

Explanation:

  • hosts: webservers: Target all machines in the webservers group.
  • become: yes: Run tasks with sudo privileges.
  • vars: Define reusable variables.
  • tasks: A list of actions to perform.

Handlers Example

Handlers are tasks triggered only when notified by another task (used for things like restarting services).

- name: Configure Nginx
  hosts: nginx
  become: yes

  tasks:
    - name: Copy nginx config
      copy:
        src: nginx.conf
        dest: /etc/nginx/nginx.conf
      notify: Restart nginx

  handlers:
    - name: Restart nginx
      service:
        name: nginx
        state: restarted

Using Variables

Variables can be defined in the playbook, inventory, or external files.

vars:
  app_user: deploy
  app_port: 8080

And then used like:

- name: Add application user
  user:
    name: "{{ app_user }}"

Real-world Playbook with Multiple Plays

---
- name: Install Docker on all hosts
  hosts: all
  become: yes

  tasks:
    - name: Install Docker dependencies
      apt:
        name: "{{ item }}"
        state: present
      loop:
        - apt-transport-https
        - ca-certificates
        - curl
        - software-properties-common

    - name: Add Docker GPG key
      apt_key:
        url: https://download.docker.com/linux/ubuntu/gpg
        state: present

    - name: Add Docker repository
      apt_repository:
        repo: deb https://download.docker.com/linux/ubuntu focal stable
        state: present

    - name: Install Docker
      apt:
        name: docker-ce
        state: present

- name: Deploy App Container
  hosts: appservers
  become: yes

  tasks:
    - name: Run nginx container
      docker_container:
        name: nginx
        image: nginx:latest
        state: started
        ports:
          - "80:80"

Best Practices

  • Use roles to organize playbooks.
  • Keep playbooks idempotent (safe to run multiple times).
  • Use variables and templates to make playbooks dynamic.
  • Use handlers to avoid unnecessary restarts.
  • Always test in staging before applying to production.

Summary Table of Key Components

ComponentDescriptionExample
hostsGroup of machines to run the playbook onhosts: webservers
tasksSteps to be performed on the remote machinesapt, copy, service
varsDefine variables used in tasksapp_port: 8080
handlersTasks triggered by notifyRestart services
rolesReusable and modular directories of playbooksroles/webserver/tasks/main.yml
becomeRun tasks with sudo privilegesbecome: yes
loopIterate over a listloop: [pkg1, pkg2]