Quick Startup with Ansible

Photo by Lukas on Unsplash

Quick Startup with Ansible

Ansible is a powerful automation tool used for configuration management, application deployment, and task automation. It operates by connecting to your nodes and pushing out small programs, called Ansible modules, to perform tasks.

Image credits: Ansible.com

The main components of Ansible are:

  1. Inventory: A list of hosts or nodes that Ansible manages.

  2. Modules: Units of work that Ansible executes. Examples include tasks for installing packages, copying files, or restarting services.

  3. Playbooks: YAML files that define a series of tasks to be executed on a set of hosts.

  4. Roles: A way to group multiple tasks and configurations to be reusable.

  5. Variables: Used to store values that can be reused in playbooks and templates.

  6. Templates: Files that have placeholders for variables and can be dynamically populated during execution.

  7. Handlers: Used to trigger actions at the end of a playbook run when certain conditions are met.

Ansible Components Overview

1. Inventory

Inventory File:

  • The default inventory file is usually named hosts or inventory.

  • By default, it is located at /etc/ansible/hosts.

  • It can be a simple INI-style file or YAML file, listing the managed nodes.

INI File:

  • An .ini file is a simple text file used for configuration, with sections, properties, and values.

  • In the context of Ansible, it defines groups of hosts and their variables.

Example (INI-style):

# Default inventory file location: /etc/ansible/hosts

[webservers]
web1.example.com
web2.example.com

[databases]
db1.example.com

# Defining variables for groups
[webservers:vars]
ansible_user=admin
ansible_ssh_private_key_file=/path/to/key

Example (YAML-style):

all:
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
      vars:
        ansible_user: admin
        ansible_ssh_private_key_file: /path/to/key
    databases:
      hosts:
        db1.example.com:

2. Modules

Modules:

  • Small programs that Ansible pushes out to nodes to perform tasks. After programs finish the execution, Ansible removes them.

  • Examples include modules for package management (apt, yum), file operations (copy, template), and service management (service).

Example:

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

Command to list available modules:

ansible-doc -l

3. Playbooks

Playbooks:

  • YAML files that define a series of tasks to be executed on hosts.

  • They contain plays, each mapping a group of hosts to roles and tasks.

Important Parts:

  • hosts: Specifies which hosts the playbook should run against.

  • tasks: Defines a list of tasks to be executed.

  • vars: Defines variables to be used within the playbook.

  • handlers: Defines handlers that can be notified by tasks.

Example:

---
- name: Configure web servers
  hosts: webservers
  vars:
    nginx_version: 1.18.0
  tasks:
    - name: Install Nginx
      apt:
        name: nginx={{ nginx_version }}
        state: present

    - name: Copy Nginx config
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart Nginx

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

4. Roles

Roles:

  • Provide a structured way to group tasks, handlers, files, templates, and variables.

  • Allow for reuse and sharing of Ansible content.

Role Directory Structure:

roles/
  webserver/
    tasks/
      main.yml
    templates/
      nginx.conf.j2
    handlers/
      main.yml
    vars/
      main.yml
    defaults/
      main.yml
    files/
    meta/
      main.yml

Example Task File (roles/webserver/tasks/main.yml):

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

The beauty of roles lies in their reusability. You can include the same role in multiple playbooks to automate the same configuration on different sets of servers. For example, like installing and configuring a web server (Apache or Nginx) or setting up a database (MySQL or PostgreSQL).

To include a role inside an Ansible playbook you can use include_role module.

This is the recommended approach for Ansible versions 2.4 and later. It offers more control and clarity.

- ansible.builtin.include_role:
    name: myrole

- name: Run tasks/other.yaml instead of 'main'
  ansible.builtin.include_role:
    name: myrole
    tasks_from: other

- name: Pass variables to role
  ansible.builtin.include_role:
    name: myrole
  vars:
    rolevar1: value from task

- name: Use role in loop
  ansible.builtin.include_role:
    name: '{{ roleinputvar }}'
  loop:
    - '{{ roleinput1 }}'
    - '{{ roleinput2 }}'
  loop_control:
    loop_var: roleinputvar

- name: Conditional role
  ansible.builtin.include_role:
    name: myrole
  when: not idontwanttorun

- name: Apply tags to tasks within included file
  ansible.builtin.include_role:
    name: install
    apply:
      tags:
        - install
  tags:
    - always

5. Variables

Variables:

  • Used to store values that can be reused in playbooks, roles, and templates.

  • Can be defined in playbooks, inventories, roles, or passed via command line.

Variable Precedence (highest to lowest):

  1. Extra vars (command line -e)

  2. Task vars (only in scope for the task)

  3. Block vars (only in scope for the block)

  4. Role and include vars

  5. Play vars (for the entire play)

  6. Inventory vars

  7. Facts (gathered or set via set_fact)

  8. Playbook group_vars

  9. Playbook host_vars

  10. Ansible configuration settings

To learn more about variables check out this article: How to Use Different Types of Ansible Variables (Examples)

1. Extra vars (command line -e)

Description:

  • Extra variables passed directly on the command line have the highest precedence.

Example:

ansible-playbook playbook.yml -e "var1=value1 var2=value2"

Playbook (playbook.yml):

---
- hosts: all
  tasks:
    - debug:
        msg: "var1={{ var1 }}, var2={{ var2 }}"

2. Task vars (only in scope for the task)

Description:

  • Variables defined within a specific task have a very high precedence.

Example:

---
- hosts: all
  tasks:
    - name: Show task variable
      debug:
        msg: "Task variable var1={{ var1 }}"
      vars:
        var1: "task_value"

3. Block vars (only in scope for the block)

Description:

  • Variables defined within a block are in scope only for tasks within that block.

Example:

---
- hosts: all
  tasks:
    - block:
        - name: Show block variable
          debug:
            msg: "Block variable var1={{ var1 }}"
      vars:
        var1: "block_value"

To learn more, check out "Blocks"

4. Role and include vars

Description:

  • Variables defined within roles or included files.

Example:

# roles/webserver/vars/main.yml
---
var1: "role_value"

# playbook.yml
---
- hosts: all
  roles:
    - role: webserver
  tasks:
    - debug:
        msg: "Role variable var1={{ var1 }}"

5. Play vars (for the entire play)

Description:

  • Variables defined within a play are in scope for the entire play.

Example:

---
- hosts: all
  vars:
    var1: "play_value"
  tasks:
    - name: Show play variable
      debug:
        msg: "Play variable var1={{ var1 }}"

6. Inventory vars

Description:

  • Variables defined in the inventory file.

Example (INI-style inventory):

# inventory
[all:vars]
var1=inventory_value

Playbook:

---
- hosts: all
  tasks:
    - name: Show inventory variable
      debug:
        msg: "Inventory variable var1={{ var1 }}"

7. Facts (gathered or set via set_fact)

Description:

  • Facts are gathered by Ansible or set during playbook execution using set_fact.

Example:

---
- hosts: all
  tasks:
    - name: Set fact variable
      set_fact:
        var1: "fact_value"

    - name: Show fact variable
      debug:
        msg: "Fact variable var1={{ var1 }}"

8. Playbook group_vars

Description:

  • Variables defined for groups in the group_vars directory within the playbook directory.

Example (group_vars/all.yml):

# group_vars/all.yml
---
var1: "group_vars_value"

Playbook:

---
- hosts: all
  tasks:
    - name: Show group_vars variable
      debug:
        msg: "Group_vars variable var1={{ var1 }}"

9. Playbook host_vars

Description:

  • Variables defined for individual hosts in the host_vars directory within the playbook directory.

Example (host_vars/hostname.yml):

# host_vars/hostname.yml
---
var1: "host_vars_value"

Playbook:

---
- hosts: hostname
  tasks:
    - name: Show host_vars variable
      debug:
        msg: "Host_vars variable var1={{ var1 }}"

10. Ansible configuration settings

Description:

  • Variables set in the Ansible configuration files (e.g., ansible.cfg).

Example (ansible.cfg):

# ansible.cfg
[defaults]
var1 = config_value

Playbook:

---
- hosts: all
  tasks:
    - name: Show config variable
      debug:
        msg: "Config variable var1={{ var1 }}"

6. Templates

Templates:

  • Jinja2 templates are used to create dynamic configuration files.

  • Variables can be embedded and will be replaced during execution.

Example Template (templates/nginx.conf.j2):

server {
    listen 80;
    server_name {{ server_name }};
    location / {
        proxy_pass http://{{ backend }};
    }
}

Example Task Using Template:

- name: Copy Nginx config
  template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/nginx.conf

7. Handlers

Handlers:

  • Special tasks that are triggered by other tasks using the notify directive.

  • Run once at the end of the playbook execution if notified.

Example:

- name: Install Nginx
  apt:
    name: nginx
    state: present
  notify: Restart Nginx

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

Understanding these components allows for efficient and effective use of Ansible for automation tasks. Each component plays a crucial role in defining the structure and functionality of your automation scripts.

References:

  1. Ansible Community Documentation

  2. Ansible Docs: How Ansible Works