[Перевод] Service mesh — это всё ещё сложно
Прим. перев.: эта небольшая статья Lin Sun из IBM в блоге CNCF — занятная иллюстрация тех сложностей, над преодолением которых сейчас трудятся инженеры популярных реализаций service mesh. С ними становится понятным, почему порог вхождения у этих продуктов остаётся довольно большим.
В августе этого года на конференции ServiceMeshCon EU мы с William Morgan из Linkerd выступили с совместным докладом под названием «Service mesh is still hard». William рассказал об инновациях в Linkerd, в то время как я затронула нововведения в Istio. Оба проекта, очевидно, активно работают над тем, чтобы упростить переход обычных пользователей на service mesh.
Этот слайд (из видео с недавним выступлением 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 оказались не способны связываться друг с другом:
Совместными с 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. от переводчика
Читайте также в нашем блоге: