company_banner

Собираем свой Nginx парой команд

    Привет!
    Меня зовут Сергей, я работаю инфраструктурным инженером в команде API платформы tinkoff.ru.

    В этой статье я расскажу о проблемах, с которыми сталкивалась наша команда при подготовке балансировщиков на основе Nginx для различных проектов. Также расскажу об инструменте, который позволил преодолеть большую часть из них.

    Nginx — это многофункциональный и активно развивающийся прокси-сервер. Он отличается большим количеством модулей, вот далеко не полный список. Каждый проект налагает определенные требования к функционалу балансировщика и версии Nginx (например наличие http/2 и проксирование grpc), и составу его модулей.

    Нам хочется видеть свежую версию с нужным набором модулей, работающую под определенным дистрибутивом Linux. В нашем случае это deb- и rpm-based системы. Вариант с контейнерами в данной статье не рассматривается.

    Нам хочется оперативно изменять функционал наших балансировщиков. И здесь сразу встает вопрос — как этого добиться, затратив как можно меньше ресурсов? А еще бы лучше наладить процесс так, чтобы мы могли задать конечное число входных параметров, а на выходе получить артефакт в виде deb/rpm пакета для нужной ОС.

    В итоге можно сформулировать ряд проблем:

    • Не всегда есть пакеты со свежей версией Nginx.
    • Нет пакетов с нужными модулями.
    • Компиляция и сборка пакета вручную занимает много времени и попросту утомительна.
    • Нет описания, как собран тот или иной инстанс Nginx.

    Чтобы решить эти проблемы, напрашивается некий инструмент, который принимал бы на вход спецификацию в человекочитаемом формате и собирал по ней пакет Nginx с нужным функционалом.

    Не найдя подходящего для нас варианта на просторах гитхаба, мы решили создать свой инструмент — nginx-builder.

    Спецификации


    В нашем инструменте мы хотели создавать описание спецификации в виде кода, который затем можно положить в Git-репозиторий. Для этого выбрали привычный для подобных вещей формат — yaml. Пример спецификации:

    nginx_version: 1.14.1
    output_package: deb
    modules:
      - module:
          name: nginx-auth-ldap
          git_url: https://github.com/kvspb/nginx-auth-ldap.git
          git_branch: master
          dependencies:
            - libldap2-dev
      - module:
          name: ngx_http_substitutions_filter_module
          git_url: https://github.com/yaoweibin/ngx_http_substitutions_filter_module.git
      - module:
          name: headers-more-nginx-module
          web_url: https://github.com/openresty/headers-more-nginx-module/archive/v0.261.zip
      - module:
          name: nginx-module-vts
          git_url: https://github.com/vozlt/nginx-module-vts.git
          git_tag: v0.1.18
      - module:
          name: ngx_devel_kit
          git_url: https://github.com/simplresty/ngx_devel_kit.git
          git_tag: v0.3.0
      - module:
          name: ngx_cache_purge
          git_url: https://github.com/FRiCKLE/ngx_cache_purge.git
      - module:
          name: ngx_http_dyups_module
          git_url: https://github.com/yzprofile/ngx_http_dyups_module.git
      - module:
          name: nginx-brotli
          git_url: https://github.com/eustas/ngx_brotli.git
          git_tag: v0.1.2
      - module:
          name: nginx_upstream_check_module
          git_url: https://github.com/yaoweibin/nginx_upstream_check_module.git
      - module:
          name: njs
          git_url: https://github.com/nginx/njs.git
          git_tag: 0.2.5
          config_folder_path: nginx
    

    Здесь мы указываем, что хотим видеть deb-пакет с версией Nginx 1.14.2 с нужным набором модулей. Секция с модулями — опциональная. Для каждого из них можно задать:

    • Название.
    • Адрес, где его можно получить:
      • Git-репозиторий. Также можно указать ветку или тег.
      • Веб-ссылка на архив.
      • Локальная ссылка на архив.

    Некоторые модули требуют установки дополнительных зависимостей, например для nginx-auth-ldap нужен установленный libldap2-dev. Необходимые зависимости также можно указать при описании модуля.

    Окружение


    В нашем инструменте можно быстро получать окружение с установленными утилитами для компиляции, сборки пакета и другим вспомогательным ПО. Здесь как нельзя лучше подходит docker-контейнер со всем необходимым (в репозитории уже есть пара примеров docker-файлов для ubuntu и centos).

    После того, как спецификация составлена и подготовлено окружение, мы запускаем наш сборщик, предварительно установив его зависимости:

    pip3 install -r requirements.txt
    ./main.py build -f [конфиг_файл].yaml -r [номер_ревизии]
    

    Номер ревизии здесь опционален и служит для версионирования сборок. Он записывается в метаинформацию пакета, что позволяет легко обновлять его на серверах.
    По логам можно наблюдать за происходящим. Вот пример основных моментов:

    builder - INFO - Parse yaml file: example.config.yaml
    builder - INFO - Download scripts for build deb package
    builder - INFO - Downloading nginx src...
    builder - INFO - --> http://nginx.org/download/nginx-1.14.1.tar.gz
    builder - INFO - Downloading 3d-party modules...
    builder - INFO - Module nginx-auth-ldap will download by branch
    builder - INFO - -- Done: nginx-auth-ldap
    builder - INFO - -- Done: ngx_http_substitutions_filter_module
    builder - INFO - Module headers-more-nginx-module will downloading
    builder - INFO - Module nginx-module-vts will download by tag
    builder - INFO - -- Done: nginx-module-vts
    builder - INFO - Module ngx_devel_kit will download by tag
    builder - INFO - -- Done: ngx_devel_kit
    builder - INFO - -- Done: ngx_cache_purge
    builder - INFO - -- Done: ngx_http_dyups_module
    builder - INFO - Downloading dependencies
    builder - INFO - Building .deb package
    builder - INFO - Running 'dh_make'...
    builder - INFO - Running 'dpkg-buildpackage'...
    dpkg-deb: building package 'nginx' in '../nginx_1.14.1-1_amd64.deb'.
    

    Так буквально парой команд мы создаем окружение и нужную сборку Nginx, и пакет появляется в директории, откуда запущен скрипт.

    Встраивание


    Также мы можем встроить наш инструмент в CI/CD процессы. В этом может помочь любая из множества существующих на сегодняшний день CI-систем, например Teamcity или Gitlab CI.

    В итоге при каждом изменении спецификации в Git-репозитории автоматически запускается сборка артефакта. Номер ревизии привязывается к счетчику запусков билда.
    Потратив еще немного времени, можно настроить отправку артефакта в локальный репозиторий пакетов, Nexus, Artifactory и так далее.

    Дополнительным плюсом является то, что конфигурационный yaml-файл можно подключить в Ansible или другую систему автоматического конфигурирования, и брать оттуда номер версии и типа пакета, которые мы хотим задеплоить.

    Что дальше


    Проект еще не завершен. Вот над чем мы работаем сейчас:

    • Расширяем возможность конфигурирования, но при этом сохраняем ее максимально простой. Не хочется определять тысячу параметров, если нужно всего два, а остальное подходит по умолчанию. К этому относятся флаги компиляции (сейчас изменить их можно во внутреннем файле конфигурации src/config.py), пути установки, пользователя для запуска.
    • Добавляем варианты автоматической отправки пакета в различные хранилища артефактов.
    • Выполнения пользовательской команды при загрузке модуля (например для использования github.com/nginx-modules/nginx_upstream_check_module нужно сначала применить патч определенной версии)
    • Добавляем проведение тестов:
      • Пакет корректно устанавливается.
      • Nginx имеет нужную версию и собран с требуемыми флагами и модулями.
      • Создаются нужные пути, учетные записи и так далее.

    Но пользоваться этим инструментом вы можете уже сейчас, а также предлагать доработки — github.com/TinkoffCreditSystems/Nginx-builder wellcome!
    • +16
    • 4,9k
    • 4
    Tinkoff.ru
    141,12
    IT’s Tinkoff.ru — просто о сложном
    Поделиться публикацией

    Комментарии 4

      0
      А вы пробовали это на POSIX Shell это делать?
        0
        Не найдя подходящего для нас варианта на просторах гитхаба


        Эм, возможно ключевое слово здесь «подходящего для нас», но а так есть как минимум github.com/cubicdaiya/nginx-build который выполняет схожие функции + умеет собирать OpenResty.

        А так, спасибо за ваше решение, попробую на досуге.
          0
          Мы увидели чрезмерность в данном решении из-за выбора языка разработки. Мы не увидели в GOlang каких-то решений которые были бы нам смертельно необходимы. Наша целевая аудитория это системные администраторы/devops инженеры(Да простит меня osminog)/SRE
          и они в большинстве своем знают python чаще чем GOlang.
          0

          А потом приходишь в рассылку nginx и тебе "попробуйте удалить все сторонние модули и воспроизвести проблему без них".

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое