Блог Слёрм

АМА-сессия Слёрма по service mesh. Часть 2

Марсель Ибраев, СТО Слёрм, вёл мероприятие, а Александр Лукьянченко, тимлид в команде архитектуры Авито, и Иван Круглов, Staff Software Engineer в Databricks, делились экспертизой.
Оба инженера имеют опыт не просто с работы какой-то конкретной реализацией service mesh, но с построением собственного, что намного круче.

Первая часть расшифровки с АМА-сессии. В первой части больше про основы service mesh, внедрение и вопросы в основном популярные, на которые спикеры готовились отвечать, в этой части более частные вопросы, заданные во время трансляции, от инженеров, погружённых в тему.

Марсель Ибраев: Вопрос от Андрея, какие вам известны техники контроля очередности запуска proxy-контейнеров? Как можно обеспечить запуск proxy-контейнера до старта (инициализации) app-контейнера?

Иван Круглов: Давайте я отвечу. Решали эту проблему. Readiness-пробы. В Kubernetes есть readiness-пробы. Мы делали так, что health check стучится в proxy, который стучится в приложение. Соответственно, у вас readiness-проба начинает отрабатывать, только когда у вас отрабатывает эта цепочка. То есть у вас и proxy поднялся, и приложение поднялось.

Александр Лукьянченко: Мы также решаем. Здесь есть правда еще один узкий кейс, когда приложение завершается. Важно, чтобы они тоже завершились в правильной последовательности. Для этого пока что нет механизма автоматического, это делается просто при pre-stop hook и какое-то количество времени, чтобы трафик успел уйти.

Марсель Ибраев: Насколько сложен конфиг каждого Service Proxy? Можете ли показать какой-нибудь продакшн пример? Нет ли проблем с рассинхронизацией конфига на разных нодах?

Иван Круглов: Конфиг Service Proxy сложен в зависимости от количества сервисов и количества endpoint этих сервисов. Я видел очень большие конфиги. Если попытаться зайти в Envoy и посмотреть конфиг — cмотреть страшно. Как на фабриках изготавливают огромные бобины метров на пять диаметром. Вот это такая бобина конфигурационного файла. Что-то там понять сложно. Пример… прямо так сходу под рукой ничего нет. Нет ли проблем с рассинхронизацией конфига на разных нодах? Нет. У меня не было из-за динамичности. Envoy может конфиги получать в двух режимах: первый это пулл, второй пуш. Первый — это когда деплой знает, где находится Control Plane. Он устанавливает с ним соединение и раз в пять секунд забирает оттуда конфигурацию. Второе — это когда Control Plane сама пушит в реалтайме конфигурацию обратно в Envoy. Теоретически возможен corner case, когда Envoy стартанул, но до Control Plane достучаться не смог, в этом случае у него может уезжать статистика. Но мы заводили отдельный график, который показывает нам, какая версия, на каких нодах, поэтому проблемы с рассинхронизацией у нас не было.

Александр Лукьянченко: У нас примерно так же. Рассинхронизация здесь может быть тогда, когда идёт какая-то деградация Сontrol Plane. Такое у нас было в виду бага. Когда есть какая-то логика, которая долго отрабатывает и просто не успевает сообщить нужную конфигурацию Envoy. Тогда это может быть.

Иван Круглов: Отвечая на вопрос про сложность конфига service mesh, хочу добавить, что конфиг сложен, но прикол в том, что подразумевается, что вы смотреть в него не будете. И это ключевая разница между Nginx, Haproxy и Envoy. У Envoy есть минимальный, так называемый, bootstrap config, который описывает, где Control Plane — где тот сервис, который отдаст конфигурацию в дальнейшем. То есть такое маленькое описание, а всю остальную конфигурацию он получает динамически. Она стримится в него в реалтайме, и по большому счёту в .config вам нужно смотреть, только если что-то надо подебажить. Это не Ngnix, когда ты открываешь Ngnix.conf и начинаешь писать его руками: тут листенер, тут сервис, тут appstream. Нет, это так не делается.

Марсель Ибраев: Продолжая эту тему, были ли такие кейсы, когда всё-таки приходилось лезть: типа трафик не совсем такой?

Иван Круглов: Да. Там тоже не всё так прямо гладко идеально. Я не очень знаю, как конкретно это происходит в Istio. Но в моей реализации service mesh у нас получилось так, что когда нужно было руками прописывать, что такой сервис находится тут. И когда получается нестыковка: где-то ошиблись в описании, приходится попытаться понять, что конкретно сделал Envoy. Когда вы посылаете запрос по HTTP в Envoy, он отвечает 400, 500 или что-то другое. И вы не всегда знаете, это сервис ответил 400 или это сам Envoy не нашёл маршрут, по которому нужно было сойти, и ответил 400. Не всегда понятно, поэтому иногда нужно и в логах посмотреть, и в конфигурации посмотреть. На начальных этапах так бывает, но это не было большой проблемой. Обычно когда мне нужно что-то дебажить, я беру конкретные инстансы, отрезаю от него всю конфигурацию, которая мне не нужна, и начинаю дебажить какой-то кусочек.

Марсель Ибраев: Как происходит обновление mesh в очень больших кластерах (больше 1000 нод), когда версии несовместимы?

Александр Лукьянченко: Никак.

Иван Круглов: Вот тут надо позвать Женю Алькова, который, по-моему, у вас, Саша, и переходил с версии 1.5 на 1.7. Там какая-то была несовместимая версия. Но вообще никак.

Александр Лукьянченко: Если отвечать на конкретно этот вопрос, то никак, потому что переходить на несовместимые версии невозможно. Если говорить про конкретные имплементации, сам Envoy, его протокол, сущности, — они все обратно совместимы в достаточно большой range-версии. И поэтому, например, недавно было обновление с версии 2.2 на 2.3 их xDS-протокола… Оно проводится просто путём того, что мы в один момент времени поддерживаем и тот, и другой протокол и постепенно переводим Envoy с одной версии на другую, затем старую версию отрубаем. Само непосредственно обновление mesh, это в первую очередь Control Plane, проходит достаточно гладко: потому что обычно есть несколько инстансов, и мы просто добавляем новую версию, то есть обновляем каждый Control Plane c масштабированием горизонтально. В случае с Data Plane обычно так же, как при внедрении service mesh с нуля, мы постепенно раскатываем новую версию по всей системе, смотрим, как она себя ведёт.

Марсель Ибраев: Тоже интересный вопрос, кстати. Можно ли добавить внешние энвои в service mesh? В кубере мы всё поставили, но у нас внешние базы на виртуалках, как тут быть?

Александр Лукьянченко: Технически никто не мешает поставить куда угодно Envoy. И у нас так сделано для внешних балансировщиков, для кейсов, где инстансы живут вне Kubernetes. По факту отличий особо никаких нет. Это тот же самый Envoy, тот же самый процесс, он просто висит где-то вне Kubernetes и потребляет данные о том, как ему нужно быть сконфигурированным из того же Control Plane. Его нужно в Discovery сделать: поставить какой-нибудь балансировщик и с помощью него отказоустойчиво ходить на несколько поднятых Control Plane, например, в том же Kubernetes.

Марсель Ибраев: Да, логично. Есть ли реализация service mesh для OpenShift? Кто знает?

Иван Круглов: Не могу ответить со стопроцентной уверенностью, но OpenShift это тот же самый Kubernetes с примочками RedHat. Наивно полагая, я не вижу проблем, чтобы поставить тот же самый Istio туда. Под капотом же обычный кубер.

Александр Лукьянченко: Так и есть. И RedHat достаточно мощно продвигают интеграцию с Istio. Так что не должно быть проблем.

Марсель Ибраев: Умеет ли service mesh применять свои фичи к egress трафику? Если я хочу настроить ретраи/circuit breaker/timeout к внешним ресурсам? И что с HTTPS в таком случае?

Иван Круглов: Да, умеет. Говоря, да, умеет, я имею ввиду: Envoy умеет это делать.
У него ретари, circuit breaker и таймауты применяются к исходящему трафику. А какие ресурсы, внешние или внутренние, не играет большой роли. В одном случае у вас будет кластер динамичный, у которого эндпоинты динамично подтягиваются, в другом — статичный кластер, который вы захардкодили. А что с HTTPS в этом случае. Здесь я немного не понимаю вопроса. Но как я у себя делаю это взаимодействие. У меня приложение по HTTP ходило на локальный хост, а Envoy уже устанавливал HTTPS-соединение. Получается, у нас как бы трафик незащищённый, но незащищённый только на loopback-интерфейсе, по сути, внутри пода или внутри ноды. При этом проблемы я не видел. А дальше устанавливается HTTPS соединение. Если здесь есть конкретные подводные камни, тогда нужно немножко уточнить вопрос.

Александр Лукьянченко: Если говорить про Istio, я бы ещё добавил, что там используется такой подход, что если мы говорим об egress трафике как трафике наружу, не из конкретного инстанса наружу, а именно из системы наружу, в интернет, то есть выделенный компонент, который там устанавливается, и делается так, что весь трафик, который идёт во вне mesh, роутится и приземляется на специальный тот же выделенный Envoy-Proxy, который называется egress, и далее отправляется уже оттуда наружу во вне системы. И там как раз можно рулить всякими политиками, куда можно ходить наружу, запрещать какие-то вещи и т.д. Такое есть решение.

Марсель Ибраев: Следующий вопрос: ожидать ли перехода всех решений на SMI (service mesh Interface)?

Александр Лукьянченко: Вот здесь у меня лично нет уверенности, что все решения придут в SMI. Но наверное, если это будет стандартом, который поддержит большинство самых популярных решений, то в итоге, да. Но сейчас я затрудняюсь ответить, будет ли это так.

Марсель Ибраев: Учитывая любовь Kubernetes к плагинам и стандартизации, почему бы нет. Насколько возможно внедрение service mesh без sidecar? Видимо, имеется ввиду без дополнительно запущенного контейнера в рамках одного пода.

Иван Круглов: Давайте отвечу, потому что у меня есть в этом опыт. Вообще возможно. Что делает sidecar? Sidecar — это, грубо говоря, штука, которая умеет принимать конфигурацию и умеет на основании этого раутить трафик. Если вы можете написать какую-нибудь библиотеку, которая будет ходить в Control Plane, запрашивать конфигурацию в нужном виде и посылать запрос, куда надо, то это по-прежнему будет service mesh. По крайней мере, как я его понимаю. И он будет работать. Известных реализаций, насколько я знаю, нет. Теоретически да, на практике боюсь не получится.

Александр Лукьянченко: Кстати, у меня вылетело из головы. Есть такая реализация одна. Мы даже как-то пробовали. Но название, к сожалению, забыл.

Иван Круглов: Это стопудово будет не мейнстрим.

Марсель Ибраев: Что нужно учитывать разработчикам, на что обратить внимание при разработке сервисов, которые будут использоваться совместно с service mesh? И нужно ли вообще что-то учитывать?

Александр Лукьянченко: У меня есть наболевшая вещь. С точки зрения перфоманса. Если мы говорим про, например, HTTP1 взаимодействие, и это взаимодействие делается по протоколу даже 1.1, но без keep-alive, надо понимать, что с точки зрения технологии того, как проходят flow запросы сквозь систему, у нас каждый раз, когда мы открываем новое TCP-соединение под новый HTTP-запрос, мы это делаем по всем Proxy. То есть мы идем на Envoy-proxy, от Envoy-Proxy дальше в следующий сервис, там на входе опять Envoy и так далее. С точки зрения эффективности, при большой нагрузке оказывает достаточно большое влияние. Если мы постоянно создаем по 10 000 новых коннектов, это не очень эффективно. Несмотря на то что Envoy умеет держать пулы и прочее, мы сталкивались с проблемами, что это плохо влияло на перформанс и конечную задержку. Это первое, что приходит в голову именно с точки зрения технической составляющей реализации сервиса. В остальном, например, трейсинг. Если вы не будете прокидывать заголовки, то автоматически никаких графов, никаких путей взаимодействия получить нельзя. Тоже важный момент. В остальном, в принципе, технология стоит немного сбоку от разработки, и, наверное, каких-то таких критериев других особо нет.

Марсель Ибраев: Очень хорошо, что есть такие вопросы, что разработчики интересуются, что вообще есть на инфраструктуре и как она там работает. Мне это очень отзывается.
Как сделать отказоустойчивый egress со статическим адресом?

Иван Круглов: Я, наверное, не до конца понимаю. Мы говорим про egress в рамках Envoy или egress в рамках Kubernetes кластера? Если в рамках Envoy, когда мы говорим про egress трафик, то есть исходящий трафик от ноды куда-то там, там проблемы со статическими адресами не вижу. Заводите кластер, в котором статически прописываете адрес. А если Istio egress в рамках кубера — тогда не подскажу.

Александр Лукьянченко: Имеется ввиду Istio egress, который выделенный компонент, у него статический адрес, и он отказоустойчив. Мне только одно приходит в голову. Сделать его не настоящим, то есть какой-то виртуальный, видимо, адрес. Иначе он не будет отказоустойчивым. Либо я неправильно понимаю вопрос. Какой-то адрес, под которым будет скрываться не один egress, а несколько. Грубо говоря, тот же кластер IP, но статичный. Его зашить с каким-то айпишником статичным, и он будет балансировать уже на реальной egress, который даже будет там переезжать с ноды на ноду.

Марсель Ибраев: Видимо, кейс в том, чтобы у нас из системы ответы в мир шли с какого-то одного ip-адреса.
Есть ли у service mesh функция API Gateway на примере Istio? Недавно появилась функция Istio service mesh virtual machine, в чём видите его полезность?

Иван Круглов: Судя по названию, Istio service mesh virtual machine — это как раз-таки возможность включить в Istio что-то, что не находится в Kubernetes. Есть ли в Istio функция API Gateway? Давайте тут я немножко поясню. Есть такая категоризация, как North-South Traffic и East-West. То есть трафик, который идёт с севера на юг, и трафик, который идёт с востока на запад. Немножко абстрактное описание. Но если мы представим себе компанию в виде квадратика, то трафик с севера на юг пересекает границы компании, границы кубика, кадратика. А East-West располагается в его рамках. North-South — это трафик внешний, который либо приходит извне, либо уходит во вне. А West-East — трафик, который остаётся в рамках компании. Так вот service mesh — это решение для East-West трафика в основной его массе. Сейчас, конечно, его начали немножко распиливать, но в своём корне service mesh — это про микросервисы, про взаимодействие между ними, про внутри компании. API Gateway это про вне компании. Когда мы выставляем свою айпишку наружу и хотим, чтобы к нам смог прийти условный рандомный разработчик. Поэтому в своем корне у service mesh фичи API Gateway нет, но современные реализации, тот же Istio Egress, это некоторый API Gаteway, но он немножко низкоуровневый. Потому что в API Gateway обычные фичи более высокоуровневые, чем то, что может позволить себе service mesh. Service mesh и API Gateway сосуществуют, у них есть некоторые пересечения, но решают они немножко разные проблемы.

Александр Лукьянченко: Кстати, по поводу терминологии, тут вопрос, что имеется в виду под API Gateway. Многие решения сейчас называют себя API Gateway, по факту являясь просто Proxy, которая настраивается гибко по правилам локейшенов, куда нужно проксировать дальше.

Иван Круглов: Оk, я под API Gateway понимаю классику жанра, не просто L7 proxy, а L7++, который умеет реализовывать бизнес-логику у себя на борту. Такого service mesh не умеет.

Марсель Ибраев: Как обеспечивается микросегментация и безопасность взаимодействия микросервисов в service mesh?

Иван Круглов: Обеспечивается она на уровне сертификатов. Еще вижу вопрос, дружит ли service mesh с сетевыми политиками? Они немножко связаны. Поясню, в чем разница. Сетевая политика — это L2, L3. А микросегментация service mesh — это L7, то есть на уровне, когда устанавливается TLS-соединение. И тут можно сделать прикольные политики. Если у вас микросервисам розданы правильные сертификаты, можно задавать гибкие политики. Например, этот сервис к этому может ходить, а к другому не может. Это не просто на уровне «вот этот ip-адрес сюда может ходить, а вот этот ip-адрес сюда не может ходить». Решение принимается на момент установки TLS-соединения.

Марсель Ибраев: Про сетевые политии, насколько я понимаю, здесь имеется ввиду по типу, как у Calico. Есть ли смысл вообще использовать их вместе с service mesh?

Иван Круглов: Смотрите, я такое не реализовывал, но если бы реализовывал, я бы про это размышлял следующим образом. Для меня сетевая политика это так называемая Coarse Grain Control — грубый контроль, когда вы хотите сделать так, что этот неймспейс или кластер в этот кластер ходить не может. Вот этот пул ip-адресов вот в этот пул ip-адресов ходить не может. Или с помощью сетевых политик я бы отделял дев от прода и от стейджинга. Такая грубая нарезка. mTLS-контроль в service mesh это более fine-grained, более тонкая настройка. Когда, например, в продакшене вы хотите разделить Data Flow: этому пользователю или сертификату можно ходить. Если у вас есть сертификат, выданный на пользователя, не на сервис, а на пользователя, то можно говорить, пройдет ли этот конкретный запрос на уровне пользователя или нет. Такой fine-grained tuning.

Александр Лукьянченко: Я бы ещё добавил, что отличие — возможно — в уровне безопасности. Потому что надо понимать, что если service mesh раскатан неполноценно, то политики не везде будут работать. Например, есть возможность тонко затюнить, какие именно запросы, какие именно коннекты перехватываются на Envoy-proxy, какие не перехватываются. И если у нас под mesh не вся инфраструктура, не весь проект, то, очевидно, политики в этих местах работать не будут. Здесь нужно контролировать, какую часть мы реально покрываем. В случае с Calico network policies, если мы используем Kubernetes уже для всей инфраструктуры, то это решение, которое гарантированно на ноды раскатит определенные политики. В этом плане есть отличия. Они несколько на разных уровнях действуют.

Марсель Ибраев: Мы уже частично отвечали на этот вопрос. Есть ли альтернатива Envoy, учитывая, что service mesh это динамическая конфигурация?

Иван Круглов: Envoy основной, Linkerd — второй. И как Саша говорил, Ngnix и Haproxy подтягиваются. Не знаю, в каком состоянии подтягивания они находятся, но они движутся в этом направлении. Если вы не хотите заниматься экзотикой, то Envoy просто мейнстрим.
Service mesh