Angie 1.10: разбор фич, планы на 1.11#
Обзор новых возможностей Angie 1.10: автоматическое проксирование Docker-контейнеров, ACME для stream-модуля, поддержка Multipath TCP, CUBIC в QUIC и планы развития на версию 1.11.
Следуя устоявшемуся квартальному ритму выпуска значимых релизов, мы выпустили стабильные версии Angie и Angie PRO 1.10 — форка nginx, развиваемого в основном бывшими ключевыми разработчиками оригинального проекта.
Как и в прошлый раз, расскажем подробнее о нововведениях, приводя примеры. Вы узнаете, в чем ключевая фишка нового релиза; также слегка приоткроем завесу тайны над тем, что у нас припасено на будущее.
А пока — краткий список нововведений, которые будут разобраны ниже:
автоматическое проксирование и балансировка веб‑сервисов в Docker‑контейнерах (или Podman);
автоматическое получение TLS‑сертификатов для потокового модуля (stream);
прием соединений Multipath TCP (MPTCP);
контроль перегрузки CUBIC в QUIC‑соединениях;
привязка сессий с внешним хранилищем в модуле stream;
новые режимы привязки сессий при проксировании HTTP‑запросов;
режим постоянного перехода на резервную группу в модуле stream.
Последние три пункта из этого списка доступны только в коммерческой версии Angie PRO. Все остальные нововведения присутствуют и в бесплатной open‑source версии Angie. Как всегда, помимо исходного кода, мы готовим пакеты для большинства актуальных операционных систем и Docker‑образы.
Итак, поехали! Для балансировки и масштабирования сервисов, запускаемых в контейнерах, перед
ними обычно ставят реверс‑прокси. Для увеличения производительности или
обновления сервисов запускают новые контейнеры и останавливают старые. Ранее,
чтобы nginx узнавал о запуске новых контейнеров или переставал направлять
запросы на остановленные, требовались дополнительные инструменты. Они обновляли
конфигурацию и инициировали ее перезагрузку — что сопровождалось всеми
сопутствующими неудобствами и недостатками этого процесса. Ситуацию немного улучшила поддержка динамического резолвинга, которую мы
добавили в Angie два года назад. Однако это решение требовало настройки и
динамического обновления DNS для контейнеров, а также не позволяло гибко
настраивать параметры балансировки и привязки сессий. Было бы удобнее, если бы балансировщик самостоятельно отслеживал изменения в
пуле контейнеров и мгновенно реагировал на них. Запросы на такую
функциональность поступали уже давно, с тех пор, как пользователи nginx
познакомились с Traefik. Однако многих не устраивала его сравнительно низкая
производительность. К тому же работать с привычным, проверенным временем
инструментом всегда комфортнее, чем осваивать новое решение с его особенностями
и ограничениями. В Angie 1.10.0 мы наконец реализовали эту возможность. Теперь в конфигурации
достаточно указать всего одну директиву с адресом Docker API: В примере используется UNIX‑сокет, но можно указать и IP‑адрес. Затем нужно
просто добавить контейнерам специальные метки (object labels в терминологии
Docker). Для HTTP‑модуля: Для модуля stream: При запуске Angie автоматически обнаружит все контейнеры с такими метками и
добавит их адреса и порты в указанную группу Возьмем, например, такую конфигурацию Angie (напоминаю, что за исключением новых
возможностей, конфиг будет аналогичен nginx): Здесь настроено проксирование HTTP на порту 80, а также проксирование порта 1883
(часто используемого для MQTT) в потоковом режиме (stream), без анализа
протокола на уровне приложений. Предположим, у нас есть сервис в контейнере, который одновременно предоставляет
веб‑интерфейс и обрабатывает MQTT‑сообщения. Чтобы Angie начал автоматически
балансировать на него трафик, добавим в При запуске контейнера его IP‑адрес в сети В upstream‑блок В upstream‑блок Используя метки, можно также задать параметры сервера (директивы Доступны почти все параметры, которые можно указать в конфигурации Angie: веса
( Замечу, что в Angie реализована не только базовая привязка сессий для HTTP и
stream, но и расширенные возможности. Например, для протокола MQTT можно
автоматически извлекать идентификатор клиента (ClientID)
или имя пользователя (Username) из пакета CONNECT и использовать их для привязки
сессии. Если контейнер поставить на паузу ( Авторизация: Для доступа к защищенному Docker API используется блок
Как всегда, за всеми деталями обращайтесь к документации по модулю: Модуль Docker опционален. Мы включаем его в наши стандартные пакеты, но если вам
эта функциональность не нужна, его всегда можно исключить из сборки
( Уже второй год мы расширяем возможности Angie по автоматическому выпуску и обновлению TLS‑сертификатов с помощью протокола ACME (его используют
Let's Encrypt и другие популярные центры сертификации). Это позволяет упростить
настройку и отказаться от сторонних утилит вроде certbot или acme.sh (хотя ничто
не мешает использовать их вместе с Angie, если вам так удобнее). До сих пор эта функциональность работала преимущественно в HTTP‑модуле, где
TLS‑терминация применяется чаще всего. Однако пользователи запрашивали ее и для
модуля stream, который проксирует произвольный TCP/UDP‑трафик, —
особенно после того, как в нем появилась поддержка виртуальных серверов
(SNI). В Angie 1.10 мы добавили полноценную поддержку ACME для Рассмотрим на примере: Эта конфигурация почти идентична типичной для nginx схеме, за исключением двух
директив: acme_client и acme. Директива resolver
задана, чтобы Angie мог в процессе работы через резолвер асинхронно запрашивать
IP‑адреса серверов Let's Encrypt. Эта директива требуется для любого
динамического резолвинга (хотя у нас есть в планах научить Angie читать
системные настройки и избавить пользователей от необходимости указывать
директиву Сервер Let's Encrypt должен убедиться, что домен принадлежит нам. Для этого
используются различные типы подтверждения (так называемый «challenge»). Пока
Angie поддерживает два типа — HTTP и DNS. В ближайшей версии мы собираемся
добавить поддержку ALPN‑подтверждения, которая не нуждается в открытии
HTTP‑порта. По умолчанию, если иного не указано в директиве Angie сам автоматически отвечает на HTTP‑проверку; для этого ему нужен только
открытый 80-порт в рамках HTTP‑модуля. В примере выше не планируется
обрабатывать какие‑либо другие запросы на этом порту, поэтому указан
return 444, что сразу же оборвет соединение для всех остальных
запросов. Но если вы обслуживаете также HTTP, то у вас уже, скорее всего, будет
обработка порта 80, и ничего дополнительно настраивать не потребуется. Также там
может быть настроен редирект на HTTPS. Далее следует главный герой нашей функциональности — блок В результате Angie сам запросит мультидоменный сертификат для
Если вы поменяете набор доменов в директиве Подробнее о всех настройках можно прочитать в документации на сайте: В будущей версии мы хотим научить модуль ACME автоматически открывать порт 80
без необходимости указывать блок Протокол MPTCP по своей сути является надстройкой для TCP, позволяющей логически
разделить соединение и поток данных. Это дает возможность агрегировать несколько
каналов для повышения пропускной способности и отказоустойчивости, а также
бесшовно переключаться между ними. Например, пользователь может покинуть зону
покрытия сети Wi‑Fi, но передача данных продолжится через мобильную сеть
практически незаметно для прикладного уровня. Для включения приема MPTCP‑соединений в Angie достаточно указать опцию
Таким образом, на 443 порту будут приниматься как обычные TCP‑соединения, так и
MPTCP. К сожалению, с поддержкой на стороне клиентов пока не все так хорошо. Она
неплохо реализована в продукции Apple, и ее можно попытаться настроить в
дистрибутивах Linux со свежими ядрами. А вот пользователи Windows и Android пока
не у дел. Также можно столкнуться с тем, что некоторые VPN‑провайдеры фильтруют
опции MPTCP в SYN/ACK‑пакетах (пакетах установки TCP‑соединения), и в этом
случае MPTCP превращается в обычный TCP. Протокол QUIC — это транспорт для протокола HTTP/3, по аналогии с тем, как TCP
выступает транспортом для протоколов HTTP/1.x и HTTP/2. Как и TCP, QUIC гарантирует доставку, поэтому через него можно передавать
большие объемы данных. Поскольку QUIC работает поверх UDP, ему потребовалось
реализовать так называемый механизм контроля перегрузки (congestion control),
как в TCP. Этот механизм следит за тем, чтобы пакеты в каждый момент времени
отправлялись с доступной пропускной способностью до конечного получателя. Если
отправлять пакеты медленнее, полоса пропускания не будет полностью
задействована. Если отправлять их быстрее, на маршрутизаторах будут
переполняться буферы, начнется потеря пакетов, и будут впустую тратиться ресурсы
на их повторную передачу. Существует целый набор подобных алгоритмов. До выхода новой версии в нашей
реализации QUIC применялся известный алгоритм контроля перегрузки NewReno, но
теперь будет использоваться CUBIC. Этот алгоритм способен более агрессивно
наращивать скорость передачи в условиях высоких задержек, что дает преимущество,
особенно при широкой пропускной способности канала. Алгоритм был портирован из свежей версии nginx. При этом в нашей реализации он
поддерживается не только для входящих соединений, но и для исходящих — при
проксировании по протоколу HTTP/3. Для использования CUBIC в HTTP/3 достаточно обновиться на свежую версию Angie.
Никаких дополнительных настроек не требуется, если у вас уже включен HTTP/3. Все перечисленные новинки были добавлены в последней бесплатной версии
Angie с открытым исходным кодом. Вопреки нелепым
фантазиям некоторых «диванных экспертов», никто нас не спонсирует и грантов не
выделяет. Разработка целиком ведется на собственные средства, и лучшая
благодарность для нас — это покупка лицензии на Angie PRO. А о том, какие еще новые возможности реализованы в
коммерческой версии, поговорим далее. Привязка сессий позволяет балансировщику направлять все соединения в рамках
одной сессии на один и тот же закрепленный бэкенд. Это требуется для
горизонтального масштабирования приложений, чтобы избежать синхронизации данных
между всеми бэкендами. Определение сессии и время ее жизни задаются в
настройках. В Angie привязку можно реализовать: по правилам конфигурации (режим с запоминанием в разделяемой памяти (режим в новом режиме Ранее этот режим был доступен только в HTTP‑модуле, но в Angie PRO 1.10 он
добавлен и в потоковом модуле ( Режим особенно полезен в двух практических сценариях: Кластер балансировщиков. Когда несколько экземпляров Angie работают
вместе, а входящие подключения клиента (в рамках одной сессии) должны
попадать на один бэкенд независимо от того, какой балансировщик их обработал.
Это позволяет и масштабировать сами балансировщики, и повышать
отказоустойчивость. Внешний «директор». Когда отдельный сервис (на основе бизнес‑логики
приложения) определяет, куда направлять соединения конкретного клиента. Оба сценария эффективно реализуются новой функцией. При этом можно использовать
почти любое хранилище или реализовать специализированный сервис‑»директор». Посмотрим на примере: В самом начале в рамках уже упомянутого ранее блока client
( В блоке Как можно заметить, настройки максимально гибки, а в качестве хранилища можно
использовать почти все что угодно. Так, в качестве хранилища может выступать и
сам Angie с модулем keyval. Более того, в рамках того
же Все это дает впечатляющую гибкость и полностью решает вопрос с масштабированием
как самого кластера балансировщиков, так и хранилища. Тут приведен лишь небольшой пример; за более подробной информацией обращайтесь к
документации: Аналогичная возможность запрашивать привязку сессии из внешнего хранилища
появилась в HTTP‑модуле еще в предыдущих версиях. В свежей же версии добавилось
несколько новых опций, указывающих, как часто следует обращаться к внешнему
хранилищу. Директива sticky в блоке Таким образом, полученная из внешнего хранилища привязка будет храниться в
разделяемой памяти и использоваться для последующих запросов в рамках сессии без
обращения к внешнему хранилищу. Время хранения привязанной сессии в разделяемой
памяти в примере выше задано как пять минут с момента последнего использования с
помощью параметра Если запросы в рамках сессии поступают часто (здесь — чаще, чем раз в пять
минут), то повторного обращения к хранилищу может не быть достаточно долго, так
как таймер устаревания сессии сбрасывается при каждом обращении. Такой режим не
всем подходит, и иногда требуется обновлять данные о сессии с некоторой
гарантированной периодичностью. Для этого теперь можно указать новую опцию
Опция отключает сброс таймера устаревания при использовании привязанной сессии.
При этом привязка сессии будет повторно запрашиваться из внешнего хранилища
согласно заданному интервалу, то есть раз в пять минут в данной конфигурации. В некоторых случаях сохранение сессии локально полностью недопустимо, либо
требуется более продвинутая логика кэширования привязки сессий. Для этого теперь
можно не задавать зону разделяемой памяти вовсе: Тогда на каждый новый запрос будет порождаться подзапрос. Ответ на него уже
можно кэшировать с использованием, например, развитых возможностей
proxy_cache: Можно даже вообще не настраивать кэширование, или же добавить скриптовой магии
на JavaScript (либо Lua): Все это дает почти неограниченные возможности по управлению привязкой сессий в
рамках кластера из балансировщиков на базе Angie PRO. Теперь настройка backup_switch (PRO) стала доступна и в
рамках модуля Мы уже обсуждали эту функциональность в контексте предыдущего релиза, где она
впервые появилась для групп upstream‑серверов в HTTP‑модуле. Поэтому не буду
сейчас на этом останавливаться — подробности читайте в предыдущей статье
<angie-1-9>. Опишу лишь кратко, что параметр позволяет избежать частого
переключения между резервной и основной группой, если серверы в одной из групп
работают нестабильно. Можно после перехода на резервную группу оставаться на ней не менее заданного
интервала времени для стабилизации ситуации: В этом примере после переключения на резерв попытки использовать серверы из
основной группы будут происходить не чаще, чем раз в минуту. Если вообще не указывать параметр В будущих версиях настройки для логики ввода резерва будут расширяться и дальше. Это, пожалуй, все, что касается коммерческой версии. Команда разработчиков Angie
также занимается доработками компонента балансировки для Angie ADC — нашего комплексного решения по управлению сетевым трафиком. Но его
релизы выходят по своему графику, и рассказ о нем выходит за рамки этой статьи.
Далее мы поговорим о планах на следующий релиз, прежде всего в рамках бесплатной
версии Angie. Помимо уже озвученных ранее планов на поддержку ALPN в ACME, первое, что
ожидается в будущей версии, — расширение возможностей статистики практически до
бесконечности. В конфигурации можно будет объявить метрику на основе любой
переменной и пересчитывать ее на указанной стадии обработки запроса. Доступны
самые разные типы метрик: счетчик, среднее, максимум‑минимум или гистограмма. Таким образом, можно будет настроить подсчет статистики под любую задачу: к
примеру, подсчитать число запросов по URI и найти самые частые, либо самые
медленные из них; посчитать количество пользователей по странам с использованием
GeoIP, или какими браузерами чаще всего они пользуются. В общем‑то, все
ограничивается только вашей фантазией. Как и со встроенными метриками, значения
пользовательских метрик будут доступны через RESTful API в формате JSON или Prometheus. Эта функциональность готовилась к выходу 1.10, но на очередной итерации ревью
выявилась серьезная проблема, исправление которой потребовало дополнительного
времени. Следуя традициям nginx, мы скрупулезно подходим к качеству кода и
вопросам ревью, при этом, напомним, цикл релизов у нас регулярный: примерно
каждые три месяца выходит очередной стабильный релиз с готовой и
протестированной к этому времени функциональностью. Помимо нового модуля статистики, есть высокие шансы, что до первого стабильного
релиза будет доведена и возможность запуска PHP‑приложений для замены PHP‑FPM.
Задача эта очень сложная и комплексная, поэтому уже довольно долго находится в
разработке. Тем не менее, многие эту функциональность ждут, и хочется оправдать
ожидания. Это, пожалуй, самое большое и интересное из того, что ждет вас в будущем релизе.
Кроме того, ожидается множество небольших полезных доработок: дополнительная
защита от slowloris‑атак, поддержка передачи TLV‑записей на бэкенд в PROXY
Protocol, автоматическая настройка DNS‑резолвера (директивы Что‑то из этого, возможно, не будет готово или не успеет пройти всего цикла
ревью и испытаний к будущему релизу, а значит будет отложено до выхода 1.12, но
мы будем стараться. Как обычно, ждем обратной связи в комментариях, в Telegram‑группе, на форуме или
в GitHub, где репозиторий Angie
недавно преодолел планку в 1500 звезд — мелочь, а приятно:Автоматизация проксирования Docker-контейнеров#
docker_endpoint unix:/var/run/docker.sock;
angie.http.upstreams.<имя_блока_upstream>.port=<порт>
angie.stream.upstreams.<имя_блока_upstream>.port=<порт>
upstream
. Любые изменения
состояния контейнеров — запуск новых, остановка старых или приостановка — будут
отслеживаться в реальном времени. Список серверов для балансировки обновится
мгновенно, без перезагрузки конфигурации.http {
docker_endpoint unix:/var/run/docker.sock;
upstream web {
zone z1 1m; # Зона разделяемой памяти для upstream
}
server {
listen 80;
location / {
proxy_pass http://web;
}
}
}
stream {
upstream mqtt {
zone z2 1m; # Зона разделяемой памяти для upstream
}
server {
listen 1883; proxy_pass mqtt;
}
}
docker-compose.yml
следующие
метки:services:
my_app:
image: my_app:latest labels:
- "angie.network=my_bridge" # Сеть Docker, из которой брать
IP
- "angie.http.upstreams.web.port=80" # HTTP-порт контейнера для
upstream `web`
- "angie.stream.upstreams.mqtt.port=1883" # Stream-порт контейнера для
upstream `mqtt`
...
my_bridge
будет автоматически
добавлен:web
(секция http
) — как сервер с портом 80mqtt
(секция stream
) — как сервер с портом
1883server
)
в upstream
:… - "angie.http.upstreams.web.weight=5" -
"angie.http.upstreams.web.max_fails=3" -
"angie.http.upstreams.web.fail_timeout=10s" -
"angie.http.upstreams.web.slow_start=60s" -
"angie.stream.upstreams.mqtt.weight=5" -
"angie.stream.upstreams.mqtt.max_conns=50" -
"angie.stream.upstreams.mqtt.sid=iot42"
weight
), настройки проверок здоровья (max_fails
,
fail_timeout
), ограничения соединений (max_conns
), идентификатор
для привязки сессий (sid
), и т. д.docker pause
), Angie автоматически
пометит соответствующий сервер в upstream как down. Это временно исключит его из
балансировки, но не приведет к сбросу накопленной статистики сервера
(доступной через мониторинг Angie) и пересчету хешей (если
используется балансировка на основе хеширования — директива hash
).client {}
, который мы реализовали в этой же версии. В нем настраиваются
параметры модуля proxy для внутренних исходящих запросов,
которые Angie сам отправляет к Docker API (и другим сервисам, например
ACME или Upstream Probe):client {
# Можно добавить заголовок для авторизации HTTP Basic proxy_set_header
Authorization "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
# Или клиентский сертификат proxy_ssl_certificate /path/to/auth.cert;
proxy_ssl_certificate_key /path/to/auth.key;
location @docker_events {} location @docker_containers {}
}
--without-http_docker_module
). А теперь перейдем к новым возможностям
модуля ACME!Автоматические TLS-сертификаты для stream#
stream
. Настройка почти
идентична HTTP‑модулю, достаточно лишь прописать пару директив.http {
resolver 127.0.0.53; # Для динамического DNS-резолвинга
acme_client my_client https://acme-v02.api.letsencrypt.org/directory;
server {
listen 80; return 444; # Закрываем соединение для всех не-ACME запросов
}
}
stream {
server {
listen 443 ssl;
server_name example.com www.example.com; # Домены для сертификата
acme my_client; # Используем ACME-клиент "my_client"
# Автоматически заполняемые переменные:
ssl_certificate $acme_cert_my_client;
ssl_certificate_key $acme_cert_key_my_client;
}
}
resolver
).acme_client
,
используется HTTP‑подтверждение.stream
. Внутри
его блока server
задана директива acme
с именем ранее
сконфигурированного клиента. Она указывает, что в данном блоке server
нужно использовать домены из директивы server_name
, и эти домены попадут
в запрос на сертификат. Сам сертификат и ключ для него будут содержаться в
переменных, соответствующих имени клиента: $acme_cert_my_client
и
$acme_cert_key_my_client
.example.com
и www.example.com
, а также будет следить за тем,
чтобы своевременно его обновлять.server_name
или укажете ту
же директиву acme my_client
в каких‑то других блоках server
с
другим набором доменов, то Angie автоматически запросит новый сертификат с
учетом ваших изменений. Функциональность из серии «один раз настроил и забыл»;
далее все будет работать автоматически и реагировать на изменения конфигурации.server
в http {}
.Multipath TCP (MPTCP)#
multipath
в директиве listen:listen 443 ssl multipath;
CUBIC в QUIC#
Привязка сессий с внешним хранилищем в stream#
route
);learn
с zone
);learn
с remote_action
, где информация о
привязке принимается из внешнего хранилища или сервиса.stream
).http {
client {
location @my_sticky {
proxy_pass http://192.0.0.1; # Внешнее хранилище/директор
}
}
}
stream {
upstream backend {
server 192.168.0.100:1986;
server 192.168.0.102:1986;
server 192.168.0.104:1986;
sticky learn
lookup=$remote_addr # Ключ сессии (IP клиента)
remote_action=@my_sticky # Location для запроса
remote_uri=/get?id=$sticky_sessid # URI запроса
remote_result=$upstream_http_x_backend; # Переменная c результатом
}
server {
listen 1986;
proxy_pass backend;
}
}
http
) объявлен location @my_sticky
, который обращается к
внешнему хранилищу или директору. В примере используется proxy_pass,
но поддерживаются и любые другие методы, например: fastcgi_pass,
Redis2,
Postgres, и
даже js_content
для сложной обработки на JavaScript.stream
директива sticky learn в группе
балансировки upstream
содержит следующие параметры:lookup=$remote_addr
— в качестве ключа для сессии используется
IP‑адрес клиента. В теории можно использовать любую переменную, которая
доступна или может быть извлечена на этапе соединения, например
$ssl_session_id, $mqtt_preread_clientid или
$rdp_cookie.remote_action=@my_sticky
— задаем, что сессию следует запрашивать в
контексте блока location
с именем @my_sticky
, который мы ранее
объявили в рамках блока client
.remote_uri=/get?id=$sticky_sessid
— задали URI для запроса сессии, где
в качестве аргумента передаем собственно идентификатор сессии, ранее указанный
через lookup
.remote_result=$upstream_http_x_backend
— идентификатор сервера, на
который мы хотим направить нашего клиента, будем брать из заголовка X‑Backend
ответа на запрос к нашему хранилищу или директору.location @my_sticky
c proxy_pass
можно воспользоваться
богатыми возможностями по кэшированию ответов и настроить директивы
proxy_cache, чтобы сократить задержки и количество обращений
к внешнему хранилищу.Новые режимы привязки сессий в HTTP#
upstream
модуля HTTP позволяет
настраивать кэширование запрошенных сессий в разделяемой памяти:sticky learn zone=my_zone:1m
lookup=$cookie_bar
remote_action=/remote_session
remote_result=$upstream_http_x_sticky_sid timeout=5m;
timeout=5m
.norefresh
:sticky learn zone=my_zone:1m
lookup=$cookie_bar remote_action=/remote_session
remote_result=$upstream_http_x_sticky_sid timeout=5m norefresh;
sticky learn lookup=$cookie_bar
remote_action=/remote_session
remote_result=$upstream_http_x_sticky_sid;
location /remote_session {
internal; proxy_pass http://sessions_store; proxy_cache session_cache;
}
location /remote_session {
internal; njs_content sessions.fetch;
}
Постоянное переключение на резерв в stream#
stream
для балансировки на уровне TCP/UDP.backup_switch permanent timeout=1m;
timeout
, то попыток возврата на
основную без вмешательства администратора не будет до тех пор, пока резерв
остается работоспособен.Планы на Angie 1.11#
resolver
),
фильтрация и форматирование журнала ошибок.