что такое istio openshift
Ликбез по запуску Istio
Istio Service Mesh
Мы в Namely уже год как юзаем Istio. Он тогда только-только вышел. У нас здорово упала производительность в кластере Kubernetes, мы хотели распределенную трассировку и взяли Istio, чтобы запустить Jaeger и разобраться. Service mesh так здорово вписалась в нашу инфраструктуру, что мы решили вложиться в этот инструмент.
Пришлось помучиться, но мы изучили его вдоль и поперек. Это первый пост из серии, где я расскажу, как Istio интегрируется с Kubernetes и что мы узнали о его работе. Иногда будем забредать в технические дебри, но не сильно далеко. Дальше будут еще посты.
Что такое Istio?
Istio — это инструмент конфигурации service mesh. Он читает состояние кластера Kubernetes и делает обновление до прокси L7 (HTTP и gRPC), которые реализуются как sidecar-ы в подах Kubernetes. Эти sidecar-ы — контейнеры Envoy, которые читают конфигурацию из Istio Pilot API (и сервиса gRPC) и маршрутизируют по ней трафик. С мощным прокси L7 под капотом мы можем использовать метрики, трассировки, логику повтора, размыкатель цепи, балансировку нагрузки и канареечные деплои.
Начнем с начала: Kubernetes
В Kubernetes мы создаем под c помощью деплоя или StatefulSet. Или это может быть просто «ванильный» под без контроллера высокого уровня. Затем Kubernetes изо всех сил поддерживает желаемое состояние — создает поды в кластере на ноде, следит, чтобы они запускались и перезапускались. Когда под создается, Kubernetes проходит по жизненному циклу API, убеждается, что каждый шаг будет успешным, и только потом наконец создает под на кластере.
Этапы жизненного цикла API:
Спасибо Banzai Cloud за крутую картинку.
Один из этапов — модифицирующие вебхуки допуска. Это отдельная часть жизненного цикла в Kubernetes, где ресурсы кастомизируются до коммита в хранилище etcd — источнике истины для конфигурации Kubernetes. И здесь Istio творит свою магию.
Модифицирующие вебхуки допуска
Когда под создается (через kubectl или Deployment ), он проходит через этот жизненный цикл, и модифицирующие вебхуки доступа меняют его, прежде чем выпустить в большой мир.
Во время установки Istio добавляется istio-sidecar-injector как ресурс конфигурации модифицирующих вебхуков:
Sidecar-поды
Sidecar-ы — это трюки нашего фокусника Istio. Istio так ловко все проворачивает, что со стороны это прямо магия, если не знать деталей. А знать их полезно, если вдруг надо отладить сетевые запросы.
Init- и прокси-контейнеры
В Kubernetes есть временные одноразовые init-контейнеры, которые можно запускать до основных. Они объединяют ресурсы, переносят базы данных или, как в случае с Istio, настраивают правила сети.
@jimmysongio нарисовал отличную схему связи между правилами iptables и прокси Envoy:
Envoy получает весь входящий и весь исходящий трафик, поэтому весь трафик вообще перемещается внутри Envoy, как на схеме. Прокси Istio — это еще один контейнер, который добавляется во все поды, изменяемые sidecar-инжектором Istio. В этом контейнере запускается процесс Envoy, который получает весь трафик пода (за некоторым исключением, вроде трафика из вашего кластера Kubernetes).
Процесс Envoy обнаруживает все маршруты через Envoy v2 API, который реализует Istio.
Envoy и Pilot
У самого Envoy нет никакой логики, чтобы обнаруживать поды и сервисы в кластере. Это плоскость данных и ей нужна плоскость контроля, чтобы руководить. Параметр конфигурации Envoy запрашивает хост или порт сервиса, чтобы получить эту конфигурацию через gRPC API. Istio, через свой сервис Pilot, выполняет требования для gRPC API. Envoy подключается к этому API на основе sidecar-конфигурации, внедренной через модифицирующий вебхук. В API есть все правила трафика, которые нужны Envoy для обнаружения и маршрутизации для кластера. Это и есть service mesh.
Обмен данными «под Pilot»
Pilot подключается к кластеру Kubernetes, читает состояние кластера и ждет обновлений. Он следит за подами, сервисами и конечными точками в кластере Kubernetes, чтобы потом дать нужную конфигурацию всем sidecar-ам Envoy, подключенным к Pilot. Это мост между Kubernetes и Envoy.
Из Pilot в Kubernetes
Когда в Kubernetes создаются или обновляются поды, сервисы или конечные точки, Pilot узнает об этом и отправляет нужную конфигурацию всем подключенным экземплярам Envoy.
Какая конфигурация отправляется?
Какую конфигурацию получает Envoy от Istio Pilot?
По умолчанию Kubernetes решает ваши сетевые вопросы с помощью sevice (сервис), который управляет endpoint (конечные точки). Список конечных точек можно открыть командой:
Это список всех IP и портов в кластере и их адресатов (обычно это поды, созданные из деплоя). Istio важно это знать, чтобы настраивать и отправлять данные о маршрутах в Envoy.
Сервисы, прослушиватели и маршруты
Когда вы создаете сервис в кластере Kubernetes, вы включаете ярлыки, по которым будут выбраны все подходящие поды. Когда вы отправляете трафик на IP сервиса, Kubernetes выбирает под для этого трафика. Например, команда
Istio и Envoy слегка меняют эту логику. Istio настраивает Envoy на основе сервисов и конечных точек в кластере Kubernetes и использует умные функции маршрутизации и балансировки нагрузки Envoy, чтобы обойти сервис Kubernetes. Вместо проксирования по одному IP Envoy подключается прямо к IP пода. Для этого Istio сопоставляет конфигурацию Kubernetes с конфигурацией Envoy.
Термины Kubernetes, Istio и Envoy немного отличаются, и не сразу понятно, что с чем едят.
Сервисы
Все те же сервисы есть в этом пространстве имен:
Как Istio узнает, какой протокол использует сервис? Настраивает протоколы для манифестов сервисов по полю name в записи порта.
Если использовать kubectl и админскую страницу переадресации портов в Envoy, видно, что конечные точки account-grpc-public реализуются Pilot как кластер в Envoy с протоколом HTTP2. Это подтверждает наши предположения:
Порт 15000 — это админская страница Envoy, доступная в каждом sidecar.
Прослушиватели
Прослушиватели узнают конечные точки Kubernetes, чтобы пропускать трафик в поды. У сервиса проверки адреса здесь одна конечная точка:
Поэтому у пода проверки адреса один прослушиватель на порте 50051:
Маршруты
В Namely мы используем Istio Ingress-Gateway для всего внутреннего GRPC-трафика:
Если переадресовать порт пода Istio-IngressGateway и посмотреть конфигурацию Envoy, мы увидим, что делает VirtualService:
Что мы гуглили, копаясь в Istio
Возникает ошибка 503 или 404
Причины разные, но обычно такие:
Что означает NR/UH/UF в логах прокси Istio?
По поводу высокой доступности с Istio
Почему Cronjob не завершается?
Когда основная рабочая нагрузка выполнена, sidecar-контейнер продолжает работать. Чтобы обойти проблему, отключите sidecar в cronjobs, добавив аннотацию sidecar.istio.io/inject: “false” в PodSpec.
Как установить Istio?
Спасибо Bobby Tables и Michael Hamrah за помощь в написании поста.
Istio
Что такое Istio?
Istio — это настраиваемая сервисная сетка (service mesh) с открытым исходным кодом, служащая для взаимодействия, мониторинга и обеспечения безопасности контейнеров в кластере Kubernetes. На момент написания этого документа Istio поддерживает только Kubernetes, однако благодаря его открытому исходному коду любой может написать расширения, позволяющие Istio работать с любым кластерным ПО. Здесь рассмотрен основной на данный момент сценарий использования Istio в контексте Kubernetes.
Kubernetes — это инструмент для управления контейнерами, базовой единицей которого является узел. Узел состоит из одного или нескольких контейнеров, а также файловых систем и других компонентов. Архитектура микросервисов может состоять из десятков различных узлов, представляющих разные микросервисы. Kubernetes управляет доступностью и потреблением ресурсов узлов, добавляя поды по мере необходимости с помощью функции автоматического масштабирования. Istio добавляет контейнеры в под для обеспечения безопасности, управляемости и мониторинга.
Являясь проектом с открытым исходным кодом, Istio может работать в любой поддерживающей его общедоступной облачной среде и любой частной облачной среде, администратор которой сочтет целесообразным его использование.
Объяснение основных принципов работы Istio можно найти в следующем видеоролике (5:13):
Сетка для сетевых сервисов
После внедрения микросервисов организации требуется поддерживать десятки или сотни отдельных приложений. Если управлять всеми конечными точками по отдельности, нужно поддерживать большое число виртуальных машин с учетом текущих потребностей. Кластерное ПО, такое как Kubernetes, может создавать поды и масштабировать их, однако Kubernetes не поддерживает маршрутизацию, правила управления трафиком и сложные инструменты мониторинга и отладки.
И здесь на помощь приходит сервисная сетка.
По мере роста числа сервисов стремительно растет и количество потенциальных каналов взаимодействия. У двух сервисов существует только два канала взаимодействия. У трех служб их шесть, а у 10 служб — 90. Сервисная сетка предоставляет универсальный способ настроить эти каналы взаимодействия, создав политику взаимодействия.
Сервисная сетка дополняет возможности сервисов и направляет трафик в соответствии с предопределенной конфигурацией. Это значит, что администратору не нужно настраивать работающий контейнер (или писать код для этого), а достаточно предоставить конфигурацию сервисной сетке, чтобы она сделала все необходимое. Раньше аналогичным образом были устроены веб-серверы и взаимодействия между службами.
Обычно для этого в кластере используется техника sidecar. Sidecar — это добавляемый в под контейнер, который обеспечивает маршрутизацию трафика между сервисами и контейнерами и наблюдение за ним.
Istio и Kubernetes
Как упоминалось выше, Istio работает поверх Kubernetes, добавляя контейнеры, которые по сути невидимы для программиста или администратора. Они называются sidecar-контейнерами и выступают в роли «посредника», который направляет трафик и отслеживает взаимодействие компонентов. Действуя совместно, они дают тройной эффект: настройка, мониторинг и управление.
Настройка
Мониторинг
Istio позволяет легко отслеживать состояние приложений, работающих в среде Kubernetes. Istio обладает более широкими возможностями для отслеживания работы кластера и узлов, чем Kubernetes, позволяя управлять состоянием приложений и визуализировать его.
Управление
Поскольку интерфейс Istio по сути аналогичен интерфейсу Kubernetes, для управления им не нужно прикладывать почти никаких дополнительных усилий. Istio позволяет пользователям создать политики, которые действуют для всего кластера Kubernetes и управляют его работой, позволяя тратить меньше времени на управление каждым кластером и сил на написание кода.
Преимущества
Основные преимущества сервисной сетки заключаются в том, что она предоставляет улучшенные возможности для отладки, мониторинга, маршрутизации, обеспечения безопасности и распределения нагрузки. Благодаря этому Istio упрощает управление обширными наборами сервисов.
Улучшенная отладка
Предположим, что у сервиса есть несколько зависимостей. Сервис pay_claim в страховой компании вызывает сервис deductible_amt, который вызывает сервис is_member_covered service, и так далее. Сложная цепочка зависимостей может состоять из 10 или 12 вызовов сервисов. Если в любом из 12 сервисов произойдет сбой, это по цепочке вызовет сбой остальных сервисов, в результате чего возникнет одна из ошибок с кодом 500 или 400, либо приложение перестанет отвечать.
Для отладки такой группы вызовов можно использовать что-то похожее на трассировку стека. Разработчики клиентской части системы могут узнать, какие элементы и в каком порядке извлекаются из веб-серверов, и изучить их. Такие программисты могут использовать каскадную диаграмму в качестве полезного инструмента отладки.
Но в этом примере не видно, что происходит внутри ЦОД, а именно как callback=parselLotamaAudiences вызывает четыре остальные веб-службы, и какая из них отвечает слишком медленно. Позднее вы узнаете о том, какие инструменты предоставляет Istio для трассировки вызовов функций с помощью похожей диаграммы.
Мониторинг и наблюдаемость
Специалистам по DevOps и ИТ-администраторам могут требоваться средства наблюдения за трафиком, позволяющие отслеживать задержку, время обслуживания, долю ошибок в трафике и другие показатели. Как правило, им удобно, чтобы все это отображалось на сводной панели. Сводная панель должна показывать итоговые или средние значения этих показателей и, желательно, предоставлять возможность делать разбивку значений по узлам, сервисам или подам. В Kubernetes нет таких встроенных возможностей.
Политика
По умолчанию Kubernetes позволяет каждому поду отправлять трафик во все остальные поды. Istio позволяет администраторам создать политику, определяющую, какие сервисы могут работать друг с другом. Например, можно разрешить сервисам вызывать только те сервисы, от которых они действительно зависят. Примером другой политики, помогающей обеспечить бесперебойную работу сервиса, является ограничение скорости передачи, позволяющее предотвратить «захлебывание» сервиса и блокировать атаки типа «Отказ в обслуживании».
Маршрутизация и распределение нагрузки
По умолчанию Kubernetes обеспечивает распределение нагрузки карусельным методом. Если микросервис предоставляется шестью подами, Kubernetes будет использовать распределитель нагрузки или «сервис», поочередно отправляющий запросы каждому поду по кругу. Однако иногда в рабочей среде может быть развернуто несколько версий одного сервиса.
Простейшим примером может быть стратегия сине-зеленого развертывания. В этом случае программное обеспечение может ввести в эксплуатацию полностью новую версию приложения, не перенаправляя на нее конечных пользователей. Введя в строй новую версию, компания может сохранить старые серверы, чтобы иметь возможность быстро переключиться на них в случае сбоя.
Благодаря Istio, этот процесс становится не сложнее использованию тегов в файле конфигурации. Администраторы могут определять тип сервиса, к которому следует подключаться, с помощью меток, и создавать правила на основе заголовков. Таким образом, к примеру, пользователи бета-версии могут направляться в «канареечный» под с новейшей сборкой, а обычные пользователи могут использовать стабильно работающую текущую сборку.
Разрыв цепочки
Если сервис перегружен или перестал работать, все последующие запросы не будут выполняться, но будут повышать загруженность системы. Благодаря тому что Istio отслеживает ошибки и задержки, он может принудительно прерывать работу сервиса, давая ему возможность восстановиться, после определенного числа запросов, указанного в политике. Для того чтобы применять эту политику в масштабах всего кластера, достаточно создать компактный текстовый файл и проинструктировать Istio использовать его в качестве новой политики.
Безопасность
Istio обеспечивает идентификацию, применение политик и шифрование по умолчанию, а также аутентификацию, авторизацию и аудит (AAA). Любые работающие под его управлением поды взаимодействуют с другими подами, используя зашифрованный трафик, защищенный от внешнего наблюдения. Служба идентификации в сочетании с шифрованием гарантирует, что ни один неавторизованный пользователь не может подделать вызов сервиса. AAA предоставляет специалистам по безопасности и эксплуатации необходимые инструменты мониторинга, сопряженные с меньшими накладными расходами.
Упрощенное администрирование
Предлагаемые Istio политики, средства идентификации и инструменты безопасности подходят и для традиционных приложений. Обычно их программисты и администраторы работают с не тем уровнем абстракции, повторно реализуя одни и те же правила обеспечения безопасности для каждого сервиса. Istio позволяет им перейти на нужный уровень, чтобы настроить политику для всего кластера через единую панель управления. Вместе с тем, для использования описанных ниже средств управления доступом, сводных панелей и инструментов отладки Istio можно добавить встраиваемый модуль, чтобы работать с ними через командную строку, а не веб-страницу.
Примеры
Визуализация сервисов
В Istio 1.1 предусмотрено новое дополнение Kiali, обеспечивающее визуализацию через веб-интерфейс. Его можно использовать для отслеживания запросов к сервису, детализации информации и экспорта хронологии запросов в формате JSON, позволяющем запросить нужную информацию и отформатировать ее необходимым способом. Приведенный ниже граф представляет собой создаваемую в режиме реального времени диаграмму зависимостей, отражающую фактически зависимости сервисов друг от друга. Он генерируется на основе фактических наблюдений за трафиком.
Трассировка вызовов сервисов
Входящий в состав Istio сервис Jaeger обеспечивает трассировку любого сервиса. В этом примере выполняется трассировка страницы продукта. Любая точка на первом рисунке представляет вызов сервиса. Щелкнув на точке, можно раскрыть каскадную диаграмму для отслеживания фактических запросов и ответов сервисов.
Также можно более детально изучить страницу продукта. Видно, что ошибки содержатся в самой странице продукта — сведения об этом успешно возвращены.
Сводные панели
Istio поставляется со многими готовыми сводными панелями для мониторинга состояния и производительности системы. Они содержат такие показатели, как использование оперативной памяти и процессора, запрос на трафик, количество ошибок с кодами 400 и 500, время выполнения запросов и многое другое. Для работы с ними достаточно установить и запустить Istio и добавить Grafana — один из входящих в комплект поставки Istio инструментов создания сводных панелей с открытым исходным кодом. В дополнение к этому Istio предоставляет еще две сводные панели: Kiali и Jaeger.
Istio в сравнении с Envoy
Istio использует значительно дополненную версию Envoy для обеспечения мониторинга, управления и ведения журнала. Отслеживается каждый под, а Istio объединяет информацию обо всех подах и предоставляет ее. Вместо того чтобы использовать Istio, можно было бы развернуть Envoy в кластере Kubernetes и написать код управления. Но по сути для этого потребовалось бы написать аналог Istio с теми рисками и затратами, которые обычно связаны с разработкой нестандартного проекта.
Учебники
На веб-сайте Istio (внешняя ссылка) содержится множество полезной документации и инструкций по началу работы с Istio.
Istio и IBM
Managed Istio поставляется в составе IBM Cloud Kubernetes Service. В рамках данной услуги предоставляются установка Istio, автоматические обновления, управление жизненным циклом компонентов среды контроля и интеграция с инструментами ведения журналов и мониторинга платформы. Добавьте управляемую интеграцию Istio к своим новым или имеющимся кластерам и возьмите свои микросервисы под контроль. Для того чтобы больше узнать о Knative, обратитесь к публикации «Knative: краткое руководство».
Для того чтобы узнать о том, как управляемая среда Kubernetes может облегчить переход в облачную среду, посмотрите наш видеоролик «Преимущества управляемой среды Kubernetes»:
Для того чтобы узнать о лучших методах организовать и ускорить развертывание контейнеров в рабочей среде, изучите отчет «Практические рекомендации по применению контейнеров и Kubernetes в рабочей среде».
Узнайте, как сервисные сетки могут помочь управлять взаимодействием между сервисами в вашем приложении, в практическом руководстве «Istio для начинающих: начало работы с сервисной сеткой» (PDF, 4,1 МБ).
Если вы уже готовы приступить к использованию IBM Cloud, зарегистрируйтесь здесь.
Что ждать от внедрения Istio? (обзор и видео доклада)
Istio — частный случай «сервисной сетки» (Service Mesh), понятия, о котором наверняка все слышали, и многие даже знают, что это такое. Мой доклад на Kuber Conf 2021 (мероприятие Yandex.Cloud, которое проходило 24 июня в Москве) посвящен возможным проблемам, к которым надо готовиться при внедрении Istio. Среди прочего я рассказал о том, как Istio влияет на трафик, какие есть возможности для его мониторинга, насколько безопасен mTLS.
Доклад отчасти отражает наш опыт работы с Istio как с одним из компонентов Kubernetes-платформы Deckhouse, отчасти основан на результатах внутренних нагрузочных тестов.
30 минут) и основную выжимку в текстовом виде.
Что такое Service Mesh
Для начала синхронизируем понимание, что такое Service Mesh.
Допустим, у вас есть приложение, оно живет своей жизнью, развивается. Вы нанимаете новых программистов, от бизнеса поступают новые задачи. Нормальная эволюция.
При этом объемы сетевого трафика растут, и в этой ситуации вы просто не можете не столкнуться с задачами по его управлению. Разберем эти задачи подробнее.
Типовая сетевая задача №1
Возьмем небольшой кусочек архитектуры — фронтенд и бэкенд. С точки зрения кластера он выглядит как две группы Pod’ов, которые общаются друг с другом.
Предположим, одному из Pod’ов стало плохо — не терминально, но приложение глючит. Health check’и в Kubernetes этого не замечают: сохраняют Pod в балансировке, и трафик на него продолжает поступать. От этого становится только хуже.
Было бы здорово выявлять эти пограничные состояния, когда вроде бы почти всё окей, но все-таки что-то идет не так. А выявив — дать нашему Pod’у отдохнуть, временно перенаправив трафик на другие Pod’ы. Такой подход называется circuit breaking.
Типовая сетевая задача №2
Вы написали новую версию бэкенда, прошли все тесты, на stage бэкенд показал себя хорошо. Но прежде, чем катить его в production, хорошо бы обкатать на настоящем трафике. То есть выделить группу пользователей для новой версии бэкенда и протестировать его на этой группе.
Если тесты прошли успешно — выкатываем бэкенд в production и обновляем все Pod’ы. Такая стратегия деплоя называется canary deployment. (Подробнее о разных стратегиях деплоя в Kubernetes мы писали здесь.)
Типовая сетевая задача №3
Например, ваш кластер развернут в публичном облаке. Из соображений отказоустойчивости вы «размазали» Pod’ы по разным зонам. При этом фронтенд- и бэкенд-Pod’ы общаются друг с другом беспорядочно, не обращая внимание на зоны. В мире облачных платформ такое беспорядочное общение не будет для вас бесплатным. Например, в AWS это выльется в дополнительные финансовые расходы, в Яндекс.Облаке — в дополнительный latency.
Нужно сделать так, чтобы фронтенды выбирали такие бэкенды, которые находятся в их зоне, а остальные бэкенды оставались бы для них «запасными». Такой способ маршрутизации называется locality load balancing.
Решаем сетевые задачи систематически
Подобные задачи по управлению сетевым трафиком можно перечислять ещё долго и каждый хотя бы раз сталкивался хотя бы с одной из них. Безусловно, у каждой из задач есть решение, которое можно реализовать на уровне приложения. Но проблема в том, что среднестатистическое приложение состоит из множества компонентов, или «шестеренок». И все они разные, к каждой нужен свой подход.
Именно для систематического решения подобных задач и придумали Service Mesh.
Service Mesh дает набор «кирпичей», из которых мы можем собирать собственные паттерны управления сетью. По-другому: Service Mesh — это фреймворк для управления любым TCP-трафиком с собственным декларативном языком. А в качестве бонуса Service Mesh предлагает дополнительные возможности для мониторинга (observability).
Благодаря Service Mesh вам не нужно задумываться о нюансах сетевого взаимодействия на уровне отдельных компонентов.
Вы можете рассматривать ваше приложение просто как дерево компонентов с очень примитивными связями. А все нюансы вынести за скобки и описать их с помощью Service Mesh.
Как это работает
Представим, что мы — большие любители «велосипедов»: мы не ищем готовые решения, потому что любим писать свои. И мы решили написать свой Service Mesh — supermesh.
Предположим, у нас есть приложение. Оно принимает запросы, генерирует новые — вот этим трафиком мы и хотим управлять. Но чтобы им управлять, нам нужно его перехватить. Для этого:
проникаем в сетевое окружение приложения;
внедряем туда наш перехватчик;
DNAT’ом перенаправляем на него входящий и исходящий трафик.
Поскольку мы работаем с Kubernetes, наше приложение «живет» в Pod’e, то есть внутри контейнера. Это значит, что мы для удобства можем «подселить» к приложению наш перехватчик в качестве sidecar-контейнера.
Теперь с этим перехваченным трафиком нужно что-то сделать, как-то его модифицировать. Очевидное решение — использовать прокси (например, nginx, HAProxy или Envoy).
Мы можем написать и свой прокси, но мы не настолько велосипедисты, поэтому остановимся на Envoy. Он хорошо вписывается в эту архитектуру, потому что умеет конфигурироваться удаленно, «на лету», и у него есть множество готовых удобных API.
В итоге мы можем перехватить трафик и влиять на него. Осталось сделать с ним что-то полезное, то есть реализовать какой-то из упомянутых выше паттернов управления — причем не абы какой, а такой, который выберет разработчик нашего приложения.
Мы могли бы передать разработчику «пульт управления» нашими sidecar’ами, чтобы он сам настраивал все нюансы. Но изначально вроде бы не этого хотели: нам нужна систематизация.
Очевидно, что нам не хватает какого-то промежуточного компонента — условного контроллера (supermeshd), который взял бы на себя управление, а разработчику предоставил декларативный язык, с помощью которого тот строил бы свои стратегии.
Теперь мы можем взять от разработчика набор паттернов, которые он хочет, а контроллер будет бегать по sidecar’ам и настраивать их. В мире Service Mesh такой контроллер называется Control Plane, а sidecar’ы с нашим перехватчиком — Data Plane.
Именно по такому принципу — естественно, с большими допущениями — и работает большинство реализаций Service Mesh: Kuma, Istio, Linkerd и пр.
В этом докладе я рассматриваю только Istio и делаю это «без объяснения причин». Кстати, согласно прошлогоднему опросу CNCF, это самое популярное Service Mesh-решение, которое используется в production.
Перед внедрением Istio к нему сразу же возникает ряд вопросов:
Как он повлияет на приложение? А на кластер?
Какие у него возможности по observability?
Надежен ли его Mutual TLS?
Как правильно засетапить Istio? А обновить?
Что, если что-то сломается?
Конечно, вопросов гораздо больше. Постараюсь ответить хотя бы на некоторые из них.
Как Istio влияет на приложение
Раньше, когда не было Istio, всё было просто и прозрачно: пользователь генерирует запрос, фронтенд генерирует дочерний запрос к бэкенду.
Как только появляется Istio, схема усложняется:
По сравнению с чистой инсталляцией «хопов» стало гораздо больше. Понятно, что это не может быть бесплатным. И самая очевидная цена — это latency.
Разработчики Istio обещают, что задержка не будет превышать 2,65 мс. Мне эти цифры показались не очень убедительными, поэтому я решил сделать свои замеры.
Нагрузочное тестирование
Для начала я написал примитивное клиент-серверное приложение. В качестве клиента использовал утилиту для нагрузочного тестирования k6, а в качестве сервера — nginx, который просто отдает статичные файлы. k6 отправляла по 10 тыс. запросов с предварительным прогревом в сторону сервера. Важно: клиент и сервер работали на разных узлах, чтобы не мешать друг другу.
Из этого приложения я собрал несколько вариантов инсталляции:
«чистую» схему, без Istio и всяких sidecar’ов;
сетап с Envoy в качестве sidecar’а;
сетап, в котором просто включен Istio;
еще один сетап с Istio, в котором задействованы 1000 правил авторизации — чтобы понять, влияют ли какие-то дополнительные правила на задержку, и как именно.
Что еще я посчитал важным сделать:
отключил логи на sidecar’ах;
включил сбор метрик sidecar’ах Istio;
использовал разные версии TLS;
включал и выключал HTTP/2;
включал и выключал keepalive на стороне клиента и между sidecar’ами;
использовал JSON-файлы трех размеров: 500Б, 200КБ, 1,7МБ;
экспериментировал с многопоточностью.
В итоге получилось 252 теста. Попробуем оценить собранные метрики.
1. Классический сценарий: примитивный клиент отправляет запросы серверу в один поток и не умеет держать keepalive.
Посмотрим на картину задержек:
Самый первый и очевидный вывод: действительно, перехват трафика не бесплатен. Причем в случае с Envoy в качестве sidecar’а и «тяжелым» файлом мы видим пятикратный рост задержки.
Уровень драматичности снижается, если мы посмотрим на полный round-trip (RTD) запроса. В самом худшем случае мы увидим троекратный оверхэд. А в некоторых случаях он почти не заметен:
Важно учитывать, что в моем случае естественный фон задержки у бэкенда крайне мал — 0,23 мс. В этом случае прирост в 2 мс кажется огромным — 800%. Но если у вас более сложный бэкенд, у которого задержка составляет десятки мс, то эти лишние 2 мс вы не заметите.
Второй вывод: по сравнению с «голым» Envoy’ем Istio все-таки дает небольшие накладные расходы. Возможно, это связано со сбором метрик и это стоит учитывать.
Третий вывод: правила авторизации, как и любые другие дополнительные настройки Istio, влияют на latency. Но это тоже не должно смущать, т. к. в реальной жизни вряд ли кому-то понадобится тысяча дополнительных правил.
Четвертый вывод: рост задержки при росте размера файла. Здесь задержка растет так же предсказуемо, и все пропорции по сравнению с «голой» инсталляцией сохраняются. То есть можно считать, что объем данных, которые мы прогоняем через Istio, на задержку не влияет.
2. Сценарий с шифрованием Mutual TLS
Результаты оказались везде более-менее одинаковыми, поэтому я покажу их на примере одной инсталляции, когда просто включен Istio:
Да, влияние есть. Но, опять же, это «копейки», которые можно не учитывать. Так что шифрование можно смело включать.
3. Любопытные наблюдения
Они не связаны напрямую с Istio, но я подумал, что ими не помешает поделиться.
Я решил: а что, если включить keepalive на клиентах? Не выиграю ли я в задержке? Потому что, во-первых, handshakes. Во-вторых, sidecar’ам надо будет поменьше думать.
Результаты покажу на примере того же сетапа с Istio:
Выигрыш хоть и небольшой, но есть. Мелочь, а приятно!
А что, если еще включить многопоточность. И вот тут я расстроился: при тестах на «средневесе» и «тяжеловесе» задержка выросла.
Разбираясь с этой проблемой, я нашел убедительное объяснение в статье блога Cloudflare, почему keepalive — это не всегда хорошо.
Итак, два главных вывода о влиянии Istio на приложение:
перехват трафика не бесплатен — можно смело закладывать накладные расходы по задержке порядка 2,5 мс;
если ваша естественная задержка измеряется в десятках и сотнях мс, лишние 2,5 мс вы не заметите.
Как Istio влияет на кластер
У нашего Istio, как и у supermeshd, который мы ранее реализовали сами, тоже есть Control Plane. Называется он istiod, и это отдельный контроллер, который работает в кластере.
Также у Istio есть свой декларативный язык, с помощью которого можно строить паттерны по управлению сетью. Технически язык представляет собой набор ресурсов Kubernetes, за которыми istiod пристально следит. Еще он следит за набором системных ресурсов: Namespace’ами, Pod’ами, узлами и т. д. В этом смысле контроллер Istio ничем не отличается от любого другого контроллера или оператора. И на практике никаких проблем с ним мы не выявили. Можем идти дальше.
Observability
У Istio есть интеграция со сторонними инструментами для мониторинга. Например, с дашбордом Kiali, с помощью которого можно визуализировать приложение в виде графа, рассмотреть отдельные связи компонентов, как они устроены, что у них «болит» и т. д.
Есть хороший набор дашбордов для графиков Grafana.
Istio также предоставляет базовые возможности для внедрения трассировки на основе Jaeger.
К сожалению, ничего из этого у вас не заработает «из коробки». Для Kiali и Grafana нужно будет установить Prometheus (и саму Grafana). В случае с трассировкой придется, как минимум, установить где-то Jaeger, а как максимум — научить ваше приложение грамотно обрабатывать HTTP-заголовки со служебными данными от трассировки.
Безопасность (Mutual TLS)
Напомню, протокол Mutual TLS (mTLS) — это взаимная, или двусторонняя, аутентификация клиента и сервера. Он нужен, когда мы хотим, чтобы наши клиент и сервер достоверно знали друг друга, не общались со всякими «незнакомцами». Также mTLS нужен, когда мы хотим зашифровать трафик между нашими приложениями. Технически это достигается с помощью обычных SSL-сертификатов.
В мире Istio у каждого Pod’а есть сертификат, который подтверждает подлинность этого Pod’а, а именно — подлинность его идентификатора (ID). В терминологии Istio идентификатор — это principal. Он состоит из трех частей:
ID кластера (Trust Domain),
ServiceAccount’а, под которым работает Pod.
За выпуск сертификатов отвечает Control Plane, на основе собственного корневого сертификата. У каждой инсталляции Istio есть собственный корневой сертификат — root CA (его не стоит путать с корневым сертификатом самого кластера). На основе корневого сертификата выпускаются индивидуальные.
Давайте разберём весь жизненный цикл индивидуального сертификата.
Envoy в Istio не общается напрямую с Control Plane: он это делает через посредника, который называется Istio agent — утилита, написанная на Go, которая живет в одном контейнере с Envoy. Этот агент отвечает за ротацию сертификатов.
Istio-agent генерирует CSR с заявкой на ID (principal), который полагается нашему Pod’у. Но сначала этот ID нужно как-то сгенерировать. С Trust Domain всё просто: агент знает, в каком кластере работает Pod (переменная в ENV). С Namespace’ом и ServiceAccount’ом чуть сложнее…
Но вообще: что такое ServiceAccount? Остановимся на этом чуть подробнее.
ServiceAccount
У Kubernetes есть свой API, который подразумевает, что с ним никто анонимно общаться не будет. С другой стороны, API подразумевает, что к нему будут общаться Pod’ы. Рядовым приложениям это, как правило, не нужно: обычно с API Kubernetes общаются контроллеры, операторы и т. п. И чтобы решить этот вопрос, придумали специальные учетные записи, которые называются ServiceAccount.
ServiceAccount — это примитивный ресурс в K8s, который в момент создания никакой информации не несет. Он просто существует в каком-то Namespace’е, с каким-то именем. Как только такой ресурс появляется в кластере, Kubernetes на это реагирует и выпускает JWT-токен. Этот токен целиком описывает появившийся ServiceAccount. То есть Kubernetes подтверждает: «в моем кластере, в таком-то Namespace’е, с таким-то именем есть ServiceAccount» — и выдает специальный токен, который складывает в Secret ( mysa-token-123 ).
Secret привязывается к ServiceAccount’у, который тем самым становится чем-то вроде ресурса со свидетельством о рождении. Данный ServiceAccount можно «привязать» к любому Pod’у, после чего, в ФС Pod’а будет автоматически примонтирован Secret с токеном, причем по заранее известному пути ( /run/secret/kubernetes.io/serviceaccount/token ). Собственно, данный токен и пригодится нам для того, чтобы узнать Namespace, в котором мы работаем, и ServiceAccount, от имени которого мы работаем.
Мы сгенерировали principal — теперь можем положить его в CSR.
Полученный CSR мы можем отправить в istiod. Но чтобы istiod поверил, что мы — это мы, в дополнение отправляем токен. Далее istiod проверяет этот токен через API K8s ( TokenReview ). Если K8s говорит, что всё хорошо, istiod подписывает CSR и возвращает в sidecar.
Для каждого Pod’а ротация сертификатов происходит раз в сутки.
Чтобы что-то взломать в этой системе, можно:
украсть сертификат (он будет действовать не более суток);
украсть токен ServiceAccount’а Pod’а, чтобы заказывать сертификаты от имени этого Pod’а;
взломать API Kubernetes — тогда можно заказать сколько угодно токенов, от имени какого угодно Pod’а;
украсть корневой сертификат Control Plane — самый примитивный и опасный взлом.
Всё это на самом деле довольно сложно реализовать. Поэтому можем считать, что mTLS в Istio безопасен.
Другие вопросы к Istio
К сожалению, осталось еще много вопросов, не раскрытых в докладе. И по каждому из этих вопросов достаточно много нюансов. Порой эти нюансы либо очень плохо описаны в документации, либо не описаны вовсе — приходится ковыряться в коде и обращаться к разработчикам Istio.
Множество из этих нюансов мы учли в модуле Istio для нашей платформы Deckhouse. С ее помощью вы можете за 8 минут развернуть готовый к использованию Kubernetes-кластер на любой инфраструктуре: в облаке, на «голом железе», в OpenStack и т. д.
Подробнее познакомиться с функциями, которые решает Istio в рамках Deckhouse, можно в нашей документации.