Аннотация. Ansible.cfg — центральный файл настроек Ansible. В статье разберём, зачем он нужен, где хранить его в реальных проектах, как сгенерировать рабочий конфиг через ansible-config init и какие параметры действительно помогают джунам и продовой команде. Отдельно покажем, какие настройки в ansible.cfg могут быть опасны и как избежать скрытых рисков.
📦 Исходники: весь код и примеры из этой и следующих статей — в репозитории — 🐙 GitHub: https://github.com/IaC-in-Russian/infra-as-code-ru
Для чего нужен ansible.cfg
ansible.cfg отвечает за поведение Ansible по умолчанию:
- откуда брать inventory;
- где лежат роли, плагины, коллекции;
- как подключаться по SSH;
- как выводить результат (формат, diff, логи);
- что делать по умолчанию (forks, сбор фактов, поведение hash’ей, Vault и т.п.).
Без него вы постоянно дописываете флаги руками.
С ним — проект ведёт себя одинаково у всех: у джуна, мидла, в CI.
Где может лежать ansible.cfg (и где он лежит у нас)
Ansible всегда ищет подходящий конфиг в строгом порядке и использует первый найденный:
- Путь из переменной окружения ANSIBLE_CONFIG.
- ansible.cfg в текущей директории.
- ~/.ansible.cfg в домашнем каталоге пользователя.
- /etc/ansible/ansible.cfg.
У нас по серии статей: ansible.cfg лежит в корне репозитория рядом с:
- inventories/
- playbooks/
- roles/
- и прочим проектным добром.
Так мы явно говорим: «Запускаешь из корня — получаешь правильные пути и поведение».
Важно. Если вы случайно запускаете Ansible из другого каталога, он может подхватить чужой ansible.cfg или системный. Симптомы: «вчера работало, сегодня Ansible не видит inventory».
ansible-config init: быстрый способ родить ansible.cfg
Вместо того чтобы писать конфиг с нуля, используем встроенный инструмент.
Базовый шаблон
ansible-config init --disabled > ansible.cfg
Что делает:
- создаётся файл ansible.cfg;
- все параметры закомментированы (#), то есть Ansible продолжает жить на дефолтах;
- вы точечно раскомментируете то, что хотите поменять.
Хороший вариант для проектов и обучения: видно, какие значения вы меняли, а какие — нет.
Шаблон с полным каталогом опций
ansible-config init --disabled -t all > ansible.cfg
Что это:
- генерирует максимально полный список опций, включая плагины;
- тоже всё закомментировано;
- файл получается большим и тяжёлым.
Использовать удобно как справочник, но не тащить целиком в рабочий репозиторий:
джуна можно просто утопить в 500+ строках опций, которые ему не нужны.
Безопасность: ansible.cfg тоже может ломать жизнь
ansible.cfg — это не «невинный конфиг». Через него можно:
- подменить library, callback_plugins, filter_plugins → можно незаметно подсунуть свой код;
- выключить host_key_checking и радостно подключаться к поддельным хостам;
- прописать vault_password_file, который лежит в репо → все видят пароль от Vault;
- включить log_path, и в логах могут оказаться токены, пароли, содержимое шаблонов.
Риски и правила:
- Не коммитим чувствительное:
никакого vault_password_file с реальным путём;
никаких приватных ключей, путей до них, временных хаков. - Проверяем ansible.cfg при ревью кода.
Он влияет на всё поведение проекта, как requirements.txt или Dockerfile. - Не доверяем чужим репам.
Клонировали проект → перед запуском смотрим ansible.cfg, особенно пути к плагинам. - Host key checking.
host_key_checking = False удобно в тестах, но в проде это окно для MITM.
Относительные пути: почему всё ломается при смене директории
Ключевой момент, который стабильно ломает джунам голову:
Относительные пути считаются от директории, где лежит ansible.cfg.
Наш пример:
[defaults]
inventory = inventories
roles_path = ../galaxy-roles:../galaxy:./roles
collections_path = ../collections
library = ../collections/
Если ansible.cfg в корне:
- inventories → ./inventories
- ./roles → роли текущего проекта
- ../galaxy-roles и ../collections → общие ресурсы вне репозитория
Если перенести ansible.cfg или запускать Ansible не из корня правильного проекта — пути поедут.
Типичная ошибка:
«У меня нет ролей / инвентори», хотя всё лежит на месте → ansible.cfg смотрит не туда.
Разбираем рабочий ansible.cfg по пунктам
[defaults]
[defaults]
inventory = inventories
inventory_plugins = inventory_plugins
forks = 20
interpreter_python = /usr/bin/python3
retry_files_enabled = False
gathering = smart
roles_path = ../galaxy-roles:../galaxy:./roles
library = ../collections/
collections_path = ../collections
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid}
max_diff_size = 1048576
Коротко:
- inventory — путь(и) к inventory по умолчанию.
- inventory_plugins — если используете свои плагины инвентори.
- forks = 20 — сколько хостов обрабатываем параллельно.
- interpreter_python — фиксируем, какой Python использовать.
- retry_files_enabled = False — Ansible не создаёт служебные *.retry-файлы при ошибках и не засоряет каталог проекта. Если что-то упало, мы сами решаем, какие хосты перезапускать (через --limit или повторный запуск плейбука).
- gathering = smart — собираем факты оптимально.
- roles_path / collections_path / library — где искать роли, коллекции, модули.
- ansible_managed — автоматическая пометка в сгенерированных файл
ах.
[ssh_connection]
[ssh_connection]
pipelining = True
transfer_method = piped
ssh_args = -o ControlMaster=auto -o ControlPersist=15m
timeout = 30
Коротко:
- pipelining = True — меньше SSH-вызовов → быстрее.
- transfer_method = piped — удобная передача без лишних временных файлов.
- ssh_args — переиспользуем соединения.
- timeout — ждать соединения не вечно.
[diff]
[diff]
diff_always = true
Всегда видно, что поменяли. Полезно, когда меняем конфиги.
[inventory]
[inventory]
ignore_patterns = templates
Не воспринимать шаблоны как inventory.
Параметры, которые часто добавляют в реальных проектах
Полный список огромный (официально см. https://docs.ansible.com/ansible/latest/reference_appendices/config.html). Мы возьмём только те, что реально встречаются.
[defaults]
remote_user = ansible # юзер по умолчанию
timeout = 30 # общий таймаут операций
log_path = ./ansible.log # лог в файле (осторожно с секретами)
stdout_callback = yaml # человекочитаемый вывод
bin_ansible_callbacks = True # включать callback'и даже без TTY
deprecation_warnings = True # не прятать важные предупреждения
force_color = True # цветной вывод в CI/tty
callbacks_enabled = profile_tasks # видеть, какие таски самые медленные
fact_caching = jsonfile
fact_caching_connection = ./.facts_cache
fact_caching_timeout = 86400
Зачем:
- remote_user — меньше -u в командах.
- stdout_callback = yaml — вывод проще читать джуну.
- profile_tasks — помогает найти «тормозные» задачи.
- fact_caching — ускоряет повторные запуски.
- log_path — удобно для CI/отладки (но следим за секретами).
Пять параметров, которые решают реальные кейсы
Давай выделим 5 «звёзд», которые реально помогают.
1. stdout_callback = yaml + bin_ansible_callbacks = True
Кейс: джун смотрит на стандартный output и ничего не понимает.
[defaults]
stdout_callback = yaml
bin_ansible_callbacks = True
Что даёт:
- вывод в более читаемом YAML-стиле;
- все callback-плагины (включая profile_tasks) показывают свои сообщения стабильно.
2. callbacks_enabled = profile_tasks
Кейс: «Playbook тормозит, но непонятно где».
[defaults]
callbacks_enabled = profile_tasks
Плагин profile_tasks показывает, сколько каждая задача выполнялась.
Зачем: быстро находим узкие места: медленные шаблоны, тяжелые shell-скрипты, лишние gather facts.
3. fact_caching = jsonfile
Кейс: большой инвентори, каждый запуск 30–60 секунд собираем факты.
Что делаем:
[defaults]
fact_caching = jsonfile
fact_caching_connection = ./.facts_cache
fact_caching_timeout = 86400
Эффект: при повторных запусках Ansible берёт факты из кэша → быстрее, меньше нагрузки.
Подводный камень: на сильно меняющихся хостах не забываем про таймаут кэша.
4. strategy = free
Кейс: один медленный хост блокирует всех.
[defaults]
strategy = free
Что делает: хосты выполняют таски независимо; медленные не держат быстрых.
Когда полезно: в CI, в массовых обновлениях, когда важна скорость.
Подводный камень: лог становится менее «ровным», джуну сложнее следить пошагово.
5. any_errors_fatal = True
Кейс: инфраструктура критичная, нельзя, чтобы половина хостов обновилась, а половина нет.
[defaults]
any_errors_fatal = True
Что делает: при серьёзной ошибке на части хостов — валим весь запуск.
Идеально для: CI/CD, изменений, которые не должны применяться частично.
Почему это работает
Логика простая:
- У Ansible есть три источника правды: командная строка, переменные окружения и ansible.cfg.
- ansible.cfg — стабильный слой, который:
выравнивает поведение между разработчиками и CI,
фиксирует пути и стратегии,
снижает количество «магии» в командах. - Когда конфиг лежит в корне проекта и живёт под ревью:
проще онбордить джунов;
меньше случайных различий «у меня так не работает»;
все изменения явные и видны в git.
Что сделали
- Объяснили, зачем нужен ansible.cfg и как он влияет на поведение Ansible.
- Показали порядок поиска конфига и зафиксировали, что используем файл в корне проекта.
- Разобрали ansible-config init в двух вариантах и когда какой использовать.
- Прошлись по рабочему примеру ansible.cfg и добавили набор реально полезных опций.
- Обсудили риски (Vault, плагины, host_key_checking) и показали 5 опций, которые решают живые кейсы.
Сделать прямо сейчас
- В корне своего проекта создай (или открой текущий) ansible.cfg.
- Сгенерируй базовый шаблон: ansible-config init --disabled > ansible.cfg
- Аккуратно раскомментируй:
inventory,
roles_path / collections_path,
SSH-настройки,
stdout_callback = yaml,
разумное значение forks. - Убедись, что:
vault_password_file не лежит в репозитории,
host_key_checking = False не используется в проде. - Включи callbacks_enabled = profile_tasks, запусти любой playbook и посмотри, где тратится время.
CTA:
Продолжаем серию по Ansible. В следующем материале разберём первый hosts.yml и базовый ansible-playbook с практическими примерами. Пиши в комментариях, какие пункты в ansible.cfg вызывают вопросы — разберём на живых кейсах, без снобизма и магии.