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; на малых кластерах его цена (ресурсы, сложность) часто не оправдана.