Собираем свой Nginx парой команд
В этой статье я расскажу о проблемах, с которыми сталкивалась наша команда при подготовке балансировщиков на основе 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!