
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 ...<output removed>... PLAY RECAP ********************************** node1: ok=9 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Playbook run took 0 days, 0 hours, 0 minutes, 14 seconds Thursday 23 December 2021 22:56:12 +0800 (0:00:00.541) 0:00:14.100 ***** =============================================================================== deploy-web-server : Install httpd and firewalld ------- 5.42s deploy-web-server : Git checkout ---------------------- 3.40s Gathering Facts --------------------------------------- 1.60s deploy-web-server : Enable and Run Firewalld ---------- 0.82s deploy-web-server : firewalld permitt httpd service --- 0.72s deploy-web-server : httpd enabled and running --------- 0.55s deploy-web-server : Set Hostname on Site -------------- 0.54s deploy-web-server : Delete content & directory -------- 0.52s deploy-web-server : Create directory ------------------ 0.41s Deploy Web service ------------------------------------ 0.04s Thursday 23 December 2021 22:56:12 +0800 (0:00:00.541) 0:00:14.099 ===================================================================== deploy-web-server ------------------------- 12.40s gather_facts ------------------------------- 1.60s include_role ------------------------------- 0.04s ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ total ------------------------------------- 14.04s
Глядя на вывод этой команды, где есть время выполнения каждой задачи, роли и т.п., четко видно, какая задача отнимает больше всего времени.
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] ...<output removed>... PLAY RECAP ************************************** node1: ok=9 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ansible-playbook site.yml 3.03s user 0.93s system 25% cpu 15.526 total
А теперь статистика с gather_facts: False:
$ time ansible-playbook site.yml PLAY [Deploying Web Server] **************** ...<output removed>... PLAY RECAP ************************************** node1: ok=8 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ansible-playbook site.yml 2.96s user 1.00s system 26% cpu 14.992 total
Понятно, что чем больше узлов, тем больше времени экономит отказ от сбора фактов.
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.
