CNI и service mesh (обзор)

Концептуальная карта: кто вообще соединяет поды (CNI) и какой слой добавляет mesh поверх.

CNI (Container Network Interface) — стандарт и плагин, который выдаёт подам IP и соединяет их в единую сеть; service mesh — слой поверх, добавляющий безопасность, управление трафиком и наблюдаемость между сервисами.

Мы уже пользовались сетью: поды получали IP, ходили друг к другу, резолвили имена. Но кто это всё обеспечивает? Сам Kubernetes сетью подов не занимается — он делегирует её плагину. А когда базовой связности становится мало (нужны шифрование, тонкая маршрутизация, метрики каждого вызова), поверх ставят service mesh. Этот урок — обзорная карта обоих слоёв, без глубокого деплоя.

Зачем нужен CNI-плагин

Kubernetes задаёт требования к сети, но не реализует её. Модель такая: у каждого пода свой уникальный IP; любой под может связаться с любым другим напрямую, без NAT; под видит себя по тому же IP, по которому его видят другие. Кто выполнит эти требования — дело конкретного CNI-плагина. Когда kubelet создаёт под, он по стандарту CNI вызывает плагин, и тот: заводит сетевой интерфейс внутри пода, выдаёт ему IP из своего диапазона и настраивает маршруты, чтобы пакеты доходили до подов на других узлах.

Поэтому свежий кластер без установленного CNI нерабочий: узлы в состоянии NotReady, поды висят в Pending — им некому выдать сеть. Популярные плагины: flannel (простой, без сетевых политик), Calico (политики, маршрутизация), Cilium (на базе eBPF, политики и наблюдаемость), Weave.

Как устроена pod-сеть

Упрощённо: каждому узлу выделяется подсеть (например, 10.244.1.0/24 на одном узле, 10.244.2.0/24 на другом), и поды узла получают адреса оттуда. Внутри узла поды соединены через виртуальный мост. Самое интересное — трафик между узлами: как пакет от пода на узле A доходит до пода на узле B? Здесь плагины расходятся в подходе.

ПодходЧто делает
Overlay (VXLAN)Заворачивает пакет пода в ещё один пакет между узлами («туннель»); просто, работает поверх любой сети, но есть накладные расходы.
Маршрутизация (L3/BGP)Узлы знают маршруты к подсетям друг друга и шлют пакеты напрямую; быстрее, но требует поддержки от сети.

Проверить, какая подсеть отдана узлам, можно так:

kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"  "}{.spec.podCIDR}{"\n"}{end}'

Из приложения это всё незаметно: под просто видит, что у него есть IP и доступны другие поды. Детали туннелей и маршрутов скрыты в CNI — в этом и смысл стандартизации.

Что добавляет service mesh

CNI даёт связность. Но в проде с десятками сервисов хочется большего: шифровать трафик между сервисами, делать canary-выкатки (5% трафика на новую версию), видеть задержки и ошибки каждого вызова, повторять упавшие запросы. Городить это в каждом приложении — дорого и неоднородно. Эту заботу берёт на себя service mesh — инфраструктурный слой поверх сети. Самые известные — Istio и Linkerd.

Механика обычно такая: рядом с каждым подом приложения автоматически запускается sidecar-прокси (часто Envoy) в том же поде. Весь входящий и исходящий трафик приложения незаметно проходит через этот прокси. Прокси управляются централизованно (control plane), и именно они реализуют возможности mesh, не требуя менять код сервисов.

mTLS, управление трафиком, наблюдаемость

Что конкретно даёт mesh поверх голого CNI:

  • mTLS — взаимное шифрование и аутентификация: sidecar'ы автоматически устанавливают TLS между собой и проверяют сертификаты друг друга. Сервисы общаются по обычному HTTP, а «по проводу» трафик зашифрован и стороны доказывают, кто они. Это zero-trust уже на уровне идентичности сервиса.
  • Управление трафиком — маршрутизация по правилам: разбить трафик 90/10 между версиями (canary), зеркалировать копию запросов на тестовую версию, ретраи и таймауты, circuit breaking при отказах.
  • Наблюдаемость — так как весь трафик идёт через прокси, mesh «из коробки» собирает метрики (RPS, задержки, доля ошибок) по каждому сервису и распределённые трейсы, рисуя карту вызовов.

Как это работает под капотом

Mesh обычно делят на data plane и control plane. Data plane — это те самые sidecar-прокси у каждого пода: они реально пропускают через себя пакеты и применяют правила (шифрование, маршрутизацию, сбор метрик). Control plane (например, istiod у Istio) — мозг: следит за сервисами в кластере, раздаёт прокси их конфигурацию и сертификаты для mTLS. Внедрение sidecar часто делает admission webhook: при создании пода он на лету дописывает в его spec контейнер-прокси, поэтому разработчик ничего не меняет в манифесте. Linkerd известен лёгким прокси на Rust и простотой, Istio — богатством возможностей ценой сложности.

Частые ошибки

Главная стратегическая ошибка — ставить service mesh «потому что модно», на маленький кластер из пары сервисов: вы получаете лишний прокси у каждого пода, заметный расход CPU/памяти и серьёзный рост операционной сложности, не используя и доли возможностей. Mesh оправдан, когда сервисов много и реально нужны mTLS/трафик-менеджмент/наблюдаемость. Вторая ошибка — путать слои: mesh не заменяет CNI (без CNI у подов вообще не будет сети) и не заменяет Ingress (mesh управляет трафиком между сервисами; вход снаружи — всё ещё через Ingress или mesh-gateway). Третья — забывать про накладные расходы sidecar при планировании ресурсов. Четвёртая — недооценивать сложность отладки: теперь между двумя сервисами стоят два прокси, и при разборе проблемы их тоже надо учитывать.

Итоги

  • Сеть подов реализует CNI-плагин, а не сам Kubernetes; без CNI узлы NotReady, поды Pending.
  • Сетевая модель: у каждого пода свой IP, связь без NAT; разные плагины (flannel/Calico/Cilium) решают межузловой трафик через overlay или маршрутизацию.
  • Service mesh — слой поверх CNI: sidecar-прокси у каждого пода добавляют mTLS, управление трафиком (canary, ретраи) и наблюдаемость без правки кода.
  • Mesh делится на data plane (прокси) и control plane (раздаёт конфиг и сертификаты, например istiod).
  • Mesh не заменяет ни CNI, ни Ingress; на малых кластерах его цена (ресурсы, сложность) часто не оправдана.
Проверьте себя
1. Почему в кластере без установленного CNI-плагина узлы остаются NotReady, а поды — в статусе Pending?
AБез CNI не запускается kubelet
BСам Kubernetes не реализует сеть подов — выдать им IP и связность некому
CCNI отвечает за планирование подов по узлам
DБез CNI не работает API-сервер
2. Что из перечисленного добавляет service mesh поверх обычной сети CNI?
AВыдаёт подам IP-адреса вместо CNI
BmTLS между сервисами, управление трафиком (canary, ретраи) и наблюдаемость без правки кода приложений
CПолностью заменяет Ingress для входящего снаружи трафика
DУскоряет межузловой трафик, убирая необходимость в CNI