Ansible Variables e Facts: configurazione dinamica senza duplicare codice
Un playbook che installa sempre lo stesso pacchetto sullo stesso server funziona. Ma nella realtà i server sono diversi: ambienti di staging e produzione con configurazioni distinte, distribuzioni Linux differenti, porte e percorsi che variano da cliente a cliente. Scrivere un playbook separato per ogni variante non è automazione: è copia-incolla.
Variables e Facts sono i due meccanismi con cui Ansible gestisce questa complessità, rendendo i playbook adattabili senza duplicare codice.
Variables: parametrizzare i playbook
Una variabile in Ansible è esattamente quello che ci si aspetta: un nome associato a un valore, utilizzabile in qualsiasi punto del playbook tramite la sintassi Jinja2 {{ nome_variabile }}.
Dove si definiscono le variabili
Ansible accetta variabili da più sorgenti. Le principali, in ordine di utilizzo più comune:
- Nel playbook, nella sezione
vars: utile per variabili locali al play - In group_vars/: variabili condivise tra tutti gli host di un gruppo
- In host_vars/: variabili specifiche per un singolo host
- Nei defaults del role: valori di default sovrascrivibili, come visto nel post sui Roles
- Da riga di comando con
-eo--extra-vars: priorità massima, sovrascrivono tutto
Esempio pratico: variabili nel playbook
Il caso più semplice: dichiarare le variabili direttamente nel play con la sezione vars.
---
- name: Deploy application
hosts: webservers
become: true
vars:
app_name: myapp
app_port: 8080
app_user: deploy
tasks:
- name: Create application directory
ansible.builtin.file:
path: /opt/{{ app_name }}
state: directory
owner: "{{ app_user }}"
mode: '0755'
- name: Configure application port
ansible.builtin.template:
src: app.conf.j2
dest: /etc/{{ app_name }}/app.conf
notify: Restart applicationdeploy_app.yml
Nota tecnica
Le variabili tra doppie parentesi graffe devono essere tra virgolette quando sono il valore completo di un parametro YAML: owner: "{{ app_user }}". Senza virgolette, YAML interpreta le parentesi graffe come un dizionario e restituisce un errore di parsing.
Variabili per ambiente: group_vars e host_vars
Per gestire ambienti diversi (staging, produzione) o host con configurazioni specifiche, si usano le cartelle group_vars e host_vars. Ansible le carica automaticamente in base al gruppo o all'host target.
# group_vars/webservers.yml
# Applied to all hosts in the [webservers] group
app_port: 80
app_user: www-data
nginx_worker_processes: autogroup_vars/webservers.yml
# host_vars/web01.yml
# Applied only to web01
app_port: 8080 # overrides group variable
nginx_worker_processes: 4host_vars/web01.yml
Quando Ansible esegue un task su web01, usa app_port: 8080 da host_vars. Su tutti gli altri host del gruppo usa app_port: 80 da group_vars. Lo stesso playbook, comportamento diverso per host diversi.
Facts: le variabili che Ansible raccoglie da solo
I Facts sono variabili raccolte automaticamente da Ansible all'inizio di ogni play, durante il task Gathering Facts. Contengono informazioni dettagliate su ogni host: sistema operativo, distribuzione, indirizzo IP, quantità di RAM, numero di CPU, hostname e molto altro.
Per vedere tutti i facts disponibili su un host:
$ ansible web01 -i inventory.ini -m ansible.builtin.setup
web01 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "Ubuntu",
"ansible_distribution_version": "22.04",
"ansible_hostname": "web01",
"ansible_default_ipv4": {
"address": "192.168.1.10"
},
"ansible_memtotal_mb": "4096",
"ansible_processor_vcpus": "2",
... hundreds more facts ...
}
}Usare i Facts nei task
I facts si usano come qualsiasi altra variabile, con la sintassi {{ ansible_* }}. Il caso più comune: installare il pacchetto corretto in base alla distribuzione rilevata.
---
- name: Install web server based on OS
hosts: webservers
become: true
tasks:
- name: Install Nginx on Debian-based systems
ansible.builtin.apt:
name: nginx
state: present
when: ansible_os_family == "Debian"
- name: Install Nginx on RedHat-based systems
ansible.builtin.dnf:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Print OS info
ansible.builtin.debug:
msg: "Running on {{ ansible_distribution }} {{ ansible_distribution_version }}"install_nginx_multiplatform.yml
Il parametro when è la condizione che Ansible valuta prima di eseguire il task. Se la condizione è falsa, il task viene saltato con stato skipping. Lo stesso playbook funziona su Ubuntu, Debian, CentOS e Rocky Linux senza modifiche.
$ ansible-playbook -i inventory.ini install_nginx_multiplatform.yml
PLAY [Install web server based on OS] **************************
TASK [Gathering Facts] ***************************************
ok: [web01]
ok: [web02]
TASK [Install Nginx on Debian-based systems] *****************
changed: [web01]
changed: [web02]
TASK [Install Nginx on RedHat-based systems] *****************
skipping: [web01]
skipping: [web02]
TASK [Print OS info] *********************************************
ok: [web01] => {
"msg": "Running on Ubuntu 22.04"
}
ok: [web02] => {
"msg": "Running on Ubuntu 22.04"
}
PLAY RECAP **************************************************
web01 : ok=3 changed=1 unreachable=0 failed=0
web02 : ok=3 changed=1 unreachable=0 failed=0Facts personalizzati
È possibile definire facts personalizzati posizionando file .fact (in formato INI o JSON) nella cartella /etc/ansible/facts.d/ di ogni host. Ansible li raccoglie automaticamente e li rende disponibili sotto ansible_local. Utile per esporre metadati specifici dell'host, come la versione dell'applicazione installata o l'ambiente di appartenenza.
# /etc/ansible/facts.d/app.fact (on the managed host)
[application]
version = 2.4.1
environment = production/etc/ansible/facts.d/app.fact
Nel playbook, il fact è accessibile come:
- name: Print application version
ansible.builtin.debug:
msg: "App version: {{ ansible_local.app.application.version }}"Priorità delle variabili
Ansible ha una gerarchia di precedenza per le variabili: quando la stessa variabile è definita in più posti, vince quella con priorità più alta. Le posizioni più usate, dalla più bassa alla più alta:
| Priorità | Sorgente | Note |
|---|---|---|
| Bassa | role defaults | defaults/main.yml nel role |
| group_vars | Variabili di gruppo | |
| host_vars | Variabili specifiche per host | |
| play vars | Sezione vars nel playbook | |
| role vars | vars/main.yml nel role | |
| Alta | extra vars (-e) | Riga di comando, sovrascrivono tutto |
Attenzione
Le vars definite nel role (in vars/main.yml) hanno priorità più alta rispetto alle host_vars e group_vars. Questo significa che non possono essere sovrascritte dall'inventory. Per variabili che devono essere sovrascrivibili dall'esterno, usare sempre defaults/main.yml.
Struttura del progetto con variabili
Integrando variables e facts, la struttura del progetto si arricchisce:
nginx-project/
├── ansible.cfg
├── inventory.ini
├── site.yml
├── group_vars/
│ ├── all.yml # variables for every host
│ └── webservers.yml # variables for webservers group
├── host_vars/
│ └── web01.yml # variables specific to web01
└── roles/
└── nginx/
├── defaults/
│ └── main.yml # overridable defaults
├── vars/
│ └── main.yml # fixed role variables
└── tasks/
└── main.ymlConclusione
Variables e Facts trasformano un playbook statico in uno strumento adattabile. Lo stesso codice installare Nginx su Ubuntu 22.04 e su Rocky Linux 9, usare la porta 80 in produzione e 8080 in staging, configurare ogni host con i propri parametri specifici, senza duplicare una riga.
I Facts in particolare rappresentano uno dei punti di forza di Ansible: l'infrastruttura descrive se stessa, e il playbook si adatta di conseguenza. Non serve conoscere in anticipo la distribuzione di ogni server: basta interrogarla al momento dell'esecuzione.