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 -e o --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 application

deploy_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: auto

group_vars/webservers.yml

# host_vars/web01.yml
# Applied only to web01
app_port: 8080          # overrides group variable
nginx_worker_processes: 4

host_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:

Gather facts from a 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.

Multiplatform run
$ 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=0

Facts 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.yml

Conclusione

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.

Iscriviti a Ansible Automation Blog

Non perdere gli ultimi articoli. Iscriviti ora per essere aggiornato sulle nuove pubblicazioni.
mario@esempio.it
Iscriviti