Факты: что Ansible знает о хосте
Урок 12 - используем факты: автоматически собранную информацию о каждом сервере.
«Не спрашивай у пользователя, сколько на сервере ядер. Ansible уже знает - это факт».
Факты (facts) - это переменные, которые Ansible сам собирает о каждом хосте перед выполнением задач: ОС и её семейство, число процессоров, объём памяти, IP-адреса, имя хоста, версия дистрибутива и сотни других параметров. Они доступны через ansible_facts.
Откуда берутся факты
В начале каждого плея, если не отключено явно, Ansible запускает модуль setup - он и собирает факты. Их можно посмотреть ad-hoc командой:
# Показать все факты о хосте
ansible web1.example.com -m setup
# Только факты про память
ansible web1.example.com -m setup -a "filter=ansible_memory_mb"
Применение фактов
- name: Поставить пакет в зависимости от ОС
ansible.builtin.package:
name: "{{ 'apache2' if ansible_facts['os_family'] == 'Debian' else 'httpd' }}"
state: present
- name: Задать число воркеров по числу ядер
ansible.builtin.set_fact:
workers: "{{ ansible_facts['processor_vcpus'] }}"
Факты особенно полезны в when и в Jinja2-шаблонах: одна и та же роль адаптируется под разные ОС и железо без ручных настроек.
Как работает под капотом
Сбор фактов - это запуск модуля setup на хосте, который опрашивает систему (через /proc, системные утилиты) и возвращает большой JSON. Этот JSON и становится словарём ansible_facts. Сбор занимает время, поэтому на больших инвентарях его иногда отключают через gather_facts: false или кешируют между запусками.
Смоделируем выбор пакета по факту ОС - типовая логика «адаптации под систему».
# Выбор имени пакета по факту об ОС
def pick_package(facts):
family = facts.get("os_family")
table = {"Debian": "apache2", "RedHat": "httpd"}
return table.get(family, "apache2")
debian_host = {"os_family": "Debian", "processor_vcpus": 4}
rhel_host = {"os_family": "RedHat", "processor_vcpus": 8}
print("Debian ->", pick_package(debian_host)) # apache2
print("RedHat ->", pick_package(rhel_host)) # httpd
print("Воркеров на RHEL:", rhel_host["processor_vcpus"])
Попробуй сам ▶ Один и тот же код выбирает разные пакеты в зависимости от факта об ОС. Так роли становятся переносимыми между дистрибутивами без правок.
Кеширование и gather_facts
- name: Быстрый плей без сбора фактов
hosts: web
gather_facts: false # факты не нужны - экономим время
tasks:
- name: Просто перезапустить сервис
ansible.builtin.service:
name: nginx
state: restarted
Если факты не используются, gather_facts: false ускоряет плей. Если используются часто - настраивают кеш фактов (fact caching), чтобы не пересобирать их каждый раз.
Частые ошибки
- Использовать факт при gather_facts: false. Если сбор отключён,
ansible_factsпуст - переменная будет undefined. - Старый синтаксис фактов. Раньше писали
ansible_os_family; современная форма -ansible_facts['os_family']. - Опираться на факт, которого нет на этой ОС. Набор фактов разный; проверяй через
setup.
Best practices
- Используй факты для переносимости ролей между дистрибутивами и железом.
- Отключай
gather_factsтам, где факты не нужны - это ускоряет прогон. - На больших инвентарях настрой кеш фактов, чтобы не пересобирать их каждый раз.
В реальной работе
Факты делают роли по-настоящему переносимыми. Одна и та же роль ставит веб-сервер и на Debian (пакет apache2), и на RHEL (пакет httpd), выбирая нужное по факту os_family - без ветвления вручную под каждый сервер. Кроме встроенных фактов, можно заводить кастомные: положить на хост файл в /etc/ansible/facts.d/, и его содержимое появится среди фактов под ключом ansible_local. Так на сервере хранят, например, метку «этот хост обслуживает такого-то клиента», и playbook'и адаптируются под неё. А на больших инвентарях обязательно настраивают кеш фактов: пересобирать сотни параметров с каждого из трёхсот серверов на каждом прогоне - дорого, кеш экономит минуты.
Итоги
Факты - автоматически собранная информация о хостах (ОС, железо, сеть), доступная через ansible_facts. Они делают роли адаптивными. Сбор можно отключать или кешировать ради скорости. Дальше превратим переменные и факты в реальные конфиги через Jinja2.