Каждый под в Kubernetes получает собственный IP-адрес, и другие поды кластера видят его напрямую. Обращение из пода на узле node-1 к поду с адресом 10.244.2.7 на узле node-2 идёт без трансляции адресов: маршрутизация есть, NAT нет. Эту схему называют flat network, и она задаёт рамки для всего, что связано с сетью в кластере.
Адрес поду выдаёт не сам Kubernetes, а CNI-плагин: Calico, Flannel, Cilium или другое установленное решение. Kubelet в момент создания пода вызывает плагин по CNI-спецификации, получает IP из выделенного диапазона и подключает сетевой интерфейс пода к общей сети.
Дальше разбираем то, что нужно при настройке и отладке: планирование Pod CIDR, различия между популярными CNI-плагинами, команды проверки связности и границу между внутренним обменом трафиком и доступом извне кластера.
Как устроена сеть подов в Kubernetes: базовая модель
Kubernetes не строит сеть подов самостоятельно. Платформа формулирует требования, а реализацию отдаёт CNI-плагину. Отсюда практический вывод: если под не получает IP или не видит соседа, причина почти всегда в CNI, маршрутах или правилах фильтрации, а не в API-сервере.
Требования Kubernetes к сети подов
Сетевая модель Kubernetes опирается на несколько требований, и они одинаковы для любого плагина:
- Уникальный IP для каждого пода. Под получает собственный адрес, уникальный в масштабе всего кластера, а не только своего узла. Адрес не переиспользуется между подами одновременно.
- Собственное сетевое пространство имён у пода. Все контейнеры одного пода делят общий сетевой namespace, поэтому у них один адрес и один набор интерфейсов.
- Прямая связность подов. Все поды могут взаимодействовать со всеми другими подами без необходимости явно создавать связи между контейнерами или отображать порты контейнеров на порты хоста.
Эти требования выполняет и Flannel с VXLAN-инкапсуляцией, и Calico в режиме L3, и Cilium на eBPF. Меняются механизмы доставки, не правила.
Время жизни адреса привязано к поду: пересоздали под, получили новый IP, чаще всего другой. Поэтому зашивать адрес пода в конфиг приложения не стоит, для stable-адресации используется Service. IP пода удобен для диагностики и временных проверок.
Что такое flat network и почему это важно
Flat network означает, что все поды кластера находятся в одном логическом адресном пространстве, независимо от узла запуска. Иерархии подсетей между подами нет, промежуточного NAT между узлами тоже. Под из 10.244.1.0/24 на node-1 общается с подом из 10.244.2.0/24 на node-2 так же, как с соседом на своём узле.
Плоская модель не отменяет маршрутизацию. Пакет проходит через veth-интерфейс, попадает в таблицу маршрутов узла-отправителя, уходит по физической сети или внутрь туннеля, доставляется на узел-получатель и там маршрутизируется в нужный под. Трансляции адресов на этом пути нет.
Практическая ценность в двух вещах. В логах приложения видны реальные IP подов-клиентов, поэтому трафик можно сопоставить с конкретным экземпляром сервиса. Диагностика сводится к проверке маршрутов и доступности адреса, без разбора цепочек DNAT.
Docker в конфигурации по умолчанию работает иначе: контейнеры в bridge-сети выходят наружу через маскарад, и внешний наблюдатель видит адрес хоста, а не контейнера. Kubernetes отказался от этой схемы ради предсказуемой адресации. Разницу между сетевыми моделями разбираем в материале Сетевая маршрутизация в Docker и Kubernetes.
IP-адресация подов: как выдаются адреса и что такое Pod CIDR
Адрес поду назначает CNI-плагин. Kubernetes передаёт ему параметры, среди которых диапазон адресов, а плагин решает, какой конкретно IP отдать конкретному поду. Диапазон этот называют Pod CIDR.
Как посмотреть IP-адрес пода
Первая команда при любой сетевой диагностике показывает адрес и узел размещения:
kubectl get pods -o wide
Колонки IP и NODE дают отправную точку: вы сразу видите, в какой подсети живёт под и на каком узле его искать в маршрутах.
kubectl describe pod <имя-пода> | grep -E 'IP|Node'
Внутри самого пода адрес виден на интерфейсе eth0:
kubectl exec -it <имя-пода> -- ip addr show eth0
Все контейнеры одного пода делят общий сетевой namespace, поэтому у sidecar-контейнера тот же адрес и тот же интерфейс, что у основного. Никакой отдельной адресации внутри пода нет.
Диапазоны адресов и планирование Pod CIDR
Pod CIDR задают один раз, при создании кластера. В kubeadm это флаг инициализации:
kubeadm init --pod-network-cidr=10.244.0.0/16
В managed-кластерах тот же параметр задаётся в консоли провайдера или в Terraform-описании. Дальше диапазон дробится между узлами, и выделенный узлу блок видно так:
kubectl get node <имя-узла> -o jsonpath='{.spec.podCIDR}'
Пример распределения: кластеру отдан 10.244.0.0/16, node-1 получил 10.244.1.0/24, node-2 получил 10.244.2.0/24. Поды на node-1 получают адреса вида 10.244.1.x, на node-2 вида 10.244.2.x. В Calico и Cilium адресация гибче: вместо жёсткого блока на узел работают IP-пулы, а блоки могут выдаваться динамически и анонсироваться через BGP.
Ошибка, которая встречается чаще всего, это пересечение Pod CIDR с другой сетью. Проверьте заранее три диапазона: подсеть подов, Service CIDR и адреса самих узлов. Service CIDR это отдельный диапазон, из которого выделяются виртуальные адреса сервисов; в kubeadm значение по умолчанию для флага --service-cidr — 10.96.0.0/12. Симптомы пересечения появляются выборочно и зависят от того, куда именно маршрутизируется конфликтующий адрес, поэтому ловить их постфактум дорого.
Service CIDR и Pod CIDR путать нельзя. Первым управляет kube-proxy, он выделяет виртуальные адреса сервисов. Вторым управляет CNI, и он раздаёт адреса подам.
CNI-плагины: как они обеспечивают связность подов
CNI (Container Network Interface) это спецификация, а не готовый продукт. Она описывает контракт между средой исполнения и сетевым плагином: JSON-конфигурационный файл и бинарник, который среда выполнения контейнеров вызывает с командами ADD, DEL, CHECK и VERSION для настройки сети подов. Саму сеть строит плагин.
Как работает CNI-плагин: вызовы kubelet
Создание сети для пода выглядит так:
- kubelet создаёт сетевой namespace для пода.
- kubelet через среду выполнения контейнеров (containerd или CRI-O) вызывает CNI-плагин с командой ADD после создания сетевого namespace пода, но до запуска контейнеров.
- Плагин создаёт виртуальный сетевой интерфейс, например пару veth: один конец уходит в namespace пода, второй остаётся на узле.
- Плагин выделяет поду адрес из своего диапазона, настраивает IP-адреса, маску подсети, маршруты и возвращает JSON-результат с назначенным IP.
При удалении пода kubelet вызывает плагин с командой DEL, и тот освобождает адрес и очищает сетевые ресурсы: интерфейсы, маршруты, правила iptables. Ошибки этого уровня видны в логах kubelet и в логах подов CNI в пространстве имён kube-system.
Минимальная конфигурация bridge-плагина с локальным пулом адресов выглядит так:
{
"cniVersion": "1.0.0",
"name": "mynet",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"ranges": [[{"subnet": "10.244.1.0/24"}]]
}
}
Параметр ipMasq включает маскарад для трафика за пределы кластера. На прямую связность подов внутри кластера он не влияет.
Сравнение Calico, Flannel и Cilium
| Критерий | Flannel | Calico | Cilium |
|---|---|---|---|
| Модель сети | overlay на VXLAN, есть режим host-gw | маршрутизация L3, BGP, возможен режим без overlay | eBPF, режим без overlay, туннелирование опционально |
| Сетевые политики | базовые | NetworkPolicy, расширенные глобальные политики | NetworkPolicy, политики на уровне L7 |
| Обработка пакетов | инкапсуляция в UDP, дополнительный заголовок | обычная маршрутизация по таблицам ядра | обработка в ядре через eBPF, без части iptables-цепочек |
| Наблюдаемость | минимум | метрики, calicoctl, логи потоков | cilium status, cilium monitor, Hubble |
| Сложность настройки | низкая | средняя, растёт при использовании BGP | средняя и выше |
| Замена kube-proxy | нет | да, в режиме eBPF | да |
Ни один из вариантов не выигрывает по всем пунктам. Flannel выбирают за предсказуемо простую установку, Calico за гибкую маршрутизацию и политики, Cilium за производительность и наблюдаемость.
Несколько уточнений по механизмам. Flannel может работать с несколькими бэкендами: VXLAN это рекомендуемый выбор, host-gw подходит опытным пользователям, которым нужен прирост производительности и чья инфраструктура это поддерживает, а UDP оставлен для отладки или очень старых ядер без поддержки VXLAN. Бэкенд VXLAN инкапсулирует пакеты средствами ядра, по умолчанию на Linux используется UDP-порт 8472, на Windows — 4789. Бэкенд host-gw создаёт IP-маршруты к подсетям через IP-адреса удалённых машин и требует прямой связности layer2 между хостами, работающими с flannel.
Calico может работать без overlay: для лучшей производительности pod-to-pod рекомендуется использовать нижележащую сеть, не требующую от Calico применения overlay, например кластер в пределах одной подсети AWS или совместимый CNI облачного провайдера. В режиме eBPF Calico заменяет kube-proxy и реализует сетевые функции Kubernetes Service напрямую, а не полагаясь на kube-proxy; запускать оба компонента одновременно расточительно по ресурсам и снижает производительность. BGP-пиры, включая глобальные, в Calico определяются через переменные конфигурации.
Cilium обеспечивает не только стандартные возможности сетевого взаимодействия, но и расширенные функции безопасности и наблюдаемости, включая поддержку сетевых политик седьмого уровня (L7).
Как выбрать CNI-плагин под инфраструктуру
Смотрите на четыре параметра: нужны ли сетевые политики на уровне L7, есть ли в команде опыт с BGP или eBPF, какой уровень наблюдаемости требуется в продакшене, и насколько критична задержка между подами.
- Небольшой кластер с простыми задачами: Flannel закрывает базовую связность с минимальной настройкой.
- Средний или крупный кластер с изоляцией трафика между командами: Calico с BGP-анонсами в сеть дата-центра.
- Требования к наблюдаемости и L7-политикам: Cilium с Hubble.
Смена CNI в работающем кластере это не переключение флага. Плагин владеет адресами и маршрутами подов, поэтому переход выполняют через пересоздание подов и часто через пересборку узлов. Подробный разбор вариантов и их конфигураций собран в материале Сети в Kubernetes: практический гайд по CNI, Pod Network и Service Network.
Прямая связность подов без NAT: как это работает на практике
Под A с адресом 10.244.1.5 отправляет пакет поду B с адресом 10.244.2.7. Пакет выходит через veth в namespace узла node-1, попадает в таблицу маршрутов, уходит к node-2 и на принимающей стороне маршрутизируется в veth пода B. Адрес источника остаётся 10.244.1.5 на всём пути.
В overlay-сетях, например во Flannel с VXLAN, пакет дополнительно инкапсулируется в UDP и распаковывается на узле-получателе. Инкапсуляция добавляет заголовок и снижает полезный размер кадра, но адрес пода внутри туннеля не меняется. NAT в этой схеме не применяется.
Проверка связности подов командами
Набор команд, которого достаточно для базовой проверки:
kubectl get pods -o wide kubectl exec -it pod-a -- ping -c 3 10.244.2.7 kubectl exec -it pod-a -- curl -sS -m 3 http://10.244.2.7:8080/healthz kubectl exec -it pod-a -- nc -zv 10.244.2.7 8080 kubectl exec -it pod-a -- nslookup kubernetes.default
Утилиты ping в минимальных образах часто нет, особенно в distroless. Тогда проверяйте доступность через curl или nc, а для отладки запускайте временный контейнер с набором сетевых инструментов. Проверку DNS выполняйте изнутри пода, так как резолвинг обслуживает CoreDNS внутри кластера, а не resolv.conf узла.
Полезная проверка с другой стороны: зайдите на узел, где целевой под не запущен, и попробуйте обратиться к его адресу напрямую. Так вы отделите проблему маршрутизации между узлами от проблемы конкретного пода. Если ICMP в кластере ограничен NetworkPolicy, ping не пройдёт, а TCP-соединение на нужный порт установится: проверяйте оба протокола.
Что происходит при недоступности подов
Типовые причины и первые команды для проверки:
- Плагин CNI не запущен или падает. kubectl get pods -n kube-system, затем kubectl logs -n kube-system <под-cni>.
- Конфликт адресов или неверный Pod CIDR. Сверьте подсети подов, сервисов и узлов.
- Сломанная маршрутизация между узлами. ip route на обоих узлах, сравните наличие маршрута до подсети соседа.
- Блокировка правилами фильтрации. iptables -L -n -v на узле-отправителе и получателе.
- Ошибка в сетевых политиках. Проверьте NetworkPolicy, которые выбирают поды по меткам.
В Calico состояние узлов и анонсов смотрят через calicoctl node status, в Cilium через cilium status и cilium monitor. Логи плагина почти всегда указывают на конкретный шаг: не удалось выделить адрес из пула, не создался veth, не применился маршрут.
Устройство таблиц маршрутов внутри пода и на узле, включая podCIDR, BGP-анонсы Calico, VXLAN у Flannel и DNAT в kube-proxy, разобрано в статье Маршрутизация в Kubernetes: таблицы маршрутов между подами и нодами.
Внутреннее взаимодействие подов и внешний доступ: в чём разница
Flat network описывает обмен трафиком внутри кластера. Как только появляется клиент снаружи, в схему добавляются Service, Ingress или внешний балансировщик, и правила меняются.
Service и kube-proxy: как трафик попадает в под
Service создаёт виртуальный адрес ClusterIP, который не привязан ни к одному сетевому интерфейсу. kube-proxy на каждом узле настраивает iptables или IPVS так, чтобы трафик на этот виртуальный адрес перенаправлялся на один из подов, выбранных по меткам. В режиме iptables это DNAT: адрес назначения подменяется на адрес пода.
Если kube-proxy в кластере заменён на eBPF-реализацию, балансировку выполняет CNI-плагин, и цепочки iptables в этом пути не участвуют. Логика остаётся той же: клиент обращается к виртуальному адресу, запрос приходит на конкретный под. Подробности по режимам работы, DNS и headless-сервисам есть в материале ClusterIP в Kubernetes: манифест, маршрутизация, kube-proxy и headless-сервис.
Ingress и LoadBalancer: когда flat network недостаточно
Механизмы доступа извне решают задачу, которую плоская сеть не решает по определению: как пустить трафик из интернета к подам.
- NodePort открывает порт на каждом узле и перенаправляет трафик на поды. Просто, но занимает диапазон портов и даёт минимум возможностей маршрутизации.
- LoadBalancer работает на L4 и требует внешнего балансировщика: облачного по умолчанию или MetalLB в bare-metal кластере.
- Ingress работает на L7, требует Ingress-контроллера (nginx, traefik и другие) и умеет маршрутизировать по домену и пути, завершать TLS и применять ограничения по частоте запросов.
На внешней границе маскарад адресов применяется: клиент видит адрес балансировщика, а не пода. Внутри кластера поды по-прежнему общаются напрямую, и эти два уровня не конфликтуют. Как связаны Service, Ingress, Network Policies и сервисная сетка, разбираем в руководстве Управление и маршрутизация сетевого трафика в Kubernetes.
Диагностика и типовые проблемы сети подов
Чек-лист проверки сети подов
- kubectl get pods -o wide: убедитесь, что под в статусе Running и получил адрес.
- kubectl get pods -n kube-system: проверьте, что поды CNI запущены и не перезапускаются.
- kubectl logs -n kube-system <под-cni>: ищите ошибки выделения адресов и настройки интерфейсов.
- kubectl exec -it pod-a -- ping -c 3 <ip-пода-b>: проверьте связность на одном узле и между узлами.
- ip route на узлах: сверьте маршруты до подсетей подов соседних узлов.
- iptables -L -n -v: проверьте правила фильтрации и счётчики срабатываний.
- Сверьте Pod CIDR, Service CIDR и адреса узлов на отсутствие пересечений.
- kubectl exec -it pod-a -- nslookup kubernetes.default: проверьте резолвинг внутри кластера.
- Для Cilium добавьте cilium status, для Calico calicoctl node status.
Идите по списку сверху вниз: он проверяет сначала состояние плагина, затем связность, затем маршруты и правила. Так вы не тратите время на маршруты, когда проблема в упавшем поде CNI.
Типовые ошибки и их решения
- Под завис в ContainerCreating. CNI не может выдать адрес или создать интерфейс. Смотрите логи плагина и свободные адреса в пуле.
- Поды на одном узле видят друг друга, на разных нет. Проблема в маршрутах между узлами или в инкапсуляции: проверьте ip route и настройки туннеля.
- ping не проходит, а TCP-соединение устанавливается. ICMP закрыт сетевой политикой, TCP разрешён. Проверяйте доступность на нужном порту.
- DNS не резолвит имена сервисов. Проверьте поды CoreDNS и Service CIDR, затем сами правила kube-proxy.
- Адреса совпали с инфраструктурной сетью. Пересмотрите Pod CIDR: смена диапазона требует пересоздания подов.
- После смены CNI-плагина часть подов недоступна. Старые поды сохранили интерфейсы прежнего плагина, их нужно пересоздать.
Итоги: что важно помнить о сети подов в Kubernetes
- Каждый под получает уникальный IP в масштабе кластера, и адрес живёт ровно столько, сколько под.
- Адреса выдаёт CNI-плагин, а не Kubernetes: kubelet через среду выполнения контейнеров вызывает плагин с командами ADD и DEL.
- Flat network означает общее адресное пространство и прямую связность подов без NAT, маршрутизация при этом остаётся.
- Pod CIDR планируют до создания кластера и не пересекают с подсетями узлов, сервисов и внешних сетей.
- Flannel проще в установке, Calico сильнее в маршрутизации и политиках, Cilium даёт обработку на eBPF и наблюдаемость.
- Для доступа извне нужны Service, Ingress или LoadBalancer: они дополняют плоскую сеть, а не заменяют её.
- Диагностика идёт от kubectl get pods -o wide и kubectl exec к ip route, iptables и статусу плагина.
Выбор плагина влияет на производительность, набор политик и сложность эксплуатации, поэтому его стоит фиксировать на этапе проектирования, а не менять в работающем продакшене. Проверьте связность в своём кластере по чек-листу выше: этого достаточно, чтобы отличить проблему уровня CNI от проблемы приложения.
Одно ограничение стоит держать в голове: конкретные команды и параметры зависят от версии Kubernetes и версии CNI-плагина, а в публичных материалах версии указывают не всегда. Смежные темы, например паттерн sidecar, где контейнеры делят сетевой namespace пода, разбираются в открытых видеоуроках уровня CKA (разбор паттерна sidecar), но поведение сети всегда сверяйте с документацией вашего плагина и релиза кластера.