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
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'
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"
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
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"
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
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"
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 }}"
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
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
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
- Ansible Community Documentation: https://docs.ansible.com/ansible_community.html
- Ansible Galaxy: https://galaxy.ansible.com
- Jinja2: https://jinja.palletsprojects.com/en/3.0.x
- YAML: https://yaml.org/spec
- GIT: https://git-scm.com
- Infrastructure-as-code Tutorial: https://serdigital64.github.io
- A:Platform64 Automation Platform: https://serdigital64.github.io
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.
Top comments (0)