Files
learning/ansible/003-playbook.md
2025-09-05 21:24:08 +02:00

406 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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*
- lopzione `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:
- linventory 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 lesecuzione di un task in base allesito 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 lesecuzione 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 dallesito 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 lhandler specificato. Durante la prima esecuzione, una volta installato il software httpd, lhandler 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 lhandler 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, questultimo 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 nellesempio 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 lopzione `--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 allinterno di una variabile, in modo da riutilizzarlo nei task successivi. Per fare ciò, si utilizza la parola chiave `register` allinterno 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.
## Vault
`Ansible Vault` consente di proteggere le informazioni sensibili utilizzate durante lesecuzione 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
Lunico 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`