📋 SYNTHÈSE — Exercices 3 & 4


✅ Exercice 3 : Idempotence — RĂ©sultats

Question

What happens if you run the configuration playbook a second time? Observe and explain.

Exécution pratique

Nous avons relancé le playbook configure_sample_app_playbook.yml deux fois de suite et capturé les résultats.

Résultats observés

1Úre exécution :

PLAY RECAP
ec2-3-142-134-207.us-east-2.compute.amazonaws.com : ok=6  changed=1  unreachable=0  failed=0  skipped=1

2Úme exécution :

PLAY RECAP
ec2-3-142-134-207.us-east-2.compute.amazonaws.com : ok=6  changed=1  unreachable=0  failed=0  skipped=1

🔍 Analyse dĂ©taillĂ©e

TĂąche1Ăšre2ĂšmeExplication
Gathering FactsokokCollecte des variables — idempotent
Install Node.js setup repositoryokokLe fichier de repo existe → skipped ou ok
Install Node.jsokokPackage dĂ©jĂ  installĂ© → yum module est idempotent
Copy sample appokokLe fichier app.js n’a pas changĂ© → no change
Check if app runningfailed (ignored)failed (ignored)Processus inexistant → pgrep retourne rc=1
Stop any existing appskippedskippedCondition when: rc==0 → false → skip
Start sample appchangedchanged❌ PROBLÈME — elle s’exĂ©cute TOUJOURS

⚠ ProblĂšme d’idempotence identifiĂ©

La tĂąche “Start sample app” est Ă©crite ainsi :

- name: Start sample app
  shell: nohup node /home/ec2-user/app.js > /tmp/app.log 2>&1 &
  args:
    chdir: /home/ec2-user/
  become_user: ec2-user

ProblĂšmes :

  1. ❌ Pas de condition when: → s’exĂ©cute TOUJOURS
  2. ❌ Pas de changed_when: false → marque TOUJOURS comme changed
  3. ❌ Pas de vĂ©rification d’état → relance l’app mĂȘme si elle tourne dĂ©jĂ 
  4. ❌ RĂ©sultat : Chaque exĂ©cution crĂ©e un nouveau processus Node → accumulation de processus sur le port 8080 → conflit potentiel

✅ Solutions proposĂ©es

Solution 1 : Idempotence minimale (ajouter condition + flag)

- name: Start sample app
  shell: nohup node /home/ec2-user/app.js > /tmp/app.log 2>&1 &
  when: app_running.rc != 0        # ✅ Ne lance que si pas dĂ©jĂ  actif
  changed_when: false               # ✅ Supprime le "changed"

RĂ©sultat : 2Ăšme exĂ©cution → skipped (condition fausse)

Solution 2 : Meilleure pratique (systemd) — RECOMMANDÉE

- name: Create systemd service for app
  copy:
    dest: /etc/systemd/system/sample-app.service
    content: |
      [Unit]
      Description=Sample Node.js App
      After=network.target
      [Service]
      Type=simple
      User=ec2-user
      ExecStart=/usr/bin/node /home/ec2-user/app.js
      Restart=on-failure
      [Install]
      WantedBy=multi-user.target
 
- name: Enable and start service
  systemd:
    name: sample-app
    state: started
    enabled: yes

RĂ©sultat : ComplĂštement idempotent — systemd gĂšre l’idempotence automatiquement

📚 Leçons apprises

  1. Idempotence = PropriĂ©tĂ© clĂ© d’Ansible — les playbooks DOIVENT pouvoir ĂȘtre relancĂ©s sans effets indĂ©sirables
  2. Signes de non-idempotence :
    • shell: ou command: sans conditions
    • TĂąches qui modifient l’état sans vĂ©rifier l’état existant
    • RedĂ©marrage/relancement sans dĂ©tection de state
  3. Bonnes pratiques :
    • Utiliser les modules de haut niveau (yum:, copy:, systemd:) — idempotents par dĂ©faut
    • Ajouter when: pour les tĂąches conditionnelles
    • Ajouter changed_when: pour contrĂŽler le signalement de changements
    • PrĂ©fĂ©rer les services systemd pour la gestion d’apps

📁 Fichiers fournis

  • Documentation dĂ©taillĂ©e : td2/EXERCISE_3_IDEMPOTENCE_ANALYSIS.md
  • 3 variantes du rĂŽle :
    • roles/sample-app/tasks/main.yml (actuelle — non-idempotente)
    • roles/sample-app/tasks/main_idempotent.yml (idempotente minimale)
    • roles/sample-app/tasks/main_systemd.yml (meilleure pratique)

🚀 Exercice 4 : DĂ©ploiement multi-instance

Question

Modify the playbook to deploy and configure multiple EC2 instances. How would you adjust the playbook and inventory?

Architecture proposée

Approche 1 : Modifier le playbook de création

Fichier : create_ec2_instances_multi.yml

vars:
  instance_count: 2  # Nombre d'instances à créer
 
tasks:
  - name: Create multiple EC2 instances
    amazon.aws.ec2_instance:
      name: "sample-app-ansible-{{ item }}"  # Noms uniques
      ...
      tags:
        Ansible: ch2_instances
        Index: "{{ item }}"
    loop: "{{ range(0, instance_count | int) | list }}"  # Crée N instances

Résultat : Crée instance_count instances en boucle

Approche 2 : Inventaire découvre automatiquement

Fichier : inventory.aws_ec2.yml (inchangé)

plugin: amazon.aws.aws_ec2
filters:
  tag:Ansible: ch2_instances  # Découvre TOUTES les instances avec ce tag
  instance-state-name: running

RĂ©sultat : Quelle que soit le nombre d’instances créées, l’inventaire les dĂ©couvre toutes automatiquement dans le groupe _ch2_instances

Approche 3 : Configuration appliquée à tous les hÎtes

Fichier : configure_sample_app_playbook.yml (inchangé)

- name: Configure the EC2 instance to run a sample app
  hosts: _ch2_instances  # Cible TOUS les hĂŽtes du groupe dynamique

Résultat : Ansible se connecte à TOUS les hÎtes du groupe en parallÚle et exécute la configuration

🎯 Workflow complet

# 1. Créer 3 instances
ANSIBLE_PYTHON_INTERPRETER="$(which python3)" \
AWS_PROFILE=labs-devops_diallo \
ansible-playbook -v create_ec2_instances_multi.yml \
  -e instance_count=3 \
  -e instance_type=t3.micro
 
# Attendre ~1-2 minutes que les instances se lancent
 
# 2. Découvrir les instances via inventaire dynamique
ansible-inventory -i inventory.aws_ec2.yml --list
# Affiche tous les hĂŽtes du groupe _ch2_instances
 
# 3. Configurer TOUTES les instances en parallĂšle
ANSIBLE_PYTHON_INTERPRETER="$(which python3)" \
AWS_PROFILE=labs-devops_diallo \
ansible-playbook -i inventory.aws_ec2.yml configure_sample_app_playbook.yml
# Ansible lance 3 connexions SSH en parallùle → configuration rapide
 
# 4. Tester les 3 apps
aws ec2 describe-instances \
  --filters "Name=tag:Ansible,Values=ch2_instances" \
  --query 'Reservations[].Instances[].[PublicIpAddress,InstanceId]' \
  --output table \
  --profile labs-devops_diallo --region us-east-2
 
# Puis curl chaque IP:8080
for IP in $(aws ec2 ... --output text); do
  echo "Testing $IP:8080..."
  curl -s "http://$IP:8080/" || echo "Failed"
done

✹ Avantages du design

✅ ScalabilitĂ© : Changer instance_count de 2 Ă  10 ne change rien d’autre
✅ Inventaire auto-dĂ©couvert : Le plugin aws_ec2 voit toutes les instances tagguĂ©es
✅ ParallĂ©lisation : Ansible se connecte aux N instances en parallĂšle (pas sĂ©quentiellement)
✅ MĂȘme config : Tous les hĂŽtes reçoivent exactement la mĂȘme configuration
✅ Pas de duplicate : Les instances ne se gĂȘnent pas (chacune sa clĂ©, son IP)

📊 Comparaison : 1 vs N instances

Aspect1 instanceN instances
Playbook créationloop: 1 ou pas de boucleloop: range(0, N)
InventaireDécouvre 1 hÎteDécouvre N hÎtes automatiquement
ConfigurationCible 1 hĂŽteCible N hĂŽtes en parallĂšle
Changement pour passer Ă  5 instancesRewrite toutJuste -e instance_count=5

📁 Fichiers fournis

  • Playbook multi-instance : scripts/ansible/create_ec2_instances_multi.yml
  • Script d’exĂ©cution : scripts/ansible/exercise_4_multi_instance.sh
    ./exercise_4_multi_instance.sh 3  # Crée 3 instances, configure toutes
  • Documentation : td2/EXERCISES_3_4_ANALYSIS.md

đŸ§č Nettoyage multi-instance

# Lister les instances
aws ec2 describe-instances \
  --filters "Name=tag:Ansible,Values=ch2_instances" "Name=instance-state-name,Values=running" \
  --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`].Value|[0]]' \
  --output table \
  --profile labs-devops_diallo --region us-east-2
 
# Terminer toutes les instances d'un coup
aws ec2 terminate-instances \
  --instance-ids i-xxx i-yyy i-zzz ... \
  --profile labs-devops_diallo --region us-east-2
 
# Nettoyer SG et clé
aws ec2 delete-security-group --group-name sample-app-ansible \
  --profile labs-devops_diallo --region us-east-2
aws ec2 delete-key-pair --key-name ansible-ch2 \
  --profile labs-devops_diallo --region us-east-2

📚 Fichiers d’accompagnement

FichierDescription
td2/EXERCISE_3_IDEMPOTENCE_ANALYSIS.mdAnalyse dĂ©taillĂ©e de l’idempotence avec solutions
td2/EXERCISES_3_4_ANALYSIS.mdExplications concepts et approches pour les deux exercices
td2/LABS_EXERCISES_3_4_SUMMARY.mdCe document — rĂ©capitulatif complet
scripts/ansible/create_ec2_instances_multi.ymlPlaybook pour créer N instances
scripts/ansible/roles/sample-app/tasks/main_idempotent.ymlVersion idempotente minimale du rĂŽle
scripts/ansible/roles/sample-app/tasks/main_systemd.ymlVersion avec systemd (meilleure pratique)
scripts/ansible/exercise_3_idempotency.shScript pour tester idempotence
scripts/ansible/exercise_4_multi_instance.shScript pour déployer N instances

🎓 Conclusions

Exercice 3 : Idempotence

L’idempotence est une propriĂ©tĂ© critique des playbooks Ansible. Notre test a rĂ©vĂ©lĂ© que la tĂąche “Start sample app” n’est pas idempotente — elle crĂ©e un nouveau processus Ă  chaque relance.

Takeaway : Toujours relancer un playbook 2x de suite en dĂ©veloppement pour vĂ©rifier l’idempotence. Utiliser changed_when:, when:, ou des modules de haut niveau.

Exercice 4 : Scalabilité horizontale

GrĂące Ă  la boucle Ansible et aux inventaires dynamiques, dĂ©ployer N instances est aussi simple que de changer une variable. Pas de code dupliquĂ©, pas de risque d’incohĂ©rence.

Takeaway : Concevoir les playbooks pour la scalabilité dÚs le départ. Utiliser les boucles, les tags, et les inventaires dynamiques pour éviter les scripts pour 1, 2, 5, 10 instances.


Tous les fichiers et scripts sont prĂȘts Ă  l’emploi.
Pour plus de détails, consultez les fichiers .md fournis dans td2/.