Exercices et projets
Objectifs
- Consolider vos connaissances Ansible
- Mettre en pratique tous les concepts
- Développer des compétences opérationnelles
Exercice 1 : Installation et premiers pas
Objectif
Installer Ansible et valider la configuration.
Tâches
- Installez Ansible sur votre machine
- Créez la structure de projet
- Configurez l'inventaire avec localhost
- Exécutez un ping test
Structure à créer
ansible-labs/
├── ansible.cfg
├── inventory/
│ └── hosts.ini
└── playbooks/
Fichiers
# inventory/hosts.ini
[local]
localhost ansible_connection=local
# ansible.cfg
[defaults]
inventory = ./inventory/hosts.ini
host_key_checking = False
Validation
ansible all -m ping
# Attendu: localhost | SUCCESS
Exercice 2 : Commandes ad-hoc
Objectif
Maîtriser les opérations de base avec les commandes ad-hoc.
Tâches
- Affichez les informations système
- Créez un répertoire /tmp/ansible-test
- Créez un fichier avec du contenu
- Vérifiez l'espace disque
Commandes
# 1. Infos système
ansible localhost -m setup -a "filter=ansible_distribution*"
# 2. Créer un répertoire
ansible localhost -m file -a "path=/tmp/ansible-test state=directory"
# 3. Créer un fichier
ansible localhost -m copy -a "content='Hello Ansible' dest=/tmp/ansible-test/hello.txt"
# 4. Espace disque
ansible localhost -a "df -h"
Exercice 3 : Premier playbook
Objectif
Écrire un playbook simple.
Tâches
Créez un playbook qui :
- Affiche un message de bienvenue
- Crée un utilisateur "testuser"
- Crée un répertoire pour cet utilisateur
Solution
# playbooks/first-playbook.yml
---
- name: Mon premier playbook
hosts: localhost
become: yes
vars:
username: testuser
user_home: /home/testuser
tasks:
- name: Afficher un message
debug:
msg: "Bienvenue dans Ansible !"
- name: Créer l'utilisateur
user:
name: "{{ username }}"
state: present
shell: /bin/bash
create_home: yes
- name: Créer le répertoire projets
file:
path: "{{ user_home }}/projets"
state: directory
owner: "{{ username }}"
mode: '0755'
Exercice 4 : Inventaire avancé
Objectif
Créer un inventaire multi-environnements.
Structure
inventory/
├── production/
│ ├── hosts.ini
│ └── group_vars/
│ ├── all.yml
│ └── webservers.yml
├── staging/
│ ├── hosts.ini
│ └── group_vars/
│ └── all.yml
└── development/
└── hosts.ini
Fichiers à créer
# inventory/production/hosts.ini
[webservers]
web-01 ansible_host=192.168.1.10
web-02 ansible_host=192.168.1.11
[databases]
db-01 ansible_host=192.168.1.20
[production:children]
webservers
databases
# inventory/production/group_vars/all.yml
---
environment: production
debug_enabled: false
log_level: warn
# inventory/production/group_vars/webservers.yml
---
http_port: 80
nginx_worker_processes: 4
Exercice 5 : Playbook avec conditions et boucles
Objectif
Utiliser les structures de contrôle.
Playbook
# playbooks/packages.yml
---
- name: Gestion des packages
hosts: localhost
become: yes
vars:
common_packages:
- vim
- htop
- curl
- git
optional_packages:
- { name: docker.io, install: true }
- { name: nginx, install: false }
tasks:
- name: Mettre à jour le cache apt
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Installer les packages communs
apt:
name: "{{ common_packages }}"
state: present
- name: Installer les packages optionnels
apt:
name: "{{ item.name }}"
state: present
loop: "{{ optional_packages }}"
when: item.install | bool
- name: Afficher les packages installés
debug:
msg: "Package {{ item.name }} - Installé: {{ item.install }}"
loop: "{{ optional_packages }}"
Exercice 6 : Créer un rôle
Objectif
Créer un rôle pour installer et configurer nginx.
Structure
ansible-galaxy init --init-path roles/ nginx
Fichiers du rôle
# roles/nginx/defaults/main.yml
---
nginx_http_port: 80
nginx_server_name: localhost
nginx_document_root: /var/www/html
# roles/nginx/tasks/main.yml
---
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Create document root
file:
path: "{{ nginx_document_root }}"
state: directory
mode: '0755'
- name: Configure nginx
template:
src: default.conf.j2
dest: /etc/nginx/sites-available/default
notify: Reload nginx
- name: Deploy index page
template:
src: index.html.j2
dest: "{{ nginx_document_root }}/index.html"
- name: Start and enable nginx
service:
name: nginx
state: started
enabled: yes
# roles/nginx/handlers/main.yml
---
- name: Reload nginx
service:
name: nginx
state: reloaded
{# roles/nginx/templates/default.conf.j2 #}
server {
listen {{ nginx_http_port }};
server_name {{ nginx_server_name }};
root {{ nginx_document_root }};
location / {
try_files $uri $uri/ =404;
}
}
{# roles/nginx/templates/index.html.j2 #}
<!DOCTYPE html>
<html>
<head>
<title>{{ nginx_server_name }}</title>
</head>
<body>
<h1>Bienvenue sur {{ nginx_server_name }}</h1>
<p>Déployé avec Ansible sur {{ ansible_hostname }}</p>
<p>Date: {{ ansible_date_time.iso8601 }}</p>
</body>
</html>
Utilisation
# playbooks/webservers.yml
---
- name: Configure web servers
hosts: webservers
become: yes
roles:
- role: nginx
nginx_server_name: example.com
nginx_http_port: 8080
Projet 1 : Stack LAMP
Objectif
Déployer une stack LAMP complète avec Ansible.
Architecture
Structure du projet
lamp-project/
├── ansible.cfg
├── inventory/
│ └── hosts.ini
├── group_vars/
│ └── all.yml
├── roles/
│ ├── common/
│ ├── apache/
│ ├── php/
│ └── mysql/
└── playbooks/
└── site.yml
Playbook principal
# playbooks/site.yml
---
- name: Deploy LAMP Stack
hosts: all
become: yes
roles:
- common
- mysql
- php
- apache
Variables
# group_vars/all.yml
---
# MySQL
mysql_root_password: "{{ vault_mysql_root_password }}"
mysql_databases:
- name: myapp
encoding: utf8mb4
mysql_users:
- name: appuser
password: "{{ vault_mysql_app_password }}"
priv: "myapp.*:ALL"
# PHP
php_version: "8.1"
php_extensions:
- php-mysql
- php-curl
- php-gd
- php-mbstring
# Apache
apache_vhosts:
- servername: myapp.local
documentroot: /var/www/myapp
Projet 2 : Déploiement d'application
Objectif
Automatiser le déploiement d'une application web.
Workflow
Playbook de déploiement
# playbooks/deploy.yml
---
- name: Deploy Application
hosts: webservers
become: yes
vars:
app_name: myapp
app_path: /var/www/{{ app_name }}
app_repo: https://github.com/myorg/myapp.git
app_branch: main
tasks:
- name: Pre-deployment tasks
block:
- name: Enable maintenance mode
copy:
content: "Maintenance in progress..."
dest: "{{ app_path }}/public/maintenance.html"
- name: Backup current version
archive:
path: "{{ app_path }}"
dest: "/backups/{{ app_name }}-{{ ansible_date_time.iso8601_basic_short }}.tar.gz"
ignore_errors: yes
- name: Deployment
block:
- name: Pull latest code
git:
repo: "{{ app_repo }}"
dest: "{{ app_path }}"
version: "{{ app_branch }}"
force: yes
register: git_result
- name: Install dependencies
command: composer install --no-dev --optimize-autoloader
args:
chdir: "{{ app_path }}"
when: git_result.changed
- name: Run database migrations
command: php artisan migrate --force
args:
chdir: "{{ app_path }}"
- name: Clear cache
command: php artisan cache:clear
args:
chdir: "{{ app_path }}"
- name: Set permissions
file:
path: "{{ app_path }}/storage"
owner: www-data
group: www-data
mode: '0775'
recurse: yes
- name: Post-deployment
block:
- name: Disable maintenance mode
file:
path: "{{ app_path }}/public/maintenance.html"
state: absent
- name: Reload PHP-FPM
service:
name: php8.1-fpm
state: reloaded
- name: Health check
uri:
url: "http://localhost/health"
status_code: 200
retries: 5
delay: 2
handlers:
- name: Restart apache
service:
name: apache2
state: restarted
Projet 3 : Infrastructure Docker
Objectif
Gérer une infrastructure Docker avec Ansible.
Playbook
# playbooks/docker-infra.yml
---
- name: Docker Infrastructure
hosts: docker_hosts
become: yes
collections:
- community.docker
vars:
docker_networks:
- name: frontend
driver: bridge
- name: backend
driver: bridge
internal: yes
docker_volumes:
- postgres_data
- redis_data
docker_containers:
- name: postgres
image: postgres:15
networks:
- backend
volumes:
- postgres_data:/var/lib/postgresql/data
env:
POSTGRES_PASSWORD: "{{ vault_postgres_password }}"
- name: redis
image: redis:7-alpine
networks:
- backend
volumes:
- redis_data:/data
- name: nginx
image: nginx:alpine
ports:
- "80:80"
networks:
- frontend
- backend
tasks:
- name: Create Docker networks
community.docker.docker_network:
name: "{{ item.name }}"
driver: "{{ item.driver | default('bridge') }}"
internal: "{{ item.internal | default(false) }}"
loop: "{{ docker_networks }}"
- name: Create Docker volumes
community.docker.docker_volume:
name: "{{ item }}"
loop: "{{ docker_volumes }}"
- name: Start containers
community.docker.docker_container:
name: "{{ item.name }}"
image: "{{ item.image }}"
networks: "{{ item.networks | default(omit) }}"
volumes: "{{ item.volumes | default(omit) }}"
ports: "{{ item.ports | default(omit) }}"
env: "{{ item.env | default(omit) }}"
state: started
restart_policy: unless-stopped
loop: "{{ docker_containers }}"
Quiz de validation
Questions
-
Quelle commande vérifie la connectivité Ansible ?
- a)
ansible --ping - b)
ansible all -m ping - c)
ansible-ping - d)
ping ansible
- a)
-
Où définir les variables à priorité maximale ?
- a) defaults/main.yml
- b) group_vars/all.yml
- c) extra-vars (-e)
- d) vars/main.yml
-
Quel module utiliser pour générer un fichier de configuration ?
- a) copy
- b) file
- c) template
- d) lineinfile
-
Que signifie "idempotent" ?
- a) Rapide à exécuter
- b) Même résultat à chaque exécution
- c) Compatible multi-OS
- d) Exécution parallèle
-
Comment organiser le code réutilisable ?
- a) Playbooks imbriqués
- b) Rôles
- c) Scripts shell
- d) Variables
Réponses
- b)
ansible all -m ping - c) extra-vars (-e) - Priorité la plus haute
- c) template - Pour les fichiers dynamiques Jinja2
- b) Même résultat à chaque exécution
- b) Rôles - Structure organisée et réutilisable
Ressources supplémentaires
Documentation officielle
Communauté
Rôles recommandés
geerlingguy.*- Rôles de qualité professionnelledebops.*- Infrastructure Debian/Ubunturobertdebock.*- Rôles multi-plateforme
Conclusion
Félicitations ! Vous avez terminé le cours Ansible.
Vous maîtrisez maintenant :
- L'installation et la configuration
- L'inventaire et les commandes ad-hoc
- Les playbooks et les variables
- Les rôles et les templates
- Ansible Galaxy et les collections
Continuez à pratiquer et explorez les projets réels !