Listino Supporto Partner Contatti 800 13.40.41

KNOWLEDGE BASE

Knowledge Base

Vai al Video

Gestire le configurazioni con Ansible

Ansible è uno strumento per la gestione delle configurazioni scritto in Python, che permette di automatizzare tutti i processi di una infrastruttura IT. Fino a prima della sua creazione, la configurazione di un numero notevole di server poteva diventare problematica, in quanto andava ripetuta macchina per macchina.

Ansible ha un po’ rivoluzionato il concetto di configurazione, perché consente di semplificare la configurazione quando si tratta di applicarla a molte macchine; è semplice, potente e non richiede l’installazione di agenti.

In questo tutorial verrà spiegato di cosa si tratta, quali vantaggi fornisce e in che modo si utilizza.

Che cos’è Ansible

Si tratta di un software di libero utilizzo che consente di automatizzare le procedure di configurazione e gestione sui sistemi Unix e Linux; è di semplice utilizzo perché rappresenta una forma di automazione leggibile da chiunque, non richiede particolari competenze in fatto di programmazione e i task impostati vengono eseguiti in ordine.

È uno strumento potente perché consente il deployment delle applicazioni, la gestione della configurazione e la gestione ottimizzata del workflow. Nello specifico è utile nel:

  • Configuration Management, ossia configurare server remoti con installazione di pacchetti, udate sistemi, specifica chiavi e servizi;
  • sicurezza e compliance, cioè mantenere server remoti sempre aggiorati e risolvere vulnerabilità in modo centralizzato;
  • Application Deployment, ossia pushare codice e deployment su server remoti, su uno o più server;
  • Continuos Delivery delle applicazioni;
  • Provisioning: per la gran parte dei provider Cloud Ansible dispone di moduli per fare il provisioning di nuovi server e nuove istanze.

Diversamente dai più conosciuti software che svolgono compiti analoghi (ad esempio Chef, Puppet e CFEngine) Ansible utilizza un'architettura agentless, ossia che non richiede l’installazione di agenti software (tipicamente servizi e demoni) che girano sulla macchina target.

Tale approccio agentless prevede che i dati siano raccolti sulla macchina target (ossia quella su cui operare la configurazione) senza che sia necessario preoccuparsi di installare, aggiornare e manutenere tool software specifici; altro vantaggio è la rapidità di sviluppo, con conseguente riduzione dei costi e del traffico di rete necessario pr operare sulle macchine target.

L’unico requisito, ovvero tool che deve essere presente nelle macchine target è il server OpenSSH: infatti Ansible utilizza il protocollo SSH e WinRM per accedere alle macchine dalla rete

Come la maggior parte dei software di configurazione, Ansible prevede due tipi di server: macchine nodi (target) e  macchine controllore; quest’ultima è quella che coordina la configurazione dei nodi, quindi esegue determinati comandi su questi, cui si connette con una chiave di accesso SSH.

Ansible: i concetti chiave

Per comprendere Ansible è opportuno descrivere quelli che ne sono i concetti chiave, ovvero:

  • Inventory: è una raccolta di nodi e gruppi ai quali Ansible può connettersi allo scopo di gestirne le configurazioni;
  • Task: sono le istruzioni che Ansible esegue sui nodi target;
  • Handler: sono istruzioni che vanno eseguite come conseguenza di una determinata azione;
  • Play: è una serie di task ordinati da eseguire sui nodi selezionati dall’inventario;
  • Playbook: è un file che contiene uno o più Play;
  • Role: rappresentano una serie di contenuti strettamente correlati che permettono di gestire meglio e mantenere una serie di Playbook.

Inventory

L’inventario di Ansible è una collezione di nodi aventi determinate caratteristiche e gruppi di nodi che possono essere connessi e gestiti tutti insieme, singolarmente o per gruppo. Abbiamo quindi una struttura con:

  • Host (nodi);
  • Gruppi;
  • Dati specifici Inventory (variabili);
  • Sorgenti statiche o dinamiche.

Un esempio di Inventory è quello riportato qui di seguito e riguarda due server e un database:

[web]

webserver1.example.com

webserver2.example.com

 

[db]

dbserver1.example.com

In questo esempio c’è un gruppo [web] comprendente due nodi (webserver1.example.com e webserver2.example.com) e un gruppo [db] con un solo nodo.

Notare che Ansible consente, nella scrittura, di raggruppare i nodi per categoria, quindi web sono i webserver, db i database ecc..

Le specifiche di configurazione in Ansible sono scritte in documenti YAML che sono, appunto, i Playbook; YAML è un linguaggio molto elementare basato principalmente sull’indentazione e per questo i Playbook sono di facile lettura anche da parte di chi non ha particolare conoscenza dei linguaggi di programmazione convenzionali.

Le specifiche di configurazione operano attraverso dei task (gestori di eventi): ad esempio, un task può aggiornare file di configurazione di un database server e un gestore di eventi chiuderebbe il database al termine dell’esecuzione del task; i task vengono eseguiti in ordine, ossia in sequenza.

Se viene scritto con la dovuta accuratezza, un Playbook può essere in grado di gestire anche situazioni inaspettate che potrebbero verificarsi sui nodi.

Task

Altro concetto importante di Ansible sono i task, ossia le le istruzioni che Ansible esegue, in ordine, sui nodi target; per l’esattezza, un task è l’applicazione di un modulo di Ansible finalizzata a eseguire una certa operazione. I moduli più usati sono, ad esempio:

  • file: permette di creare una directory se non esiste;
  • yum: permette di installare un pacchetto non presente nel sistema;
  • service: esegue il servizio passato come parametro;
  • template: costruisce un file di configurazione a partire da un template specificato;
  • get_url: recupera un file archivio dall’URL specificato come parametro;
  • git: clona un repository da codice sorgente.

L’immagine seguente mostra un esempio di task, il cui file inizia con tasks: e prosegue con i singoli task, ciascuno dei quali inizia con un trattino.

Nel primo task, come prima operazione installiamo un pacchetto di nome httpd che è già presente nel sistema e per sovrascriverlo utilizziamo state: latest, comando che ordina di installare l’ultima versione (se il package è della stessa versione, l’operazione non verrà eseguita). Nel caso di questo task, il pacchetto è Apache.

Notate che tutti i task hanno un nome, non necessario ma utile per trovarlo facilmente anche se è all’interno di una lista.

Nel secondo task carichiamo un file (quello il cui nome e percorso seguono src:) dalla macchina locale e con il modulo copy lo scriviamo nei server il cui percorso che segue dest: ,ovvero, nel caso specifico, var, www, html.

L’ultimo task riavvia un servizio, il cui nome è httpd, riavvia Apache; lo stato (state) è restarted perché dev’essere riavviato.

Questo esempio è indicativo della praticità di Ansible, perché con una decina di righe di istruzioni si installa pacchetto, si copiano dei file e si riavvia il servizio corrispondente al pacchetto Apache installato sul nodo.

Handler

Passiamo adesso agli handler, i quali sono speciali task eseguiti alla fine di un Play, se ciò è notificato da un altro task, al verificarsi di un cambiamento. Per esempio, se un task esegue l’aggiornamento di un database o di un file di configurazione, essendo stata eseguita una modifica lo stesso task notifica a un apposito handler di riavviare il servizio affinché la modifica stessa abbia effetto.

Riprendendo l’esempio del task fatto in precedenza, per chiarire la sintassi aggiungiamo l’istruzione notify:restart httpd che rimanda all’handler restart httpd, il quale viene chiamato solo se si verifica la condizione di notify (immagine seguente).

Sostanzialmente quando si scrive un handler si crea una sorta di label e di conseguenza Ansible quando trova la relativa istruzione sospende l’esecuzione del Playbook, salta all’handler e poi la riprende.

Play e Playbook di Ansible

Andiamo ora ad approfondire due concetti che possono essere confusi, ma che sono in realtà distinti: i play sono una serie di task ordinati da eseguire sui nodi selezionati dall’inventario, mentre il Playbook è un file Ansible che contiene uno o più play, vale a dire un raccoglitore di play.

Un esempio di playbook è riportato nell’immagine qui di seguito, che ne mostra il file YAML corrispondente: in questo caso specifico il Playbook contiene un solo Play, quindi Playbook e Play sono la stessa cosa, ma se già ci fossero due Play le due entità sarebbero diverse.

Questo Play contiene due task e inizia con la definizione degli host destinatari (hosts: web) che in questo caso sono quelli del gruppo [web], il comando become: dove il parametro yes indica che gli host divengono tali dopo l’installazione, quindi le variabili che definiamo (vars:) che qui sono una e in particolare la porta http (http_port: 80).

Il primo task in ordine di esecuzione fa uso del modulo yum, quindi abbiamo l’aggiornamento del package e il caricamento del file (quello il cui nome e percorso seguono src:) dalla macchina locale, quindi con il modulo copy lo scriviamo nei server il cui percorso che segue dest: ,ovvero, nel caso specifico, var, www, html.

Role di Ansible

Sono ruoli e rappresentano una serie di contenuti strettamente correlati che permettono di ottimizzare la gestione e la manutenzione di una serie di Playbook complessi. I role riguardano quindi la parte organizzativa dei Playbook e ne migliorano l’affidabilità e la leggibilità, facilitano la condivisione, il riutilizzo e la standardizzazione di processi di automazione della configurazione degli host, consentono ai contenuti Ansible di esistere indipendentemente da Playbook, progetti e anche organizzazioni e offrono vantaggi funzionali come la risoluzione di percorsi di file e valori predefiniti.  

Nell’immagine seguente vedete due role chiamati common/ e apache/ inseriti in un progetto Ansible.

Per ogni role, nell’esempio proposto abbiamo creato file, template, task ecc.

I ruoli sono common/ e apache/ e sono delle directory indicate a titolo di esempio; in realtà al loro interno ci saranno poi file tipo Playbook dentro files/ ecc.

I Roles servono quando la configurazione diventa complessa, più di quanto visto negli esempi essenziali mostrati sinora; infatti siccome Ansible si esegue in un unico file, è bene definirli ciascuno con un nome e con quello che li comporrà: appunto, files, templates, vars, defaults e quant’altro. La definizione si fa con la sintassi mostrata nell’immagine, ossia si parte dal nome file .yml a inizio riga, seguito nella riga sottostante con roles/ allineato. Poi un punto di tabulazione a destra si scrivono i nomi dei ruoli terminanti con / e sotto ciascuno si elencano le funzionalità, tabulate ciascuna un punto più avanti del nome del ruolo.

Questa struttura permette di organizzare i contenuti in cartelle specifiche e di definire dove si trovano: in tasks si troveranno i Play, in hadlers gli handler task, in files i sorgenti, in variables si mettono le variabili,  e via di seguito. 

Come funziona Ansible

Il funzionamento di Ansible si comprende analizzando lo schema proposto nell’immagine seguente, nella quale il cuore è il computer sul quale viene installato e dal quale operiamo: prende il nome di Ansible Management Node (può essere virtuale o fisica) e in pratica su di esso si configura l’Inventory con tutti gli IP address dei nodi e poi si creano i Playbook; è possibile creare dei moduli o dei plugin per estendere le funzionalità.

I moduli sono pezzi di codice che vengono trasferiti ai nodi e lì eseguiti per soddisfare la dichiarazione di un determinato task e possono essere usati da CLI o automatizzati in un task all’interno di un playbook.

I playbook e i moduli vengono eseguiti sui nodi riepilogati nell’Inventory; sostanzialmente, quando creiamo un playbook facciamo uso sempre di moduli e talvolta di plugin, quindi quindi richiamando i nodi dall’Inventory verrà eseguito il deployment su ciascuno di essi.

Nel momento in cui avvia il deploy, le configurazioni contenute nei Playbook vengono trasferite alle macchine corrispondenti: è possibile sia applicare la stessa configurazione a tutti i nodi, sia creare configurazioni distinte per ciascun nodo o gruppo di nodi.

Utilizzare Ansible

Ora è il momento di vedere come si lavora con Ansible, supponendo di averlo già installato nel proprio computer che sarà utilizzato come Management Node; va innanzitutto precisato che per impostazione predefinita Ansible rende già disponibile un file host che si può utilizzare (salvandolo poi con il nome desiderato) come modello per creare l’Inventory. Ma nulla vieta di creare da zero un proprio file Inventory.

Nell’utilizzo di Ansible è molto comodo appoggiarsi a servizi come Galaxy (http://galaxy.ansible.com) che sostanzialmente è un portale dove cercare, riutilizzare e condividere progetti Ansible già pronti. Questo consente di realizzare e condividere i propri progetti di automazione delle configurazioni partendo da contenuti esistenti elaborati da membri della comunità Ansible. Prima di iniziare a lavorare con Ansible è consigliabile dare un’occhiata a Galaxy perché fornisce molti spunti utili e progetti sviluppati sui quali fare pratica: ad esempio per mySQL, interfacce di rete, NGNIX e via di seguito. Per scaricare il progetto d’interesse basterà  accedere al relativo repository GitHub e cliccare sul nome, per eseguire il pull dell’interno repository sul nostro computer locale.

Il trasferimento e l’installazione si effettuano eseguendo il comando:

 $ ansible-galaxy install

seguito dal nome del progetto all’interno dell’ambiente Ansible.

È anche possibile creare un progetto da zero, senza appoggiarsi ad alcun modello; nel caso dell’inventory, possiamo crearci un nostro file “hosts” dall’editor di testo e di introdurvi, per esempio, il contenuto mostrato nella figura seguente.

Il nostro file hosts definisce la rete e contiene i nomi dei nodi, che nello specifico sono tre divisi in due gruppi chiamati webservers e server03; al file abbiamo passato la variabile globale [all:vars] che stabilisce che l’utente del computer locale (su cui gira Ansible), chiamato root, sarà autorizzato ad operare sui nodi. La variabile è definita globale perché è di tipo all.

Chiudiamo e salviamo questo file di configurazione, quindi torniamo alla riga di comando e impartiamo un classico comando Ansible: ansible all -i -m ping, che esegue il modulo ping verso tutti i nodi presenti nell’inventario (-i). La risposta dovrebbe essere quella visibile nell’immagine seguente, ossia contenente tre risposte, ciascuna proveniente dagli host dei due gruppi.

Notate che se avessimo voluto effettuare il ping verso un solo gruppo di nodi, ad esempio del gruppo webservers, il comando avrebbe dovuto essere: ansible webservers -i -m ping.

Adesso immaginiamo di voler arrestare il servizio apache sull’unico nodo appartenente al gruppo server03: il comando da impartire è:

ansible server03 -i hosts -m service -a “name=apache state=stopped2”

dove -i definisce che il comando è per un nodo dell’inventario, -m indica il modulo service e -a il comando riguardante il servizio, che in questo caso riceve lo stato “stopped”. Per far ripartire tale servizio sullo stesso server è sufficiente impartire il comando:

ansible server03 -i hosts -m service -a “name=apache state=started2”

Creare un playbook Ansible

Ora che abbiamo costruito l’inventario, ossia l’elenco dei nodi cui destinare le configurazioni, vediamo come si crea la configurazione stessa, contenuta in un Playbook; allo scopo occorre aprire l’interfaccia a riga di comando e da qui impartire il comando per creare il relativo file YAML: nello specifico lo chiameremo apache.yml.

Aperto il file, la prima cosa che dobbiamo fare è dargli un nome: nello specifico, installa apache, visto che vogliamo che installi apache sui server specificati; inoltre, vogliamo sia installato il pacchetto htop.

L’installazione dei pacchetti viene specificata dal comando with_items, cui segue l’elenco corrispondente e sarà eseguita su tutti i nodi (hosts: all) dall’utente remoto root. Notate che è fondamentale rispettare l’indentazione (tabulazione) che vedete nell’esempio, altrimenti al momento dell’esecuzione il playbook restituirà dei messaggi d’errore e non verrà eseguito.

Il file che otteniamo è quello mostrato qui di seguito ed è poi il nostro Playbook, con tutte le due componenti correttamente indentate.

A questo punto se vogliamo eseguire il nostro playbook ritorniamo alla nostra interfaccia a riga di comando e impartiamo da essa il comando per l’esecuzione:

ansible-playbook -v apache.yml

seguito da Invio. Il playbook verrà quindi eseguito.

Chiaramente è possibile definire l’installazione di altri pacchetti ed anche la configurazione di file di applicazioni specifiche: per esempio possiamo installare apache, mySQL e WordPress e poi configurare il file di WordPress, così da costruire il server in modo che ospiti un sito creato, appunto, in WordPress.

Utilizzo di funzionalità aggiuntive

Ai Playbook possono essere associate funzionalità chiamate Templates, Loops, Conditionals, Tags e Blocks. I template sono modelli di Playbook che consentono, dinamicamente, di settare e modificare variabili dei play, generare file come quelli di configurazione partendo da variabili, nonché gestire Conditional logic: per esempio se bisogna installare php, al posto di creare tanti Playbook quante sono le versioni disponibili basta crearne uno solo come Template, contenente come variabile la versione da installare e ogni volta che si deve eseguire, gli si passa la versione da installare.

I loop possono eseguire un task o operazioni multiple come, ad esempio, creare molti utenti su un server, installare pacchetti software o ripetere uno step di polling verso gli host fino al raggiungimento di un determinato risultato. 

Per esempio, nell’immagine seguente creiamo un loop per installare un certo numero di pacchetti su un nodo utilizzando un unico task invece di tanti; il pacchetto è httpd (la sua ultima versione).

Il nome del task (che fa uso del modulo yum) è virgolettato e tra parentesi abbiamo item, che rimanda alla descrizione degli oggetti da installare. In altre parole il comando in cui il nome non è univoco ma contiene “{{item}} avrà per parametri quelli specificabili nell’apposita sezione che segue e che vedete chiamata with_tems: dove in questo caso è possibile elencare, ciascuno preceduto su un trattino e su una riga (perché l’esecuzione è sequenziale, come già spiegato…), i nomi dei pacchetti.

Nell’esempio i pacchetti sono solo due, ovvero httpd e mod_wsgi ma avrebbero potrebbero posuto essere decine e decine; anche qui, un loop consente di automatizzare la procedura.

I conditionals sono in pratica l’esecuzione di task (attività) condizionata al verificarsi di certe condizioni valutate a run-time (ossia in corso d’esecuzione) come variabili, fact o il risultato di un task precedente. Un esempio di Conditional logico è:

- yum:

  name: httpd

  state: latest

 when: ansible_os_family = = “RedHat”

dove la condizione segue when: e impone che il task sia eseguito solo se sul server remoto è installata una distribuzione di Linux RedHat. Questo permette di installare un certo pacchetto solo a condizione che il server remoto (il nodo) sia in grado di utilizzarlo.

Ripe Ncc Member
vmware
CloudLinux
Plesk
HP
Microsoft