GNU/Linux >> Linux Esercitazione >  >> Linux

Come creare un Playbook Ansible

Alcune settimane fa, ho iniziato a utilizzare Ansible per semplificare le attività amministrative per le molteplici organizzazioni che supporto. Inoltre, volevo soprattutto semplificare la gestione della mia flotta di otto o nove host (il conteggio esatto cambia frequentemente). Ho fatto tutta la mia automazione usando gli script Bash da quando ho iniziato a usare Linux. Ho usato script per automatizzare la distribuzione di altri script di automazione degli aggiornamenti, file di configurazione del sistema e dell'utente, aggiornamenti a versioni più recenti di Fedora e aggiornamenti a nuove versioni di Fedora. E questo non include tutti quei piccoli compiti ad hoc che sorgono su quella che sembra essere una base oraria.

Gli script continueranno a svolgere un ruolo essenziale nella mia automazione amministrativa. Tuttavia, sembra che Ansible possa assumere molte attività e svolgerle molto meglio di script anche complessi. Riguarda il playbook e in questo articolo ne creo uno in grado di eseguire un aggiornamento del sistema tenendo conto delle differenze di sistema.

Di recente ho scritto del mio primo giorno di utilizzo di Ansible. Se non hai letto quell'articolo, potresti volerlo fare prima di continuare con questo. Questo articolo presuppone che tu abbia una familiarità di base con l'uso di Ansible. Se hai letto il mio articolo al link sopra, dovresti essere in grado di seguire questo testo senza difficoltà.

Questo articolo è diviso in due parti, quindi assicurati di leggere la seconda metà. In questa sezione definiremo alcuni importanti concetti e termini di Ansible, discuteremo i commenti e implementeremo la prima riproduzione del playbook. La seconda parte continua con le due riproduzioni rimanenti, alcune informazioni di follow-up e il mio elenco di risorse.

Il playbook di questo articolo non richiede l'installazione di moduli o raccolte Ansible oltre a quelli predefiniti predefiniti. Questo playbook è stato testato con Ansible 2.9.14.

[ Ai lettori è piaciuto anche: Aggiungi un repository e installa un pacchetto nel modo Ansible ]

Cos'è un playbook?

Mentre scrivevo questo articolo, stavo anche guardando alcune sessioni dell'AnsibleFest virtuale di quest'anno. Mentre guardavo, ho sviluppato la mia descrizione di un playbook, che ha senso per me. Questa descrizione contiene frammenti di saggezza da playbook di molti dei presentatori, oltre ad alcuni libri e post di blog che ho letto.

Ecco la mia definizione:

Un playbook Ansible è una descrizione creata dall'uomo dello stato desiderato di uno o più computer. Ansible legge il playbook, confronta lo stato effettivo dei computer con lo stato specificato nel playbook ed esegue le attività necessarie per rendere tali computer conformi allo stato descritto nel playbook.

Aggiornamenti

L'installazione degli aggiornamenti sui moderni host Linux è un'attività quasi costante, resa importante dal numero di correzioni di sicurezza e miglioramenti delle funzionalità che escono continuamente. Se alcuni software, come kernel, glibc o systemd vengono aggiornati, è necessario riavviare anche l'host. È inoltre necessario eseguire alcune attività aggiuntive, come l'aggiornamento del database della pagina man.

Sebbene disponga di installazioni di aggiornamento automatizzate con uno script interessante, alcuni dei miei host devono essere trattati in modo leggermente diverso rispetto ad altri. Ad esempio, non voglio aggiornare contemporaneamente il mio firewall e il mio server e-mail/web/DHCP/DNS. Se il server si riavvia, il firewall non può ottenere le informazioni necessarie per procedere con i propri aggiornamenti e nemmeno gli altri host nella mia rete. Se il firewall si interrompe, l'accesso ai repository Fedora esterni viene perso sul mio server e su tutti gli altri host interni. Ciò significa attendere il riavvio di questi due host prima che gli aggiornamenti possano iniziare sugli altri host.

Quindi eseguivo quegli aggiornamenti avviando gli script sul firewall e quindi aspettando che finisse, quindi spostandomi sul server e aspettando che finisse prima di eseguire un piccolo programma da riga di comando per eseguire lo script di aggiornamento in sequenza su il resto dei miei ospiti. Avrei potuto scrivere queste dipendenze nei miei script, ma i miei primi giorni con Ansible mi hanno mostrato che ha già quelle capacità e molte altre che renderebbero il mio compito molto più semplice. Davvero, MOLTO più semplice. E nel complesso più veloce, senza alcun intervento da parte mia.

La strategia Ansible

Ansible utilizza una strategia hub per la gestione degli host. Il software Ansible è installato sull'host che funge da controller. Il software Ansible lato client non esiste, quindi non è necessario installarne nessuno sugli host remoti.

Ansible utilizza SSH, che è già installato da quasi tutte le distribuzioni Linux, per comunicare con host remoti. Sebbene gli amministratori di sistema possano scegliere di utilizzare le password per l'accesso remoto agli host, ciò riduce sicuramente l'efficienza e la natura pratica di uno strumento come Ansible. Quindi, come la maggior parte degli altri amministratori, utilizzo coppie di chiavi pubbliche/private (PPKP), che sono considerate più sicure delle password e consentono l'automazione delle attività da uno a migliaia di host remoti senza alcun intervento da parte dell'amministratore.

Ansible invia comandi agli host remoti tramite SSH e utilizza i risultati per determinare il successo del comando. Può anche utilizzare questi risultati per determinare la prossima linea di condotta utilizzando il condizionale quando dichiarazioni.

Definizione dei requisiti

Proprio come qualsiasi programma, scritto in C, Python, Bash o qualsiasi altro linguaggio, inizio sempre con una serie di requisiti. Hai letto il mio libro, The Linux Philosophy for SysAdmins, vero? Questo vale anche per strumenti come Ansible. Ho bisogno di definire dove sto andando in modo da poter identificare quando sono arrivato.

Questi sono i requisiti per il mio playbook Ansible:

Gioca 1:controller Ansible

  1. In primo luogo, installa gli aggiornamenti sul nodo di controllo Ansible.
  2. Aggiorna il database della pagina man.
  3. Spegnere se necessario. Questo è diverso per il mio nodo di controllo rispetto agli altri host a causa di una strana scheda madre che non esegue un riavvio corretto.
  4. Accedi dopo il riavvio ed esegui nuovamente il playbook. Poiché il nodo di controllo è già nello stato desiderato, non verranno eseguite ulteriori azioni e verrà avviata la riproduzione 2.

Gioca 2:Server

  1. Installa gli aggiornamenti sui firewall e sui server in serie, ovvero uno alla volta.
  2. Aggiorna il database della pagina man.
  3. Riavvia se necessario.
  4. Aspetta il riavvio del primo host, se necessario, prima di iniziare il successivo.

Gioca 3:workstation

  1. Non iniziare ad aggiornare le workstation finché i server non sono stati completati.
  2. Installa gli aggiornamenti su ogni computer in esecuzione contemporaneamente in parallelo.
  3. Aggiorna il database della pagina man.
  4. Riavvia se necessario.

Sì, lo so che ci sono altri modi per farlo. Ho pensato di fare il controller Ansible per ultimo in modo da non dover affrontare il riavvio del playbook dopo il riavvio del controller. Ma il modo in cui faccio le cose è eseguire prima gli aggiornamenti sulla mia workstation principale, che è anche il mio nodo di controllo Ansible, e quindi eseguire alcuni test prima di aggiornare il resto dei sistemi, quindi questa strategia funziona perfettamente per questo. Le tue esigenze saranno probabilmente diverse dalle mie, quindi dovresti usare il metodo che funziona meglio per te. Il problema di Ansible è che è sufficientemente flessibile per soddisfare esigenze diverse.

Ora che ho i requisiti per un'attività, posso iniziare il playbook.

Sintassi

I playbook Ansible devono essere conformi alla sintassi e alla formattazione YAML standard. Gli errori più frequenti che ho riscontrato sono i miei stessi errori di formattazione. Questo di solito è dovuto al fatto che ho usato o meno i trattini iniziali come richiesto, oppure ho usato il rientro sbagliato.

I nomi delle giocate iniziano nella prima colonna del playbook e ogni attività successiva è rientrata di esattamente due spazi . Esattamente due spazi fanno rientrare ogni azione in un'attività e le attività secondarie sono ulteriormente rientrate esattamente di due spazi. Qualsiasi altro numero di spazi o l'uso di spazi bianchi diversi dagli spazi, come le schede, genererà un errore di runtime. Anche lo spazio bianco extra alla fine di una riga genera un errore.

Farai errori di formattazione e imparerai rapidamente a vedere i problemi. Ci sono alcuni strumenti che posso utilizzare per aiutarci a individuare questi errori prima di tentare di eseguire i playbook e possono far risparmiare molto tempo a lungo termine.

Avvio del playbook

Quindi iniziamo un playbook che eseguirà tali attività nella sequenza richiesta. 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.

Il nostro playbook conterrà tre play per gestire ogni tipo di host che ho identificato nella dichiarazione dei requisiti. Ogni riproduzione avrà una logica leggermente diversa ma produrrà lo stesso risultato:uno o più host con tutti gli aggiornamenti installati.

Il mio playbook si chiama doUpdates.yml e si trova in /root/ansible/Updates directory, che ho creato per questo progetto. Il programma Bash installato dalle riproduzioni in questo playbook si trova in /root/ansible/Updates/files directory.

Esploriamo questo playbook una sezione alla volta.

Definire questo come un file YAML

Inizio tutto il mio codice con commenti ben strutturati in modo che il nome del file e una breve descrizione di questo playbook esistano per me o per qualche altro amministratore di sistema in futuro. I playbook possono contenere commenti, anche se ho visto pochi articoli o libri che ne menzionano.

Come amministratore di sistema che crede nella documentazione di tutto, trovo che i commenti possano essere molto utili. Non si tratta tanto di dire nei commenti le stesse cose che faccio nel nome dell'attività, ma si tratta invece di identificare lo scopo di gruppi di attività e assicurarmi di registrare i motivi per cui faccio determinate cose in un certo modo o ordine. Questo può aiutare con problemi di debug in un secondo momento, quando potrei aver dimenticato il mio pensiero originale. Come in Bash, i commenti iniziano con un # .

La funzione principale di questa prima sezione sono i tre trattini (--- ) utilizzati per definirlo come file YAML. Il yml l'estensione sul nome del file sta per YAML. Ho visto un paio di significati per questo, ma la mia scommessa è su "Yet Another Markup Language", nonostante abbia visto alcune affermazioni secondo cui YAML non è uno.

########################################################################
#                             doUpdates.yml
#------------------------------------------------------------------
# This playbook installs all available RPM updates on the inventory hosts.
#
#    
#------------------------------------------------------------------
#
# Change History              
# Date        Name         Version   Description
# 2020/10/01  David Both   00.00     Started new code
# 2020/10/10  David Both   01.00     First release code finished
# 2020/10/18  David Both   01.01     Minor changes to sequence and
#                                    fix a couple minor problems.
#
########################################################################
---

La prima giocata

La prossima sezione definisce la prima riproduzione nel playbook. I playbook possono avere una o più riproduzioni e il nostro ne ha tre:uno per l'host di controllo su cui viene eseguito Ansible, uno per i due server sulla mia rete e uno per il resto delle workstation. Successivamente, definisco la prima commedia:dopotutto, questo è un playbook.

Si noti che la riproduzione inizia nella colonna zero, e quindi c'è un rientro rigoroso delle righe rimanenti nella riproduzione. Nessuna istruzione definisce l'inizio del gioco. Ansible utilizza la rigida struttura YAML per determinare dove inizia ogni gioco e compito.

########################################################################
#######################################################################
# Play 1 - Do updates for host david
########################################################################
########################################################################
- name: Play 1 - Install updates on david - the Ansible controler
  hosts: david
  remote_user: root
  vars:
    run: false
    reboot: false

Ci imbatteremo frequentemente in varie parole chiave, quindi ecco alcune spiegazioni che vorrei avere quando ho iniziato a lavorare con Ansible.

nome :Questa riga è il nome della riproduzione e il nome della riproduzione viene visualizzato nel flusso di dati STDOUT. In questo modo è facile identificare ogni riproduzione che viene eseguita per tenerne traccia mentre guardo o visualizzo il flusso reindirizzato in un secondo momento. La parola chiave è richiesta per ogni gioco e attività, ma il contenuto del testo è facoltativo.

host :Definisce i nomi host su cui verrà eseguita la riproduzione. Può contenere un elenco di nomi host separati da spazi o il nome di un gruppo di host. Il gruppo host ei nomi di tutti gli host elencati devono essere visualizzati nel file di inventario. Per impostazione predefinita, è /etc/ansible/hosts ma può essere un altro file purché utilizzi -i (--inventory ) opzione per specificare il file alternativo.

utente_remoto :questa riga non è un requisito, ma specifica l'utente che Ansible agirà come sull'host remoto. Se l'utente sull'host remoto è lo stesso dell'utente sull'host locale, questa riga non è necessaria. Per impostazione predefinita, Ansible utilizza sull'host remoto lo stesso ID utente dell'utente che esegue il playbook Ansible. Lo uso qui semplicemente a scopo informativo. Eseguo la maggior parte dei playbook come root su localhost, quindi Ansible accede all'host remoto come root.

vari :In questa sezione è possibile definire una o più variabili, utilizzabili come in qualsiasi linguaggio di programmazione. In questo caso, li uso nelle istruzioni condizionali "quando" più avanti nel playbook per controllare il percorso di esecuzione.

L'ambito delle variabili è limitato alla sezione in cui sono definite. In questo caso, sono definiti in Play 1, quindi sono limitati a quel gioco. Se voglio usarli nelle riproduzioni successive, dovrò reimpostarli in ogni riproduzione in cui sono richiesti. Se una variabile è impostata in un'attività, allora sono disponibili solo all'interno di quell'attività e non nel resto di quella riproduzione.

I valori delle variabili possono essere sovrascritti dalla riga di comando utilizzando -e (--extra_variables ) opzione per specificare un valore diverso. Lo vedremo quando sarà il momento di eseguire il playbook.

I compiti

Questo è l'inizio della sezione delle attività per Play 1. L'attività :la parola chiave è rientrata esattamente di due spazi. Ogni attività deve avere un nome istruzione, anche se non c'è testo per il nome. Il testo rende più facile seguire la logica del playbook e viene visualizzato sullo schermo durante l'esecuzione per assistere mentre seguo l'avanzamento in tempo reale.

tasks:
########################################################################
# Do some preliminary checking 
########################################################################
    - name: Install the latest version of the doUpdates script
      copy:
        src: /root/ansible/Updates/files/doUpdates
        dest: /usr/local/bin
        mode: 0774
        owner: root
        group: root



    - name: Check for currently available updates
      command: doUpdates -c
      register: check
    - debug: var=check.stdout_lines

Questa prima sezione contiene tre attività. La prima attività copia un programma Bash che ho scritto sull'host di destinazione. Il secondo esegue il programma appena installato e assegna—registra—il flusso di dati STDOUT da doUpdates programma alla variabile "check". La terza attività stampa sullo schermo tutte le righe STDOUT nella variabile di controllo.

Diamo un'occhiata alle nuove parole chiave un po' più in dettaglio:

copia :La parola chiave copy definisce l'inizio di una stanza che può copiare uno o più file da una posizione di origine specificata (src ) in una località di destinazione specificata (destinazione ). Le parole chiave in questa sezione definiscono vari aspetti dell'operazione di copia e lo stato finale del file copiato.

sorgente :Questo è il percorso completo e il nome del file da copiare. In questo caso, copierò solo un singolo file, ma è facile copiare tutti i file in una directory o solo quelli che corrispondono a un modello di glob di file. Il file di origine viene in genere archiviato in una posizione nell'albero delle directory dell'hub Ansible. In questo caso, il percorso completo del mio file di origine si trova in /root/ansible/Updates/files/doUpdates .

destinazione :questo è il percorso di destinazione sugli host di destinazione in cui verrà copiato il file di origine.

modalità :La parola chiave mode definisce la modalità file che verrà applicata al file copiato. Indipendentemente dalla modalità file del file di origine, Ansible imposterà la modalità file su quella specificata in questa istruzione. Ad esempio, rwxr_xr__ o 0754 . Assicurati di utilizzare tutti e quattro i byte quando usi il formato ottale.

proprietario :questo è l'account del proprietario che verrà applicato al file.

gruppo :Questo è l'account di gruppo che verrà applicato al file.

comando :qualsiasi comando della shell Linux, script della shell o programma da riga di comando insieme a opzioni e argomenti può essere utilizzato con questa parola chiave. Ho utilizzato il programma Bash che è stato appena installato per ottenere alcune informazioni che non sono facilmente ottenibili utilizzando i built-in di Ansible, come dnf .

registrati :Questa parola chiave imposta lo STDOUT dal comando specificato sopra in una variabile denominata "check". Il quando: la parola chiave può interrogare il contenuto di questa variabile. Viene quindi utilizzato come condizionale per determinare se l'attività di cui fa parte verrà eseguita. Lo vedremo nella prossima sezione.

debug :stampa il contenuto della variabile specificata sullo schermo. Lo uso spesso come strumento di debug. Lo trovo utile per il debug. Suggerimento, suggerimento.

Ora un po' sui miei doUpdates Programma Bash.

Inizialmente ho scritto questo programma Bash per eseguire effettivamente gli aggiornamenti che ora ho iniziato a fare con Ansible. Contiene del codice che determina se gli aggiornamenti sono disponibili. Determina anche se il kernel, systemd o glibc sono stati aggiornati, ognuno dei quali dovrebbe richiedere un riavvio per avere il pieno effetto. Il mio programma emette un paio di righe su STDOUT che posso usare in Ansible come condizionale per decidere se riavviare l'host di destinazione. Lo uso in questa sezione successiva, che esegue gli aggiornamenti effettivi e quello successivo esegue uno spegnimento per la mia workstation principale. Un codice simile esegue un riavvio su tutti gli altri host, come vedrai.

Lo STDOUT di questo programma utilizzato con -c l'opzione appare così quando sono disponibili aggiornamenti, ma non è richiesto un riavvio. Posso usare un'espressione regolare per cercare in qualsiasi testo in questo flusso di dati stringhe di chiavi, che possono essere utilizzate in un quando :condizionale per determinare se viene eseguita un'attività specifica.

TASK [debug] ******************************************************************************************************************************************
ok: [wally1] => {
    "check.stdout_lines": [
        "########## 48 updates ARE available for host wally1.both.org. ##########",
        "########## Including: ##########",
        "Last metadata expiration check: 1:47:12 ago on Tue 20 Oct 2020 01:50:07 PM EDT.",
        "Updates Information Summary: available",
        "    3 Security notice(s)",
        "        2 Moderate Security notice(s)",
        "    3 Bugfix notice(s)",
        "    2 Enhancement notice(s)",
        "    2 other notice(s)",
        "########## A reboot will NOT be required after these updates are installed. ##########",
        "Program terminated normally"
    ]
}

La prossima sezione immediatamente sopra esegue gli aggiornamenti effettivi se tutti i condizionali nel quando :le affermazioni sono vere. Questa sezione utilizza Ansible dnf integrato gestore di pacchetti.

########################################################################
# Do the updates.
########################################################################
# Install all available updates
    - name: Install all current updates
      dnf:
        name: "*"
        state: latest
      when: (check.stdout | regex_search('updates ARE available')) and run == "true"

dnf :chiama il built-in Ansible che si interfaccia con il gestore di pacchetti DNF. Sebbene sia un po' limitato nelle sue capacità, può installare, rimuovere e aggiornare i pacchetti. Una delle limitazioni del modulo DNF è che non ha il check-update funzione. Pertanto, continuo a utilizzare il mio programma Bash per scoprire l'elenco dei pacchetti da aggiornare e da quello determinare se è necessario eseguire un riavvio (o uno spegnimento). Ansible ha anche YUM e APT integrati.

nome :Fornisce il nome del pacchetto su cui operare. In questo caso, il carattere glob del file * denota tutti i pacchetti installati.

stato :Il valore "latest" per questa parola chiave indica che tutti i pacchetti installati devono essere portati alla versione più recente. Alcune delle altre opzioni di stato sono "presente", il che significa che il pacchetto è installato ma non necessariamente l'ultima versione, e "assente", che significa rimuovere il pacchetto se è installato.

quando :questa frase condizionale specifica le condizioni che devono essere soddisfatte per l'esecuzione di questa attività. In questo caso, gli aggiornamenti verranno installati solo quando la stringa di testo definita nell'espressione regolare è presente nella variabile "check" precedentemente registrata e la variabile "run" è impostata su "true".

Ora che gli aggiornamenti sono stati eseguiti, potrebbe essere necessario riavviare, quindi vediamo come posso affrontarlo. Il prossimo compito lo fa per noi.

Innanzitutto, ho un po' di documentazione tramite commenti, che descrive che ho eseguito uno spegnimento anziché un riavvio per questo host a causa di un potenziale problema hardware. Questo è un perfetto esempio del motivo per cui dovremmo includere commenti nel nostro codice e nei playbook perché spiegano perché questa particolare giocata è necessaria e perché è diversa dalle altre. È anche un ottimo esempio di come posso trattare un host in modo diverso dagli altri.

########################################################################
# Now poweroff host david because of MB problems that won't let it
# do a reboot without manual intervention. Need to see if I
# can figure out this problem and fix it but it is a hardware issue
# and this is just a temporary circumvention. 
########################################################################
    - name: Poweroff this host if necessary and reboot extra variable is true
      command: poweroff
      when: (check.stdout | regex_search('reboot will be required')) and reboot == "true" and run == "true"

In questa attività, invio il poweroff comando invece dell'azione preferita di riavvio del computer. Lo faccio per il motivo indicato nei commenti:perché la scheda madre sulla mia workstation principale, che è anche il mio hub Ansible, non si riavvia correttamente. Ciò è probabilmente dovuto a un'errata configurazione da parte mia piuttosto che a qualsiasi tipo di malfunzionamento. Non ho ancora scoperto il motivo perché trovo che il tempo che ho già dedicato alle ricerche e alle modifiche alla configurazione del BIOS ha superato il mio limite di tolleranza e ho bisogno di portare a termine il lavoro. Ogni tanto ci lavoro un po' di più, ma non vale più il tempo extra.

L'esecuzione del playbook si interrompe dopo lo spegnimento (o il riavvio se il dispositivo hub Ansible si riavvia correttamente), quindi è necessario riavviarlo dopo che alla fine si è riattivato. Questa volta, poiché gli aggiornamenti sono stati installati, lo spegnimento o il riavvio non si verificano e viene eseguita la riproduzione successiva.

E questo conclude la prima commedia.

[ Hai bisogno di più su Ansible? Partecipa a un corso di panoramica tecnica gratuito di Red Hat. Ansible Essentials:Semplicità nell'automazione Panoramica tecnica. ] 

Conclusione

Abbiamo trattato molte informazioni qui e spero che una solida spiegazione delle parole chiave e delle attività sia stata utile. È anche chiaro quale sia la mia opinione sui commenti:sono critici. Play 1 avvia il nostro playbook Ansible.

Nella seconda parte di questo articolo, concluderemo il playbook con due ulteriori riproduzioni per gestire il firewall e i server, e quindi il resto degli host sulla rete. Fornirò anche alcuni dettagli e concetti di follow-up.


Linux
  1. Come creare un file in Ansible

  2. Come passare variabili extra a un playbook Ansible

  3. Come installare pacchetti software con un playbook Ansible

  4. Come creare un utente Linux usando Ansible

  5. come creare un playbook Ansible per ottenere le versioni del sistema operativo degli host remoti?

Come creare playbook Ansible per l'automazione IT

Come creare ed eseguire file Ansible Playbook

Come ho usato Ansible per automatizzare gli aggiornamenti a casa

Come installare Ansible su Debian 8 (Jessie)

Come installare Ansible su Debian 9 (Stretch)

Come installare Ansible su Ubuntu 16.04 (Xenial)