Главный аргумент против service mesh был один и тот же годами: чтобы получить mTLS и наблюдаемость, нужно засунуть Envoy-прокси в каждый под. Это лишний процесс, лишняя память, лишний рестарт при каждом деплое sidecar-инжектора и отдельная головная боль с init-контейнерами и порядком старта. Ambient-режим Istio убирает сайдкар из этого уравнения: mTLS и часть телеметрии приходят почти даром на уровне ноды, а тяжёлая L7-логика включается только там, где она реально нужна.
Содержание
Открыть содержание
Зачем вообще нужен service mesh
Service mesh решает узкий, но болезненный набор задач: шифрование трафика между сервисами без правок в коде приложений, единая точка для ретраев и таймаутов, наблюдаемость на уровне “кто с кем и как долго говорил” без инструментирования каждого сервиса вручную. Istio стал де-факто стандартом для Kubernetes именно потому, что решал всё это декларативно — через CRD, а не через библиотеки, которые нужно тащить в каждый сервис на любом языке.
Но всю эту функциональность годами покупали одной и той же ценой — сайдкаром в каждом поде, независимо от того, нужна ли конкретному сервису хоть одна из продвинутых возможностей. Ambient — это попытка Istio разделить цену и функциональность так, чтобы платить только за то, что реально используется.
Что не так с сайдкарами
Классический Istio работает через sidecar injection: вебхук на этапе создания пода добавляет к контейнеру приложения ещё один контейнер — Envoy. Дальше весь трафик пода идёт через iptables-редирект в этот Envoy, который и делает mTLS, ретраи, метрики и маршрутизацию.
Модель рабочая, но с ощутимой ценой:
- Память и CPU на каждый под. Envoy — не бесплатный процесс: типичный сайдкар съедает от нескольких десятков до сотен мегабайт, даже если под почти не получает трафика. На кластере с тысячами подов это заметная статья расходов только на mesh-слой.
- Рестарт приложения при обновлении сайдкара. Новая версия Envoy — это новый под, потому что сайдкар живёт в одном lifecycle с приложением. Обновление mesh становится обновлением всего флота подов.
- Сложность инъекции. Вебхук должен успеть отработать до старта контейнера приложения, порядок старта контейнеров и
holdApplicationUntilProxyStarts— источник далеко не одного production-инцидента с “приложение стартовало раньше прокси и получило connection refused”. - Прокси есть у всех, даже если нужен не всем. Простому сервису, которому нужен только mTLS между подами, ставится тот же тяжёлый L7-прокси, что и сервису с сложной маршрутизацией — оверхед платят все одинаково.
Архитектура ambient: ztunnel и waypoint
Ambient разбивает то, что раньше делал один Envoy-сайдкар, на два независимых слоя, которые включаются раздельно.
ztunnel (L4) — маленький прокси, написанный на Rust, один экземпляр на ноду (DaemonSet), а не на под. Он забирает у сайдкара самую частую и самую дешёвую по логике работу: устанавливает mTLS-туннель между подами, собирает базовые L4-метрики (кто с кем говорит, сколько байт, какой статус соединения) и применяет L4-политики авторизации (allow/deny по identity). ztunnel не парсит HTTP, не делает ретраи, не смотрит заголовки — и именно поэтому он маленький и дешёвый.
waypoint (L7) — полноценный Envoy-прокси, но теперь не привязанный к каждому поду. Он разворачивается на сервис или namespace, только когда кому-то нужна L7-функциональность: маршрутизация по заголовкам, ретраи, таймауты, canary по весам, AuthorizationPolicy по HTTP-методу или пути. Если такой функциональности не требуется — waypoint просто не разворачивается, и трафик идёт напрямую через ztunnel-ы отправителя и получателя.
Ключевое отличие от sidecar-модели: L4-возможности (mTLS, базовые метрики, идентичность) есть у всех бесплатно, а L7-возможности (маршрутизация, ретраи, детальные HTTP-политики) — только у тех сервисов, которые их явно попросили. Раньше это была бинарная развилка «весь Istio целиком или ничего», теперь — шкала с двумя ступенями.
mTLS между подами без перезапуска приложений
Самое ощутимое отличие на практике — mTLS в ambient появляется без единого перезапущенного пода. Поскольку ztunnel живёт вне пода приложения и перехватывает трафик на уровне ноды через CNI-плагин, включение mesh для namespace сводится к тому, чтобы ztunnel начал видеть трафик этих подов — сами поды при этом не трогаются.
Это принципиально меняет операционную модель внедрения: в sidecar-режиме включение mesh на существующем namespace означало rolling restart всех деплойментов (чтобы вебхук успел заинжектить сайдкар). В ambient — это лейбл на namespace, который подхватывается на лету.
Механика редиректа тоже другая. Sidecar перенаправляет трафик пода на себя через iptables-правила, которые генерирует init-контейнер при старте пода. Ambient использует CNI-плагин Istio, который на уровне ноды заворачивает трафик подов из размеченного namespace в локальный ztunnel через HBONE-туннель (HTTP-based Overlay Network Encapsulation) — специальный протокол поверх mTLS, разработанный именно для ambient. Для приложения разница невидима: оно как отправляло и принимало обычные TCP-соединения, так и продолжает, только по пути они теперь всегда идут через ztunnel и всегда зашифрованы.
Постепенное включение: от L4 ко всему остальному
Ambient проектировался как модель с явными, обратимыми ступенями, а не «всё или ничего»:
- L4 на весь namespace. Один лейбл — и все поды в namespace получают mTLS, идентичность и базовые метрики через ztunnel. Приложения продолжают работать как ни в чём не бывало.
- Waypoint там, где нужен L7. Как только конкретному сервису требуется маршрутизация по заголовку, канареечный релиз по весам или
AuthorizationPolicyс условием по HTTP-пути — для него разворачивается waypoint. Остальные сервисы в том же namespace продолжают работать через один ztunnel, без L7-оверхеда. - Отключение так же просто, как включение. Убрать лейбл или удалить waypoint — не rolling restart, а обратимая операция на уровне конфигурации.
Практически это значит, что миграция с “mesh нет вообще” до “mesh с L7 на критичных сервисах” больше не требует единого решения на весь кластер — можно двигаться сервис за сервисом, оценивая, где L7 действительно окупается.
Сравнение с mesh на базе Cilium/eBPF
Ambient — не единственный ответ на “сайдкары дорого”. Cilium Service Mesh и похожие eBPF-решения атакуют ту же проблему с другой стороны: вместо прокси-процесса на ноду они используют eBPF-программы в ядре для L3/L4-маршрутизации и политик. У обоих подходов общая идея — вынести дешёвую, частую работу из userspace-прокси, но механика и trade-off’ы разные.
| Sidecar (Istio classic) | Istio ambient | Cilium (eBPF-mesh) | |
|---|---|---|---|
| L4-балансировка и политики | Envoy-сайдкар в каждом поде | ztunnel, один на ноду | eBPF-программы в ядре, без userspace-прокси на L4 |
| mTLS | сайдкар, per-pod | ztunnel, per-node | обычно через отдельный L7-прокси (например, отдельный waypoint) |
| L7 (HTTP-маршрутизация, ретраи) | сайдкар всегда | waypoint, точечно | отдельный L7-прокси при необходимости |
| Оверхед на под без L7-нужд | высокий (полный Envoy) | минимальный (только ztunnel на ноде) | минимальный (eBPF в ядре) |
| Обновление без рестарта приложения | нет | да (ztunnel вне пода) | да (eBPF не в поде) |
| Зрелость на 2026 | стабильна много лет | GA с 1.24, multi-cluster в alpha с 1.27 | зрелая для L3/L4, L7-часть моложе |
| Экосистема политик и CRD | самая широкая (Istio CRD) | те же CRD, что и classic Istio | своя модель (CiliumNetworkPolicy и родственные) |
Практический вывод: если вы уже используете Istio CRD (VirtualService, AuthorizationPolicy) и хотите сохранить экосистему — ambient даёт тот же API с меньшим оверхедом. Если вы выбираете mesh с нуля и CNI уже Cilium — есть смысл посмотреть на его встроенный mesh, чтобы не тащить второй компонент поверх уже работающего eBPF-датаплейна.
Есть и менее очевидный фактор выбора — операционная зрелость команды. eBPF-программы работают в ядре хоста, а значит требуют более свежих ядер и аккуратной работы с обновлениями узлов: баг в eBPF-коде потенциально роняет не под, а всю ноду. ztunnel — обычный userspace-процесс, который падает и перезапускается как любой другой под, а отлаживать его можно привычными средствами (логи, kubectl exec, профилировщики). Для команд, которые уже умеют эксплуатировать Istio classic, миграция на ambient — это смена профиля установки, а не смена инструментария и ментальной модели.
Что нужно, чтобы попробовать ambient
Минимум для проверки на существующем кластере: Kubernetes 1.28+, CNI, совместимый с ambient-редиректом (Istio ставит собственный CNI-плагин), и istioctl актуальной версии.
# установка control plane с ambient-профилем
istioctl install --set profile=ambient --skip-confirmation
# проверяем, что ztunnel и istio-cni поднялись как DaemonSet на каждой ноде
kubectl get pods -n istio-system -l app=ztunnel -o wide
kubectl get pods -n istio-system -l k8s-app=istio-cni-node -o wide
Включаем ambient на namespace — приложения не трогаем:
kubectl label namespace shop istio.io/dataplane-mode=ambient
Добавляем waypoint для одного сервиса, которому нужен L7 (например, канареечный роутинг по заголовку):
istioctl waypoint apply --namespace shop --for service --name checkout
L7-политика на конкретный сервис — только он теперь идёт через waypoint, остальные сервисы namespace продолжают работать через один ztunnel:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: checkout-only-internal
namespace: shop
spec:
targetRef:
kind: Service
name: checkout
action: ALLOW
rules:
- from:
- source:
namespaces: ["shop", "gateway"]
to:
- operation:
methods: ["GET", "POST"]
Как убедиться, что работает
Проверяем, что трафик между подами в namespace действительно зашифрован mTLS, не заходя ни в один под:
# смотрим на статус ztunnel-соединений для namespace
istioctl ztunnel-config connections <ztunnel-pod-name> -n istio-system
# ждём, что протокол соединений — HBONE (mTLS-туннель ambient),
# а не голый TCP
Второй быстрый способ — заглянуть в логи ztunnel и убедиться, что он видит трафик нужного namespace:
kubectl logs -n istio-system -l app=ztunnel --tail=50 | grep shop
Если waypoint развёрнут, проверяем, что трафик к сервису идёт именно через него, а не напрямую — в istioctl proxy-config для waypoint-пода должны появиться маршруты для checkout.
Полезная проверка на трезвость перед тем, как включать ambient на проде, — сравнить потребление памяти mesh-слоя до и после на staging-копии реального namespace. Разница между суммой памяти всех sidecar-контейнеров и памятью одного ztunnel на ноду — это и есть тот самый выигрыш, о котором говорят бенчмарки, и на конкретной нагрузке он может отличаться от заявленных ~70%.
Итог
Ambient снимает главный аргумент, из-за которого команды годами откладывали внедрение service mesh: mTLS и базовая видимость трафика теперь стоят одного ztunnel на ноду, а не Envoy-процесса на каждый под, и включаются без единого перезапуска приложения. Плата за это — модель стала двухслойной, и придётся осознанно решать, каким сервисам нужен waypoint и L7, а каким хватит L4. Это честная сделка: сложность теперь пропорциональна тому, что реально нужно сервису, а не размазана поровну по всему кластеру.