Привет, Хабр! Мы в команде Nova Container Platform сделали перевод статьи для тех, кто хочет разобраться, как строить сети в Kubernetes. Делюсь им, надеюсь, вам будет полезно.
В мире Kubernetes мы каждый день слышим, как ipvs сравнивают с iptables, или, скажем, pureLB с metalLB, или же виртуальную топологию (overlay) с физической (underlay), или Nodeport с Loadbalance, и т.д. Сейчас я вам все растолкую.
А вы знаете ответы на эти вопросы?
Как управлять всеми сетевыми параметрами?
Как pureLB подключается к CNI?
Как сервис ClusterIP подключается к IPVS?
Почему, используя Nodeport, я не вижу открытый порт через netstat?
Даже если да, я, пожалуй, продолжу и, поверьте, найду, чем вас удивить.
Обзор всего, везде и сразу
Конечно, непросто в одном месте собрать полезную информацию сразу с двадцати веб-сайтов и статей, но все же я постарался, дабы облегчить вам жизнь.
Я расскажу, как все эти штуки связаны с Kubernetes и как они интегрируются. Вот вам много знакомых и не очень слов на английском: Load-balance, ipvs, iptables, BGP, bridge, CNI, PureLB, endpoint, svc, overlay, underlay, ipip, kube-proxy, ingress controller.
Давайте быстро пройдемся по каждому:
1. Как связаны между собой плагин CNI (Container Network Interface), контроллер балансировщика нагрузки (LB controller) и сетевой прокси (Kube-proxy)
CNI: конфигурирует сеть Kubernetes, создавая и настраивая сетевой интерфейс для каждого контейнера. Агент Kubelet вызывает CNI, чтобы настроить сетевые интерфейсы и назначить им IP-адреса.
CNI работает по двум моделям:
Инкапсулированная (виртуальная топология, overlay)
Неинкапсулированная (физическая топология, underlay)
Инкапсулированная: представлена технологиями VXLAN и IPSEC. Реализует проброс L2 поверх L3 на несколько узлов Kubernetes. Уровень L2 изолирован, так что распределять маршруты не нужно. Создается IP-заголовок, который предоставляет IP-пакет. Эта модель создает мост, соединяющий рабочие узлы и поды (pods). Управление соединениями реализуется через CRI (Container Runtime Interface).
Неинкапсулированная: маршрутизирует пакеты между контейнерами на L3. Рабочие узлы нужны, чтобы управлять распределением маршрутов с помощью BGP и, как следствие, распределять имеющуюся у подов информацию о маршрутизации. Эта модель подразумевает реализацию сетевого маршрутизатора на нескольких рабочих узлах.
CNI может использовать обе архитектуры.
Контроллер балансировщика нагрузки: MetalLB, PureLB… работает в Kubernetes как сервис типа LoadBalancer (балансировщик нагрузки).
При создании сервиса балансировщика нагрузки (LB) назначенный внешний IP-адрес будет создан как вторичный адрес для основного интерфейса, что позволит маршрутизатору BGP BIRD захватывать IP-адреса и добавлять маршруты, адреса и прочие настройки.
Когда назначен новый IP-адрес:
В случае виртуальной сети будут применяться IPVS или iptables.
В случае физической сети дополнительно будет применяться еще и таблица маршрутизации.
Kube-proxy: задает сетевые правила в iptables, ipvs…
Kube-proxy добавляет сетевые политики, трансляцию сетевых адресов (NAT), правила переадресации и т.п.
Вот вам простой пример:
Когда вы создаете svc, kube-proxy добавляет правила в iptables.
Кстати, netfilter можно заменить на EBPF, а IPtables – на IPVS.
Итак, резюмируем:
Kube-proxy: задает сетевые правила в IPTABLES, IPVS и т.д.
CNI: предоставляет общий интерфейс для базовых сетей, маршрутизирует трафик до мест назначения и выполняет другие сопутствующие функции.
Контроллер балансировщика нагрузки: балансирует нагрузку и обновляет интерфейс хоста для добавления вторичных IP-адресов.
2. С пода на под / из контейнера в контейнер – одноузловая конфигурация (на базе IP-адреса)
Через среду выполнения контейнеров, например containerd, CRI-O или Mirantis, создается пользовательский мост (CBR), Veth (виртуальный Ethernet), Ethernet (eth), и задаются все сетевые параметры. Большинство интерфейсов сред выполнения контейнеров (CRI) используют для этого плагины CNI, в том числе опции Calico, Flannel и Cilium.
Все контейнеры внутри пода используют одну и ту же сеть, поскольку находятся внутри одного и того же пространства сетевых имен.
Контейнер pause отвечает за сетевые соединения и межпроцессное взаимодействие (IPC) в Kubernetes.
Виртуальное устройство Veth будет создано под CBR для каждого пода, и L2-маршрутизация будет идти по этому мосту. Например, пакеты из под1 в под2 идут через CBR, а NAT в этом случае не используется.
3. С пода на под / из контейнера в контейнер – многоузловые конфигурации (на базе IP-адреса)
Как IP-адрес пода маршрутизируется по сети узлов?
Оба узла находятся в одной и той же сети, т.е. могут видеть друг друга;
CNI создает на каждом узле маршрут к каждому поду.
Поскольку на CBR в узле-1 нет MAC-адреса пода4, пакеты идут через интерфейс, указанный в таблице маршрутизации. Это может быть туннель, другой интерфейс, eth0 или... На самом деле все зависит от структуры.
У каждого узла в Kubernetes есть свой собственный метод бесклассовой адресации (CIDR), который позволяет маршрутизировать трафик на правильный узел.
4. С пода на под / из контейнера в контейнер – многоузловые конфигурации (на базе IP-адреса службы)
В случае служб ключевую роль играет IPTABLES/IPVS. В Netfilter IP-адрес службы произвольно изменится на IP-адрес связанного пода (по алгоритму балансировки нагрузки). Kube-proxy отвечает за актуализацию правил Netfilter и назначение IP-адресов подов службам.
Когда узел получает пакет, предназначенный для svc, в Netfilter правила сопоставляются со службой, а пакет маршрутизируется на IP-адрес пода назначения.
Но как?
Службы обновляют совокупности конечных точек (endpoint slices) IP-адресами подов, сопоставляя метки подов, указанные в селекторе службы. Когда селектор сопоставляет метки подов, соответствующая информация (IP-адреса, порты, протоколы и пр.) извлекается и вставляется в совокупность конечных точек (endpoint slice), ассоциированную со службой.
Помните, что службы, конечные точки, Nodeports и LB – всего лишь правила в IPTABLES/IPVS.
Что произойдет, если вызвать службу по имени? До сих пор мы упоминали лишь маршрутизацию по IP-адресу.
В Kubernetes есть DNS-сервер, обычно CoreDNS или KubeDNS.
DNS-под видится извне как служба kubernetes со статическим IP-адресом кластера, парсинг которого до каждого контейнера выполняется при запуске.
Теперь все просто: имена будут разрешаться внутри контейнеров DNS-сервером Kubernetes.
Готовы увидеть все, везде и сразу? Самое время
Calico: Все сетевое взаимодействие выполняется через Calico, виртуальную (IPIP) и физическую (BGP) сети.
Как я писал выше, IP-адреса всех подов назначаются мосту CBR, чьи функции в данном случае выполняет интерфейс моста kube-ipvs;
У каждого пода есть свой собственный виртуальный интерфейс;
tunl0 (IPIP) – виртуальный интерфейс, который соединяет узлы друг с другом в архитектуре виртуальной сети. Иными словами, все IP-адреса пода проходят через этот туннель;
PureLB - контроллер балансировщика нагрузки, который также управляет сетью хоста, реализуя kube-lb0 как виртуальный интерфейс, и добавляет IP-адреса балансировщика нагрузки в основной интерфейс хоста в качестве вторичных IP-адресов;
PureLB также совместим с протоколами маршрутизации с BGP, OSPF… Поскольку у нас маршрутизатор BGP BIRD уже реализован с помощью Calico, PureLB понимает это и не будет создавать другой маршрутизатор BGP;
BGP захватывает все IP-адреса, назначенные интерфейсам, и задает маршрут к ним в таблице маршрутизации.
До тех пор, пока пакет из пода 1 не захочет попасть в под 5 в другом узле, kube-ipvs не сможет выдать в ответ то, чего сам не знает, так что следующий уровень – это таблица маршрутизации, обновленная с помощью BGP. Маршрутизация до места назначения будет выполняться через интерфейс tunl0, потому что у нас архитектура виртуальной сети. Если вызвать службу, то в игру вступят правила ipvs.
Теперь мы знаем, что конечные точки, службы, Nodeports и LB – всего лишь правила в IPVS. Давайте это запомним:
У нас есть служба типа LoadBalancer для нашего ingress-контроллера, а это значит, что ingress доступен извне. Когда мы вызываем этот IP-адрес, пакеты направляются на нужный узел, и потом IPVS переадресует их на NodePort (NAT) для маршрутизации между узлами и поиска правильного узла.
Затем NodePort ассоциируется с ClusterIP, который знает IP-адреса подов ingress-контроллера. Это полезная настройка, потому что, как только ingress-контроллер получает пакет, он по заданным правилам маршрутизирует его на нужную службу и потом на под назначения.
В этой статье я ставил себе целью не дать исчерпывающее объяснение по каждому компоненту, а собрать в одном месте информацию для тех, кто уже в теме.
Я брал информацию из нескольких источников. Вот ссылки на них:
https://medium.com/thermokline/comparing-k8s-load-balancers-2f5c76ea8f31