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

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

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

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

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

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

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

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

Источник: krakend.io/docs
Источник: 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.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 продукт с подобными функциональными возможностями.

Комментарии (7)


  1. baldr
    30.12.2023 08:27
    +5

    Дмитрий, разрешите покритиковать вашу статью.. Для меня из неё непонятно практически ничего. Всё что я отсюда понял - есть такой замечательный инструмент и он как-то вам помог что-то сделать. За деталями я пошел на офсайт и на самой первой странице документации картинка мне объяснила больше чем вся ваша статья.

    Спасибо за сведения о новом инструменте, но я лично плюс статье поставить не могу. Минусы, впрочем, тоже не буду.


    1. Crash13
      30.12.2023 08:27
      -3

      Вероятно, Вы имели ввиду, что в статье "непонятно практически ВСЁ", а не "ничего"?

      Просто для себя уточнить Вашу мысль задал вопрос.


      1. baldr
        30.12.2023 08:27
        +3

        Ок, "всё непонятно" и "не понятно ничего" - две грамматически более правильные формы, если вы к этому решили прицепиться.


        1. Crash13
          30.12.2023 08:27

          Я уточнял для себя вопрос, а не грамматические формы.

          Хотел бы прицепиться, то не уточнял бы в своем вопросе, что это было для себя. Прочтите мой вопрос внимательно.

          И, откуда в людях агрессия на уточняющие вопросы?...

          На всякий случай, вопрос в этом сообщении был риторическим.


  1. PuerteMuerte
    30.12.2023 08:27
    +1

    Дмитрий, разрешите покритиковать вашу статью (c) Для меня в принципе понятно, что у вас за инструмент, но непонятно главное - зачем он нужен? Похожая функциональность есть "из коробки" в любом облаке, будь-то AWS API Gateway или там Azure API Management. Чем ваша тулза отличается от дефолтных, чтобы был смысл добавлять ещё одно звено в тулчейн?


    1. baldr
      30.12.2023 08:27

      Ну, побродив по документации, я вижу что смысл в таком инструменте есть. Помимо того, что он помогает, частично, избавиться от фатального недостатка встроенных в облако сервисов, он еще и расширяем с помощью самописных плагинов. Есть интеграция с брокерами через AMQP, например, что тоже интересно. Их неуклюжее объяснение Backend-For-Frontend принципа мне не нравится, но, тем не менее, многие встроенные фичи довольно интересные.

      Однако, к статье именно что вопросы - как он применяется и чем именно он выигрывает относительно чего-либо другого. В данный момент в статье больше описаны какие-то малоинтересные детали деплоя.


  1. ernst_vm
    30.12.2023 08:27
    +1

    Было бы интересно сравнение, например, с Spring Cloud Gateway.