LFCA 92 ๐ง Ansible โ Concepts
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
| Concept | Definition |
|---|---|
| Control node | Machine running Ansible |
| Managed node | Target device |
| Inventory | List of managed nodes |
| Playbook | YAML file with plays |
| Play | Maps hosts to tasks |
| Task | Call to a module |
| Module | Unit of work |
| Handler | Task run when notified |
| Role | Reusable bundle of tasks |
| Collection | Distribution format |
The Commands
| Command | Purpose |
|---|---|
ansible-playbook | Run a playbook |
ansible | Run an ad hoc command |
ansible-inventory | Inspect the inventory |
ansible-doc | Show module documentation |
ansible-galaxy | Manage roles and collections |
The Inventory Variables
| Variable | Purpose |
|---|---|
ansible_host | IP or hostname |
ansible_user | SSH user |
ansible_port | SSH port |
ansible_ssh_private_key_file | SSH key path |
The Module Examples
| Module | Purpose |
|---|---|
apt | Debian package management |
yum | Red Hat package management |
service | Service management |
copy | Copy files |
template | Render Jinja2 templates |
user | User 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
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Connection refused | SSH not enabled | Enable SSH on the node |
| Permission denied | Wrong user or key | Check ansible_user and key |
| Playbook not idempotent | Shell commands used | Use modules |
| Handler not running | Task not changed | Check the changed status |
| Inventory not found | Wrong path | Check ansible.cfg |
| Secrets in playbook | Hardcoded | Use 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
| Item | Value |
|---|---|
| Ansible | Agentless IT automation tool |
| Language | YAML |
| Control node | Where Ansible runs |
| Managed nodes | Target devices |
| Inventory | List of managed nodes |
| Playbook | YAML file with plays |
| Play | Maps hosts to tasks |
| Task | Call to a module |
| Module | Unit of work |
| Handler | Task run when notified |
| Role | Reusable bundle |
| Connection | SSH |
| LFCA weight | DevOps 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
okinstead ofchanged.
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.
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!