Ускоряем Ansible

    Турбокомпрессор в разрезе

    Ни для кого не секрет, что с настройками «по умолчанию» 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_tranfer_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 для ускорения своих проектов вы используете?

    • 66.7%pipelining = true36
    • 33.3%gathering = smart/explicit18
    • 48.2%ssh_args = "-o ControlMaster=auto -o ControlPersist=..."26
    • 16.7%transfer_method = piped9
    • 63.0%forks = XXX34
    • 7.4%Ничего из этого, только Mitogen4
    • 7.4%Mitogen + отмечу, какие именно из этих настроек4

    Хотите ещё разного про Ansible?

    • 76.9%да, конечно60
    • 23.1%да, только хочу больше хардкорных штук!18
    • 0.0%нет, и даром не надо0
    • 0.0%нет, сложнаааааа!!!0

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 28

      0

      Отличная статья, большое спасибо! Узнал еще пару интересных нюансов об инструменте

        0

        smart gathering ничего не ускоряет, потому что в хороших плейбуках сказано gather_facts: false пока не нужно и правильный subset, если нужно.


        Насчёт tranfer_method я прочитал тут первый раз и это пойдёт в мой список для экспериментов. ControlMaster мы не используем, потому что залипающие соединения, к сожалению, портят жизнь, и преизрядно. Любые ребуты или манипуляции с сетью на целевых хостах, и ControlMaster из ускорителя превращается в замедлитель отладки.

          +3
          Изменение конфигурации сетевых интерфейсов при подключении к хосту по сети выглядит как-то так:
          СМЕРТЕЛЬНО ОПАСНО! НЕ ПОВТОРЯТЬ!


          Ну просто не смог удержаться от вставки этого видео.
            0

            netplan apply.


            Плюс, это же автоматизация и CI, если оно в этом месте сломается, значит код сломан, надо фиксить. Если же код не сломан, то операция проходит без особых проблем.

              +2

              netplan фу-фу-фу. Посмотрел я на это поделие убунтоводов и выпилил от греха подальше

                +3

                При работе с дистрибутивом глупо бороться с дистрибутивом. Либо меняйте дистрибутив, либо используйте, что дали.


                Для базовых задач настройки сети его хватает, если нужно странного, то нужны альтернативные методы. Это совершенно не отменяет романтику с перезапуском сети с новыми настройками (топик-то по ControlMaster у ssh для ansible).


                ЗЫ Я обычно для странных сетевых штук использую systemd-юниты. Очень, очень удобно в контексте зависимостей и порядка исполнения.

                  +1
                  При работе с дистрибутивом глупо бороться с дистрибутивом

                  почему бороться? Во-первых, нетплан — это хоть и навязываемый, но не единственный метод настройки сети. Во-вторых, убунту прекрасно работает с другими способами, которых достаточно много — и с systemd-networkd, и c NetworkManager, и с ifup.


                  Я обычно для странных сетевых штук использую systemd-юниты. Очень, очень удобно в контексте зависимостей и порядка исполнения.

                  несомненно верно, что systemd прекрасен, учитывая, что с ним реально можно творить много интересных штук. Да и контейнеризацию в него завезли.

                    +1

                    Немного попиарю незнакомого чувака из интернета, вот вполне хорошая и работающая роль ansible-netplan


                    IMHO: для серверной/облачной 20.04 вполне жизнеспособен один самостоятельный netplan, для десктопа уж лучше network-manager с плагинами и «огромным гуищем»

          0
          А если после всё вышеперечисленное, не особо помогло (на моих экспериментах это были максимум десятки процентов ускорения), то обязательно попробуйте таки Mitogen.

          Проблемы с ним автор, кмк _сильно_ преувеличил, за несколько лет моей эксплуатации ничего особо серьезного с ним не было, а ускорение он дает в разы.
            0

            Оно на крае сознания плавало, но когда я его смотрел он был слишком молодым. Посмотреть пристальнее, наверное, стоит. Записал в нашу research queue.

              +1
              за несколько лет моей эксплуатации ничего особо серьезного с ним не было, а ускорение он дает в разы.
              очень сильно зависит от задач. Например, если у вас 90% занимает скачивание и восстановление дампа БД, то митоген ничем не поможет
                0
                Есессно, он помогает тем сильнее, чем больше отдельных тасок исполняется.
                То есть чем сложнее _конфигурация_ — тем лучше она им оптимизируется.
                Дампы сливать/вливать, имхо, не самый типичный сценарий для ансибла.
                  0
                  Дампы сливать/вливать, имхо, не самый типичный сценарий для ансибла.

                  а какой тогда типичный? Если мы говорим про классическое использование ансибла в терраформ и пакере для подготовки машин к работе, то там даже ssh не нужен, не говоря уже о митогене :-/

                    0
                    На мой взгляд «типичный» — это настройка условного кластера приложения, состоящего из N виртуальных или бареметал серверов.
                    Для локальной работы из tf/packer механики из статьи тоже неприменимы так то.
                      0

                      Ansible, cluster… Выглядит своеобразно. Объясню почему — потому что мои коллеги, которые разворачивали ту же Кафку ансиблом, не носили написать нормальные плейбуки с последовательным рестартом нод кластера, чтобы обеспечить непрерывность работы сервиса. Но вот deploy A/B уже мы на ансибл писали, без downtime… И по факту это получается не просто один плейбук на все, а коллекция плейбуков под каждую конкретную задачу.
                      Я уж не говорю о том, что приходит кубернетес и берет эти проблемы на себя.

                        0
                        Ну у меня это вполне решено.
                        Мой типичный кластер это консул/постгрес/редис/номад/зукипер/кликхауз/прометей с графаной/опять же кафка, всякая более мелкая обвязка вокруг.

                        Тот же кубик ведь тоже забутстрапить чем-то надо, и ускорить kubespray — милейшее дело.
                          0
                          Тот же кубик ведь тоже забутстрапить чем-то надо, и ускорить kubespray — милейшее дело.

                          зачем kubespray? не нужен он ) кластер сетапит себя сам — rke up или terraform, или решения вроде https://github.com/kvaps/kubefarm

                            0
                            Ок, пусть так себя сетапит, мы например вообще не юзаем кубик, номада нам вполне достаточно. А он так себя не сетапит, и мы его льем ансиблом.

                            В целом те техники про которые собсно статья написана, все равно ни с локальными конфигами, ни с заливкой дампов не помогут.
                            А там где будут эффективны эти настройки, будет эффективен и митоген.
                  0
                  > если у вас 90% занимает скачивание и восстановление дампа БД
                  То, кстати, и описанные в статье методы тоже не помогут.
                  0

                  Пока плейбуки простые — всё будет работать. Я так и написал. Это, кстати, тоже по результатам чтения исходников
                  Mitogen: одно перекрытие штатных загрузчиков чего стоит.

                    0
                    Я не очень понимаю, а что считать простыми плейбуками?
                    Точнее на каком уровне начинается сложность, на которой все должно сломаться?

                    Мне кажется у меня далеко не простые плейбуки, куча ролей как своих так и из гелекси.
                    Есть свои плагины для переменных и сторонный vault плагин.
                    Все работает без проблем.
                  0

                  Взял толстючую job'у на 50 минут (80% — анисбл, остальное тесты через testinfra и инфраструктурное). Было 51 minutes and 27 seconds, поменял transfer_method = piped стало 51 minutes and 56 seconds. В пределах погрешности — не поменялось.

                    0

                    Данная настройка ускоряет только обмен с файлами с управляемым хостом (см.текст и доку по ссылке).

                      0

                      Я понимаю. Разумеется, в проекте достаточно и copy, и template. Эксперимент показал, что существенного прироста это не даёт. Штатный протокол достаточно большой, а модули достаточно медленные, чтобы смена формата передачи файлов не давала никакого ощутимого изменения.

                    +1

                    Было бы интересно увидеть сравнения времени выполнения одного и того же плейбука на разных версиях python, например, 2.7 и 3.8. Будет ли хоть какая то заметная разница?

                      +1
                      UPD. Иcправил опечатку. BubaVV, благодарю!
                        0
                        UPD. Добавил предупреждение о том, что из пары значений smart|explicit придётся выбрать что-то одно. edo1h, благодарю!
                          0

                          Как-то писал про Mitogen,: https://habr.com/ru/post/453520/

                          Only users with full accounts can post comments. Log in, please.