[Перевод] Service mesh — это всё ещё сложно

Прим. перев.: эта небольшая статья Lin Sun из IBM в блоге CNCF — занятная иллюстрация тех сложностей, над преодолением которых сейчас трудятся инженеры популярных реализаций service mesh. С ними становится понятным, почему порог вхождения у этих продуктов остаётся довольно большим.

В августе этого года на конференции ServiceMeshCon EU мы с William Morgan из Linkerd выступили с совместным докладом под названием «Service mesh is still hard». William рассказал об инновациях в Linkerd, в то время как я затронула нововведения в Istio. Оба проекта, очевидно, активно работают над тем, чтобы упростить переход обычных пользователей на service mesh.

qkgvpiytalvsbzxvbaqdnav2b0s.png
Этот слайд (из видео с недавним выступлением William Morgan и Lin Sun) лаконично подытоживает актуальные плюсы и минусы сервисных сеток

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

Обычно выделяют два типа технических ролей для сервисной сетки: владельцы платформ и владельцы сервисов. Как следует из названия, владельцы платформ (также называемые mesh-админами) контролируют сервисную платформу и определяют общую стратегию и реализацию перехода на SM для владельцев сервисов. Владельцы сервисов контролируют один или несколько сервисов в SM.

Развитие данной технологии упростило использование сервисных сеток владельцами платформ. Ключевые проекты в этой области внедряют различные способы, упрощающие конфигурирование сети, настройку политик безопасности и общую визуализацию. Например, в Istio владельцы платформ могут определять политики аутентификации и авторизации на любом нужном уровне. Владельцы платформ могут настраивать на входном шлюзе хосты, порты или параметры для TLS, делегируя конфигурацию маршрутизации и задание политик для трафика целевого сервиса владельцам этого сервиса. Владельцы сервисов, следующие проверенным и универсальным сценариям, выигрывают от улучшений в удобстве использования Istio и легко переносят свои микросервисы в mesh. С другой стороны, владельцам сервисов, реализующим менее распространенные сценарии, приходится многому учиться и многое узнавать.

Я считаю, что service mesh сложна для понимания по следующим причинам:

1. Отсутствие четкого представления о том, нужна ли вам сервисная сетка


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

  • Сколько сотрудников в инженерной организации?
  • Сколько у вас микросервисов?
  • На каких языках они написаны?
  • Имеется ли опыт по внедрению Open Source-проектов?
  • На каких платформах работают сервисы?
  • Какие именно функции SM вам необходимы?
  • Имеют ли эти функции стабильный статус в соответствующей версии service mesh?


Усложняет положение то, что ответы могут сильно варьироваться для разных SM-проектов. Например, раньше в самой Istio использовались микросервисы, чтобы максимально полно использовать возможности service mesh. Однако с версии 1.5 мы отказались от этого подхода и решили объединить множество компонентов управляющего слоя Istio в монолитное приложение ради снижения эксплуатационной сложности. Конкретно в этом случае было логично запустить один монолитный сервис вместо четырех или пяти микросервисов.

2. Сервис может сломаться сразу же после подключения sidecar-контейнера


В прошлый День благодарения я пыталась помочь пользователю запустить сервис ZooKeeper в SM, используя последние версии соответствующих Helm-чартов. ZooKeeper работает в Kubernetes как StatefulSet. При попытке подключить sidecar с Envoy в pod’ы ZooKeeper те отказывались работать и постоянно перезапускались, поскольку не могли определить лидера и установить связь друг с другом. По умолчанию ZooKeeper использует IP-адрес pod’а для связи между серверами. Однако Istio и другие сервисные сетки требуют, чтобы рабочие нагрузки функцонировали с localhost’ом (127.0.0.1) внутри pod’а. В результате серверы ZooKeeper оказались не способны связываться друг с другом:

xfar71jkxdxsesfrlrni6fm2apu.jpeg

Совместными с upstream-сообществом усилиями мы придумали временное решение в конфигурации для ZooKeeper’а (а также для Cassandra, Elasticsearch, Redis и Apache NiFi)… Не сомневаюсь, что есть и другие приложения, не совместимые с sidecar-контейнерами. Пожалуйста, расскажите сообществу о них.

3. Сервис может демонстрировать странное поведение во время запуска или остановки


Контейнер с приложением может запуститься до sidecar’а и вызвать сбой приложения. То же самое справедливо для остановки: sidecar может завершить работу до основного контейнера.

В Kubernetes отсутствует стандартный способ задавать зависимости контейнеров. Существует соответствующее предложение — Sidecar Kubernetes Enhancement Proposal (KEP), — однако оно пока не реализовано (более того, в октябре его признали неправильным шагом в развитии Kubernetes и закрыли в надежде на появление иных подходов, реализуемых в других KEP«ах, — прим. перев.). Кроме того, некоторое время обязательно уйдет на стабилизацию этой функции. Тем временем владельцы сервисов могут столкнуться с неожиданном поведением во время запуска или остановки.

Чтобы справиться с этой проблемой, Istio внедрил в конфигурацию глобальную опцию для владельцев платформ, позволяющую отложить запуск приложения до тех пор, пока sidecar не будет готов. В скором времени планируется добавить аналогичную опцию на уровне pod’а.

4. Конфигурацию сервиса можно не менять, но вносить изменения в код придется в любом случае


Одна из амбициозных целей проекта service mesh — реализовать концепцию «нулевой» конфигурации для владельцев сервисов. Некоторые проекты (вроде Istio) добавили интеллектуальное обнаружение протоколов, чтобы упростить переход на SM. При этом мы по-прежнему рекомендуем пользователям явно прописывать протоколы в production. После добавления опции appProtocol в Kubernetes у владельцев сервисов появился стандартный способ настройки протоколов приложения для сервисов Kubernetes, работающих в более новых версиях K8s (например, в 1.19) [стабилизация этой фичи случилась в K8s 1.20 — прим. перев.].

К сожалению, аналогичная «нулевая» концепция для кода невозможна, если мы хотим в полной мере воспользоваться преимуществами service mesh.

  • Чтобы владельцы сервисов и платформ могли проводить трассировку сервисов, критически важно, чтобы trace-заголовки распространялись на все сервисы.
  • Чтобы избежать путаницы и неожиданного поведения, крайне важно проанализировать повторные попытки и таймауты в коде сервиса, чтобы понять, следует ли их подкорректировать, и оценить их совместимость с повторными попытками и таймаутами, настроенными с помощью sidecar-прокси.
  • Чтобы sidecar мог исследовать трафик, отправляемый из контейнера с приложением, и максимально использовать содержимое этого трафика для принятия решений (таких как маршрутизация на основе запросов или авторизация на основе заголовков), владельцы сервисов обязаны убедиться, что из сервиса-отправителя в сервис-получатель идет обычный трафик, и возложить на sidecar-прокси работу по безопасному «апгрейду» соединений.


5. Владелец сервиса должен понимать нюансы настройки на стороне клиента и сервиса


До работы над service mesh я понятия не имела, что в Envoy так много настроек, связанных с таймаутами и повторными попытками. Большинству пользователей знакомы таймауты запросов, таймауты простоя и количество повторных попыток, но есть ряд нюансов и сложностей:

  • Если говорить о таймауте простоя, в Envoy имеется параметр idle_timeout для протокола HTTP. Он используется как менеджером HTTP-соединений Envoy (HTTP connection manager), так и в HTTP-подключениях к upstream-кластерам. В свою очередь, stream_idle_timeout задает таймаут для потока без какой-либо активности (upstream или downstream), при этом idle_timeout на уровне маршрута (route-level) имеет приоритет над stream_idle_timeout.
  • Использование автоматических повторных попыток (automatic retries) также сопряжено с некоторыми сложностями. Это не просто число попыток, а максимальное количество разрешенных повторных попыток, что может не соответствовать фактическому числу повторных попыток. Оно зависит от условий, таймаутов для запросов маршрута и интервалов между попытками, которые должны попадать в общий таймаут для запросов и соответствовать «бюджету повторных попыток».


В мире service mesh контейнер-отправитель с контейнером-получателем связывают три пула соединений (вместо одного в обычных кластерах):

  • от контейнера-отправителя к sidecar-прокси-отправителю;
  • от sidecar-прокси-отправителя к sidecar-прокси-получателю;
  • от sidecar-прокси-получателя к контейнеру-получателю.


У каждого из этих пулов — своя отдельная конфигурация. Karl Stoney в этой отличной статье раскрывает всю сложность ситуации, поясняет, как на любом из трех уровней что-то может «сломаться», и что делать, чтобы это исправить.

Заключение


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

P.S. от переводчика


Читайте также в нашем блоге:

© Habrahabr.ru