Как заставить Ansible работать быстрее – 8 советов по плейбукам

6d910b1c60d028df718970a462feaa98.jpg

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
 
......
 
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]
......
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] ****************
 
......
 
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.

© Habrahabr.ru