Как заставить Ansible работать быстрее – 8 советов по плейбукам
Ansible — это мощный и простой инструмент автоматизации с открытым кодом. Он помогает оптимизировать множество задач по эксплуатации ИТ-инфраструктуры, от самых простых, наподобие установки программных пакетов, до весьма сложных, вроде развертывания кластера с несколькими узлами или многоэтапного обновления операционной системы. Сегодня мы расскажем, как оптимизировать плейбуки Ansible, чтобы создаваемые вами автоматизации работали быстрее.
Советы по оптимизации плейбуков
1. Выясните, какие задачи отнимают больше всего времени
Бывает, что та или иная задача (task) в составе плейбука выглядит простой и безобидной, но именно на нее уходит большая часть времени выполнения всего плейбука. Выявить такие задачи можно с помощью callback-плагинов, таких как timer
, profile_tasks
и profile_roles
.
Для начала включим использование этих плагинов в ansible.cfg
:
[defaults]
inventory = ./hosts
callbacks_enabled = timer, profile_tasks, profile_roles
Теперь выполним команду ansible-playbook
:
$ ansible-playbook site.yml
PLAY [Deploying Web Server] ************
TASK [Gathering Facts] **********************
Thursday 23 December 2021 22:55:58 +0800 (0:00:00.055) 0:00:00.055
Thursday 23 December 2021 22:55:58 +0800 (0:00:00.054) 0:00:00.054
ok: [node1]
TASK [Deploy Web service] *******************
Thursday 23 December 2021 22:56:00 +0800 (0:00:01.603) 0:00:01.659
Thursday 23 December 2021 22:56:00 +0800 (0:00:01.603) 0:00:01.658
...
Глядя на вывод этой команды, где есть время выполнения каждой задачи, роли и т.п., четко видно, какая задача отнимает больше всего времени.
2. Отключите сбор фактов
При выполнении плейбука каждая команда play с помощью модуля setup
запускает скрытую задачу gathering facts. Эта задача собирает сведения об удаленном узле, где выполняется автоматизация, и пишет их в переменную ansible_facts
. Но если вы никак не используется эти сведения в своем плейбуке, то это просто пустая трата времени. Чтобы отключить сбор фактов, достаточно прописать gather_facts: False
в play.
Для примера посмотрим статистику, когда сбор фактов включен:
$ time ansible-playbook site.yml
PLAY [Deploying Web Server] *********************
TASK [Gathering Facts] **************************
ok: [node1]
...
А теперь статистика с gather_facts: False
:
$ time ansible-playbook site.yml
PLAY [Deploying Web Server] ****************
...
Понятно, что чем больше узлов, тем больше времени экономит отказ от сбора фактов.
3. Настройте параллельное выполнение
Ansible выполняет каждую задачу не на всех узлах сразу, а партиями. Размер партий настраивается через параметр forks
и по умолчанию равен 5. Поэтому Ansible запускает задачу на первых пяти узлах, ждет, пока она на них выполнится, затем берет следующие пять узлов и т.д. Когда задача выполнится на всех узлах, Ansible берет следующую задачу из плейбука и опять начинает выполнять ее партиями по пять узлов.
Чтобы распараллелить задачу по большему числу узлов, надо поменять значение параметра forks
в ansible.cfg
:
[defaults]
inventory = ./hosts
forks=50
Значение forks
также можно динамически менять при запуске плейбука с помощью опции --forks
(сокращенно -f
):
$ ansible-playbook site.yaml --forks 50
Примечание. Чем больше узлов, на которых Ansible выполняет задачи параллельно, тем больше ресурсов CPU и памяти ему нужно на машине, где крутится узел управления Ansible (control node). Поэтому настраивайте forks
аккуратно.
4. Оптимизируйте SSH
Установление SSH-сеанса — процесс довольно медленный, и выполняется он в фоновом режиме. Когда у вас много задач в плейбуке и много узлов, на которых они должны выполниться, общее время работы плейбука существенно увеличивается.
Бороться с этим можно с помощью параметров ControlMaster
и ControlPersist
в ansible.cfg
(секция ssh_connection
):
ControlMaster — позволяет «утрамбовать» несколько одновременных SSH-сеансов с удаленным узлом в одно сетевое подключение. Это экономит время, поскольку сетевое подключение к узлу производится только при первом SSH-сеансе, а последующие просто работают через это подключение.
ControlPersist — время, в течение которого неактивный SSH-сеанс остается открытым в фоновом режиме. Например,
ControlPersist=60s
означает, что неактивное соединение живет 60 секунд:
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
5. Отключите проверку SSH-ключей хоста в динамической среде
По умолчанию Ansible проверяет и верифицирует SSH-ключи хоста для защиты от атак с подменой сервера или man-in-the-middle. На такую проверку тоже уходит время. Если у вас полностью контролируемая среда с неизменяемыми управляемыми узлами (ВМ или контейнеры), то при переустановке или воссоздании узла его ключ будет другим. В таких средах можно отключить проверку ключей с помощью параметра host_key_checking =
False
в ansible.cfg
:
[defaults]
host_key_checking = False
Примечание. За пределами контролируемых сред отключать эту проверку очень не рекомендуется. Поэтому применяйте этот способ только когда четко понимаете, что делаете.
6. Активируйте параметр pipelining
Когда Ansible использует SSH при копировании файлов, скриптов и выполнении других команд, то в фоновом режиме выполняется ряд операций SSH. Можно уменьшить количество SSH-соединений, включив параметр pipelining (по умолчанию он отключен) в ansible.cfg
:
# ansible.cfg
pipelining = True
7. Грамотно варьируйте стратегии выполнения
По умолчанию Ansible использует линейную стратегию — ждет, пока текущая задача сценария не завершится на всех узлах, и лишь потом переходит к следующей задаче.
Если у вас нет зависимостей с привязкой к задачам или управляемым узлам, то можно изменить значение параметра strategy
на free
. Тогда Ansible будет прогонять сценарную последовательность задач на каждом узле независимо, не дожидаясь, пока каждая задача выполнится на всех узлах:
- hosts: production servers
strategy: free
tasks:
При необходимости можно разработать свои или использовать готовые плагины стратегий, такие как Mitogen с программированием подключений и выполнения на Python.
8. Используйте асинхронные задачи
При выполнении задачи Ansible дожидается ее завершения, и лишь затем закрывает соединение с управляемым узлом. Когда у вас есть долгоиграющие задачи (бэкап дисков, установка пакетов и т.д.), это может неоправданно увеличивать общее время выполнения. Если следующие задачи сценарии не зависят от этой долгой задачи, то можно использовать режим async
с соответствующим интервалом опроса poll
, чтобы Ansible не ждал завершения долгой задачи и переходил к следующим:
---
- name: Async Demo
hosts: nodes
tasks:
- name: Initiate custom snapshot
shell:
"/opt/diskutils/snapshot.sh init"
async: 120 # Maximum allowed time in Seconds
poll: 05 # Polling Interval in Seconds
Резюме
Время выполнения плейбуков Ansible зависит от множества конфигурационных параметров, оптимальные значения которых определяются спецификой конкретной ИТ-среды и применяемых в ней автоматизаций. Мы рассмотрели далеко не весь список, есть целый ряд других параметров, таких как serial
, throttle
, run_once
и других, о которых можно подробнее узнать в документации Ansible.