Table of Contents
- 4.1 Ansible playbooks
- 4.2 Ansible facts and debugging
- 4.3 Demonstration — Writing and Running Playbooks
- 4.4 Demo — Playbook Troubleshooting
1. Understand the architecture and fundamental concepts of Ansible
1.1 Ansible Architecture
Course objectives
This course will teach you how to configure Ansible and use it to automate everyday IT tasks. You’ll start by understanding how Ansible works and explore its key components. Next, you’ll learn how to set up your own Ansible environment, run ad-hoc commands, and write simple playbooks for basic configuration management. By the end of the course, you will be ready to use Ansible with confidence for small- and medium-scale automation tasks.
The metaphor of filming
To understand the architecture of Ansible, it is useful to make an analogy with a film production. Everyone on set has a role, and the director does the magic.
- The control node acts as the director. This is where Ansible lives. The control node gives instructions, chooses who does what and when. We install Ansible on the control node and run it from there.
- Managed nodes are like actors. They receive the instructions and execute them, but they don’t need to know the whole script or install anything extra. These are the machines you want to configure or automate.
The control node in detail
The control node is where we install the Ansible automation engine. It also contains all the resources needed to run the playbooks:
- inventories (host lists)
- The roles
- The modules
- The playbooks
The control node connects to managed hosts to send them instructions via SSH for Linux systems, or WinRM for Windows systems.
Where can Ansible be installed?
The most common and recommended place to install Ansible is on a Linux machine. Any modern distribution works: Ubuntu, Debian, CentOS, Fedora or Red Hat Enterprise Linux. Other options exist:
- macOS: Ansible can be installed easily via Homebrew.
- Containers: Ansible can run from a container image, which is ideal for CI/CD pipelines or isolated tests.
- Virtual environments: Ansible can be installed in virtual environments as long as the OS is compatible.
Managed nodes
The managed nodes are managed remotely via the network by the control node, so no agent must be installed. They simply need to be accessible via SSH or WinRM from the Ansible control node. Their location is defined on the control node in the inventory.
When the control node connects to a managed node, it generally performs administrative tasks such as:
- Install software
- Create users
- Configure services, etc.
To do this, he must authenticate with a privileged account on the managed node. On Linux or macOS this means using a normal user with sudo access, while on Windows it’s usually an administrator account via WinRM.
Agentless architecture
Since we do not need to install anything on the managed nodes, Ansible offers an agentless architecture. Here are the advantages and limitations of this approach:
Advantages:
- No need to install or maintain an agent on managed nodes — setup is faster and cleaner.
- Lightweight — low resource usage on target machines because no agents are running on them.
- Uses SSH or WinRM, which are standard protocols — no need to install additional software.
- Tasks run instantly — no waiting for agent check-ins.
Limitations:
- Without an agent running constantly, Ansible cannot react to real-time events.
- Requires stable network connection to run tasks.
- Credential security is critical — any SSH keys or WinRM passwords used must be managed securely.
1.2 Ansible components and YAML syntax
The four main components of Ansible
Continuing the movie shooting metaphor:
| Component | Metaphor | Technical description |
|---|---|---|
| Inventories | Casting list | Configuration file that tells Ansible which systems to communicate with |
| Playbooks | Film script | Files written in YAML format that tell managed nodes what to do and in what order |
| Modules | The actors who play | Units of code that perform specific tasks (install packages, manage files, etc.) |
| Plugins | The production team | Pieces of code that extend core Ansible functionality (logging, login, etc.) |
Overview of Ansible architecture in practice
┌─────────────────────────────────────────────┐
│ CONTROL NODE │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ Playbooks│ │Inventory │ │ Modules │ │
│ └──────────┘ └──────────┘ └───────────┘ │
│ Ansible Engine │
└─────────────────┬───────────────────────────┘
│ SSH (Linux/macOS)
│ WinRM (Windows)
┌─────────┴─────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ MANAGED NODE │ │ MANAGED NODE │
│ (Linux/Mac) │ │ (Windows) │
│ Pas d'agent │ │ Pas d'agent │
└───────────────┘ └───────────────┘
What is YAML?
Ansible uses YAML (YAML Ain’t Markup Language). YAML is a human-readable data format used to define structured data. Ansible playbooks, roles, tasks, and variables are all written in YAML. YAML allows users to write automation with syntax close to natural English, making it easy to understand and maintain.
If you’re familiar with JSON, YAML is a similar but much cleaner concept.
Important point: Indentation is essential in YAML. Indentation errors are the most common cause of errors in Ansible.
Essential YAML syntax rules
1. The document header (optional but recommended)
It is good practice to start each YAML file with three hyphens:
---
This clearly indicates to tools and editors: “this is a YAML document.”
2. Key-value format
name: mon-serveur
port: 8080
enabled: true
This structure makes the configuration easy to read, understand and organize.
3. Lists
Use a hyphen - for each element in a list:
packages:
- nginx
- httpd
- curl
4. Sensitivity to white space
YAML uses spaces to define parent-child relationships. Consistent spacing is essential. We generally use two spaces per indentation level.
---
- name: Mon premier play
hosts: webservers
tasks:
- name: Installer nginx
dnf:
name: nginx
state: present
In this example:
name,hosts,tasksare at the same level (2 spaces)- Content of
tasksis indented by 4 spaces - Arguments of module
dnfare indented by 8 spaces
Warning: Most YAML errors in Ansible come from bad indentation. Special attention must be paid to this.
2. Setting up the laboratory environment
2.1 Installation and configuration of Ansible
Control node prerequisites
Before installing Ansible, make sure your control node meets the basic requirements:
- RHEL 9.0 or newer installed
- Python 3.8 or newer
- Internet access to retrieve packages
- A valid Red Hat subscription (even the free developer version)
Ansible also works on older versions of Red Hat Enterprise Linux, but it is recommended to stay on the most recent versions.
Steps to prepare the RHEL control node
# Étape 1 : Enregistrer le système auprès de Red Hat
subscription-manager register
# Étape 2 : Installer Ansible
dnf install ansible-core
# Étape 3 : Créer un utilisateur ansible sur les managed nodes et configurer SSH
useradd ansible
passwd ansible
ssh-keygen
ssh-copy-id ansible@node1
ssh-copy-id ansible@node2
Linux managed node prerequisites
To manage a Linux machine with Ansible:
- Python 2.6 or later — Ansible modules run through Python
- SSH enabled — this is how the control node connects to managed nodes
- An account with administrator privileges — Ansible requires elevated access for certain system changes
Windows managed node prerequisites
For Windows systems managed with Ansible:
- PowerShell 3.0 or higher
- WinRM enabled and configured — Ansible connects to Windows hosts via WinRM
- WinRM traffic must be authorized in the firewall
- The account used must have administrator privileges
Demo — Installing Ansible on RHEL
The demonstration follows these practical steps:
1. Check hosts in /etc/hosts
id
# Résultat : uid=0(root) ...
cat /etc/hosts
# node1 et node2 sont définis avec leurs adresses IP
2. Register the system with subscription-manager
subscription-manager register
# Saisir le nom d'utilisateur Red Hat
# Saisir le mot de passe Red Hat
# Le système est enregistré sous le nom "control"
subscription-manager repos --list
# Lister tous les dépôts disponibles
3. Install ansible-core
dnf list ansible-core
# Vérifier la disponibilité du package
dnf install ansible-core
# Confirmer l'installation
4. Register managed nodes
# Sur node2
ssh node2
subscription-manager register
# Saisir les identifiants Red Hat
sudo dnf list httpd
# Valider l'accès au dépôt Red Hat
# Sur node1
ssh node1
subscription-manager register
sudo dnf list httpd
5. Create the ansible user on all nodes
# Sur le control node
sudo useradd ansible
sudo passwd ansible
# Mot de passe : redhat
# Sur node1
ssh node1
sudo useradd ansible
sudo passwd ansible
# Mot de passe : redhat
exit
# Sur node2
ssh node2
sudo useradd ansible
sudo passwd ansible
# Mot de passe : redhat
exit
6. Configure SSH keys for passwordless access
# Sur le control node, se connecter en tant qu'ansible
su - ansible
cd ~
# Générer une paire de clés SSH
ssh-keygen
# Appuyer sur Entrée pour toutes les options par défaut
# Transférer la clé publique vers node1
ssh-copy-id ansible@node1
# Saisir le mot de passe : redhat
# Transférer la clé publique vers node2
ssh-copy-id ansible@node2
# Saisir le mot de passe : redhat
# Valider l'accès sans mot de passe
ssh node1
# Connexion réussie sans mot de passe
exit
ssh node2
# Connexion réussie sans mot de passe
exit
7. Configure sudo privileges without password
# Sur node1
ssh node1
sudo vim /etc/sudoers.d/ansible
# Ajouter la ligne suivante :
ansible ALL=(ALL) NOPASSWD:ALL
exit
# Sur node2
ssh node2
sudo vim /etc/sudoers.d/ansible
# Ajouter la ligne suivante :
ansible ALL=(ALL) NOPASSWD:ALL
# Tester les privilèges sudo
sudo systemctl restart crond
# Fonctionne sans demande de mot de passe
exit
8. Create the ansible directory and validate with a ping command
# Sur le control node, en tant qu'utilisateur ansible
mkdir ansible
cd ansible
# Créer l'inventaire
vim inventory
# Contenu :
node1
node2
# Valider le laboratoire avec des commandes ad-hoc ping
ansible node1 -i inventory -m ping
# Réponse : pong ✓
ansible node2 -i inventory -m ping
# Réponse : pong ✓
2.2 Ansible inventories
What is inventory?
Imagine you are planning a big event like a wedding. You have a guest list that details who is invited, their contact details, etc. In Ansible, an inventory serves a similar role. It’s a structured file that specifies all the systems or hosts you manage, organizing them into groups and defining their attributes.
Two types of inventories
1. Static inventory
A file that you write yourself. You list your servers and group them manually. It’s simple and ideal for smaller, stable environments.
2. Dynamic inventory
Automatically generates host lists by querying external sources like cloud providers or other services. Ideal for environments where servers appear and disappear frequently.
Structure of static inventories
Simple inventory (individual hosts)
node1
node2
192.168.1.10
Inventory with groups
Names in square brackets [...] indicate groups. Each row under a group is a host.
[webservers]
node1
node2
[databaseservers]
db1
db2
Inventory with nested groups (group of groups)
If you want to run a task on multiple groups at once, use nested groups. Define a new group and list group names (not individual hosts) in it. Ansible will automatically include all hosts in these subgroups.
[webservers]
node1
[databaseservers]
node2
[production:children]
webservers
databaseservers
The keyword
:childrentells Ansible that this group contains references to other groups.
Dynamic Inventories
Instead of writing your host list by hand, Ansible can connect to another system like AWS or Azure and ask: “What machines do I have right now?” » It gets the response in real time and builds the inventory automatically. Ideal for cloud environments where servers are constantly being created or shut down.
Python dynamic inventory script example
#!/usr/bin/env python3
import json
inventory = {
"webservers": {
"hosts": ["node1", "node2"]
}
}
print(json.dumps(inventory))
# Rendre le script exécutable
chmod +x dynamic_inventory.py
# Tester le script
./dynamic_inventory.py
# Sortie JSON : {"webservers": {"hosts": ["node1", "node2"]}}
# Utiliser avec une commande Ansible
ansible webservers -i dynamic_inventory.py --list
Demonstration — Working with Inventories
Simple inventory
vim simple_inventory
# Contenu :
node1
node2
# Lister tous les hôtes
ansible all -i simple_inventory --list
# Lister les hôtes non groupés (ungrouped)
ansible ungrouped -i simple_inventory --list
Inventory with groups
vim group_inventory
# Contenu :
[webservers]
node1
[databaseservers]
node2
# Valider les groupes
ansible webservers -i group_inventory --list
# Sortie : node1
ansible databaseservers -i group_inventory --list
# Sortie : node2
ansible all -i group_inventory --list
# Sortie : node1, node2
ansible ungrouped -i group_inventory --list
# Sortie : (vide — tous les hôtes sont dans des groupes)
Inventory with nested groups
vim nested_groups_inventory
# Contenu :
[webservers]
node1
[databaseservers]
node2
[production:children]
webservers
databaseservers
# Valider
ansible production -i nested_groups_inventory --list
# Sortie : node1 et node2
Use IP addresses in inventory
Ansible is not dependent on names, you can also use IP addresses:
# simple_inventory avec IP
192.168.1.101
node2
ansible all -i simple_inventory --list
# L'IP est listée normalement
ansible all -i simple_inventory -m ping
# Les deux hôtes (IP et nom) répondent avec pong
3. Working with Ad Hoc Commands
3.1 Ansible ad-hoc commands
What is an ad-hoc command?
Ad-hoc commands are quick commands that you can run from your terminal and get results immediately. They’re perfect for times when you don’t want to write an entire playbook — for example to restart a server or check if a service is working.
Structure of an ad-hoc order
ansible <target> -i <inventory> -m <module> -a "<arguments>"
| Element | Description |
|---|---|
<target> | Sets the host or group on which to run the command |
-i | Sets the inventory file to use |
-m | Tells Ansible which module to use |
-a | Add module specific arguments |
Common options for ad-hoc commands
| Options | Description |
|---|---|
-b | Use privilege escalation (become) |
--become-user | Run as a specific user |
-u | Set SSH username for login |
-v | Increase command verbosity |
--check | Perform a dry run — the command runs but no changes are made |
--list-hosts | Show which hosts will be targeted without running anything on those hosts |
The ansible.cfg configuration file
Instead of entering all these options with each command, you can define them once in the ansible.cfg file. This file is the main Ansible configuration file. It tells Ansible how to behave by default.
[defaults]
inventory = inventory.ini
remote_user = ansible
[privilege_escalation]
become = true
become_method = sudo
become_user = root
Parameter explanation:
inventory— Tells Ansible to useinventory.inias inventory file (avoid typing-ievery time)remote_user— Sets the default SSH user that Ansible will usebecome— Tells Ansible to use privilege escalationbecome_method— Indicates that Ansible will usesudoto switch to a more privileged userbecome_user— Tells Ansible to run tasks as therootuser
Ansible core modules
Module copy
Copying files from the control node to the managed nodes. Ideal for deploying configuration files, HTML pages or scripts.
ansible all -i inventory -m copy -a "src=/etc/hosts dest=/home/ansible/hosts.file"
Module file
Manages file attributes like permissions, ownership, or even creates empty files and directories.
# Créer un répertoire
ansible all -i inventory -m file -a "path=/home/ansible/testdir state=directory mode=077"
Module ping
This is not a typical network ping. This is Ansible’s way of checking if it can connect to this host and run Python. This is often the first thing we use to test if Ansible works.
ansible all -i inventory -m ping
Module command
Executes a command on the remote machine. More secure than the shell module, but does not support pipes or shell features.
ansible all -i inventory -m command -a "uptime"
ansible all -i inventory -m command -a "whoami"
Module shell
Similar to the command module, but allows all shell functionality like piping, redirection or the use of environment variables.
ansible all -i inventory -m shell -a "echo $HOME > /home/ansible/home.txt"
Module lineinfile
Ensures that a specific line exists (or does not exist) in a specific file. Ideal for modifying configuration files without replacing the entire file.
ansible all -i inventory -m lineinfile -a "path=/etc/motd line='Welcome to the server'"
Demonstration — Ad-hoc Commands in Action
Setting up the environment
# Créer le répertoire de travail
mkdir ansible
cd ansible
# Créer l'inventaire
vim inventory
# Contenu :
# node1
# node2
# Créer le fichier de configuration
vim ansible.cfg
# Contenu :
[defaults]
inventory = inventory
remote_user = ansible
[privilege_escalation]
become = true
become_method = sudo
become_user = root
Test connectivity
ansible node1 -m ping
# Réponse : pong ✓
ansible node2 -m ping
# Réponse : pong ✓
Use the command module
# Commande uptime sur tous les hôtes
ansible all -m command -a "uptime"
# Commande whoami (devrait afficher root car privilege escalation est activée)
ansible all -m command -a "whoami"
# Résultat : root sur node1 et node2
Use the shell module
# Rediriger la valeur de $HOME vers un fichier
ansible all -m shell -a "echo $HOME > /home/ansible/home.txt"
# Les deux hôtes rapportent changed
# Valider sur node1
ssh node1
ls
# home.txt est présent
cat home.txt
# Contenu : /home/ansible
exit
Use the copy module
# Copier /etc/hosts vers tous les managed nodes
ansible all -m copy -a "src=/etc/hosts dest=/home/ansible/hosts.file"
# Les deux nœuds rapportent changed
# Valider sur node1
ssh node1
ls
cat hosts.file
# Contenu identique au /etc/hosts du control node
exit
Use the file module
# Créer un répertoire
ansible all -m file -a "path=/home/ansible/testdir state=directory mode=077"
# Les deux nœuds rapportent changed
# Valider
ansible all -m command -a "ls /home/ansible"
# testdir est présent
Use lineinfile module
# Ajouter une ligne dans /etc/motd
ansible all -m lineinfile -a "path=/etc/motd line='Welcome to the server'"
# Les deux serveurs rapportent changed
3.2 Software and service management
Package Management Modules
Managing packages and services is one of the most common tasks in system administration. Ansible offers several modules depending on the target operating system:
| Module | Target system | Description |
|---|---|---|
dnf | Red Hat, Fedora, CentOS | Package Manager for Red Hat Systems |
yum | Older versions Red Hat | Package Manager (old version) |
apt | Debian, Ubuntu | Package Manager for Debian Systems |
package | Universal | Universal interface — connects to the correct backend depending on the OS |
Using the dnf module
With the dnf module, you can install, remove or update software, as you would with the dnf command on the command line, but on several servers at the same time.
The two key parameters:
name— the package to managestate— what we want to do with this package
Examples of use of the dnf module:
# Installer nginx
- name: Installer nginx
dnf:
name: nginx
state: present # present = installé
# Supprimer nginx
- name: Supprimer nginx
dnf:
name: nginx
state: absent # absent = supprimé
# Mettre à jour tous les packages (caractère générique)
- name: Mettre à jour tous les packages
dnf:
name: "*"
state: latest
# Installer plusieurs packages à la fois
- name: Installer plusieurs packages
dnf:
name: nginx,httpd,curl
state: present
Using the service module
The service module manages Linux services.
| Parameter | Possible values | Description |
|---|---|---|
name | service name | The service to manage |
state | started, stopped, restarted | The desired state |
enabled | true, false | If the service will start automatically on reboot |
# Démarrer httpd
- name: Démarrer httpd
service:
name: httpd
state: started
# Arrêter httpd
- name: Arrêter httpd
service:
name: httpd
state: stopped
# Redémarrer et activer au démarrage
- name: Redémarrer httpd et l'activer
service:
name: httpd
state: restarted
enabled: true
For Windows systems, we use the
win_servicemodule instead.
Demonstration — Software and Service Management
Environment validation
ls
# ansible.cfg et inventory sont présents
cat inventory
# node1
# node2
cat ansible.cfg
# inventory, remote_user, privilege escalation configurés
Install a package with dnf
# Installer httpd sur node2
ansible node2 -m dnf -a "name=httpd state=latest"
# node2 rapporte changed — httpd installé en version la plus récente
Start a service
# Démarrer httpd sur tous les hôtes
ansible all -m service -a "name=httpd state=started"
# Les deux nœuds rapportent changed
# Valider avec systemctl status
ansible all -m command -a "systemctl status httpd"
# httpd est démarré sur node1 et node2
Stop a service
# Arrêter httpd
ansible all -m service -a "name=httpd state=stopped"
# Les deux rapportent changed
# Valider
ansible all -m command -a "systemctl status httpd"
# httpd est inactif sur les deux serveurs
Reboot and enable on startup
# Redémarrer httpd et l'activer au démarrage
ansible all -m service -a "name=httpd state=restarted enabled=1"
# Les deux rapportent changed
# Valider
ansible all -m command -a "systemctl status httpd"
# httpd est actif ET activé sur les deux serveurs
Stop and delete a package
# Arrêter le service
ansible all -m service -a "name=httpd state=stopped"
# Supprimer le package
ansible all -m dnf -a "name=httpd state=absent"
# httpd est supprimé de node1 et node2
4. Configuration Management Basics
4.1 Ansible playbooks
What is a playbook?
The best way to think of a playbook is as a cookbook for configuring and managing hosts. Much like a recipe book, a playbook answers the following questions:
- What — What do you want to do? (tasks)
- Where — Which hosts are targeted? (the hosts)
- How — In what way? (modules and arguments)
Advantages of playbooks
Playbooks provide several benefits:
- Repeatability — Playbooks allow tasks to be repeated exactly the same way every time, whether on one server or on 100.
- Predictability — Once a playbook is written, the outcome is predictable.
- Reusability — A playbook is reusable in different environments (development, staging, production).
- Idempotence — This is one of the key features of Ansible.
Idempotence explained
Idempotence: Ansible only makes changes if necessary. If the system is already what you asked for, Ansible does nothing.
This avoids unnecessary reboots, service restarts, or installations.
Basic components of a play
A play can contain:
| Component | Mandatory | Description |
|---|---|---|
name | No (optional) | Description of the game |
hosts | Yes | Individual hosts or groups targeted by the play |
tasks | Yes | The list of operations to be performed on these hosts |
These components are just the basics — there are others not covered in this course.
Modules: bare name vs. FQCN
Bare name (short name)
Use a module without specifying the collection it comes from:
- name: Installer nginx
dnf:
name: nginx
state: present
When we write dnf, Ansible assumes that we are talking about the dnf module from the Ansible built-in collection by default. It’s quick and simple, but comes with a risk: if two collections have modules with similar names, it can cause problems.
FQCN (Fully Qualified Collection Name)
Format: namespace.collection.module_name
- name: Installer nginx
ansible.builtin.dnf:
name: nginx
state: present
The FQCN tells Ansible exactly where to find the module. This is particularly useful when working with multiple roles or external collections, and is the recommended approach especially for:
- Shared or team environments
- Using Ansible lint or other automation tools
- Clarity, maintainability and compatibility
Colored playbook output
When running an Ansible playbook, the output in the terminal is color coded:
| Color | Meaning |
|---|---|
| Green | Ansible checked the system status and found that it already matched what was requested — no changes made (OK) |
| Yellow | Ansible has made a change to the system to bring it to the desired state (CHANGED) |
| Red | A failure — either the task cannot run, something went wrong, or a prerequisite was missing (FAILED) |
Structure of a complete playbook
---
- name: Mon premier play
hosts: webservers
tasks:
- name: Installer nginx
dnf:
name: nginx
state: present
- name: Démarrer nginx
service:
name: nginx
state: started
enabled: true
- name: Créer la page d'accueil
copy:
content: "<h1>Hello from Ansible!</h1>"
dest: /var/www/html/index.html
Key points to observe:
- File starts with
--- - play
nameis optional but recommended hoststargets thewebserversgroup defined in the inventory- Each task in
taskshas aname(optional but recommended), a module and arguments - Indentation (visually represented as blue bars in slides) defines parent-child relationships
Reminder: Most errors in Ansible come from bad indentation.
Run playbook
ansible-playbook playbook.yml
4.2 Ansible facts and debugging
What is Ansible facts?
Ansible facts are information automatically collected by Ansible on your managed hosts when it connects to them. Examples of facts:
- OS type and version
- IP Address
- Hostname
- Disk size
- Memory
- CPU
- And much more…
Automatic collection of facts
When Ansible runs a playbook, one of the first things it does is collect default facts. This can be controlled via the gather_facts option.
---
- name: Mon play
hosts: all
gather_facts: no # Désactiver la collecte automatique des facts
tasks:
- name: Ma tâche
# ...
By setting
gather_facts: no, Ansible will no longer run its internalsetupmodule to collect system information before running tasks.
Collect facts manually
We can also collect the facts manually via an ad-hoc command with the setup module:
ansible all -m setup
The setup module does the same thing Ansible does in the background when gather_facts is enabled.
Example of facts in JSON format
{
"ansible_hostname": "node1",
"ansible_default_ipv4": {
"gateway": "192.168.1.1",
"address": "192.168.1.101",
"interface": "eth0"
}
}
Define your own facts
1. In a playbook with set_fact
- name: Définir un fact personnalisé
set_fact:
mon_fact: "valeur_personnalisee"
2. Persistently in /etc/ansible/facts.d
Create a file with the extension .fact in /etc/ansible/facts.d on managed hosts, either in INI format or in JSON format.
# Créer le répertoire (sur le managed node)
mkdir -p /etc/ansible/facts.d
# Créer un fact en format INI
cat > /etc/ansible/facts.d/custom.fact << EOF
[general]
app_version=1.0
environment=production
EOF
Important: Files must have the
.factextension to be correctly interpreted by Ansible.
Debugging and Troubleshooting Tools
When something goes wrong in Ansible, here are the steps to follow:
1. Read the error message
The error message generally points in the right direction.
2. Increase verbosity with -v
ansible-playbook playbook.yml -v # Verbosité niveau 1
ansible-playbook playbook.yml -vv # Verbosité niveau 2
ansible-playbook playbook.yml -vvv # Verbosité niveau 3
ansible-playbook playbook.yml -vvvv # Verbosité maximale
The more vs, the more detail you get about what Ansible is doing in the background.
3. Check syntax with --syntax-check
ansible-playbook playbook.yml --syntax-check
Quickly checks the playbook for YAML or syntax errors without running any tasks.
4. Dry run with --check
ansible-playbook playbook.yml --check
Shows what would change without making any actual changes.
5. Use the debug module
- name: Afficher une variable
debug:
msg: "La valeur est {{ ma_variable }}"
- name: Afficher un fact
debug:
var: ansible_hostname
The debug module allows you to display variables or messages in a playbook, very useful for understanding what is really happening.
Troubleshooting checklist:
| Point to check | Description |
|---|---|
| YAML Syntax | YAML is sensitive to spaces — main cause of errors |
| Modules and arguments | Did we use the correct module? The right arguments? |
| Inventory | Incorrect hostnames or missing groups can crash everything |
Module debug | View variables or outputs to see what’s actually happening |
4.3 Demonstration — Writing and Executing Playbooks
Setting up the YAML development environment
# Lister le répertoire courant
ls
# ansible.cfg et inventory sont déjà présents
cat inventory
# node1
# node2
cat ansible.cfg
# inventory, remote_user, privilege_escalation configurés
# Se déplacer dans le home de l'utilisateur ansible
cd /home/ansible
# Créer un fichier .vimrc pour faciliter l'édition YAML
vim .vimrc
# Ajouter :
autocmd FileType yaml setlocal ai ts=2 sw=2 et
This
.vimrcfile configures vim to use consistent spacing (2 spaces) when creating YAML files, reducing indentation errors.
Write and run a simple playbook
cd ~/ansible
vim playbook.yml
---
- name: My first play
hosts: node1
tasks:
- name: Ensure file exists
file:
path: /home/ansible/mytext.txt
state: touch
- name: Add welcome
lineinfile:
path: /home/ansible/mytext.txt
line: "Welcome from Playbook"
# Exécuter le playbook
ansible-playbook playbook.yml
Expected output:
PLAY [My first play] **********************************************************
TASK [Gathering Facts] ********************************************************
ok: [node1]
TASK [Ensure file exists] *****************************************************
changed: [node1]
TASK [Add welcome] ************************************************************
changed: [node1]
PLAY RECAP ********************************************************************
node1 : ok=3 changed=2 unreachable=0 failed=0
- Gathering Facts: Ansible automatically collects information on node1
- Ensure file exists: The status
changedindicates that the file has been created - Add welcome: The status
changedindicates that the line has been added
If we restart the playbook, the tasks will report
ok(green) instead ofchanged(yellow) — this is idempotence in action: Ansible checks that the desired state has already been reached and does not redo anything.
4.4 Demo — Playbook Troubleshooting
This demo shows how to address and correct common errors in playbooks.
Initial environment
ls
# ansible.cfg, inventory, trouble-playbook.yml
Error 1: Indentation error
ansible-playbook trouble-playbook.yml
# ERREUR : indentation error
vim trouble-playbook.yml
# La deuxième tâche n'est pas correctement alignée
# Corriger l'indentation pour qu'elle corresponde aux autres tâches
# Sauvegarder et quitter
Validate syntax before executing
ansible-playbook trouble-playbook.yml --syntax-check
# ERROR : Le groupe 'webservers' n'existe pas dans l'inventaire
vim trouble-playbook.yml
# Changer : hosts: webservers
# En : hosts: all
# Sauvegarder et quitter
ansible-playbook trouble-playbook.yml --syntax-check
# OK — syntaxe correcte
Error 2: User problem / become_user
ansible-playbook trouble-playbook.yml
# ERREUR : problème avec l'utilisateur
# Ajouter plus de verbosité pour diagnostiquer
ansible-playbook trouble-playbook.yml -vvv
# Le paramètre become_user est "ansibL" au lieu de "ansible"
vim trouble-playbook.yml
# Corriger : become_user: ansibL → become_user: ansible
# Sauvegarder et quitter
ansible-playbook trouble-playbook.yml
# SUCCÈS — le playbook s'exécute correctement
Step-by-step troubleshooting strategy
1. Lire le message d'erreur
↓
2. Si pas assez d'info → ansible-playbook ... -vvv
↓
3. Vérifier la syntaxe → ansible-playbook ... --syntax-check
↓
4. Dry run → ansible-playbook ... --check
↓
5. Vérifier l'inventaire (groupes, noms d'hôtes)
↓
6. Vérifier les modules et arguments utilisés
↓
7. Utiliser le module debug pour inspecter les variables
5. Course Summary
Congratulations! This course is over.
What you learned
During this training, you have:
- Understood Ansible architecture and its key components:
- The control node and managed nodes
- Agentless architecture
- Inventories, modules, playbooks and plugins
- Mastered YAML syntax:
- Key-value format
- Lists
- Indentation (fundamental rule)
- Configured your own laboratory environment:
- Installing Ansible on RHEL with subscription-manager
- Creating an ansible user with SSH access without password
- Configuring sudo privileges without password
- Validation with ad-hoc ping commands
- Worked with inventories:
- Static inventories (single, groups, nested groups)
- Dynamic inventories (Python scripts)
- Targeting individual hosts, groups and subgroups
- Used ad-hoc commands with essential modules:
ping,command,shell,copy,file,lineinfilednf/yum/aptfor package managementservicefor service management
- Created and executed Ansible playbooks:
- Basic structure of a playbook and play
- Idempotency
- Bare name vs. FQCN
- Interpretation of colored output
- Collected and used Ansible facts:
- Automatic collection
- Deactivation with
gather_facts: no - Manual collection with
setupmodule - Setting custom facts with
set_fact
- Debugged and troubleshooted playbooks:
-v,-vv,-vvvfor verbosity--syntax-checkfor syntax validation--checkfor dry rundebugmodule to inspect variables
6. Command Quick Reference
Installation
# Enregistrer RHEL
subscription-manager register
# Installer Ansible
dnf install ansible-core
# Vérifier la version
ansible --version
Ad-hoc commands
# Syntaxe générale
ansible <target> -i <inventory> -m <module> -a "<args>"
# Ping
ansible all -m ping
# Exécuter une commande
ansible all -m command -a "uptime"
# Copier un fichier
ansible all -m copy -a "src=/source dest=/destination"
# Gérer un service
ansible all -m service -a "name=httpd state=started enabled=true"
# Installer un package
ansible all -m dnf -a "name=nginx state=present"
Playbook management
# Exécuter un playbook
ansible-playbook playbook.yml
# Vérifier la syntaxe
ansible-playbook playbook.yml --syntax-check
# Dry run
ansible-playbook playbook.yml --check
# Avec verbosité
ansible-playbook playbook.yml -vvv
# Collecter les facts
ansible all -m setup
Inventories
# Lister tous les hôtes
ansible all -i inventory --list
# Lister les hôtes d'un groupe
ansible webservers -i inventory --list
# Lister les hôtes non groupés
ansible ungrouped -i inventory --list
7. Typical file structure for an Ansible project
ansible/
├── ansible.cfg # Configuration principale
├── inventory # Fichier d'inventaire
├── playbook.yml # Playbook principal
├── group_vars/ # Variables par groupe
│ ├── webservers.yml
│ └── databaseservers.yml
├── host_vars/ # Variables par hôte
│ ├── node1.yml
│ └── node2.yml
└── roles/ # Rôles réutilisables
└── webserver/
├── tasks/
│ └── main.yml
└── handlers/
└── main.yml
Search Terms
ansible · environment · configuration · infrastructure · ci/cd · devops · playbook · ad-hoc · facts · inventories · commands · management · node · architecture · demonstration · yaml · components · control · managed · playbooks · prerequisites · service · troubleshooting · command