DEV Community

SerDigital64
SerDigital64

Posted on • Updated on • Originally published at serdigital64.github.io

Ansible Concepts

Ansible Overview

Ansible is an automation engine that executes tasks described in YAML + Jinja2 to bring the target system to a known state.

At its core, Ansible is a python module:

(ansible) [sysadmin@cnt84 ~]$ pip list | egrep -i -- 'ansible|jinja|yaml|markup'
ansible      4.3.0
ansible-core 2.11.3
Jinja2       3.0.1
MarkupSafe   2.0.1
PyYAML       5.4.1
Enter fullscreen mode Exit fullscreen mode

The engine along with other helpers are available as stand-alone programs that can be run directly from the command line:

  • ansible : used to run individual tasks.
  • ansible-playbook : used to execute a batch of tasks in multiple targets.
  • ansible-config : used to define engine configuration settings.
  • ansible-doc : used to show documentation of several ansible components.
  • ansible-galaxy : used to interact with the ansible packaging system.

Ansible Tasks

The minimum execution unit in Ansible is a task. Each task will focus on managing a particular component of the target host.

The main difference between an Ansible Task and traditional shell script commands is that the task defines the what (target state) and not the how (action).

For example, to set file permissions using a Bash script you need to define how it will be done:

#!/bin/bash

echo "Example: Set file permissions"
/usr/bin/chmod '0644' '/tmp/test.file'
Enter fullscreen mode Exit fullscreen mode

To achieve the same result using Ansible Tasks you define what will be the end-state of the component:

--------
- name: "Example: Set file permissions"
  ansible.builtin.file:
    mode: "0644"
    path: "/tmp/test.file"
Enter fullscreen mode Exit fullscreen mode

Here the component is the Linux file /tmp/test.file managed by the ansible.builtin.file Ansible Module and the end-state is defined by the mode attribute.

See below common shell script actions and their equivalent Ansible Tasks

Bash Ansible
Action: Copy FileA to DestinationB Target State: FileA must be present in DestinationB
Action: Set FileA Owner to UserX Target State: UserX must own FileA
Action: Start the ServiceX Target State: ServiceX must be in started state
Action: Install PackageX Target State: PackageX must be installed

Ansible Modules

Ansible Modules are used to represent components in Ansible Tasks and are intended to hide the complexity of how the component is manipulated to achieve the desired end-state.

A set of modules are already included in Ansible for managing common components. For example:

Component Module Name End-State
Linux File copy Source File is present in the Target Path
Linux File file File attributes are set (ownership, permissions, etc)
Linux File lineinfile The text line is included (or not) in the target file
Linux OS Package package The OS package is present (or not) in the target host
Linux OS Service service The OS service is started (or not) in the target host
OS User user OS User is created (or not) in the target host
OpenSSH authorized_keys OpenSSH key is present (or not) in the authorized_keys file

Additional modules developed by product owners or the OSS community are available at the Ansible Galaxy site and can be installed using the ansible-galaxy command.

For example, to add the openssh_keypair Ansible Module included in the community provided community.crypto.openssh_keypair Ansible Collection:

(ansible) [sysadmin@cnt84 ~]$ ansible-galaxy collection install community.crypto
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/download/community-crypto-1.7.1.tar.gz to /home/sysadmin/.ansible/tmp/ansible-local-321219he000qkm/tmpd12y1_sb/community-crypto-1.7.1-xrp950jz
Installing 'community.crypto:1.7.1' to '/home/sysadmin/.ansible/collections/ansible_collections/community/crypto'
community.crypto:1.7.1 was installed successfully

Enter fullscreen mode Exit fullscreen mode

Ansible Playbooks

Similar to what scripts are for traditional shells like bash, Ansible Playbooks are YAML files used to create automation jobs.

The minimum Ansible Playbook contains one or more Ansible Tasks and the explicit declaration of the target host where the end-state will be set.

The following example playbook sets test-server21 as the target host where the end-state for the package component will be set. In this case, the desired end-state is to have the package lsof installed.

- hosts: test-server21
  tasks:
    - name: "Deploy LSOF tool"
      ansible.builtin.package:
        name:
          - "lsof"
      state: "present"
Enter fullscreen mode Exit fullscreen mode

Ansible Playbooks can contain additional features to facilitate the creation of complex automation jobs:

  • Job management: defines how tasks are going to be executed based on the number of target hosts (sequentially, in parallel, etc.)
  • Error handling: provides features for recovering from failed tasks.
  • Event Handlers: defines special tasks that are only executed when certain conditions are met. For example, the application X configuration reload handler is executed when the configuration update task sets a new parameter value
  • External Variable Definition: allows the inclusion of YAML files that contains variables definitions only.
  • Roles: allows the inclusion of roles. Roles are similar to Ansible Modules but implemented using Ansible Tasks.

To run Ansible Playbooks use the command ansible-playbook:

(ansible) [sysadmin@cnt84 ~]$ ansible-playbook hello_world.yml

PLAY [localhost] *****************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [Hello World] ***************************************************************************************************
ok: [localhost] => {
    "msg": "Hello World"
}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Enter fullscreen mode Exit fullscreen mode

YAML and Jinja

Ansible doesn't have a language on its own for defining tasks.
Instead, it uses the data definition language YAML for declaring desired end-state and the template engine Jinja2 for embedding simple programming functions into YAML files.

For example, let's define the file_path variable in a stand-alone YAML file:

--------
file_path: "/tmp/test.file"
Enter fullscreen mode Exit fullscreen mode

Now we can use the file_path variable to set the path attribute.
To use the variable a Jinja2 template must be added to the YAML declaration using the expression container "{{ }}":

--------
- name: "Example: Include variable from file"
  include_vars:
    file: "example_var_definition.yml"
- name: "Example: Set file permissions"
  ansible.builtin.file:
    mode: "0644"
    path: "{{ file_path }}"
Enter fullscreen mode Exit fullscreen mode

Ansible Infrastructure

Ansible defines two types of infrastructure components:

  • Control Node: central compute node where the automation engine is installed and from where Ansible Tasks are executed.
  • Managed Node: target node that Ansible Tasks will manage to reach the defined end-state. Nodes can be regular compute nodes (RedHat Linux Enterprise, Ubuntu, etc.) or non-compute nodes such as storage devices, network devices, appliances, etc.

Communication between Control Nodes and Managed Nodes is implemented using Connection Plugins. The default plugin for Linux nodes is ssh.

Use the command ansible-doc -t connection -l to show available plugins:

(ansible) [sysadmin@cnt84 ~]$ ansible-doc -t connection -l | egrep '^ssh'
ssh                            connect via ssh client binary
Enter fullscreen mode Exit fullscreen mode

For tasks that requires privileged access to manage the component Ansible provides Become Plugins. The default plugin for Linux based nodes is sudo.

Use the command ansible-doc -t become -l to show available plugins:

(ansible) [sysadmin@cnt84 ~]$ ansible-doc -t become -l | egrep '^sudo|^su'
su                           Substitute User
sudo                         Substitute User DO
Enter fullscreen mode Exit fullscreen mode

Content Organization

Ansible doesn't enforce a strict directory structure for content organization. Instead, it provides configuration parameters that can be used to define locations based on the resource type.

The following is a basic directory structure that can be used for simple to medium size deployments:

Path Content Ansible Parameter
etc/ Ansible configuration files ANSIBLE_CONFIG
files/ Site wide data files
inventories/ Ansible Playbooks inventory files, host_vars and group_vars ANSIBLE_INVENTORY
collections/ Collections installed from Ansible-Galaxy ANSIBLE_COLLECTIONS_PATHS
roles/ Ansible Roles ANSIBLE_ROLES_PATH
playbooks/ Ansible Playbooks ANSIBLE_PLAYBOOK_DIR
logs/ Execution logs ANSIBLE_LOG_PATH

Once resources are organized you should consider managing the content using a version control system like GIT. This is key to implement the infrastructure as code strategy.

References & Resources

Copyright information

This article is licensed under a Creative Commons Attribution 4.0 International License. For copyright information on the product or products mentioned inhere refer to their respective owner.

Disclaimer

Opinions presented in this article are personal and belong solely to me, and do not represent people or organizations associated with me in a professional or personal way. All the information on this site is provided "as is" with no guarantee of completeness, accuracy or the results obtained from the use of this information.

Discussion (0)