408 lines
14 KiB
Markdown
408 lines
14 KiB
Markdown
# Playbook
|
||
|
||
Un playbook Ansible è un file testuale, scritto in formato YAML, che definisce una sequenza di operazioni (`task`) da eseguire su uno o più nodi.
|
||
|
||
Un playbook può contenere uno o più *Play*. Ogni Play è composto da una serie di *task*, che a loro volta possono richiamare uno o più moduli.
|
||
|
||
## Struttura di un playbook
|
||
|
||
Di seguito è riportato un esempio di playbook:
|
||
|
||
```yaml
|
||
---
|
||
- name: install and start httpd
|
||
hosts: databases
|
||
|
||
tasks:
|
||
- name: install httpd
|
||
apt:
|
||
name: httpd
|
||
state: latest
|
||
become: true
|
||
|
||
- name: start httpd
|
||
service:
|
||
name: httpd
|
||
state: started
|
||
become: true
|
||
```
|
||
|
||
- `name`: specifica il nome del play, che descrive l'azione da eseguire
|
||
- `hosts`: indica i nodi sui quali il play sarà eseguito
|
||
- `tasks`: contiene un elenco di operazioni da eseguire
|
||
|
||
In questo esempio:
|
||
|
||
- il playbook contiene un unico play
|
||
- il play ha il compito di installare e avviare il servizio httpd su un gruppo di host denominato *databases*
|
||
- sono definiti due task: il primo installa il pacchetto httpd tramite il *modulo apt*, mentre il secondo avvia il servizio httpd utilizzando il *modulo service*
|
||
- l’opzione `become: true` indica che i task devono essere eseguite con privilegi elevati, tipicamente utilizzando sudo
|
||
|
||
Un esempio di playbook con due play:
|
||
|
||
```yaml
|
||
---
|
||
- name: install and start apache
|
||
hosts: webservers
|
||
|
||
tasks:
|
||
- name: install apache
|
||
apt:
|
||
name: apache2
|
||
state: latest
|
||
become: true
|
||
|
||
- name: start apache
|
||
service:
|
||
name: apache2
|
||
state: started
|
||
become: true
|
||
|
||
- name: install and start mysql
|
||
hosts: databases
|
||
|
||
tasks:
|
||
- name: install mysql
|
||
apt:
|
||
name: mysql-server
|
||
state: latest
|
||
become: true
|
||
|
||
- name: start mysql
|
||
service:
|
||
name: mysql
|
||
state: started
|
||
become: true
|
||
```
|
||
|
||
## Esecuzione di un playbook
|
||
|
||
Per eseguire un playbook, è necessario utilizzare il comando `ansible-playbook`, specificando:
|
||
|
||
- l’inventory file, se custom, con l'opzione `-i`
|
||
- il percorso del playbook
|
||
- eventuali opzioni aggiuntive, come `-ask-vault-pass`, che richiede la password per decifrare i file crittografati con `ansible-vault`
|
||
|
||
```bash
|
||
ansible-playbook -i inventory playbook/my-playbook.yml -K --ask-vault-pass
|
||
```
|
||
|
||
## Conditionals
|
||
|
||
Le istruzioni condizionali consentono di modificare il comportamento di un playbook in base a specifiche condizioni.
|
||
|
||
L'istruzione condizionale più semplice si applica a un singolo task, utilizzando la parola chiave `when`. In questo caso, il task verrà eseguito solo sui nodi in cui la condizione specificata è soddisfatta.
|
||
|
||
### Tipologie di condizioni
|
||
|
||
Le condizioni possono basarsi su diversi tipi di dati:
|
||
|
||
- `ansible_facts`: attributi specifici di ogni host, messi a disposizione da Ansible. Questi fanno riferimento a caratteristiche del nodo, come il tipo sistema operativo, le caratteristiche hardware e altre proprietà rilevanti. Sono utili per adattare il comportamento del playbook in base alle caratteristiche del nodo target
|
||
- `registered variables`: variabili che contengono il risultato di task precedenti. È possibile condizionare in questo modo l’esecuzione di un task in base all’esito di un task già eseguito
|
||
- `variabili` definite nel playbook o nell'inventory
|
||
|
||
Un semplice esempio di condizione `when`:
|
||
|
||
```yaml
|
||
---
|
||
- name: playbooks with conditions
|
||
hosts: db
|
||
become: true
|
||
|
||
tasks:
|
||
- name: install postgres
|
||
apt:
|
||
name: postgresql
|
||
state: latest
|
||
when: ansible_distribution == 'Ubuntu'
|
||
```
|
||
|
||
Un esempio di `registered variables`:
|
||
|
||
```yaml
|
||
---
|
||
- name: Install and Start HTTPD Service
|
||
hosts: webservers
|
||
become: true
|
||
|
||
tasks:
|
||
- name: Install the httpd package
|
||
apt:
|
||
name: httpd
|
||
state: present
|
||
register: httpd_installation
|
||
|
||
- name: Start the httpd service
|
||
service:
|
||
name: httpd
|
||
state: started
|
||
when: httpd_installation.changed == true
|
||
```
|
||
|
||
Questo task utilizza il modulo apt per installare il pacchetto httpd. Durante l'esecuzione, il risultato dell'installazione viene registrato nella variabile `httpd_installation`. Avvia infine il servizio httpd, ma solo se l'installazione del pacchetto è stata completata con successo.
|
||
|
||
## Loops
|
||
|
||
I loop in Ansible consentono di ripetere un task più volte all'interno di un playbook, evitando la necessità di riscrivere blocchi di codice che eseguono la stessa operazione.
|
||
|
||
I tre tipi principali di loop sono:
|
||
|
||
- `Liste`
|
||
- `Liste di hash`
|
||
- `Dizionari`
|
||
|
||
### Liste
|
||
|
||
Per i loop di liste, si utilizza la parola chiave `loop`, seguita da una lista di stringhe. Il task verrà eseguito tante volte quante sono le stringhe nella lista, e `{{ item }}`, nel task, assumerà il valore dell'elemento iesimo.
|
||
|
||
```yaml
|
||
---
|
||
- name: playbook with loop
|
||
hosts: db
|
||
become: true
|
||
|
||
tasks:
|
||
- name: add users
|
||
user:
|
||
name: "{{ item }}"
|
||
loop:
|
||
- userOne
|
||
- userTwo
|
||
```
|
||
|
||
### Liste di hash
|
||
|
||
Per i loop di liste di hash, si utilizza la medesima parola chiave loop, ma la lista contiene elementi `chiavi: valore`. In questo caso, si può accedere ai valori usando la sintassi `{{ item.key }}`.
|
||
|
||
```yaml
|
||
---
|
||
- name: Playbook con loop su lista di hash
|
||
hosts: db
|
||
become: true
|
||
|
||
tasks:
|
||
- name: add users
|
||
user:
|
||
name: "{{ item.name }}"
|
||
uid: "{{ item.uid }}"
|
||
shell: "{{ item.shell }}"
|
||
loop:
|
||
- { name: 'userOne', uid: 1001, shell: '/bin/bash' }
|
||
- { name: 'userTwo', uid: 1002, shell: '/bin/zsh' }
|
||
```
|
||
|
||
## Blocks
|
||
|
||
I blocchi in Ansible vengono impiegati per due finalità principali:
|
||
|
||
- *raggruppare task* correlati tra loro, in modo da applicare direttive comuni a un insieme di operazioni
|
||
- *gestire gli errori* che possono verificarsi durante l’esecuzione dei task, consentendo di definire azioni specifiche in caso di fallimento o di successo
|
||
|
||
Tutte le direttive associate a un blocco vengono automaticamente ereditate da tutti i task contenuti al suo interno.
|
||
|
||
I blocchi offrono due sezioni dedicate alla gestione degli errori:
|
||
|
||
- `rescue`: contiene i task che vengono eseguiti immediatamente nel caso in cui almeno uno dei task all'interno del blocco generi un errore
|
||
- `always`: contiene i task che vengono eseguiti indipendentemente dall’esito dei task nel blocco, sia in caso di successo che di fallimento
|
||
|
||
Un esempio di **raggruppamento**:
|
||
|
||
```yaml
|
||
---
|
||
- name: block
|
||
hosts: db
|
||
tasks:
|
||
- block:
|
||
- name: list user
|
||
command: ls -l /usr/
|
||
- name: list root
|
||
command: ls -l /root/
|
||
- name: list bin
|
||
command: ls -l /bin/
|
||
- name: list home
|
||
command: ls -l ~/
|
||
become: yes
|
||
- name: list home
|
||
command: "ls -l ~/"
|
||
```
|
||
|
||
La direttiva `become: yes` è associata al blocco e viene applicata a tutti i task al suo interno, semplificando la gestione delle operazioni correlate.
|
||
|
||
Un esempio di **gestione di errori**:
|
||
|
||
```yaml
|
||
---
|
||
- name: Error handling example
|
||
hosts: db
|
||
tasks:
|
||
- block:
|
||
- name: Execute a command that fail
|
||
command: /bin/false
|
||
|
||
rescue:
|
||
- name: Handle the error
|
||
debug:
|
||
msg: "The command failed, executing an alternative action."
|
||
|
||
always:
|
||
- name: Always execute this command
|
||
debug:
|
||
msg: "This action is executed regardless of the block's result."
|
||
```
|
||
|
||
In questo caso, il task nella sezione `rescue` viene eseguito solo se il comando /bin/false fallisce, mentre il task nella sezione `always` viene eseguito in ogni circostanza.
|
||
|
||
## Handlers
|
||
|
||
Gli `handler` in Ansible consentono l'esecuzione condizionale di specifiche operazioni, attivate solo quando un task determina modifiche su un nodo target.
|
||
|
||
```yaml
|
||
---
|
||
- name: playbook with handlers
|
||
hosts: db
|
||
become: true
|
||
|
||
tasks:
|
||
- name: install httpd
|
||
apt:
|
||
name: httpd
|
||
state: present
|
||
notify:
|
||
- Start httpd
|
||
|
||
handlers:
|
||
- name: Start httpd
|
||
service:
|
||
name: httpd
|
||
state: started
|
||
```
|
||
|
||
La parola chiave `notify` serve a richiamare l’handler specificato. Durante la prima esecuzione, una volta installato il software httpd, l’handler verrà attivato e avvierà il servizio. Nelle esecuzioni successive, qualora il pacchetto sia già presente e non subisca modifiche, il task non verrà eseguito e, di conseguenza, neppure l’handler associato verrà richiamato.
|
||
|
||
Per impostazione predefinita, gli handlers vengono eseguiti solo dopo che tutti i task del playbook sono stati completati. Questo significa che, anche se più task notificano lo stesso handler, quest’ultimo verrà eseguito una sola volta.
|
||
|
||
## Tags
|
||
|
||
I tag consentono di contrassegnare specifici task, offrendo la possibilità di selezionare quali parti eseguire di un playbook.
|
||
|
||
Per aggiungere un tag a un task, è sufficiente utilizzare la direttiva `tags` seguita da un elenco di etichette. Ogni task può essere associato a uno o più tag, come illustrato nell’esempio seguente:
|
||
|
||
```yaml
|
||
---
|
||
- name: playbook with tags
|
||
hosts: db
|
||
become: true
|
||
|
||
tasks:
|
||
- name: install httpd
|
||
apt:
|
||
name: httpd
|
||
state: present
|
||
tags:
|
||
- http
|
||
|
||
- name: install postgres
|
||
apt:
|
||
name: postgresql
|
||
state: present
|
||
tags:
|
||
- db
|
||
```
|
||
|
||
In questo esempio, ogni task è associato a un tag specifico, rispettivamente http e db. In questo modo, è possibile eseguire solo i task contrassegnati da un determinato tag.
|
||
|
||
### Tag speciali
|
||
|
||
Ansible offre due tag speciali, `always` e `never`: un task contrassegnato con il tag *always* verrà sempre eseguito, indipendentemente dai tag specificati nella riga di comando. Al contrario, un task contrassegnato con il tag *never* non verrà mai eseguito, a meno che non venga esplicitamente richiesto tramite l’opzione `--tags`.
|
||
|
||
### Esecuzione tramite riga di comando
|
||
|
||
Utilizzando l'opzione `--tags`, è possibile specificare i task da eseguire:
|
||
|
||
```bash
|
||
ansible-playbook playbook.yml --tags "http"
|
||
```
|
||
|
||
Questo comando eseguirà solo i task contrassegnati con il tag http.
|
||
|
||
Al contrario, per escludere task specifici dall'esecuzione, si utilizza l'opzione `--skip-tags`:
|
||
|
||
```bash
|
||
ansible-playbook playbook.yml --skip-tags "db"
|
||
```
|
||
|
||
Questo comando salterà l'esecuzione di tutti i task contrassegnati con il tag db.
|
||
|
||
## Variabili
|
||
|
||
Le variabili sono utilizzate per memorizzare valori, seguendo la sintassi `key: value`.
|
||
|
||
Per fare riferimento a una variabile in Ansible, si utilizza la sintassi `Jinja2`, racchiudendo il nome della variabile tra le parentesi graffe doppie `{{ }}`. Ad esempio, se si definisce una variabile come `config_path: /opt/my_app/config`, il riferimento a questa variabile sarà `{{ config_path }}`.
|
||
|
||
Le variabili possono essere utilizzate in diversi contesti:
|
||
|
||
- Inventory
|
||
- Playbook: variabili definite direttamente nel playbook utilizzando la parola chiave `vars`
|
||
- Command line: variabili passate tramite la riga di comando utilizzando l'opzione `--extra-vars`
|
||
- File esterni: variabili definite in file esterni, richiamabili nel playbook con la parola chiave `vars_file`
|
||
|
||
```yaml
|
||
---
|
||
- name: Example playbook with variables
|
||
hosts: webservers
|
||
vars:
|
||
app_name: my_app
|
||
config_file_path: /etc/{{ app_name }}/config.yml
|
||
|
||
tasks:
|
||
- name: Copy the configuration file
|
||
copy:
|
||
src: files/config.yml
|
||
dest: "{{ config_file_path }}"
|
||
owner: root
|
||
group: root
|
||
mode: '0644'
|
||
```
|
||
|
||
### Registrazione del valore di una variabile
|
||
|
||
È possibile registrare il risultato di un task all’interno di una variabile, in modo da riutilizzarlo nei task successivi. Per fare ciò, si utilizza la parola chiave `register` all’interno del task:
|
||
|
||
```yaml
|
||
---
|
||
- name: playbook with variables
|
||
hosts: db
|
||
|
||
tasks:
|
||
- name: get uptime
|
||
shell: uptime
|
||
register: uptime
|
||
|
||
- debug:
|
||
var: uptime.stdout
|
||
```
|
||
|
||
In questo esempio, il task *get uptime* esegue il comando uptime e registra il risultato nella variabile *uptime*. Successivamente, il valore di *uptime.stdout* viene visualizzato utilizzando il modulo debug.
|
||
|
||
E' possibile registrare il valore delle vartiabili. E' quindi possibile salvare il risultato di un task all'interno di una variabile e riutilizzarla in task successibvi. Nel task, per fare questo, si deve utilizzare la parola chiave `register`.
|
||
|
||
## Vault
|
||
|
||
`Ansible Vault` consente di proteggere le informazioni sensibili utilizzate durante l’esecuzione di playbook, come indirizzi, password, chiavi di accesso e altri dati riservati. Qualsiasi dato che non si desidera lasciare in chiaro può essere protetto tramite i vault.
|
||
|
||
La crittografia delle informazioni può avvenire principalmente in due modi:
|
||
|
||
- **A livello di file**: Ansible consente di criptare un intero file utilizzando il comando `ansible-vault create example.yml`. Per modificare il file, è necessario utilizzare il comando `ansible-vault edit example.yml`, mentre per leggerne il contenuto, si può utilizzare il comando `ansible-vault view example.yml`
|
||
- **A livello di variabile**: con il comando `ansible-vault encrypt_string 'example' --name 'the secret'` é possibile criptare solo una variabile che sarà successivamente inserita in un playbook o in altre configurazioni
|
||
|
||
### Algoritmo di crittografia
|
||
|
||
L’unico algoritmo di crittografia supportato da Ansible Vault è `AES256`.
|
||
|
||
### Esecuzione del playbook
|
||
|
||
Durante l'esecuzione del playbook, è necessario immettere la password per consentire ad Ansible di decifrare il contenuto criptato. Questo può essere fatto in due modi:
|
||
|
||
- Utilizzare il comando `--ask-vault-pass`, che richiede all'utente di digitare la password direttamente nella console
|
||
- Specificare il path di file contenente la password tramite l'opzione `--vault-password-file`
|