Ricerca nel sito web

Il mio primo giorno con Ansible


Un amministratore di sistema condivide informazioni e consigli su come utilizzare Ansible nel mondo reale configurando i computer sulla sua rete.

Ottenere un nuovo computer, fisico o virtuale, attivo e funzionante richiede tempo e richiede molto lavoro, sia che si tratti della prima volta che della cinquantesima. Per molti anni ho utilizzato una serie di script e RPM da me creati per installare i pacchetti di cui avevo bisogno e per eseguire numerose operazioni di configurazione per i miei strumenti preferiti. Questo approccio ha funzionato bene e ha semplificato il mio lavoro, oltre a ridurre la quantità di tempo che passo a digitare i comandi.

Sono sempre alla ricerca di modi migliori per fare le cose e, ormai da diversi anni, sento e leggo di Ansible, che è un potente strumento per automatizzare la configurazione e la gestione del sistema. Ansible consente a un amministratore di sistema di definire uno stato specifico per ciascun host in uno o più playbook e quindi di eseguire tutte le attività necessarie per portare l'host in quello stato. Ciò include l'installazione o l'eliminazione di varie risorse come pacchetti RPM o Apt, file di configurazione e altri file, utenti, gruppi e molto altro.

Ho ritardato a lungo l'apprendimento di come usarlo perché... roba. Fino a poco tempo fa, quando mi sono imbattuto in un problema che pensavo che Ansible potesse risolvere facilmente.

Questo articolo non è una guida completa per iniziare con Ansible; piuttosto, ha lo scopo di fornire informazioni su alcuni dei problemi che ho riscontrato e su alcune informazioni che ho trovato solo in luoghi molto oscuri. Molte delle informazioni che ho trovato in varie discussioni online e gruppi di domande e risposte su Ansible non erano corrette. Gli errori andavano da informazioni molto vecchie senza alcuna indicazione della data o della provenienza a informazioni semplicemente errate.

È noto che le informazioni contenute in questo articolo funzionano, anche se potrebbero esserci altri modi per ottenere le stesse cose, e funzionano con Ansible 2.9.13 e Python 3.8.5.

Il mio problema

Tutte le mie migliori esperienze di apprendimento iniziano con un problema che devo risolvere, e questa non ha fatto eccezione.

Ho lavorato su un piccolo progetto per modificare i file di configurazione per il file manager Midnight Commander (mc) e inviarli a vari sistemi sulla mia rete per i test. Sebbene disponga di uno script per automatizzare questa operazione, è comunque necessario un po' di dimestichezza con un ciclo della riga di comando per fornire i nomi dei sistemi a cui voglio inviare il nuovo codice. Il gran numero di modifiche che stavo apportando ai file di configurazione mi ha reso necessario inviare frequentemente quelli nuovi. Ma, proprio quando pensavo di avere la nuova configurazione giusta, ho riscontrato un problema e avrei dovuto fare un'altra operazione dopo aver apportato la correzione.

Questo ambiente rendeva difficile tenere traccia di quali sistemi disponessero dei nuovi file e quali no. Ho anche un paio di ospiti che devono essere trattati diversamente. E la mia piccola conoscenza di Ansible suggerisce che probabilmente sarebbe in grado di fare tutto o la maggior parte di ciò di cui ho bisogno.

Iniziare

Avevo letto numerosi buoni articoli e libri su Ansible, ma mai in un "Devo farlo funzionare ORA!" tipo di situazione. E ora era... beh, ADESSO!

Rileggendo questi documenti, ho scoperto che parlano principalmente di come installare Ansible da GitHub utilizzando, aspetta, Ansible. È fantastico, ma volevo solo iniziare, quindi l'ho installato sulla mia workstation Fedora utilizzando DNF e la versione nel repository Fedora. Facile.

Ma poi ho iniziato a cercare le posizioni dei file e a provare a determinare quali file di configurazione dovevo modificare, dove conservare i miei playbook, che aspetto ha un playbook e cosa fa. Avevo un sacco di domande (finora) senza risposta che mi giravano per la testa.

Quindi, senza ulteriori descrizioni delle mie tribolazioni, ecco le cose che ho scoperto e che mi hanno fatto andare avanti.

Configurazione

I file di configurazione di Ansible sono conservati in /etc/ansible. Ha senso, vero, dato che /etc è dove i programmi di sistema dovrebbero conservare i loro file di configurazione. I due file con cui dovevo lavorare sono ansible.cfg e hosts.

ansible.cfg

Dopo aver iniziato con alcuni degli esercizi che ho trovato nei documenti e online, ho iniziato a ricevere messaggi di avviso sulla deprecazione di alcuni vecchi file Python. Quindi, ho impostato deprecation_warnings su false in ansible.cfg e quei messaggi di avviso rossi arrabbiati si sono interrotti:

deprecation_warnings = False

Questi avvertimenti sono importanti, quindi li rivisiterò più tardi e capirò cosa devo fare. Ma per ora non ingombrano più lo schermo e offuscano gli errori di cui devo davvero preoccuparmi.

Il file degli host

A differenza del file /etc/hosts, il file hosts è anche conosciuto come file di inventario ed elenca gli host sulla tua rete. Questo file consente di raggruppare gli host in set correlati, come server, workstation e praticamente qualsiasi designazione di cui hai bisogno. Questo file contiene il proprio aiuto e numerosi esempi, quindi non entrerò nei noiosi dettagli qui. Tuttavia, ci sono alcune cose da sapere.

Gli host possono essere elencati al di fuori di qualsiasi gruppo, ma i gruppi possono essere utili per identificare host con una o più caratteristiche comuni. I gruppi utilizzano il formato INI, quindi un gruppo di server ha il seguente aspetto:

[servers]
server1
server2
...etc.

Un nome host deve essere presente in questo file affinché Ansible possa lavorarci sopra. Anche se alcuni sottocomandi ti consentono di specificare un nome host, il comando fallirà a meno che il nome host non sia nel file hosts. Un host può anche essere elencato in più gruppi. Quindi server1 potrebbe anche essere un membro del gruppo [webservers] oltre al gruppo [servers] e un membro del gruppo [ubuntu] per differenziarlo dai server Fedora.

Ansible è intelligente. Se per il nome host viene utilizzato l'argomento all, Ansible esegue la scansione del file ed esegue le attività definite su tutti gli host elencati nel file. Ansible tenterà di lavorare su ciascun host una sola volta, indipendentemente dal numero di gruppi in cui appare. Ciò significa anche che non è necessario che esista un gruppo "tutti" definito perché Ansible può determinare tutti i nomi host nel file e creare il proprio elenco di nomi host univoci.

Un'altra piccola cosa a cui prestare attenzione sono le voci multiple per un singolo host. Utilizzo i record CNAME nel mio file di zona DNS per creare nomi con alias che puntano ai record A per alcuni dei miei host. In questo modo, posso fare riferimento a un host come host1 o h1 o myhost. Se utilizzi più nomi host per lo stesso host nel file hosts, Ansible proverà a eseguire le sue attività su tutti quei nomi host; non ha modo di sapere che si riferiscono allo stesso host. La buona notizia è che ciò non influisce sul risultato complessivo; ci vuole solo un po' più di tempo poiché Ansible lavora sui nomi host secondari e determina che tutte le operazioni sono già state eseguite.

Fatti ansibili

La maggior parte dei materiali che ho letto su Ansible parlano di fatti Ansible, che "sono dati relativi ai sistemi remoti, inclusi sistemi operativi, indirizzi IP, file system allegati e altro ancora". Queste informazioni sono disponibili in altri modi, come lshw, dmidecode, il filesystem /proc e altro, ma Ansible genera un file JSON contenente questa informazione. Ogni volta che Ansible viene eseguito, genera questi dati concreti. C'è una quantità incredibile di informazioni in questo flusso di dati, tutte in coppie <"variable-name": "value">. Tutte queste variabili possono essere utilizzate all'interno di un playbook Ansible. Il modo migliore per comprendere l'enorme quantità di informazioni disponibili è visualizzarle tu stesso:

# ansible -m setup <hostname> | less

Capito quello che intendo? Tutto quello che avresti sempre voluto sapere sull'hardware del tuo host e sulla distribuzione Linux è lì e può essere utilizzato in un playbook. Non sono ancora arrivato al punto in cui devo utilizzare quelle variabili, ma sono certo che lo farò nei prossimi due giorni.

Moduli

Il comando ansible sopra usa l'opzione -m per specificare il modulo "setup". Ansible ha molti moduli già integrati, quindi non è necessario utilizzare -m per quelli. Ci sono anche molti moduli scaricabili che possono essere installati, ma quelli integrati fanno tutto ciò di cui ho avuto bisogno finora per i miei progetti attuali.

Playbook

I playbook possono essere posizionati quasi ovunque. Dato che devo eseguire i miei playbook come root, ho inserito i miei in /root/ansible. Finché questa directory è la directory di lavoro attuale (PWD) quando eseguo Ansible, può trovare il mio playbook. Ansible dispone anche di un'opzione di runtime per specificare un playbook e una posizione diversi.

I playbook possono contenere commenti, anche se ho visto pochissimi articoli o libri che lo menzionano. Come amministratore di sistema che crede nella documentazione di tutto, trovo che l'utilizzo dei commenti possa essere molto utile. Non si tratta tanto di dire nei commenti le stesse cose che dico nel nome dell'attività; si tratta piuttosto di identificare lo scopo di gruppi di compiti e di assicurarmi di registrare le ragioni per cui faccio determinate cose in un certo modo o ordine. Questo può aiutare con il debug dei problemi in un secondo momento, quando potrei aver dimenticato il mio pensiero originale.

I playbook sono semplicemente raccolte di attività che definiscono lo stato desiderato di un host. Un nome host o un gruppo di inventario viene specificato all'inizio del playbook e definisce gli host su cui Ansible eseguirà il playbook.

Ecco un esempio del mio playbook:

################################################################################
# This Ansible playbook updates Midnight commander configuration files.        #
################################################################################
- name: Update midnight commander configuration files
  hosts: all
  
  tasks:
  - name: ensure midnight commander is the latest version
    dnf:
      name: mc
      state: present

  - name: create ~/.config/mc directory for root
    file:
      path: /root/.config/mc
      state: directory
      mode: 0755
      owner: root
      group: root

  - name: create ~/.config/mc directory for dboth
    file:
      path: /home/dboth/.config/mc
      state: directory
      mode: 0755
      owner: dboth
      group: dboth


  - name: copy latest personal skin
    copy:
      src: /root/ansible/UpdateMC/files/MidnightCommander/DavidsGoTar.ini
      dest: /usr/share/mc/skins/DavidsGoTar.ini
      mode: 0644
      owner: root
      group: root

  - name: copy latest mc ini file
    copy:
      src: /root/ansible/UpdateMC/files/MidnightCommander/ini
      dest: /root/.config/mc/ini
      mode: 0644
      owner: root
      group: root

  - name: copy latest mc panels.ini file
    copy:
      src: /root/ansible/UpdateMC/files/MidnightCommander/panels.ini
      dest: /root/.config/mc/panels.ini
      mode: 0644
      owner: root
      group: root
<SNIP>

Il playbook inizia con il proprio nome e gli host su cui agirà: in questo caso, tutti gli host elencati nel mio file hosts. La sezione task elenca le attività specifiche richieste per rendere l'host conforme allo stato desiderato. Questo playbook inizia con un'attività in cui il DNF integrato di Ansible aggiorna Midnight Commander se non è la versione più recente. Le attività successive assicurano che le directory richieste vengano create se non esistono e il resto delle attività copia i file nelle posizioni corrette. Queste attività file e copia possono anche impostare la proprietà e le modalità file per le directory e i file.

I dettagli del mio playbook vanno oltre lo scopo di questo articolo, ma ho utilizzato un attacco di forza bruta per risolvere il problema. Esistono altri metodi per determinare quali utenti necessitano dell'aggiornamento dei file anziché utilizzare un'attività per ciascun file per ciascun utente. Il mio prossimo obiettivo è semplificare questo manuale per utilizzare alcune delle tecniche più avanzate.

Gestire un playbook è facile; basta usare il comando ansible-playbook. L'estensione .yml sta per YAML. Ho visto diversi significati per questo, ma la mia scommessa è su "Yet Another Markup Language", nonostante alcuni affermino che YAML non lo sia.

Questo comando esegue il playbook che ho creato per aggiornare i miei file Midnight Commander:

# ansible-playbook -f 10 UpdateMC.yml

L'opzione -f specifica che Ansible dovrebbe eseguire il fork fino a 10 thread per eseguire operazioni in parallelo. Ciò può accelerare notevolmente il completamento complessivo delle attività, soprattutto quando si lavora su più host.

Produzione

L'output di un playbook in esecuzione elenca ogni attività e i risultati. Un ok significa che lo stato della macchina gestito dall'attività è già definito nella stanza dell'attività. Poiché lo stato definito nell'attività è già vero, Ansible non ha dovuto eseguire le azioni definite nella stanza dell'attività.

La risposta changed indica che Ansible ha eseguito l'attività specificata nella stanza per portarla allo stato desiderato. In questo caso, lo stato della macchina definito nella stanza non era vero, quindi sono state eseguite le azioni definite per renderlo vero. Su un terminale che supporta i colori, le linee TASK vengono visualizzate a colori. Sul mio host con la configurazione del colore del terminale ambra su nero, le righe TASK sono visualizzate in ambra, le righe modificate sono in marrone e ok le linee sono visualizzate in verde. Le righe di errore vengono visualizzate in rosso.

Il seguente output proviene dal playbook che utilizzerò eventualmente per eseguire la configurazione post-installazione sui nuovi host:

PLAY [Post-installation updates, package installation, and configuration] 

TASK [Gathering Facts] 
ok: [testvm2]

TASK [Ensure we have connectivity] 
ok: [testvm2]

TASK [Install all current updates] 
changed: [testvm2]

TASK [Install a few command line tools] 
changed: [testvm2]

TASK [copy latest personal Midnight Commander skin to /usr/share] 
changed: [testvm2]

TASK [create ~/.config/mc directory for root] 
changed: [testvm2]

TASK [Copy the most current Midnight Commander configuration files to /root/.config/mc] 
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/DavidsGoTar.ini)
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/ini)
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/panels.ini)

TASK [create ~/.config/mc directory in /etc/skel] 
changed: [testvm2]

<SNIP>

La mucca

Se hai installato il programma cowsay sul tuo computer, noterai che i nomi dei TASK appaiono nel fumetto della mucca:

 ____________________________________
< TASK [Ensure we have connectivity] >
 ------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Se non disponi di questa divertente funzionalità e la desideri, installa il pacchetto cowsay utilizzando il gestore pacchetti della tua distribuzione. Se lo hai e non lo vuoi, disabilitalo impostando nocows=1 nel file /etc/ansible/ansible.cfg.

Mi piace la mucca e penso che sia divertente, ma riduce la quantità di spazio sullo schermo che può essere utilizzata per visualizzare i messaggi. Quindi l'ho disabilitato dopo che ha iniziato a intralciarmi.

File

Come per il mio compito su Midnight Commander, spesso è necessario installare e mantenere file di vario tipo. Esistono tante "migliori pratiche" per creare un albero di directory per l'archiviazione dei file utilizzati nei playbook quanti sono gli amministratori di sistema, o almeno tante quanti sono gli autori che scrivono libri e articoli su Ansible.

Ho scelto una struttura semplice che per me ha senso:

/root/ansible
└── UpdateMC
    ├── files
    │   └── MidnightCommander
    │       ├── DavidsGoTar.ini
    │       ├── ini
    │       └── panels.ini
    └── UpdateMC.yml

Dovresti usare qualunque struttura funzioni per te. Tieni solo presente che qualche altro amministratore di sistema probabilmente dovrà lavorare con qualunque cosa tu abbia configurato, quindi dovrebbe esserci un certo livello di logica in questo. Quando utilizzavo gli script RPM e Bash per eseguire le attività post-installazione, il mio repository di file era un po' disperso e sicuramente non strutturato con alcuna logica. Mentre lavoro alla creazione di playbook per molte delle mie attività amministrative, introdurrò una struttura molto più logica per la gestione dei miei file.

Esecuzioni multiple di playbook

È sicuro eseguire un playbook tutte le volte che è necessario o desiderato. Ciascuna attività verrà eseguita solo se lo stato non corrisponde a quello specificato nella stanza dell'attività. Ciò semplifica il ripristino dagli errori riscontrati durante le precedenti esecuzioni del playbook. Il playbook interrompe l'esecuzione quando rileva un errore.

Durante il test del mio primo playbook, ho commesso molti errori e li ho corretti. Ogni ulteriore esecuzione del playbook, presupponendo che la mia soluzione sia valida, salta le attività il cui stato corrisponde già a quello specificato ed esegue quelle che non lo corrispondono. Quando la correzione funziona, l'attività precedentemente non riuscita viene completata correttamente e vengono eseguite anche tutte le attività successive nel mio playbook, finché non si verifica un altro errore.

Ciò semplifica anche i test. Posso aggiungere nuove attività e, quando eseguo il playbook, vengono eseguite solo quelle nuove attività perché sono le uniche che non corrispondono allo stato desiderato dell'host di test.

Alcuni pensieri

Alcune attività non sono appropriate per Ansible perché esistono metodi migliori per ottenere uno stato macchina specifico. Il caso d'uso che mi viene in mente è quello di riportare una VM a uno stato iniziale in modo che possa essere utilizzata tutte le volte necessarie per eseguire test a partire da quello stato noto. È molto più semplice portare la VM nello stato desiderato e quindi scattare un'istantanea dello stato corrente della macchina. Ritornare a quella istantanea sarà solitamente più semplice e molto più veloce rispetto all'utilizzo di Ansible per riportare l'host allo stato desiderato. Questo è qualcosa che faccio più volte al giorno quando cerco articoli o provo un nuovo codice.

Dopo aver completato il mio playbook per l'aggiornamento di Midnight Commander, ho avviato un nuovo playbook che utilizzerò per eseguire attività post-installazione sugli host Fedora appena installati. Ho già fatto buoni progressi e il playbook è un po' più sofisticato e meno brutale del mio primo.

Durante il mio primo giorno di utilizzo di Ansible, ho creato un playbook che risolve un problema. Ho anche avviato un secondo playbook che risolverà il grosso problema della configurazione post-installazione. E ho imparato molto.

Anche se mi piace molto utilizzare gli script Bash per molte delle mie attività amministrative, sto già scoprendo che Ansible può fare tutto ciò che voglio e in un modo che possa mantenere il sistema nello stato che desidero. Dopo solo un giorno di utilizzo, sono un fan di Ansible.

Risorse

Il documento più completo e utile che ho trovato è la Guida per l'utente sul sito Web Ansible. Questo documento è inteso come riferimento e non come un documento informativo o introduttivo.

Opensource.com ha pubblicato molti articoli su Ansible nel corso degli anni e li ho trovati molto utili per le mie esigenze. Il sito Web Enable Sysadmin contiene anche molti articoli Ansible che ho trovato utili. Puoi saperne ancora di più dando un'occhiata all'AnsibleFest che si terrà questa settimana (13-14 ottobre 2020). L’evento è completamente virtuale e la registrazione è gratuita.

Articoli correlati: