| |

LFCA 92 ๐Ÿง Ansible โ€” Concepts

โฑ๏ธ Estimated read: 13 min | |

Ansible is an open-source, command-line IT automation tool written in Python. It is used to configure systems, deploy software, and orchestrate advanced IT workflows. Its defining characteristics are simplicity and ease of use: it uses a human-readable language (YAML), requires no software installed on the managed machines, and connects over standard SSH . The LFCA exam places Ansible under DevOps Fundamentals, which carries 12โ€“16% of the total weight. Configuration management is a core DevOps topic, and Ansible is the most widely used tool in that category .

Key point: Ansible is agentless. Unlike Puppet and Chef, which require a daemon running on every managed node, Ansible connects to nodes over SSH, pushes small programs called modules to them, executes the modules, and removes them when finished . No agent, no database, no daemon. This is what makes Ansible simpler to set up and maintain than its alternatives .


Why Ansible exists

Configuration management tools before Ansible required an agent installed on every server. The agent polled a central server for instructions. The architecture was complex and the overhead was significant. Ansible changed the model.

The agentless problem. Puppet and Chef require a daemon on every node. The daemon consumes resources even when nothing is changing. It must be installed, configured, and maintained. Ansible removes the agent entirely. It uses SSH, which is already installed on every Linux server. The connection is established only when a playbook runs. When Ansible is idle, nothing runs on the managed nodes .

The simplicity problem. Ansible playbooks are written in YAML. YAML reads like documentation. A new team member can read a playbook and understand what it does without learning a domain-specific language. Puppet and Chef use Ruby-based DSLs, which are more powerful but have a steeper learning curve .

The ordering problem. Ansible executes tasks in order. The playbook is a sequential list. The order is explicit. This is different from Puppet’s declarative model, where the order is determined by the dependency graph. Ansible’s explicit ordering makes it easier to reason about what will happen .

The push model problem. Ansible uses a push model. The control node initiates the connection, pushes the configuration, and disconnects. Puppet and Chef use a pull model. The agent polls the server for instructions. The push model gives the administrator more control over when changes happen .

The trade-off. Ansible is simpler, but it is slower than a pull-based system for very large infrastructures. The SSH connection overhead adds up when managing thousands of nodes. Ansible compensates with parallelism, but a pull-based system can scale further for the largest environments.


a. The Architecture

Ansible has two roles: the control node and the managed nodes .

The control node is the machine where Ansible is installed. It can be a laptop, a desktop, or a server. It can be any computer that meets the software requirements. Multiple control nodes are possible, but Ansible does not coordinate between them . The control node is where the ansible-playbook command runs.

The managed nodes are the target devices. They can be servers, network appliances, or any computer. Ansible is not installed on the managed nodes. The only requirement is that the nodes have Python installed (Python 2.7 or Python 3.5+) and that SSH is enabled .

The connection between the control node and the managed nodes is made over SSH by default. Ansible connects to the node, pushes a module, executes it, and removes it. The module communicates with the control node through JSON over standard output .

The configuration file (ansible.cfg) controls Ansible’s behavior. It can specify the default inventory location, the remote user, the SSH port, and other settings. The file is usually stored in the project directory and version-controlled with the playbooks .


b. The Inventory

The inventory is the list of managed nodes. It is the answer to the question “which machines does this playbook target?” The inventory can be a static file or a dynamic script .

A static inventory is an INI file that lists hosts and groups. The default location is /etc/ansible/hosts, but a project-specific inventory is usually used .

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

[databases]
db1.example.com

[production:children]
webservers
databases

The [webservers] block defines a group of hosts. The [databases] block defines another group. The [production:children] block defines a parent group that contains the other two groups. The :children suffix is how Ansible defines a group of groups .

Variables can be assigned to hosts and groups. The [webservers:vars] block assigns variables to every host in the group .

[webservers:vars]
ansible_user=deploy
http_port=80

The ansible_user variable is a connection variable. It tells Ansible which user to use when connecting to the hosts. The http_port variable is an application variable that the playbook can reference .

The inventory can also be dynamic. Ansible supports dynamic inventory plugins that pull the list of hosts from cloud providers like AWS, Azure, and Google Cloud. The inventory is generated at runtime, so the list is always current .


c. Playbooks, Plays, and Tasks

A playbook is a YAML file that contains one or more plays. The playbook is the top-level unit. The ansible-playbook command runs a playbook .

A play maps a group of hosts to a set of tasks. The play defines which hosts to target, which user to connect as, and whether to use privilege escalation. A playbook can contain multiple plays, each targeting a different group of hosts .

---
- name: Configure web servers
  hosts: webservers
  become: yes

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present

    - name: Start nginx
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: yes

The hosts key specifies the target group from the inventory. The become key enables privilege escalation (sudo). The tasks key is an ordered list of tasks .

A task is a call to an Ansible module. The task has a name (for readability) and the module invocation. The module is the unit of work. Each module has a specific purpose: apt installs packages on Debian-based systems, yum installs packages on Red Hat-based systems, service manages services, copy copies files, template renders a Jinja2 template and copies the result .

Handlers are a special form of task. They only execute when notified by a previous task that resulted in a changed status. A handler is typically used to restart a service after its configuration file changes. The handler runs once, at the end of the play, even if it is notified multiple times .


d. Modules, Roles, and Collections

A module is the code that Ansible pushes to the managed node and executes. Modules are idempotent when possible. They check the current state of the system and only make changes if the state differs from the desired state. The apt module with state: present installs the package if it is not already installed. If the package is already present, the module does nothing and reports ok instead of changed .

Roles are a way to organize playbooks into reusable units. A role is a directory with a predefined structure: tasks/, handlers/, templates/, files/, vars/, and defaults/. The role encapsulates everything needed for a specific function: installing a web server, configuring a database, deploying an application. The role is then imported into a play .

- name: Configure web servers
  hosts: webservers
  roles:
    - common
    - nginx
    - myapp

Collections are the distribution format for Ansible content. A collection can contain playbooks, roles, modules, and plugins. Collections are installed from Ansible Galaxy, the community hub for sharing Ansible content. The collection format replaced the older role-only distribution and is the modern way to package and share Ansible code .


Complete Example Session

This session demonstrates the core Ansible workflow: inventory, playbook, and execution.

# ============================================
# PART 1: THE INVENTORY
# ============================================

# inventory.ini
[webservers]
web1 ansible_host=192.168.1.10
web2 ansible_host=192.168.1.11

[webservers:vars]
ansible_user=deploy
http_port=80

[databases]
db1 ansible_host=192.168.1.20

# The inventory groups the hosts.
# The variables are assigned to the webservers group.

# ============================================
# PART 2: THE PLAYBOOK
# ============================================

# site.yml
---
- name: Configure web servers
  hosts: webservers
  become: yes

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Copy nginx configuration
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: Restart nginx

    - name: Ensure nginx is running
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: Restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted

# The play targets the webservers group.
# The tasks install nginx, copy the config, and ensure the service is running.
# The handler restarts nginx when the config changes.

# ============================================
# PART 3: THE RUN
# ============================================

# ansible-playbook -i inventory.ini site.yml

# Output:
# PLAY [Configure web servers] ***************************
#
# TASK [Gathering Facts] *********************************
# ok: [web1]
# ok: [web2]
#
# TASK [Install nginx] ***********************************
# ok: [web1]
# ok: [web2]
#
# TASK [Copy nginx configuration] ************************
# changed: [web1]
# changed: [web2]
#
# TASK [Ensure nginx is running] *************************
# ok: [web1]
# ok: [web2]
#
# RUNNING HANDLER [Restart nginx] ************************
# changed: [web1]
# changed: [web2]
#
# PLAY RECAP *********************************************
# web1 : ok=5 changed=2 unreachable=0 failed=0
# web2 : ok=5 changed=2 unreachable=0 failed=0

# The "ok" status means no change was needed.
# The "changed" status means the task modified the system.

# ============================================
# PART 4: THE SECOND RUN
# ============================================

# ansible-playbook -i inventory.ini site.yml

# Output:
# PLAY RECAP *********************************************
# web1 : ok=5 changed=0 unreachable=0 failed=0
# web2 : ok=5 changed=0 unreachable=0 failed=0

# No "changed" statuses.
# The system is already in the desired state.
# The playbook is idempotent.

# ============================================
# PART 5: THE AD HOC COMMAND
# ============================================

# ansible webservers -i inventory.ini -m ansible.builtin.service -a "name=nginx state=started"

# Output:
# web1 | SUCCESS => {
#     "changed": false,
#     "name": "nginx",
#     "state": "started"
# }
# web2 | SUCCESS => {
#     "changed": false,
#     "name": "nginx",
#     "state": "started"
# }

# The ad hoc command runs a single module on the target hosts.
# The "changed": false means nginx is already running.

# ============================================
# PART 6: THE INVENTORY INSPECTION
# ============================================

# ansible-inventory -i inventory.ini --list

# Output:
# {
#     "_meta": { "hostvars": {} },
#     "all": { "children": ["ungrouped", "webservers", "databases"] },
#     "webservers": { "hosts": ["web1", "web2"] },
#     "databases": { "hosts": ["db1"] }
# }

# The ansible-inventory command inspects the inventory.

# ============================================
# PART 7: THE MODULE DOCUMENTATION
# ============================================

# ansible-doc ansible.builtin.apt

# Output: the documentation for the apt module.
# It shows the parameters, return values, and examples.

# ============================================
# PART 8: THE CONFIGURATION FILE
# ============================================

# ansible.cfg
[defaults]
inventory = ./inventory.ini
remote_user = deploy
host_key_checking = False
retry_files_enabled = False

# The configuration file controls Ansible's behavior.
# It is stored in the project directory.

# ============================================
# PART 9: THE VERSION CONTROL
# ============================================

# git add inventory.ini site.yml ansible.cfg
# git commit -m "Add web server configuration"
# git push origin main

# The configuration is stored in Git.
# The commit history is the audit log.

# ============================================
# PART 10: THE PRINCIPLES
# ============================================

# Agentless: no software on managed nodes
# Idempotent: same operation, same result
# Declarative: describe the desired state
# YAML: human-readable playbooks
# Push-based: control node initiates
# SSH: standard connection

The ten parts cover the inventory, the playbook, the run, the second run, the ad hoc command, the inventory inspection, the module documentation, the configuration file, the version control, and the principles.


Quick Reference

The Core Concepts

ConceptDefinition
Control nodeMachine running Ansible
Managed nodeTarget device
InventoryList of managed nodes
PlaybookYAML file with plays
PlayMaps hosts to tasks
TaskCall to a module
ModuleUnit of work
HandlerTask run when notified
RoleReusable bundle of tasks
CollectionDistribution format

The Commands

CommandPurpose
ansible-playbookRun a playbook
ansibleRun an ad hoc command
ansible-inventoryInspect the inventory
ansible-docShow module documentation
ansible-galaxyManage roles and collections

The Inventory Variables

VariablePurpose
ansible_hostIP or hostname
ansible_userSSH user
ansible_portSSH port
ansible_ssh_private_key_fileSSH key path

The Module Examples

ModulePurpose
aptDebian package management
yumRed Hat package management
serviceService management
copyCopy files
templateRender Jinja2 templates
userUser management

Best Practices

โœ… Do This:

# Store inventory and playbooks in version control
git add inventory.ini site.yml                                    # โœ…
# Use roles for reusable content
- name: Configure web servers
  hosts: webservers
  roles: [nginx]                                                  # โœ…
# Use handlers for service restarts
notify: Restart nginx                                             # โœ…
# Use idempotent modules
apt: { name: nginx, state: present }                              # โœ…

โŒ Don’t Do This:

# Don't use shell commands when a module exists
- shell: apt install nginx                                        # โŒ
# Don't hardcode secrets in playbooks
password: "hardcoded"                                             # โŒ
# Don't configure servers manually
ssh web1 "apt install nginx"                                      # โŒ
# Don't put everything in one playbook
# Use roles to organize.                                          # โŒ

Common Pitfalls

PitfallWhy It HappensFix
Connection refusedSSH not enabledEnable SSH on the node
Permission deniedWrong user or keyCheck ansible_user and key
Playbook not idempotentShell commands usedUse modules
Handler not runningTask not changedCheck the changed status
Inventory not foundWrong pathCheck ansible.cfg
Secrets in playbookHardcodedUse Ansible Vault

Real-World Examples

1. Inventory

[webservers]
web1 ansible_host=192.168.1.10

2. Playbook

- hosts: webservers
  tasks:
    - name: Install nginx
      apt: { name: nginx, state: present }

3. Run

ansible-playbook -i inventory.ini site.yml

4. Ad Hoc

ansible webservers -m service -a "name=nginx state=started"

5. Handler

notify: Restart nginx

6. Role

roles:
  - common
  - nginx

7. Variable

[webservers:vars]
http_port=80

8. Template

- name: Copy config
  template: { src: nginx.conf.j2, dest: /etc/nginx/nginx.conf }

9. Check Mode

ansible-playbook -i inventory.ini site.yml --check

10. Version Control

git add . && git commit -m "Add Ansible config"

Visual

The Ansible Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CONTROL NODE                                โ”‚
โ”‚    Ansible installed                         โ”‚
โ”‚    ansible-playbook command                  โ”‚
โ”‚       โ”‚                                      โ”‚
โ”‚       โ”‚  SSH                                โ”‚
โ”‚       โ–ผ                                      โ”‚
โ”‚  MANAGED NODES                               โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”‚
โ”‚    โ”‚ web1    โ”‚ โ”‚ web2    โ”‚ โ”‚ db1     โ”‚       โ”‚
โ”‚    โ”‚ (Python)โ”‚ โ”‚ (Python)โ”‚ โ”‚ (Python)โ”‚       โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚
โ”‚                                              โ”‚
โ”‚  No agent on the nodes.                      โ”‚
โ”‚  Modules pushed via SSH.                     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Playbook Structure

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  PLAYBOOK (YAML)                             โ”‚
โ”‚    โ”œโ”€ Play 1: webservers                     โ”‚
โ”‚    โ”‚    โ”œโ”€ Task: Install nginx               โ”‚
โ”‚    โ”‚    โ”œโ”€ Task: Copy config                 โ”‚
โ”‚    โ”‚    โ””โ”€ Handler: Restart nginx            โ”‚
โ”‚    โ””โ”€ Play 2: databases                      โ”‚
โ”‚         โ”œโ”€ Task: Install postgres            โ”‚
โ”‚         โ””โ”€ Handler: Restart postgres         โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Idempotency

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  IDEMPOTENCY                                 โ”‚
โ”‚                                              โ”‚
โ”‚  Run 1: Install nginx โ”€โ”€> changed            โ”‚
โ”‚  Run 2: Install nginx โ”€โ”€> ok (no change)     โ”‚
โ”‚  Run 3: Install nginx โ”€โ”€> ok (no change)     โ”‚
โ”‚                                              โ”‚
โ”‚  The result is the same.                     โ”‚
โ”‚  The operation is safe to repeat.            โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Inventory

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  INVENTORY                                   โ”‚
โ”‚                                              โ”‚
โ”‚  [webservers]                                โ”‚
โ”‚    web1 ansible_host=192.168.1.10            โ”‚
โ”‚    web2 ansible_host=192.168.1.11            โ”‚
โ”‚                                              โ”‚
โ”‚  [databases]                                 โ”‚
โ”‚    db1 ansible_host=192.168.1.20             โ”‚
โ”‚                                              โ”‚
โ”‚  [production:children]                       โ”‚
โ”‚    webservers                                โ”‚
โ”‚    databases                                 โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
AnsibleAgentless IT automation tool
LanguageYAML
Control nodeWhere Ansible runs
Managed nodesTarget devices
InventoryList of managed nodes
PlaybookYAML file with plays
PlayMaps hosts to tasks
TaskCall to a module
ModuleUnit of work
HandlerTask run when notified
RoleReusable bundle
ConnectionSSH
LFCA weightDevOps Fundamentals, 12โ€“16%

Key takeaways:

  • Ansible is agentless. It does not require any software installed on the managed nodes. It connects over SSH, pushes modules to the nodes, executes them, and removes them. No agent, no daemon, no database .
  • The inventory is the list of managed nodes. It can be a static INI file or a dynamic script. It defines hosts and groups. Variables can be assigned to hosts and groups .
  • A playbook is a YAML file with plays. A play maps a group of hosts to a set of tasks. A task is a call to a module. The tasks are executed in order .
  • Modules are the units of work. Each module has a specific purpose: package management, service management, file copying, user management. Modules are idempotent when possible. They check the current state and only make changes if necessary .
  • Handlers are tasks that run only when notified. They are typically used to restart a service after its configuration changes. The handler runs once at the end of the play .
  • Roles are reusable bundles of tasks. They organize playbooks into logical units. A role has a predefined directory structure with tasks, handlers, templates, and variables .
  • Ansible is idempotent. Running a playbook twice produces the same result. If the system is already in the desired state, the playbook reports ok instead of changed .

Remember: Ansible is the simplest of the configuration management tools. It is agentless. It uses SSH. It uses YAML. The inventory is the list of nodes. The playbook is the configuration. The play is the mapping. The task is the action. The module is the work. The handler is the restart. The role is the reuse. Ansible is the tool that turns a provisioned server into a configured one.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!