KrakenD — новый друг для вашего backend

Привет, сообществу! Меня зовут Блинов Дмитрий и я отвечаю за инфраструктуру в нашем стартапе. Это моя первая статья и в ней я бы хотел рассказать про API Gateway KrakenD и про его наиболее интересные возможности.

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

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

Единая точка входа

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

Агрегация и преобразование эндпоинтов

KrakenD способен не просто проксировать запросы к бэкенду, а полноценно манипулировать их наполнением. Так как в конфигурации шлюза полностью описана спецификация каждого эндпоинта, KrakenD может объединять тела ответов в один, а также удалять и редактировать поля в нем по заданным параметрам.

Например, для клиента приложения требуется собрать данные сразу из нескольких микросервисов. Обычно — это был бы запрос к основному сервису, который бы сам обратился за остальными данными к другим микросервисам, либо же это сразу несколько запросов к разным сервисам. Если к данной задаче подключить KrakenD то у нас появится отдельный эндпоинт, под которым шлюз сам сделает нужные запросы к сервисам, соберет их реквесты в один с нужными полями и отправит клиенту. Дополнительно, он также может добавить в тело ответа еще и статические данные, которым можно хранить непосредственно в контейнере шлюза, например, когда необходимо сделать mock-данные какого-либо сервиса.

Источник: krakend.io/docs

Валидация JWT

JWT-токены — это популярный и современный подход к авторизации пользователей, но когда речь идет о микросервисном подходе ключевым блоком в архитектуре становится сервис авторизации. На него накладывается большая нагрузка, когда необходимо помимо авторизации еще и валидировать запросы к другим сервисам. Помочь ему со второй задачей также может KrakenD, хотя в авторизацию он тоже умеет. Получив доступ к JWK кодированном в base64 он может самостоятельно проверять авторизованы ли поступающие запросы к сервисам. Также есть функционал проверки источника JWK, но в примере ниже он отключен за невостребованностью, так-как источником является наш собственный микросервис.

Пример конфигурации KrakenD для валидации JWT:

{
  "extra_config": {
    "auth/validator": {
      "alg": "HS512",
      "kid": "sim2",
      "jwk_url": "http://auth-service/getJWK",
      "disable_jwk_security": true,
      "cookie_key": "token"
    }
  }
}

Пример тела эндпоинта jwk_url получения JWK для KrakenD:

{
  "keys": [
    {
      "kty": "oct",
      "k": "YouSuperSecretJWKbase64",
      "kid": "sim2",
      "alg": "HS512"
    }
  ]
}

Генерация конфигурации

Бесспорно, при большом количестве микросервисов растет и количество эндпоинтов, для которых еще и требуется спецификация. Конфигурация, с которой запускается KrakenD — это всего один файл, написанный, например, в формате JSON или YAML, поэтому итоговый конфиг может с легкостью вырасти в тысячи строк, превратившись в нечто, что невероятно сложно поддерживать. Для решения данной задачи в KrakenD существует Flexible-конфигурация, на основе Go Templates. Она позволяет рендерить итоговую конфигурацию шлюза по заданным параметрам и шаблонам, с применением переменных и уровнями абстракций в них, прямо как Helm Chart. Переменные можно передавать как через окружение, так и заранее указывать их в специальном файле под каждый контур (dev, uat, prod).

Доработка для генерации конфигурации

Так-как данное решение базируется на Go Templates то в нём есть один существенный недостаток для активно развивающегося приложения — это невозможность динамического добавления шаблонов в конфигурацию, например, передавая имя шаблона через переменную в цикле. Конфигурации эндпоинтов каждого микросервиса у нас хранится в директории шаблонов и периодически там появляются новые файлики. Чтобы эндпоинты из нового файла попали в итоговую конфигурацию их шаблон нужно было бы добавить в основную конфигурацию. Это было не удобно, поэтому придумали простое решение: до начала рендеринга find«ом мы проходимся по директории с шаблонами и собираем название всех найденных файлов по заданной регулярке и потом с помощью sed«а просто добавляем их в основную конфигурацию и запускаем рендеринг конфига. Так мы позволили разработчикам не переживать о том, как их новые эндпоинты необходимо применить.

Пример: ДО и ПОСЛЕ формирования списка шаблонов эндпоинтов микросервисов

Пример: ДО и ПОСЛЕ формирования списка шаблонов эндпоинтов микросервисов

Трассировка и мониторинг запросов

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

Источник: krakend.io/docs

В нашем кейсе мы используем KrakenD совместно с Jaeger для подробной трассировки запросов и анализа производительности в процессе разработки. Чтобы настроить интеграцию необходимо лишь в конфигурацию шлюза написать спецификацию подключения к нему и параметры экспорта запросов, например, включить туда только определенные запросы или какой-то процент от общего объема.

Пример спецификации для Jaeger:

{
  "telemetry/opencensus": {
    "sample_rate": 25,
    "reporting_period": 5,
    "enabled_layers": {
        "backend": true,
        "router": true,
        "pipe": true
    },
    "exporters": {
      "jaeger": {
        "agent_endpoint": "http://jaeger.host:14268/api/traces",
        "service_name": "krakend"
      }
    }
  }
}

Дополнительно, так как KrakenD написан на Go и является Open Source решением, к нему можно написать собственный плагин для интеграции с какими-либо собственными приложениями.

Итог

Для нас KrakenD стал функциональным и гибким инструментом создания единого API, но для него приходится генерировать достаточно большую конфигурацию, прописывая для каждого эндпоинта множество необходимых настроек. Из-за большого количества параметров приходится тратить время на штудирование документации. Также достаточно обширный объем возможностей шлюза доступен только в Enterprise версии продукта, поэтому приходится придумывать собственные способы реализации подобных возможностей на базе Community версии. В целом нам нравится использование KrakenD в нашем приложении, учитывая, что на текущий момент мы не смогли найти Open Source продукт с подобными функциональными возможностями.

© Habrahabr.ru