Lab Ansible Débutant : découvrir Ansible par la pratique avec SSH, Playbooks, Apache et MariaDB

Quand on parle d’automatisation, on fait souvent référence à Ansible. Pourtant, il peut parfois sembler complexe à comprendre au premier abord, et il n’est pas toujours évident de visualiser concrètement son utilité dans un environnement informatique.

À travers ce premier lab de découverte, je vous propose de découvrir Ansible par la pratique, en réalisant pas à pas plusieurs actions simples et concrètes sur des serveurs Linux.

Vous apprendrez notamment à :

  • configurer une connexion SSH par clés ;
  • créer un inventaire Ansible ;
  • tester la connectivité des machines ;
  • exécuter vos premiers playbooks ;
  • automatiser les mises à jour Debian ;
  • déployer Apache ;
  • installer et configurer MariaDB.

L’objectif de ce lab est de vous montrer qu’Ansible n’est pas réservé aux grandes infrastructures, mais qu’il peut rapidement devenir un outil simple, puissant et très utile au quotidien.

Consignes du Lab

Objectif

Découvrir les bases d’Ansible en administrant plusieurs serveurs Debian depuis un serveur de contrôle.

Environnement disponible

Vous disposez de :

  • 1 serveur de contrôle avec Ansible a installé
  • 2 clients Debian
    • ansible-client1
    • ansible-client2

Informations de connexion

  • Utilisateur : root
  • Mot de passe : formation

Ce que vous allez réaliser

  1. Générer une clé SSH
  2. Configurer l’accès aux clients
  3. Installer Ansible et créer un inventaire YAML
  4. Tester la connexion avec ansible ping
  5. Créer votre premier playbook
  6. Mettre à jour les serveurs Debian
  7. Installer Apache sur un client
  8. Installer MariaDB sur un autre client

Conseils

  • Relancez les playbooks plusieurs fois pour observer l’idempotence.
  • Prenez le temps de lire les retours des commandes.
  • Vérifiez la syntaxe YAML (indentation importante).

Ressources


'; }// ── Timer ──────────────────────────────────────────────── function startTimer2(uid, expiresAt) { if (s2[uid] && s2[uid].timerInt) clearInterval(s2[uid].timerInt); var exp = new Date(expiresAt.slice(-1)==='Z' ? expiresAt : expiresAt.replace(' ','T')+'Z').getTime(); var tick = function() { var ms = Math.max(0, exp - Date.now()); var m = Math.floor(ms/60000); var ss = Math.floor((ms%60000)/1000); var txt = (ms<60000?'⚠ ':'↗ ') + m + ':' + ('0'+ss).slice(-2); lbl2(uid, txt, ms<60000?'warn':'active'); if (ms<=0) { clearInterval(s2[uid].timerInt); sessionEnd2(uid); } }; tick(); if (s2[uid]) s2[uid].timerInt = setInterval(tick, 1000); }// ── Fin session ────────────────────────────────────────── function sessionEnd2(uid) { lsDel2(uid); if (s2[uid] && s2[uid].timerInt) clearInterval(s2[uid].timerInt); delete s2[uid]; var wrap = document.querySelector('#' + uid); var lbl = wrap ? wrap.dataset.label || 'Ouvrir le terminal' : 'Ouvrir le terminal'; lbl2(uid, wrap ? wrap.querySelector('.rdp2-lbl').dataset.orig || lbl : lbl, ''); st2(uid, ''); var app = document.getElementById(uid + '-app'); if (app) app.innerHTML = ''; }// ── Stop ───────────────────────────────────────────────── function stop2(uid) { var s = s2[uid]; if (!s) return; st2(uid, 'Arrêt…'); fetch(s.conductor + '/internal/stop', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({session_id: s.sessionId}), credentials:'include' }).finally(function() { if (s.win && !s.win.closed) s.win.close(); sessionEnd2(uid); }); } window.rdp2Stop = function(uid) { stop2(uid); };// ── Liens app ──────────────────────────────────────────── function renderApp2(uid, urlApp, urlAppExtra) { var el = document.getElementById(uid + '-app'); if (!el) return; var h = ''; if (urlApp) h += '🌐 Site'; if (urlAppExtra) h += '🔧 Admin'; h += ''; el.innerHTML = h; }// ── Écrire dans la popup ───────────────────────────────── function writePopup(win, html) { try { win.document.open(); win.document.write(html); win.document.close(); } catch(e) {} }// ── Poll ───────────────────────────────────────────────── function poll2(uid) { var s = s2[uid]; if (!s || !s.win || s.win.closed) { sessionEnd2(uid); return; }fetch(s.conductor + '/internal/session/' + s.sessionId) .then(function(r) { return r.json(); }) .then(function(d) { if (d.status === 'running' && (d.url_terminal || d.url_app)) { // Rediriger la popup vers le terminal var target = d.url_terminal || d.url_app; if (!s.win.closed) s.win.location.href = target;// Boutons app + stop sous le bouton principal renderApp2(uid, d.url_app, d.url_app_extra);// Timer dans le bouton if (d.expires_at) startTimer2(uid, d.expires_at);// Sauvegarder lsSave2(uid, { sessionId: s.sessionId, conductor: s.conductor, urlTerminal: d.url_terminal, urlApp: d.url_app, urlAppExtra: d.url_app_extra, expiresAt: d.expires_at, });} else if (d.status === 'error') { if (!s.win.closed) writePopup(s.win, '' + '' + 'Erreur de démarrage — vous pouvez fermer cette fenêtre.'); st2(uid, 'Erreur'); lsDel2(uid); delete s2[uid]; } else { // Mettre à jour le message dans la popup var statusMsg = d.status === 'launching' ? 'Démarrage du conteneur…' : 'Initialisation…'; try { var el = s.win.document.getElementById('m'); if (el) el.textContent = statusMsg; } catch(e) {} st2(uid, statusMsg); setTimeout(function() { poll2(uid); }, 2000); } }) .catch(function() { setTimeout(function() { poll2(uid); }, 3000); }); }// ── Lancement ──────────────────────────────────────────── function launch2(uid) { var wrap = document.querySelector('#' + uid); if (!wrap) return;// Session active → remettre la popup au premier plan if (s2[uid] && s2[uid].sessionId) { if (s2[uid].win && !s2[uid].win.closed) { s2[uid].win.focus(); return; } // Popup fermée mais session active → réouvrir var saved = lsGet2(uid); if (saved && saved.urlTerminal) { var w2 = openPopup(uid); if (w2) { w2.location.href = saved.urlTerminal; s2[uid].win = w2; } return; } }// ── OUVRIR LA POPUP IMMÉDIATEMENT (action utilisateur directe) ── var win = openPopup(uid); if (!win) { st2(uid, 'Popups bloquées — autorisez ce site puis réessayez'); return; }// Afficher l'écran de chargement dans la popup writePopup(win, loadingHtml('Connexion au serveur…'));var conductor = wrap.dataset.conductor; s2[uid] = { win: win, sessionId: null, conductor: conductor, timerInt: null };var b = wrap.querySelector('.rdp2-btn'); if (b) { b.disabled = true; b.querySelector('.rdp2-lbl').textContent = 'Démarrage…'; }// JWT frais via admin-ajax var fd = new FormData(); fd.append('action', 'rdr_get_jwt'); fd.append('nonce', wrap.dataset.nonce || ''); fetch(window.ajaxurl || '/wp-admin/admin-ajax.php', { method:'POST', body:fd, credentials:'include' }) .then(function(r) { return r.ok ? r.json() : {}; }) .catch(function() { return {}; }) .then(function(jwtData) { if (win.closed) { delete s2[uid]; return; }var body = { stack_slug: wrap.dataset.stack }; var ttl = wrap.dataset.ttl; if (ttl && ttl !== 'null') body.ttl = parseInt(ttl); if (jwtData && jwtData.jwt) body.jwt = jwtData.jwt;// Mettre à jour le message try { var el = win.document.getElementById('m'); if(el) el.textContent = 'Lancement du stack…'; } catch(e){}fetch(conductor + '/lab/launch', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body), credentials:'include' }) .then(function(r) { return r.json(); }) .then(function(d) { if (d.error) { writePopup(win, '' + '' + '
' + '
' + d.error + '
' + '
Vous pouvez fermer cette fenêtre
' + ''); st2(uid, d.error); delete s2[uid]; if (b) { b.disabled=false; b.querySelector('.rdp2-lbl').textContent = wrap.querySelector('.rdp2-lbl').dataset.orig || 'Ouvrir'; } return; } s2[uid].sessionId = d.session_id; st2(uid, 'Initialisation…'); poll2(uid); }) .catch(function(e) { st2(uid, 'Erreur réseau'); writePopup(win, 'Erreur réseau'); delete s2[uid]; }); }); }function openPopup(uid) { var wrap = document.querySelector('#' + uid); var w = parseInt(wrap && wrap.dataset.w) || 960; var h = parseInt(wrap && wrap.dataset.h) || 620; var left = Math.round((screen.width - w) / 2); var top = Math.round((screen.height - h) / 2); return window.open('about:blank', uid + '_w2', 'width=' + w + ',height=' + h + ',left=' + left + ',top=' + top + ',menubar=no,toolbar=no,location=no,scrollbars=yes,resizable=yes'); }// ── Reprendre après reload ─────────────────────────────── function tryRestore2(uid) { var saved = lsGet2(uid); if (!saved || !saved.expiresAt) return; var exp = new Date(saved.expiresAt.slice(-1)==='Z' ? saved.expiresAt : saved.expiresAt.replace(' ','T')+'Z').getTime(); if (Date.now() >= exp) { lsDel2(uid); return; }s2[uid] = { win: null, sessionId: saved.sessionId, conductor: saved.conductor, timerInt: null }; renderApp2(uid, saved.urlApp, saved.urlAppExtra); startTimer2(uid, saved.expiresAt); }// ── Init ───────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.rdp2-wrap').forEach(function(el) { var lbl = el.querySelector('.rdp2-lbl'); if (lbl) lbl.dataset.orig = lbl.textContent.trim(); tryRestore2(el.id); }); });document.addEventListener('click', function(e) { var b = e.target.closest('.rdp2-btn'); if (b) { launch2(b.dataset.uid); } });})();