Intermediate

Ansible Environment Configuration

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...

Table of Contents

  1. Module 1 — Understanding the architecture and fundamental concepts of Ansible
  1. Setting up the laboratory environment
  1. Working with Ad Hoc Commands
  1. Configuration Management Basics
  1. Course Summary

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:

ComponentMetaphorTechnical description
InventoriesCasting listConfiguration file that tells Ansible which systems to communicate with
PlaybooksFilm scriptFiles written in YAML format that tell managed nodes what to do and in what order
ModulesThe actors who playUnits of code that perform specific tasks (install packages, manage files, etc.)
PluginsThe production teamPieces 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, tasks are at the same level (2 spaces)
  • Content of tasks is indented by 4 spaces
  • Arguments of module dnf are 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:

  1. Python 2.6 or later — Ansible modules run through Python
  2. SSH enabled — this is how the control node connects to managed nodes
  3. An account with administrator privileges — Ansible requires elevated access for certain system changes

Windows managed node prerequisites

For Windows systems managed with Ansible:

  1. PowerShell 3.0 or higher
  2. WinRM enabled and configured — Ansible connects to Windows hosts via WinRM
  3. WinRM traffic must be authorized in the firewall
  4. 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 :children tells 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>"
ElementDescription
<target>Sets the host or group on which to run the command
-iSets the inventory file to use
-mTells Ansible which module to use
-aAdd module specific arguments

Common options for ad-hoc commands

OptionsDescription
-bUse privilege escalation (become)
--become-userRun as a specific user
-uSet SSH username for login
-vIncrease command verbosity
--checkPerform a dry run — the command runs but no changes are made
--list-hostsShow 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 use inventory.ini as inventory file (avoid typing -i every time)
  • remote_user — Sets the default SSH user that Ansible will use
  • become — Tells Ansible to use privilege escalation
  • become_method — Indicates that Ansible will use sudo to switch to a more privileged user
  • become_user — Tells Ansible to run tasks as the root user

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:

ModuleTarget systemDescription
dnfRed Hat, Fedora, CentOSPackage Manager for Red Hat Systems
yumOlder versions Red HatPackage Manager (old version)
aptDebian, UbuntuPackage Manager for Debian Systems
packageUniversalUniversal 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 manage
  • state — 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.

ParameterPossible values ​​Description
nameservice nameThe service to manage
statestarted, stopped, restartedThe desired state
enabledtrue, falseIf 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_service module 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:

  1. Repeatability — Playbooks allow tasks to be repeated exactly the same way every time, whether on one server or on 100.
  2. Predictability — Once a playbook is written, the outcome is predictable.
  3. Reusability — A playbook is reusable in different environments (development, staging, production).
  4. 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:

ComponentMandatoryDescription
nameNo (optional)Description of the game
hostsYesIndividual hosts or groups targeted by the play
tasksYesThe 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:

ColorMeaning
GreenAnsible checked the system status and found that it already matched what was requested — no changes made (OK)
YellowAnsible has made a change to the system to bring it to the desired state (CHANGED)
RedA 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 name is optional but recommended
  • hosts targets the webservers group defined in the inventory
  • Each task in tasks has a name (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 internal setup module 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 .fact extension 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 checkDescription
YAML SyntaxYAML is sensitive to spaces — main cause of errors
Modules and argumentsDid we use the correct module? The right arguments?
InventoryIncorrect hostnames or missing groups can crash everything
Module debugView 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 .vimrc file 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 changed indicates that the file has been created
  • Add welcome: The status changed indicates that the line has been added

If we restart the playbook, the tasks will report ok (green) instead of changed (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:

  1. Understood Ansible architecture and its key components:
  • The control node and managed nodes
  • Agentless architecture
  • Inventories, modules, playbooks and plugins
  1. Mastered YAML syntax:
  • Key-value format
  • Lists
  • Indentation (fundamental rule)
  1. 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
  1. Worked with inventories:
  • Static inventories (single, groups, nested groups)
  • Dynamic inventories (Python scripts)
  • Targeting individual hosts, groups and subgroups
  1. Used ad-hoc commands with essential modules:
  • ping, command, shell, copy, file, lineinfile
  • dnf/yum/apt for package management
  • service for service management
  1. Created and executed Ansible playbooks:
  • Basic structure of a playbook and play
  • Idempotency
  • Bare name vs. FQCN
  • Interpretation of colored output
  1. Collected and used Ansible facts:
  • Automatic collection
  • Deactivation with gather_facts: no
  • Manual collection with setup module
  • Setting custom facts with set_fact
  1. Debugged and troubleshooted playbooks:
  • -v, -vv, -vvv for verbosity
  • --syntax-check for syntax validation
  • --check for dry run
  • debug module 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

Interested in this course?

Contact us to book it or get a custom training plan for your team.