Хабрахабр

Istio и Kubernetes в production. Часть 2. Tracing

В прошлой статье мы рассмотрели базовые компоненты Service Mesh Istio, познакомились с системой и ответили на основные вопросы, которые обычно возникают в начале работы с Istio. В этой части мы посмотрим на то, как организовать сбор tracing информации по сети.

И действительно, мы добавляем в каждый узел сети специальный прокси-сервер, через который проходит весь TCP-трафик.
Первое, что приходит в голову многим разработчикам и системным администраторам, когда они слышат слова Service Mesh — это tracing. К сожалению, в реальности появляется множество нюансов, которые необходимо учитывать. Кажется, что теперь можно легко отправлять информацию обо всех сетевых взаимодействиях в сети. Давайте рассмотрим их.

Заблуждение номер один: мы можем бесплатно получить данные о походах по сети

На самом деле, относительно бесплатно мы можем лишь получить соединенные стрелками узлы нашей системы и rate данных, который проходит между сервисами (по сути — только количество байтов в единицу времени). Однако в большинстве случаев наши сервисы общаются по какому-то протоколу прикладного уровня, такому как, HTTP, gRPC, Redis и так далее. И, конечно, мы хотим видеть трейсинг информацию именно по этим протоколам, хотим видеть rate запросов, а не rate данных. Хотим понимать latency запросов по нашему протоколу. Наконец, мы хотим видеть полный путь, который проходит запрос от входа в нашу систему до получения ответа пользователем. Эта задача решается уже не так просто.

Как мы помним из первой части, для сбора телеметрии у Istio есть отдельный компонент, который называется Mixer. Для начала давайте рассмотрим как выглядит отправка tracing span'ов с точки зрения архитектуры в Istio. 0.* отправка производится напрямую с прокси серверов, а именно, с envoy proxy. Однако, в текущей версии 1. Другие протоколы возможно подключить, но только через плагин. Envoy proxy поддерживает отправку tracing span'ов по протоколу zipkin из коробки. Если мы хотим использовать, например, Jaeger протокол и отправлять tracing span'ы по UDP, то нам нужно будет собрать свой istio-proxy образ. С Istio мы сразу получаем собранный и настроенный envoy proxy, в котором поддерживается только zipkin протокол. Поэтому, если мы хотим обойтись без большого количества кастомных настроек, круг используемых технологий для хранения и приема tracing span'ов уменьшается. Поддержка кастомных плагинов для istio-proxy есть, однако она все еще в alpha версии. Сам zipkin протокол предполагает отправку всей tracing информации на коллекторы по HTTP протоколу, что достаточно накладно. Из основных систем, по сути, сейчас можно использовать сам Zipkin, либо Jaeger, но отправлять туда все по zipkin совместимому протоколу (что значительно менее эффективно).

А это значит, что proxy серверы, которые стоят рядом с каждым сервисом, должны понимать какое именно взаимодействие происходит сейчас. Как я уже сказал, трейсить мы хотим протоколы прикладного уровня. Для того, чтобы трейсы отправлялись, нужно, во-первых, включить такую опцию в главном mesh config'е и, что очень важно, проименовать все порты у service сущностей kubernetes в соответствии с протоколом, который в используется в сервисе. По умолчанию, Istio настраивает для всех портов plain TCP тип, что означает, что никаких трейсов отправляться не будет. То есть, например, вот так:

apiVersion: v1
kind: Service
metadata: name: nginx
spec: ports: - port: 80 targetPort: 80 name: http selector: app: nginx

Можно также использовать составные имена, например http-magic (Istio увидит http и распознает этот порт как http endpoint). Формат такой: proto-extra.

В итоге, конечно, нужно будет изменить эту логику на стандартную и перейти на конвенцию именования всех портов. Для того, чтобы не патчить огромное количество конфигураций для определения протокола, можно воспользоваться грязным workaround’ом: пропатчить Pilot компонент в момент, когда он как раз выполняет логику определения протокола.

В получившейся конфигурации нужно посмотреть у нужного сервиса поле operation. Для того, чтобы понять действительно ли протокол определен верно, нужно зайти в любой из sidecar контейнеров с envoy proxy и сделать запрос на порт admin интерфейса envoy с location /config_dump. Для того, чтобы кастомизировать в Istio значение этого параметра (мы затем будем видеть его в нашей tracing системе), необходимо на этапе запуска sidecar контейнера указать флаг serviceCluster. Оно используется в Istio как идентификатор того, куда происходит запрос. Например, его можно вот так вычислять из переменных, полученных из downward API kubernetes:

--serviceCluster $.$(echo ${POD_NAME} | sed -e 's/-[a-z0-9]*-[a-z0-9]*$//g')

Хороший пример для понимания того, как работает tracing в envoy, есть тут.

Сам endpoint для отправки tracing span’ов необходимо также указать в флагах запуска envoy proxy, например: --zipkinAddress tracing-collector.tracing:9411

Заблуждение номер два: мы можем недорого получить полные трейсы прохода запросов по системе из коробки

К сожалению, это не так. Сложность внедрения зависит от того, каким образом у вас уже реализовано взаимодействие сервисов. Почему так?

Нужно иметь какой-то идентификатор связи. Дело в том, что для того, чтобы istio-proxy смог понять соответствие входящих запросов в сервис с выходящими из этого же сервиса, недостаточно просто перехватывать весь трафик. Список таких заголовков: В HTTP envoy proxy используются специальные заголовки, по которым envoy понимает какой именно запрос к сервису порождает конкретные запросы в другие сервисы.

  • x-request-id,
  • x-b3-traceid,
  • x-b3-spanid,
  • x-b3-parentspanid,
  • x-b3-sampled,
  • x-b3-flags,
  • x-ot-span-context.

Если у вас единая точка, например, базовый клиент, в котором можно добавить такую логику, то все отлично, вам лишь нужно будет дождаться обновления этой библиотеки у всех клиентов. Но если у вас очень гетерогенная система и нет унификации в походе из сервисов в сервисы по сети, то это скорее всего будет большой проблемой. Без добавления подобной логики вся tracing информация будет лишь «одноуровневой». То есть мы получим все межсервисные взаимодействия, но они не будут склеены в единые цепочки прохода по сети.

Заключение

Istio предоставляет удобный инструмент для сбора tracing информации по сети, однако надо понимать, что для внедрения потребуется адаптировать свою систему и учесть особенности реализации Istio. В итоге нужно решить два основных момента: определение протокола прикладного уровня (который должен поддерживаться envoy proxy) и настройку проброса информации о связанности запросов в сервис от запросов из сервиса (с помощью header’ов, в случае HTTP протокола). Когда эти вопросы решены, мы получаем мощный инструмент, который позволяет прозрачно собирать информацию с сети даже в очень гетерогенных системах, написанных на множестве различных языков и фреймворков.

В следующей статье про Service Mesh рассмотрим одну из самых больших проблем Istio – большое потребление оперативной памяти каждым sidecar прокси контейнером и обсудим, как с ней можно бороться.

Теги
Показать больше

Похожие статьи

Добавить комментарий

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

Кнопка «Наверх»
Закрыть