ADG Оставить заявку
Блог DevOps 5 мин чтения

Istio 0.5 в тестовом K8s-кластере: mTLS и traffic shifting - первые выводы

Разворачиваем Istio 0.5 в тестовом Kubernetes-кластере: настраиваем mTLS между сервисами и пробуем traffic shifting. Что такое service mesh на практике и чего стоит sidecar.

Контекст момента

Istio 0.5 - релиз service mesh для Kubernetes с mTLS, traffic management и observability

Istio 0.5 вышел в начале февраля, и мы наконец выделили время нормально поковыряться с ним в тестовом кластере. Разговоров про service mesh последние полгода много, но разница между «слышали концепцию» и «запустили и потрогали» оказалась значительной.

Что такое Istio и зачем оно

Идея service mesh - вынести сетевую логику из приложения в инфраструктурный слой. Retry, timeout, circuit breaker, mTLS, трассировка запросов - всё это приложение обычно реализует само, в коде. Istio предлагает другую модель: рядом с каждым подом запускается sidecar-прокси (Envoy), и весь трафик идёт через него. Приложение ничего не знает, логика - в прокси.

Звучит красиво. Посмотрим как оно на практике.

Установка 0.5: Helm или руками

Мы ставили через Helm chart - в 0.5 это основной рекомендованный способ. В кластер разворачивается несколько компонентов:

  • Pilot - управляет конфигурацией Envoy-прокси, раздаёт правила маршрутизации
  • Mixer - принимает телеметрию и применяет политики (rate limiting, ACL)
  • Istio-CA - управляет сертификатами для mTLS
  • Ingress - отдельный под для входящего трафика

Сам Envoy-sidecar инжектируется в поды двумя способами: вручную через istioctl kube-inject или автоматически через MutatingAdmissionWebhook (в 0.5 это ещё alpha). Мы использовали ручной вариант - надёжнее и понятнее что происходит.

Первая установка заняла минут сорок с учётом возни с RBAC. В Kubernetes 1.9 RBAC включён по умолчанию, и часть Istio-компонентов требует специфических ClusterRole - это не всегда очевидно из документации 0.5.

mTLS между сервисами

Первое что хотелось проверить - mutual TLS между сервисами без изменений в коде приложения. В Istio это делается через MeshPolicy и DestinationRule.

Включаем mTLS для всего mesh:

apiVersion: config.istio.io/v1alpha2
kind: MeshPolicy
metadata:
  name: default
spec:
  peers:
  - mtls: {}

И говорим клиентам использовать TLS при обращении к сервисам через DestinationPolicy:

apiVersion: config.istio.io/v1alpha2
kind: DestinationPolicy
metadata:
  name: default
spec:
  destination:
    name: "*.svc.cluster.local"
  trafficPolicy:
    tls:
      mode: MUTUAL

После применения - трафик между подами с sidecar идёт по mTLS. Проверяем через istioctl get destinationpolicies и прямо из пода через openssl s_client - сертификаты в канале выданы Istio-CA, rotation происходит автоматически. На тестовом стенде с тремя сервисами всё заработало без изменений в коде приложений.

Ограничение 0.5: поды без sidecar (системные компоненты kube-system, например) могут иметь проблемы при строгом mTLS - надо явно исключать или настраивать permissive mode. Это временами неочевидно.

Traffic shifting: канареечные деплойменты

Второй кейс который нас интересовал - управление трафиком между версиями. В чистом Kubernetes канарейку делают через соотношение реплик: 9 v1 + 1 v2 = 10% трафика на v2. Грубо и через количество подов.

Istio позволяет задать вес напрямую через RouteRule:

apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
  name: reviews-v2-rollout
spec:
  destination:
    name: reviews
  route:
  - labels:
      version: v1
    weight: 80
  - labels:
      version: v2
    weight: 20

Здесь labels - это label selector подов нужной версии. 80% трафика на v1, 20% на v2, независимо от количества реплик каждой версии. Меняешь weight - меняется распределение, без изменения деплойментов.

На тестовом стенде это работает именно так как написано. Если нужно откатиться - меняешь weight на 100/0 и применяешь. Для сравнения: в нашем текущем подходе к канарейкам через количество реплик это была бы операция с деплойментами.

Накладные расходы на sidecar: честно

Тут надо говорить без прикрас. Каждый под получает дополнительный контейнер Envoy. На нашем тестовом стенде с простыми HTTP-сервисами:

  • Память - Envoy просит ~50-60 MB per pod в тестовых условиях. На кластере с сотней подов это несколько гигабайт только на прокси.
  • CPU - при умеренной нагрузке почти незаметно. При высоком RPS - надо мерять, мы пока не нагружали серьёзно.
  • Latency - дополнительный hop через localhost через iptables rules. На наших тестах добавляет единицы миллисекунд. Для большинства сервисов - нормально, для latency-sensitive - надо проверять.
  • Сложность - это главное. Дебажить проблемы с сетью теперь надо с пониманием что трафик идёт через Envoy. kubectl logs не даёт полной картины, нужен istioctl.

Mixer в 0.5 - отдельная история. Он участвует в каждом запросе для применения политик, и это синхронный вызов. При высокой нагрузке Mixer может стать узким местом. В 0.5 есть возможность кешировать политики на стороне Envoy, но конфигурируется это вручную.

Что мы из этого вынесли

Концепция работает, но порог входа высокий. Istio 0.5 - это не «поставил и забыл». Это дополнительный операционный слой с собственными CRD, собственным CLI, собственной моделью отладки.

Для простого кластера из трёх-пяти сервисов - вероятно избыточно. Для крупного продукта где десятки сервисов говорят друг с другом, и нужны mTLS, наблюдаемость трафика, канарейки на уровне трафика - история интереснее.

На managed-кластерах мы пока смотрим на это как на инструмент для отдельных сложных случаев, а не как на стандартный компонент. Нужно больше практики с 0.5 прежде чем рекомендовать это в production. Плюс хочется посмотреть как разовьётся Mixer - он сейчас выглядит как потенциальное узкое место при серьёзных нагрузках.

Следующий шаг - прогнать нагрузочный тест на тестовом стенде и замерить реальный overhead Envoy при разных RPS. Результаты опубликуем.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.