Задачи, которые решает Istio

Istio — фреймворк централизованного управления сетевым трафиком, реализующий подход Service Mesh.

В частности, Istio прозрачно решает для приложений следующие задачи:

Рекомендуем ознакомиться с видео, где мы обсуждаем архитектуру Istio и оцениваем накладные расходы.

Mutual TLS

Данный механизм — это главный метод взаимной аутентификации сервисов. Принцип основывается на том, что при всех исходящих запросах проверяется серверный сертификат, а при входящих — клиентский. После проверок, sidecar-proxy получает возможность идентифицировать удалённый узел и использовать эти данные для авторизации, либо в прикладных целях.

Каждый сервис получает собственный идентификатор в формате <TrustDomain>/ns/<Namespace>/sa/<ServiceAccount>, где TrustDomain в нашем случае — это домен кластера. Каждому сервису можно выделять собственный ServiceAccount или использовать стандартный “default”. Полученный идентификатор сервиса можно использовать как в правилах авторизации, так и в прикладных целях. Именно этот идентификатор используется в качестве удостоверяемого имени в TLS-сертификатах.

Данные настройки можно переопределить на уровне Namespace.

Авторизация

Управление авторизацией осуществляется с помощью ресурса AuthorizationPolicy. В момент, когда для сервиса создаётся этот ресурс, начинает работать следующий алгоритм принятия решения о судьбе запроса:

  • Если запрос попадает под политику DENY — запретить запрос.
  • Если для данного сервиса нет политик ALLOW — разрешить запрос.
  • Если запрос попадает под политику ALLOW — разрешить запрос.
  • Все остальные запросы — запретить.

Иными словами, если явно что-то запретить, то работает только запрет. Если же что-то явно разрешить, то будут разрешены только явно одобренные запросы (запреты, при этом, имеют приоритет).

Для написания правил авторизации можно использовать аргументы:

  • идентификаторы сервисов и wildcard на их основе (mycluster.local/ns/myns/sa/myapp или mycluster.local/*),
  • namespace,
  • диапазоны IP,
  • HTTP-заголовки,
  • JWT-токены из прикладных запросов.

Маршрутизация запросов

Основной ресурс для управления маршрутизацией — VirtualService, он позволяет переопределять судьбу HTTP или TCP-запроса. Доступные аргументы для принятия решения о маршрутизации:

  • Host и любые другие заголовки,
  • URI,
  • метод (GET, POST и пр.),
  • лейблы Pod’а или namespace источника запросов,
  • dst-IP или dst-порт для не-HTTP запросов.

Управление балансировкой запросов между Endpoint-ами сервиса

Основной ресурс для управления балансировкой запросов — DestinationRule, он позволяет настроить нюансы исходящих из Pod’ов запросов:

  • лимиты/таймауты для TCP,
  • алгоритмы балансировки между Endpoint-ами,
  • правила определения проблем на стороне Endpoint-а для выведения его из балансировки,
  • нюансы шифрования.

Важно! Все настраиваемые лимиты работают для каждого Pod’а клиента по отдельности! Если настроить для сервиса ограничение на одно TCP-соединение, а клиентских Pod’а три, то сервис получит три входящих соединения.

Observability

Трассировка

Istio позволяет осуществлять сбор трейсов с приложений и инъекцию трассировочных заголовков если таковых нет. При этом важно понимать:

  • Если запрос инициирует на сервисе вторичные запросы, то для них необходимо наследовать трассировочные заголовки средствами приложения.
  • Jaeger для сбора и отображения трейсов потребуется устанавливать самостоятельно.

Grafana

В стандартной комплектации с модулем предоставлены дополнительные доски:

  • Доска для оценки производительности и успешности запросов/ответов между приложениями.
  • Доска для оценки работоспособности и нагрузки на control plane.

Kiali

Инструмент для визуализации дерева сервисов вашего приложения. Позволяет быстро оценить обстановку в сетевой связности благодаря визуализации запросов и их количественных характеристик непосредственно на схеме.

Архитектура кластера с включенным Istio

Компоненты кластера делятся на две категории:

  • control plane — управляющие и обслуживающие сервисы. Под control plane обычно подразумевают Pod’ы istiod.
  • data plane — прикладная часть Istio. Представляет собой контейнеры sidecar-proxy.

Архитектура кластера с включенным Istio

Все сервисы из data plane группируются в mesh. Его характеристики:

  • Общее пространство имён для генерации идентификатора сервиса в формате <TrustDomain>/ns/<Namespace>/sa/<ServiceAccount>. Каждый mesh имеет идентификатор TrustDomain, который в нашем случае совпадает с доменом кластера. Например: mycluster.local/ns/myns/sa/myapp.
  • Сервисы в рамках одного mesh имеют возможность аутентифицировать друг друга с помощью доверенных корневых сертификатов.

Элементы control plane:

  • istiod — ключевой сервис, обеспечивающий решение следующих задач:
    • Непрерывная связь с API Kubernetes и сбор информации о прикладных сервисах.
    • Обработка и валидация с помощью механизма Kubernetes Validating Webhook всех Custom Resources, которые связаны с Istio.
    • Компоновка конфигурации для каждого sidecar-proxy индивидуально:
      • Генерация правил авторизации, маршрутизации, балансировки и пр.
      • Распространение информации о других прикладных сервисах в кластере.
      • Выпуск индивидуальных клиентских сертификатов для организации схемы Mutual TLS. Эти сертификаты не связаны с сертификатами, которые использует и контролирует сам Kubernetes для своих служебных нужд.
    • Автоматическая подстройка манифестов, определяющих прикладные Pod’ы через механизм Kubernetes Mutating Webhook:
      • внедрение дополнительного служебного контейнера sidecar-proxy.
      • внедрение дополнительного init-контейнера для адаптации сетевой подсистемы (настройка DNAT для перехвата прикладного трафика).
      • перенаправление readiness и liveness-проб через sidecar-proxy.
  • operator — компонент, отвечающий за установку всех ресурсов, необходимых для работы control plane определённой версии.
  • kiali — панель управления и наблюдения за ресурсами Istio и пользовательскими сервисами под управлением Istio. Позволяет:
    • Визуализировать связи между сервисами.
    • Диагностировать проблемные связи между сервисами.
    • Диагностировать состояние control plane.

Для приёма пользовательского трафика требуется доработка Ingress-контроллера:

  • К Pod’ам контроллера добавляется sidecar-proxy, который обслуживает только трафик от контроллера в сторону прикладных сервисов (параметр IngressNginxController enableIstioSidecar у ресурса IngressNginxController).
  • Сервисы не под управлением Istio продолжают работать как раньше, запросы в их сторону не перехватываются сайдкаром контроллера.
  • Запросы в сторону сервисов под управлением Istio перехватываются сайдкаром и обрабатываются в соответствии с правилами Istio (подробнее о том, как активировать Istio для приложения).

Контроллер istiod и каждый контейнер sidecar-proxy экспортируют собственные метрики, которые собирает кластерный Prometheus.

Архитектура прикладного сервиса с включенным Istio

Особенности

  • Каждый Pod сервиса получает дополнительный контейнер — sidecar-proxy. Технически этот контейнер содержит два приложения:
    • Envoy — проксирует прикладной трафик и реализует весь функционал, который предоставляет Istio, включая маршрутизацию, аутентификацию, авторизацию и пр.
    • pilot-agent — часть Istio, отвечает за поддержание конфигурации Envoy в актуальном состоянии, а также содержит в себе кеширующий DNS-сервер.
  • В каждом Pod’е настраивается DNAT входящих и исходящих прикладных запросов в sidecar-proxy. Делается это с помощью дополнительного init-контейнера. Таким образом, трафик будет перехватываться прозрачно для приложений.
  • Так как входящий прикладной трафик перенаправляется в sidecar-proxy, то readiness/liveness-трафика это тоже касается. Подсистема Kubernetes, которая за это отвечает, не рассчитана на формирование проб в формате Mutual TLS. Для адаптации, все существующие пробы автоматически перенастраиваются на специальный порт в sidecar-proxy, который перенаправляет трафик на приложение в неизменном виде.
  • Для приёма запросов извне кластера, необходимо использовать подготовленный Ingress-контроллер:
    • Pod’ы контроллера аналогично имеют дополнительный контейнер sidecar-proxy.
    • В отличие от Pod’ов приложения, sidecar-proxy Ingress-контроллера перехватывает только трафик от контроллера к сервисам. Входящий трафик от пользователей обрабатывает непосредственно сам контроллер.
  • Ресурсы типа Ingress требуют минимальной доработки в виде добавления аннотаций:
    • nginx.ingress.kubernetes.io/service-upstream: "true" — Ingress-контроллер в качестве upstream будет использовать ClusterIP сервиса вместо адресов Pod’ов. Балансировкой трафика между Pod’ами теперь занимается sidecar-proxy. Используйте эту опцию только если у вашего сервиса есть ClusterIP.
    • nginx.ingress.kubernetes.io/upstream-vhost: "myservice.myns.svc" — sidecar-proxy Ingress-контроллера принимает решения о маршрутизации на основе заголовка Host. Без данной аннотации, контроллер оставит заголовок с адресом сайта, например Host: example.com.
  • Ресурсы типа Service не требуют адаптации и продолжают выполнять свою функцию. Приложениям всё так же доступны адреса сервисов вида servicename, servicename.myns.svc и пр.
  • DNS-запросы изнутри Pod’ов прозрачно перенаправляются на обработку в sidecar-proxy:
    • Требуется для разыменования DNS-имён сервисов из соседних кластеров.

Жизненный цикл пользовательского запроса

Приложение с выключенным Istio

Приложение с включенным Istio

Как активировать Istio для приложения

Основная цель активации — добавить sidecar-контейнер к Pod’ам приложения, после чего Istio сможет управлять трафиком.

Рекомендованный способ добавления sidecar-ов — использовать sidecar-injector. Istio умеет “подселять” к вашим Pod’ам sidecar-контейнер с помощью механизма Admission Webhook. Настраивается с помощью лейблов и аннотаций:

  • Лейбл к namespace — обращает внимание sidecar-injector-а на ваш namespace, после установки лейбла, к новым Pod’ам будут подселяться sidecar-ы:
    • istio-injection=enabled — использовать самую свежую установленную версию Istio.
    • istio.io/rev=v1x13 — использовать конкретную версию Istio для данного namespace.
  • Аннотация к Pod’уsidecar.istio.io/inject ("true" или "false"), позволяет локально переопределить политику sidecarInjectorPolicy. Эти аннотации работают только в namespace, обозначенных лейблами из списка выше.

Также существует возможность добавить sidecar к индивидуальному Pod’у в namespace без установленных лейблов istio-injection=enabled или istio.io/rev=vXxYZ путём установки лейбла sidecar.istio.io/inject=true.

Важно знать! Istio-proxy, который работает в качестве sidecar-контейнера тоже потребляет ресурсы и добавляет накладные расходы:

  • Каждый запрос DNAT-ится в envoy, который обрабатывает это запрос и создаёт ещё один. На принимающей стороне — аналогично.
  • Каждый envoy хранит информацию обо всех сервисах в кластере, что требует памяти. Больше кластер — больше памяти потребляет envoy. Решение — CustomResource Sidecar.

Также важно подготовить Ingress-контроллер и Ingress-ресурсы приложения:

  • включить enableIstioSidecar у ресурса IngressNginxController,
  • добавить аннотации на Ingress-ресурсы приложения:
    • nginx.ingress.kubernetes.io/service-upstream: "true" — Ingress-контроллер в качестве upstream будет использовать ClusterIP сервиса вместо адресов Pod’ов. Балансировкой трафика между Pod’ами теперь занимается sidecar-proxy. Используйте эту опцию только если у вашего сервиса есть ClusterIP.
    • nginx.ingress.kubernetes.io/upstream-vhost: "myservice.myns.svc" — sidecar-proxy Ingress-контроллера принимает решения о маршрутизации на основе заголовка Host. Без данной аннотации, контроллер оставит заголовок с адресом сайта, например Host: example.com.

Федерация и мультикластер

Поддерживается две схемы межкластерного взаимодействия:

Принципиальные отличия:

  • Федерация объединяет суверенные кластеры:
    • у каждого кластера собственное пространство имён (для Namespace, Service и пр.),
    • доступ к отдельным сервисам между кластерами явно обозначен.
  • Мультикластер объединяет созависимые кластеры:
    • пространство имён у кластеров общее — каждый сервис доступен для соседних кластеров так, словно он работает на локальном кластере (если это не запрещают правила авторизации).

Федерация

Общие принципы федерации

  • Федерация требует установления взаимного доверия между кластерами. Соответственно, для установления федерации, нужно в кластере A сделать кластер Б доверенным, и аналогично в кластере Б сделать кластер А доверенным. Технически это достигается взаимным обменом корневыми сертификатами.
  • Для прикладной эксплуатации федерации необходимо также обменяться информацией о публичных сервисах. Чтобы опубликовать сервис bar из кластера Б в кластере А, необходимо в кластере А создать ресурс ServiceEntry, который описывает публичный адрес ingress-gateway кластера Б.

Включение федерации

При включении федерации (параметр модуля istio.federation.enabled = true) происходит следующее:

  • В кластер добавляется сервис ingressgateway, чья задача проксировать mTLS-трафик извне кластера на прикладные сервисы.
  • В кластер добавляется сервис, который экспортит метаданные кластера наружу:
    • корневой сертификат Istio (доступен без аутентификации),
    • список публичных сервисов в кластере (доступен только для аутентифицированных запросов из соседних кластеров),
    • список публичных адресов сервиса ingressgateway (доступен только для аутентифицированных запросов из соседних кластеров).

Управление федерацией

Для построения федерации необходимо:

  • В каждом кластере создать набор ресурсов IstioFederation, которые описывают все остальные кластеры.
  • Каждый ресурс, который считается публичным в рамках федерации, необходимо пометить лейблом federation.istio.deckhouse.io/public-service=.

Мультикластер

Общие принципы

  • Мультикластер требует установления взаимного доверия между кластерами. Соответственно, для построения мультикластера, нужно в кластере A сделать кластер Б доверенным, и в кластере Б сделать кластер А доверенным. Технически это достигается взаимным обменом корневыми сертификатами.
  • Для сбора информации о соседних сервисах, Istio подключается напрямую к API-серверу соседнего кластера. Данный модуль Deckhouse берёт на себя организацию соответствующего канала связи.

Включение мультикластера

При включении мультикластера (параметр модуля istio.multicluster.enabled = true) происходит следующее:

  • В кластер добавляется прокси для публикации доступа к API-серверу посредством стандартного Ingress-ресурса:
    • Доступ через данный публичный адрес ограничен авторизацией на основе Bearer-токенов, подписанных доверенными ключами. Обмен доверенными публичными ключами происходит автоматически средствами Deckhouse при взаимной настройке мультикластера.
    • Непосредственно прокси имеет read-only доступ к ограниченному набору ресурсов.
  • В кластер добавляется сервис, который экспортит метаданные кластера наружу:
    • Корневой сертификат Istio (доступен без аутентификации).
    • Публичный адрес, через который доступен API-сервер (доступен только для аутентифицированных запросов из соседних кластеров).
    • Список публичных адресов сервиса ingressgateway (доступен только для аутентифицированных запросов из соседних кластеров).
    • Публичные ключи сервера для аутентификации запросов к API-серверу и к закрытым метаданным данным (выше).

Управление мультикластером

Для сборки мультикластера необходимо в каждом кластере создать набор ресурсов IstioMulticluster, которые описывают все остальные кластеры.

Накладные расходы

Примерная оценка накладных расходов при использовании Istio. Для ограничения потребления ресурсов путём ограничения поля видимости sidecar, возможно использование ресурса Sidecar.