Pull to refresh

Ускоряем Ansible

Reading time 4 min
Views 12K
Турбокомпрессор в разрезе

Ни для кого не секрет, что с настройками «по умолчанию» Ansible может делать своё дело не слишком быстро. В статье я укажу на несколько причин этого и предложу полезный минимум настроек, которые, вполне возможно, реально увеличат скорость работы вашего проекта.

Обсуждаем здесь и далее Ансибл 2.9.x, который был установлен в свежесозданный virtualenv вашим любимым способом.

После установки создаём рядом с вашим плейбуком файл «ansible.cfg» — такое расположение позволит переносить данные настройки вместе с проектом, плюс загружаться будут они вполне автомагически.

Конвейеризация


О том, что нужно использовать pipelining, то есть не копирование модулей в ФС целевой системы, а передачу обёрнутого в Base64 zip-архива непосредственно на stdin интерпретатора Python, кто-то уже мог слышать, а кто-то — нет, но факт остаётся фактом: эта настройка по-прежнему остаётся недооценённой. К сожалению, какой-то из популярных дистрибутивов Linux по умолчанию раньше настраивал sudo не очень хорошо — так, что эта команда требовала наличия tty (терминала), поэтому в Ansible эту очень полезную настройку оставили выключенной по умолчанию.

pipelining = True

Сбор фактов


Знаете ли вы, что с настройками по умолчанию Ansible для каждого плея инициирует сбор фактов по всем хостам, которые в нём участвуют? В общем, если не знали, то теперь знаете. Для того, чтобы этого не происходило, нужно включить либо режим явного запроса на сбор фактов (explicit), либо режим smart. В нём факты будут собираться только с тех хостов, которые не встречались в предыдущих плеях.
UPD. При копировании вам придётся выбрать из этих настроек какую-то одну.

gathering = smart|explicit

Переиспользование ssh-соединений


Если вы когда-нибудь запускали Ansible в режиме вывода отладочной информации (опция «v», повторённая от одного до девяти раз), то, возможно, замечали, что ssh-соединения постоянно устанавливаются и разрываются. Так вот, здесь тоже существует пара тонкостей.

Избежать этапа повторной установки ssh-соединения можно на двух уровнях сразу: и непосредственно в клиенте ssh, и при передаче файлов на управляемый хост с управляющего.
Для переиспользования открытого ssh-соединения достаточно просто передать нужные ключи ssh-клиенту. Тогда он начнёт делать следующее: при первой установке ssh-соединения дополнительно создавать так называемый control socket, при последующих — проверять существование этого самого сокета, и при успехе переиспользовать существующее ssh-соединение. А чтобы это всё имело смысл, зададим время сохранения соединения при неактивности. Подробнее можно прочитать в документации по ssh, а в контексте Ansible мы просто используем «проброс» нужных опций ssh-клиенту.

ssh_args = "-o ControlMaster=auto -o ControlPersist=15m"

Для переиспользования уже открытого ssh-соединения при передаче файлов на управляемый хост достаточно указать ещё одну неизвестную настройку ssh_transfer_method. Документация на этот счёт крайне скупа и вводит в заблуждение, ведь эта опция вполне себе работающая! Зато чтение исходного кода позволяет понять, что именно будет происходить: на управляемом хосте будет запущена команда dd, напрямую работающая с нужным файлом.

transfer_method = piped

Кстати, в ветке «develop» эта настройка также существует и никуда не делась.

Ножа не бойся, бойся вилки


Ещё одна полезная настройка — forks. Она определяет количество рабочих процессов, которые будут одновременно подключаться к хостам и выполнять таски. Из-за особенностей Python как ЯП используются именно процессы, а не потоки, потому что Ansible всё ещё поддерживает Python 2.7 — никаких вам asyncio, нечего тут асинхронщину разводить! По умолчанию Ansible запускает пять воркеров, но если правильно попросить, то запустит больше:

forks = 20

Только сразу предупреждаю, что здесь возможны некоторые сложности, связанные с имеющимся объёмом памяти на управляющей машине. Иначе говоря, поставить forks=100500, конечно, можно, но кто сказал, что будет работать?

Сводим всё вместе


В итоге для ansible.cfg (ini-формат) нужные настройки могут выглядеть так:

[defaults]
gathering = smart|explicit
forks = 20
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=15m
transfer_method = piped

А если ты желаешь спрятать всё в нормальный YaML-inventory здорового человека, то он может выглядеть примерно вот так:

---
all:
  vars:
    ansible_ssh_pipelining: true
    ansible_ssh_transfer_method: piped
    ansible_ssh_args: -o ControlMaster=auto -o ControlPersist=15m

К сожалению, с настройками «gathering = smart/explicit» и «forks = 20» такое не пройдёт: их YaML-эквивалентов не существует. Либо задаём их в ansible.cfg, либо передаём через переменные окружения ANSIBLE_GATHERING и ANSIBLE_FORKS.

Про Mitogen
— А где здесь про Mitogen? — вправе спросить ты, уважаемый читатель. В этой статье — нигде. Но если ты реально готов читать его код и разбираться, почему твой плейбук падает с Mitogen, а с ванильным Ansible нормально работает, или почему этот же плейбук доселе исправно работал, а после обновления стал делать странное — что ж, Mitogen потенциально может быть твоим инструментом. Применяй, разбирайся, пиши статьи — прочитаю с интересом.

Почему лично я не использую Mitogen? Потому что гладиолус он работает, только пока таски реально простые и всё хорошо. Однако стоит свернуть чуть влево или вправо — всё, приехали: в ответ в тебя летит горсть невнятных исключений, и для завершения картины не хватает только расхожей фразы «всем спасибо, все свободны». В общем, я просто не желаю тратить время на выяснение причин очередного «подземного стука».

Часть этих настроек были обнаружены в процессе чтения исходного кода connection plugin'а под говорящим названием «ssh.py». Результатами чтения делюсь в надежде на то, что это вдохновит ещё кого-то смотреть в исходники, читать их, проверять реализацию, сравнивать с документацией — ведь всё это рано или поздно принесёт вам свои положительные результаты. Удачи!
Only registered users can participate in poll. Log in, please.
Какие из перечисленных настроек Ansible для ускорения своих проектов вы используете?
69.86% pipelining = true 51
35.62% gathering = smart/explicit 26
45.21% ssh_args = "-o ControlMaster=auto -o ControlPersist=..." 33
20.55% transfer_method = piped 15
63.01% forks = XXX 46
8.22% Ничего из этого, только Mitogen 6
8.22% Mitogen + отмечу, какие именно из этих настроек 6
73 users voted. 44 users abstained.
Only registered users can participate in poll. Log in, please.
Хотите ещё разного про Ansible?
76.92% да, конечно 60
23.08% да, только хочу больше хардкорных штук! 18
0% нет, и даром не надо 0
0% нет, сложнаааааа!!! 0
78 users voted. 7 users abstained.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+22
Comments 31
Comments Comments 31

Articles