Как настроить Apache APISIX для гео-маршрутизации

Как настроить Apache APISIX для гео-маршрутизации

7 ноября 2022 г.

Apache APISIX, шлюз API под руководством Apache, поставляется с множеством подключаемых модулей для реализации вашего варианта использования. Однако иногда искомый плагин недоступен. Хотя создать свой собственный всегда возможно, иногда это необходимо. Сегодня я покажу вам, как направлять пользователей в соответствии с их местоположением, не написав ни одной строчки кода на Lua.

Почему геомаршрутизация?

Гео-маршрутизация предназначена для пересылки HTTP-запросов на основе физического местоположения пользователя, определяемого по его IP-адресу. Причин для этого много, и вот парочка из них. Обратите внимание, что я буду использовать страну как фактор, зависящий от местоположения, но подойдет любой меньший или больший масштаб. Это шкала, с которой я лучше всего знаком - и, вероятно, самая полезная.

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

Однако некоторые приложения растут вместе с бизнесом. Когда это происходит, возникает потребность в интернационализации и локализации. Приложение отвечает за обработку таких геозависимых факторов. i18n должен изначально обрабатываться техническим стеком, например, в Java. . l10n более ситуативен, но также не должен быть проблемой.

Проблемы возникают, когда бизнес-правила расходятся от страны к стране, главным образом из-за законов. Другие причины включают партнерство. Представьте себе интернет-магазин, у которого есть филиалы во многих странах. Вы можете выбрать партнера по доставке, но доступные партнеры зависят от страны. Хотя сохранение единой кодовой базы всегда является мудрым выбором, даже самый лучший дизайн может только замедлить хаос из множества бизнес-правил. В какой-то момент разделение приложения God на несколько приложений, зависящих от страны, неизбежно.

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

Наконец, вы также можете развернуть новую версию приложения только для одной страны. В этом случае вы должны отслеживать не (только) технические метрики, а бизнес-метрики во времени. Затем вы решите, расширять ли новую версию для других стран на их основе или больше работать над последней версией перед дальнейшим развертыванием.

Настройка Apache APISIX для геомаршрутизации

Хотя я разработчик по профессии (и увлечения!), я прагматичен. Я убежден, что каждую строку кода, которую я не пишу, мне не нужно поддерживать. Apache APISIX не предлагает гео-маршрутизацию, но построен на основе Nginx. Последний предоставляет функцию геомаршрутизации, хотя и не по умолчанию.

Следующие инструкции основаны на Docker, чтобы каждый мог следовать им независимо от своей платформы.

Нам нужно выполнить несколько шагов, чтобы настроить геомаршрутизацию в Apache APISIX:

  1. Создайте собственный образ Docker
  2. Добавьте необходимый библиотечный модуль
  3. Добавить его зависимости
  4. Настройка Apache APISIX

Для гео-маршрутизации Nginx требуется модуль ngx_http_geoip_module. Но если мы попытаемся установить его через менеджер пакетов, он также установит nginx, который конфликтует с экземпляром nginx, встроенным в Apache APISIX. Поскольку нам нужна только библиотека, мы можем получить ее из соответствующего образа Docker:

FROM nginx:1.21.4 as geoiplib

FROM apache/apisix:2.15.0-debian

COPY --from=geoiplib /usr/lib/nginx/modules 
    /ngx_http_geoip_module.so /usr/local/apisix/modules/ngx_http_geoip_module.so      #1
  1. Скопируйте библиотеку из образа nginx в образ apache/apisix

Обычная установка пакета устанавливает все зависимости, даже те, которые нам не нужны. Поскольку мы копируем только библиотеку, нам нужно установить зависимости вручную. Это просто:

ЗАПУСТИТЬ apt-get update && apt-get install -y libgeoip1

Nginx предлагает два способа активации модуля: через командную строку или динамически в файле конфигурации nginx.conf. Первое невозможно, так как мы не контролируем ситуацию, так что второе — наш единственный вариант. Чтобы обновить файл конфигурации Nginx с модулем во время запуска, Apache APISIX предлагает ловушку в своем файле конфигурации:

nginx_config:
  main_configuration_snippet: |
    load_module     "modules/ngx_http_geoip_module.so";

Приведенное выше сгенерирует следующее:

# Configuration File - Nginx Server Configs
# This is a read-only file, do not try to modify it.
master_process on;

worker_processes auto;
worker_cpu_affinity auto;

# main configuration snippet starts
load_module     "modules/ngx_http_geoip_module.so";

... 

Модуль GeoIP использует база данных Maxmind GeoIP. Мы установили его неявно на предыдущем шаге; мы должны настроить модуль так, чтобы он указывал на него:

nginx_config:
  http_configuration_snippet: |
    geoip_country   /usr/share/GeoIP/GeoIP.dat;

С этого момента каждый запрос, проходящий через Apache APISIX, имеет географическую привязку. Это переводится как Nginx, добавляющий дополнительные переменные. Согласно документации:

<цитата>

При использовании этой базы данных доступны следующие переменные:

  • $geoip_country_code двухбуквенный код страны, например, "RU", "US".
  • $geoip_country_code3 трехбуквенный код страны, например, "RUS", "USA".
  • $geoip_country_name название страны, например, "Российская Федерация", "США".

- - Модуль ngx_http_geoip_module

Тестирование геомаршрутизации

Вы можете поверить, что вышеизложенное работает - и это действительно так, но я хотел бы это доказать. Я создал специальный проект с простой архитектурой:

* Apache APISIX настроен, как указано выше. * Два апстрима, один на английском и один на французском

upstreams:
  - id: 1
    type: roundrobin
    nodes: "english:8082": 1
  - id: 2
    type: roundrobin
    nodes: "french:8081": 1
routes:
  - uri: /
    upstream_id: 1
  - uri: /
    upstream_id: 2
#END 

С помощью этого фрагмента каждый пользователь получает доступ к восходящему потоку на английском языке. Я намерен направить пользователей, находящихся во Франции, на французский апстрим, а остальных — на английский. Для этого нам нужно настроить второй маршрут:

routes:
  - uri: /
    upstream_id: 2
    vars: [["geoip_country_code", "==", "FR"]]   #1
    priority: 5                                  #2

  1. Здесь происходит волшебство; см. ниже.
  2. По умолчанию правила сопоставления маршрутов оцениваются в произвольном порядке. Нам нужно, чтобы это правило было оценено в первую очередь. Поэтому мы увеличиваем приоритет - по умолчанию 10.

Большинство пользователей Apache APISIX привыкли сопоставлять маршруты, методы и домены, но есть больше к нему. Можно сопоставить переменные Nginx, как показано выше. В нашем случае маршрут совпадает, если переменная geoip_country_code равна "FR".

Обратите внимание, что для vars удобочитаемость важнее мощности. Используйте атрибут filter_func(vars), если вам нужна более сложная логика.

На данный момент мы все еще не можем протестировать нашу функцию, так как нам нужно будет изменить наш IP-адрес. К счастью, схитрить можно (немного), и чит полезен в других сценариях. Представьте, что Apache APISIX не имеет прямого доступа к Интернету, а находится за обратным прокси-сервером. Для этого может быть несколько причин: «история», один RP, указывающий на несколько шлюзов, находящихся в ведении разных команд, и т. д.

В этом случае IP-адрес клиента будет прокси-сервером RP. Для распространения исходного IP-адреса клиента согласованным методом является добавление HTTP-заголовка запроса X-Forwarded-For:

<цитата>

Заголовок запроса X-Forwarded-For (XFF) является фактически стандартным заголовком для определения исходного IP-адреса клиента, подключающегося к веб-серверу через прокси-сервер.

Когда клиент напрямую подключается к серверу, IP-адрес клиента отправляется на сервер (и часто записывается в журналы доступа к серверу). Но если клиентское соединение проходит через какие-либо прямые или обратные прокси-серверы, сервер видит только IP-адрес конечного прокси-сервера, от которого часто мало толку. Это особенно верно, если конечный прокси-сервер является балансировщиком нагрузки, который является частью той же установки, что и сервер. Таким образом, чтобы предоставить серверу более полезный IP-адрес клиента, используется заголовок запроса X-Forwarded-For.

- X-Forwarded-For

Модуль Nginx предлагает эту конфигурацию, но ограничивает ее диапазоном IP-адресов. Для тестирования настраиваем на любой IP; в рабочей среде мы должны установить его на IP-адрес RP.

nginx_config:
  http: geoip_proxy     0.0.0.0/0; 

Наконец-то мы можем протестировать установку:

curl localhost:9080

{
  "lang": "en",
  "message": "Welcome to Apache APISIX"
}

curl -H "X-Forwarded-For: 212.27.48.10" localhost:9080 #1

  1. 212.27.48.10 – французский IP-адрес.

{
  "lang": "fr",
  "message": "Bienvenue à Apache APISIX"
}

Бонус: журналы и мониторинг

Новую переменную легко использовать в журналах Apisix. Я бы посоветовал это по двум причинам:

  • Сначала убедиться, что все в порядке.
  • В долгосрочной перспективе для мониторинга трафика, например отправки его в Elasticsearch и отображения на информационной панели Kibana.

Просто настройте его соответствующим образом:

nginx_config:
  http:
    access_log_format: "$remote_addr - $remote_user [$time_local][$geoip_country_code] $http_host "$request" $status $body_bytes_sent $request_time "$http_referer" "$http_user_agent" $upstream_addr $upstream_status $upstream_response_time" #1

  1. Оставьте переменные журнала по умолчанию и добавьте код страны.

Заключение

Гео-маршрутизация необходима для успешных приложений и бизнеса. Apache APISIX не предоставляет его «из коробки». В этом посте я показал, как можно легко настроить его, используя возможности Nginx.

Исходный код этого сообщения можно найти на GitHub.

Дальше:


Первоначально опубликовано на сайте A Java Geek 6 ноября 2022 г.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE