Kubernetes для самых маленьких. Часть 37: Как устроена сеть Windows-узлов и какой CNI выбрать?

Все части серии «Kubernetes для самых маленьких»

В прошлой части мы разобрали, из чего состоит Windows-узел: kubelet и containerd — службы Windows, контейнеры создаёт HCS, сеть — HNS, kube-proxy и сетевой плагин работают в HostProcess-контейнерах, а метка kubernetes.io/os, taint и RuntimeClass разводят поды по своим узлам. Сегодня — сеть такого узла целиком. На Linux-узлах она устроена так, как описано в части 14 и части 15: veth cali…, маршруты /26 от Felix, VXLAN в режиме CrossSubnet, правила nftables от Felix и kube-proxy. На Windows ничего этого нет: ни veth, ни таблицы маршрутов в привычном смысле, ни netfilter. Разберём, что их заменяет — HNS и VFP, — какие режимы сети бывают на Windows, какие сетевые плагины на нём работают и с какими ограничениями, как работает kube-proxy в режиме winkernel и почему кластеру с Windows-узлами нужен Calico в режиме VXLAN во всех направлениях и без BGP. Учебный кластер серии работает иначе — VXLANCrossSubnet и BGP, — поэтому в конце выберем, где запускать Windows-узлы. Рекомендуемый путь — отдельный тестовый кластер, сразу собранный под Windows-воркеры: его сеть разберём здесь, а соберём его в части 38. Альтернатива — перевести существующий кластер; этот путь тоже разберём по шагам, с рисками и откатом. Кластера с Windows-узлом у нас пока нет, поэтому эта часть, как и прошлая, — об устройстве; всё описанное увидим вживую в части 38.


Что меняется по сравнению с Linux

Требования сетевой модели Kubernetes на Windows те же: у каждого пода свой адрес, поды достают друг до друга без NAT, узел достаёт до своих подов. Меняется всё, что под этими требованиями:

Задача Linux-узел Windows-узел
изолированная сеть пода сетевое пространство имён (netns) сетевой отсек (network compartment)
интерфейс пода veth-пара cali… виртуальный адаптер (vNIC) на порту виртуального коммутатора Hyper-V
кто создаёт интерфейс CNI-плагин через системные вызовы ядра CNI-плагин через API службы HNS
маршрут к блоку соседа маршрут ядра от BIRD или Felix политика RemoteSubnetRoute в HNS-сети, исполняет VFP
VXLAN интерфейс vxlan.calico, записи FDB и ARP HNS-сеть типа Overlay с VSID 4096, инкапсуляцию делает VFP
Service таблица ip kube-proxy в nftables объекты LoadBalancer в HNS, исполняет VFP
NetworkPolicy таблица ip calico в nftables ACL-политики на конечных точках HNS, исполняет VFP
natOutgoing маскарадинг в nftables политика OutBoundNAT на конечной точке пода
инструменты ip, nft, tcpdump, conntrack Get-HnsNetwork, Get-HnsEndpoint, hnsdiag, vfpctrl, pktmon

Видно, что почти каждая строка справа упирается в два компонента — HNS и VFP. С них и начнём.


HNS: кто строит сеть на Windows-узле

На Linux сетевой плагин сам создаёт veth, назначает адреса и пишет маршруты — это системные вызовы ядра, доступные любому процессу с нужными правами. На Windows так не делают: все сетевые объекты контейнеров создаёт системная служба HNS (Host Networking Service, служба hns). Плагин CNI, kube-proxy и Felix — её клиенты: они описывают желаемое состояние в JSON и отправляют его через API HCN (Host Compute Network), а HNS превращает описание в конфигурацию виртуального коммутатора. Документация Kubernetes прямо говорит, что Windows хранит адреса DNS, маршруты и другие сетевые настройки не в файлах вроде /etc/resolv.conf, а в реестре и в объектах HNS, поэтому CNI-плагины на Windows обязаны работать через HNS, а не подкладывать файлы в контейнер.

Объекты HNS:

  • Сеть (network) — сегмент, к которому подключаются поды: тип (Overlay, L2Bridge и другие, о них ниже), подсеть с адресом шлюза, политики уровня сети (номер VXLAN-сегмента, маршруты к подсетям других узлов). При создании первой сети HNS создаёт виртуальный коммутатор Hyper-V (vSwitch) и привязывает его к физическому адаптеру — у нас к адаптеру Ethernet.
  • Конечная точка (endpoint) — подключение одного пода: порт коммутатора, виртуальный адаптер с MAC-адресом, IP-адрес, шлюз, DNS и политики уровня конечной точки (ACL, OutBoundNAT). Это аналог veth-пары вместе с маршрутом /32 на узле.
  • Пространство имён HNS (namespace) — то, что Windows называет сетевым отсеком (network compartment): собственный набор интерфейсов и своя таблица маршрутов, отдельная от хоста. По смыслу это netns. Отсек создаётся на под, в нём живёт pause-контейнер, и все контейнеры пода делят его, как на Linux делят сетевое пространство имён.
  • Балансировщик (load balancer) — правило «виртуальный адрес и порт → список адресов конечных точек». Их создаёт kube-proxy, по объекту на каждый порт каждого сервиса.

Важная деталь про виртуальный коммутатор. Когда HNS привязывает его к физическому адаптеру, адаптер Ethernet перестаёт иметь собственный IP: его адрес переезжает на новый виртуальный адаптер хоста vEthernet (Ethernet), подключённый к тому же коммутатору. Хост с этого момента сам — один из «гостей» своего коммутатора. На несколько секунд при создании коммутатора узел пропадает из сети, и сессии удалённого управления рвутся; документация Calico отдельно предупреждает, что в облаках при этом может пропасть маршрут к службе метаданных. Это нормальное поведение при первом запуске сетевого плагина на узле.

 k8s-lab-win-1
 ┌──────────────────────────────────────────────────────────────────┐
 │  отсек пода web              отсек другого пода                  │
 │  ┌────────────────────┐      ┌────────────────────┐              │
 │  │ vNIC               │      │ vNIC               │              │
 │  │ 172.21.41.6/26     │      │ 172.21.41.5/26     │              │
 │  └─────────┬──────────┘      └─────────┬──────────┘              │
 │            │ порт                      │ порт                    │
 │  ┌─────────┴───────────────────────────┴──────────────────────┐  │
 │  │ виртуальный коммутатор Hyper-V                             │  │
 │  │ расширение VFP: ACL, балансировка, NAT, VXLAN              │  │
 │  └─────────┬───────────────────────────┬──────────────────────┘  │
 │            │ порт                      │ внешний порт            │
 │  ┌─────────┴──────────┐      ┌─────────┴──────────┐              │
 │  │ vEthernet          │      │ Ethernet           │              │
 │  │ (Ethernet)         │      │ физический адаптер │              │
 │  │ 192.168.10.25/24   │      │ без IP-адреса      │              │
 │  └────────────────────┘      └─────────┬──────────┘              │
 └────────────────────────────────────────┼─────────────────────────┘
                                          ▼
                                   сеть 192.168.10.0/24

При запуске пода containerd через HCS (Host Compute Service — службу, которая создаёт и запускает контейнеры) создаёт отсек и вызывает CNI-плагин, плагин просит HNS создать в своей сети конечную точку и прикрепить её к отсеку, а kubelet, как и на Linux, получает адрес пода и пишет его в status.podIP. Из PowerShell с HNS работает встроенный в Windows Server 2025 модуль HostNetworkingService (Get-HnsNetwork, Get-HnsEndpoint, Get-HnsNamespace, Get-HnsPolicyList) и консольная утилита hnsdiag.


VFP: правила внутри виртуального коммутатора

HNS решает, что должно быть: какие адреса, какие ACL, какие балансировщики. Исполняет это VFP (Virtual Filtering Platform) — расширение виртуального коммутатора Hyper-V, через которое проходит каждый пакет между его портами. Это та же технология, на которой построена программно-определяемая сеть хостов Azure: VFP разрабатывали, чтобы на каждом физическом сервере облака применять политики виртуальных сетей тысяч клиентов, не трогая сетевое оборудование.

Как VFP устроена:

  • Слои (layers). У каждого порта коммутатора — упорядоченный набор слоёв. Слой — таблица правил «условие → действие», которую программирует один владелец: слой ACL для политик, слой балансировки и NAT для сервисов, слой маршрутизации и инкапсуляции для оверлея. Пакет проходит слои по очереди, как цепочки netfilter, и каждый слой может отбросить его или изменить заголовки.
  • Преобразование заголовков (header transposition). Действие правила в VFP — не «отправить в такую-то цепочку», а описание того, как переписать заголовки: заменить адрес назначения, добавить внешний заголовок VXLAN, подменить MAC.
  • Единый поток (unified flow). Первый пакет нового соединения проходит все слои, и VFP складывает их действия в одно итоговое преобразование, например «заменить адресат 10.97.141.163:80 на 172.21.211.8:8080 и обернуть в VXLAN к 192.168.10.24». Преобразование запоминается в кэше потоков, и следующие пакеты соединения слои уже не проходят — к ним сразу применяется готовое преобразование, а к ответам — обратное. По смыслу это conntrack вместе с правилами NAT, только сделанные внутри коммутатора.
 пакет из vNIC пода
   │
   ▼
 кэш потоков VFP ── поток известен ──► применить готовое преобразование ──► дальше
   │
   │ новый поток
   ▼
 слой ACL                 Felix:      разрешено ли политиками?
   ▼
 слой балансировки и NAT  kube-proxy: ClusterIP → адрес пода, OutBoundNAT
   ▼
 слой маршрутизации       Calico:     блок соседа → обернуть в VXLAN к его узлу
   ▼
 сложить действия в единый поток, запомнить, применить

С этой моделью связано одно известное ограничение — исходящий ICMP через NAT. ICMP — служебный протокол IP для сообщений об ошибках и проверки доступности, на нём работает ping (часть 8 сетевой серии). Документация Kubernetes перечисляет его среди ограничений сети Windows: эхо-запрос от пода к адресу внутри той же сети (к поду, в том числе на другом узле) проходит, а запрос наружу, который нужно оттранслировать через OutBoundNAT, может не вернуться к поду. На свежих сборках Windows Server 2025 с Calico в режиме VXLAN ping наружу у нас проходил, так что ограничение зависит от сборки ОС и сетевого плагина. Правило отсюда одно: «ping до шлюза не проходит» на Windows-поде — ещё не признак поломки, а связность наружу проверяют через curl.exe или Test-NetConnection -Port, которые работают по TCP.

Слои и правила порта показывает утилита vfpctrl (/list-vmswitch-port, затем /port <имя> /list-layer), но для повседневной диагностики хватает уровня HNS. Пакеты на Windows ловит встроенный pktmon — аналог tcpdump, который видит пакет и на портах виртуального коммутатора.


Режимы сети: l2bridge и overlay

Тип HNS-сети определяет, как пакеты подов выходят с узла. Windows поддерживает пять типов, и документация Kubernetes перечисляет их все, но для Kubernetes на своём железе важны два.

L2bridge. Поды подключены к внешнему коммутатору, их адреса видны в физической сети как есть, без обёртки. Чтобы физический коммутатор не учил MAC-адреса сотен короткоживущих подов, VFP подменяет MAC-адрес источника пакетов подов на MAC-адрес узла, а на входе — обратно (MAC rewrite). Пакет от пода к поду на соседнем узле уходит в сеть с IP-адресами подов и MAC-адресами узлов — ровно как прямая маршрутизация Calico на Linux из части 14. Отсюда и требование: узлы должны быть L2-соседями или маршрутизатор должен знать, где какой блок подов (статические маршруты либо BGP). В этом режиме работают Flannel host-gw (через плагин win-bridge), Calico с BGP без инкапсуляции и Azure CNI. Документация Kubernetes называет его самым производительным.

Overlay. Пакеты подов между узлами заворачиваются в VXLAN — протокол, который упаковывает Ethernet-кадр целиком в UDP-датаграмму (на Windows — только порт 4789) с заголовком, где записан 24-битный номер сегмента VNI (часть 18 сетевой серии). В терминах Windows номер сегмента называется VSID. Физическая сеть видит только UDP между адресами узлов, и ей не нужно знать о сети подов. В этом режиме работают Flannel VXLAN (через плагин win-overlay) и Calico VXLAN. Таблица режимов в документации Kubernetes до сих пор помечает overlay как beta, хотя feature gate WinOverlay, который включал его в kube-proxy, стабилен с 1.34.

 l2bridge: пакет пода на проводе
 [Ethernet: MAC k8s-lab-win-1 → MAC k8s-lab-node-1][IP 172.21.41.6 → 172.21.211.8][TCP …]

 overlay: тот же пакет
 [Ethernet: узел → узел][IP 192.168.10.25 → 192.168.10.24][UDP → 4789][VXLAN, VNI 4096]
     [Ethernet: VTEP → VTEP][IP 172.21.41.6 → 172.21.211.8][TCP …]

Остальные три типа:

  • L2tunnel — вариант l2bridge только для Azure: весь трафик подов отправляется на физический хост виртуализации, где к нему применяются политики облачной сети. Вне Azure не используется.
  • Transparent — поды подключены к внешнему коммутатору без подмены MAC-адресов, каждый виден в физической сети со своим MAC; на виртуальной машине гипервизор должен разрешать подмену MAC (MAC spoofing). Ни маршрутизации между узлами, ни балансировки этот режим не даёт, и документация Kubernetes упоминает его только для ovn-kubernetes, который строит поверх коммутатора собственную сеть на Open vSwitch.
  • NAT — поды за трансляцией адресов WinNAT, снаружи доступны только через проброс портов узла. Это режим Docker на одной машине, и он противоречит сетевой модели Kubernetes, где поды видят друг друга по своим адресам. В Kubernetes не используется.

Какие плагины работают на Windows

Сетевой плагин в смешанном кластере должен работать на обоих типах узлов и одинаково понимать сеть подов. Выбор на Windows заметно уже, чем на Linux:

Плагин Тип HNS-сети на Windows Между узлами kube-proxy на Windows NetworkPolicy на Windows Ограничения и статус
Flannel host-gw l2bridge (win-bridge) напрямую, узлы в одной L2-сети нужен, winkernel нет стабилен по документации Kubernetes
Flannel VXLAN overlay (win-overlay) VXLAN, UDP 4789, VNI 4096 нужен, winkernel нет beta; узел достаёт только до своих подов; DirectRouting на Windows нет
Calico VXLAN overlay VXLAN без CrossSubnet, BGP в кластере выключен нужен, winkernel да нет IPIP, IPv6, eBPF, WireGuard, политик для хостов; один блок на узел, 4 адреса блока заняты
Calico BGP l2bridge без инкапсуляции, BGP через маршрутизатор Windows нужен, winkernel да на узлах нужна роль RRAS; рефлекторы маршрутов — только Linux; узлам нужна L2-связность или маршрутизатор с BGP
Antrea сеть HNS с Open vSwitch Geneve, VXLAN или STT не нужен: AntreaProxy да подготовка узла скриптом после каждой перезагрузки; таблица совместимости в документации доходит до Kubernetes 1.30
ovn-kubernetes Transparent с OVS или hybrid overlay GENEVE, STT или VXLAN не нужен в режиме OVS в режиме OVS вне OpenShift на Windows почти не встречается
Azure CNI l2bridge, l2tunnel адреса подов из виртуальной сети Azure нужен через Azure только AKS и Azure
Amazon VPC CNI адреса из VPC вторичные адреса или префиксы на сетевом интерфейсе нужен через дополнения только EKS
Cilium — — — — Windows не поддерживает

Теперь по каждому подробнее.

Эталонные плагины win-bridge и win-overlay. Это CNI-плагины из проекта containernetworking/plugins, которые создают в HNS сеть типа L2Bridge или Overlay и конечные точки в ней. Сами по себе они не раздают подсети узлам и не знают о соседях — это делает тот, кто их вызывает. Документация Kubernetes отмечает, что они не реализуют операцию CHECK и поэтому не соответствуют спецификации CNI 0.4.0 и новее.

Flannel — простой сетевой плагин: демон flanneld на каждом узле берёт подсеть узла из spec.podCIDR объекта Node и прописывает маршруты к подсетям соседей. Сетевых политик Flannel не реализует. На Windows он делегирует создание сети эталонным плагинам. Бэкенд host-gw — маршруты к подсетям соседей через их адреса, без обёртки, поверх win-bridge; документация Kubernetes называет его стабильным. Бэкенд VXLAN — поверх win-overlay, beta; на Windows номер VNI должен быть 4096 или больше, порт — только 4789, а режим DirectRouting (аналог CrossSubnet: соседям в своей подсети без обёртки) и VXLAN GBP на Windows не поддерживаются. Ещё одно ограничение из документации Kubernetes: узел с Flannel VXLAN достаёт только до подов на себе. Для нас Flannel не подходит по двум причинам. В основном учебном кластере уже Calico, и менять сетевой плагин живого кластера — это пересоздать сеть всех подов. А тестовый кластер для Windows-узлов мы собираем похожим на основной, чтобы опыт переносился с одного на другой, — с тем же Calico и с сетевыми политиками из части 20, которых Flannel не умеет.

Calico работает на Windows в двух режимах, и оба уже, чем на Linux. Его разберём подробно в следующем разделе.

Antrea — сетевой плагин на Open vSwitch (OVS): программном коммутаторе, которым управляют потоковыми правилами по протоколу OpenFlow — «пакет с такими-то полями → такие-то действия». На Windows OVS работает расширением виртуального коммутатора Hyper-V, то есть встаёт на место, где у остальных плагинов работает VFP, и Antrea программирует одинаковые правила на Linux и на Windows. Между узлами Antrea умеет туннели трёх видов: Geneve (обёртка в UDP, порт 6081, похожая на VXLAN, но с расширяемыми полями-опциями в заголовке), VXLAN и STT (Stateless Transport Tunneling — обёртка, которая выглядит для сетевой карты как TCP, чтобы карта могла сама резать большие пакеты). Главное отличие от остальных: AntreaProxy по умолчанию заменяет kube-proxy на Windows-узлах, и ставить туда kube-proxy документация Antrea не велит. Ограничения из неё же: подготовительный скрипт нужно выполнять после каждой перезагрузки узла (HNS-сеть Antrea её не переживает), первый запуск агента ненадолго прерывает сеть узла, а драйвер OVS в поставляемом пакете подписан тестовой подписью.

ovn-kubernetes — сетевой плагин на OVN (Open Virtual Network — надстройке над OVS, которая описывает логические коммутаторы, маршрутизаторы и балансировщики и сама раскладывает их в правила OVS на узлах). Документация Kubernetes описывает его на Windows в режиме Transparent с OVS, без kube-proxy. На практике с Windows-узлами он встречается в OpenShift, и там схема другая — hybrid overlay: Linux-узлы живут в OVN, а Windows-узлы получают обычную HNS-сеть типа Overlay с VXLAN.

Azure CNI и Amazon VPC CNI выдают подам адреса прямо из виртуальной сети облака. Azure CNI на Windows работает в режимах l2bridge и l2tunnel. В EKS адреса Windows-подам раздаёт VPC Resource Controller — вторичные адреса или префиксы /28 на сетевом интерфейсе (ENI) узла, причём на Windows-узле используется только один интерфейс. Оба плагина имеют смысл только в своём облаке.

Cilium — сетевой плагин на eBPF, механизме ядра Linux, который позволяет загружать в ядро проверенные программы обработки пакетов. На Windows такого ядра нет, и официальной поддержки Windows-узлов у Cilium нет: даже в AKS вариант Azure CNI Powered by Cilium документация описывает как доступный только для Linux. Проект eBPF for Windows существует, но полноценного датаплейна Cilium для Windows-узлов на нём нет.


Calico на Windows

На Windows-узле Calico ставится тем же Tigera operator, что и на Linux: оператор запускает DaemonSet calico-node-windows из HostProcess-подов. HostProcess-контейнер — процесс, который работает прямо на хосте, в его сети и с доступом к его файловой системе, но запускается и обновляется как обычный под; через него сетевой плагин получает права, нужные для работы с HNS, не будучи установленным на узел вручную. В поде calico-node-windows init-контейнеры uninstall-calico (убирает Calico, поставленный на узел прежним способом — скриптами и службами Windows) и install-cni (кладёт бинарники и конфигурацию CNI), а основные контейнеры — felix и node (в режиме BGP к ним добавляется confd). Felix на Windows делает то же, что на Linux, но через HNS: создаёт ACL-политики на конечных точках подов и политики маршрутизации в HNS-сети. Документация Calico поддерживает на Windows только установку оператором, только хранилище в API Kubernetes и containerd 1.6 и новее (на k8s-lab-win-1 — containerd 2.2.2). Из версий Windows в требованиях Calico на момент написания названы Windows Server 1809 и 2022; Windows Server 2025, на котором работает наш Windows-узел, в этом списке нет, хотя сам Kubernetes его поддерживает. В части 38 связка Calico 3.33 и Windows Server 2025 у нас заработает, но формально Calico её не подтверждает — это стоит иметь в виду и проверять перед обновлениями Calico.

Два режима и чего нет

VXLAN. HNS-сеть Calico типа Overlay, VSID 4096, UDP 4789 — единственный порт VXLAN, который поддерживает Windows. Для каждого блока подов на другом узле Felix добавляет в HNS-сеть политику RemoteSubnetRoute: «подсеть назначения — такая-то, адрес узла (provider address) — такой-то, MAC его VTEP — такой-то, номер сегмента — 4096». VTEP (VXLAN Tunnel Endpoint) — точка, где кадры заворачиваются в VXLAN и разворачиваются обратно; на Linux это интерфейс vxlan.calico с собственным MAC-адресом. Это ровно та же информация, которую Felix на Linux раскладывает в маршрут через vxlan.calico, запись ARP и запись FDB (таблицы, по которой VXLAN-интерфейс выбирает, на какой адрес узла отправить кадр с данным MAC-адресом назначения).

Ограничение режима, из-за которого основной учебный кластер в нынешнем виде Windows-узел не примет: CrossSubnet на Windows не поддерживается, и документация Calico требует, чтобы при Calico VXLAN BGP в кластере был выключен. Смешать нельзя: bgp в ресурсе Installation — настройка всего кластера, а режим инкапсуляции задаётся пулу, общему для всех узлов. Значит, пул должен быть VXLAN Always — обёртка между любыми двумя узлами, в том числе между Linux-узлами в одной подсети, — а BGP выключен: маршруты к блокам на Linux и так прописывает Felix, BIRD для них не нужен.

BGP без инкапсуляции. HNS-сеть типа L2Bridge, адреса подов видны в физической сети, маршруты к блокам Windows-узел получает по BGP. Своего демона BGP в Calico для Windows нет: confd настраивает встроенный маршрутизатор Windows — службу RRAS (Routing and Remote Access Service), в состав которой входит BGP. Поэтому на каждом Windows-узле нужно поставить компоненты RemoteAccess, RSAT-RemoteAccess-PowerShell и Routing, перезагрузиться и включить RRAS в режиме только маршрутизации. Если в кластере используются рефлекторы маршрутов (route reflectors — BGP-узлы, которые пересылают маршруты всем клиентам, чтобы не держать полную сетку сессий), они должны быть Linux-узлами: Windows-узел рефлектором быть не может. Ещё условие: без внешнего маршрутизатора с BGP Linux- и Windows-узлы должны быть в одной L2-сети. Пул в этом режиме — с encapsulation: None.

Чего нет на Windows ни в одном режиме, по таблице ограничений Calico:

  • IPIP — инкапсуляция IP-в-IP (IP-протокол 4), которую Calico умеет на Linux: в Windows её нет, и пул с IPIP в кластере с Windows-узлами использовать нельзя;
  • IPv6 — с Calico (и вообще в overlay/VXLAN) IPv6 на Windows-узлах не поддерживается, только IPv4;
  • eBPF-датаплейн — функция ядра Linux;
  • WireGuard — протокол VPN в ядре Linux, которым Calico умеет шифровать трафик между узлами;
  • политики для хостов (host endpoints) и анонс адресов сервисов по BGP;
  • Typha — кэширующий посредник между API и Felix из части 14 — на Windows-узлах не запускается, его реплики живут только на Linux;
  • CrossSubnet и настройка MTU для VXLAN.

IPAM: strictAffinity, один блок и четыре адреса

Подсеть HNS-сети создаётся один раз и потом не меняется: Windows не умеет обновлять параметры подсети существующей сети, и документация Calico прямо говорит, что часть настроек после подключения первого пода не применяется, а смена, например, VNI требует осушить узел, удалить HNS-сеть Calico и поставить его заново. Отсюда несколько правил IPAM для Windows-узлов:

  • Один блок на узел. kube-proxy на Windows поддерживает только одну подсеть на HNS-сеть, поэтому Windows-узел получает ровно один блок пула. При стандартном blockSize: 26 — 64 адреса.
  • Четыре адреса блока заняты. Windows-узел резервирует первые три адреса своего блока и последний: адрес сети, шлюз HNS-подсети, служебный адрес и широковещательный адрес; у блока 172.21.41.0/26 узла k8s-lab-win-1 это .0, .1, .2 и .63. Подам остаётся 60. Когда они кончатся, новые поды на узле не получат адрес, а не займут его в чужом блоке: Windows-узлы не заимствуют адреса из чужих блоков, даже если пул заполнен. Поэтому на Windows-узле разумно ограничить maxPods kubelet значением не больше 60 — иначе планировщик будет отправлять туда поды, которым не достанется адреса. Если подов нужно больше, блок задают крупнее до того, как пул начал раздаваться: blockSize существующего пула не меняется.
  • strictAffinity: true. В ресурсе IPAMConfig Calico есть параметр строгой привязки: с ним IPAM выдаёт узлу адреса только из блоков, закреплённых за ним самим, и заимствование (borrowing) из части 14 выключается для всех узлов. Зачем это Windows: если Linux-узел займёт адрес из блока Windows-узла, этот адрес окажется внутри HNS-подсети Windows-узла, и VFP будет считать его своим, локальным — пакеты к поду на Linux-узле до него не дойдут. Документация Calico требует включить strictAffinity до присоединения Windows-узлов. Цена для Linux — та же, что для Windows: когда в пуле не останется свободных блоков, новый под не получит адрес. В пуле /16 с блоками /26 — 1024 блока, так что и в тестовом кластере (172.21.0.0/16), и в основном (172.20.0.0/16) это теоретическая опасность.
  • natOutgoing применяется при создании пода. На Windows маскарадинг — это политика OutBoundNAT на конечной точке пода со списком исключений (адреса пула и сети сервисов, к которым трансляция не нужна). Политика вешается один раз, при создании конечной точки, поэтому изменение natOutgoing в пуле касается только новых подов.

Сетевые политики на Windows

Felix переводит NetworkPolicy и политики Calico в ACL-правила HNS на конечных точках подов, а VFP исполняет их в слое ACL. Работает это так же, как на Linux, с одним предупреждением из документации Calico: даже простые политики могут требовать от датаплейна Windows много ресурсов, особенно правила, где одновременно заданы селекторы источника и назначения: такие правила разворачиваются во множество записей ACL. Документация советует разбивать такие правила на отдельные правила для входящего и исходящего трафика. И ещё: перезапуск Felix или изменение политик могут сбросить установленные соединения между подами пакетами TCP RST.

Что выбираем

Варианта два: VXLAN Always без BGP или BGP без инкапсуляции. У нас все узлы в одной сети 192.168.10.0/24, поэтому сработали бы оба. Выбираем VXLAN Always с выключенным BGP:

  • на Windows-узле не нужны RRAS и роли маршрутизации — меньше компонентов на Server Core, меньше того, что нужно обновлять и диагностировать;
  • сеть подов не зависит от топологии физической сети: Windows-узел может появиться в другой подсети, и ничего не придётся менять;
  • это основной путь в документации Calico для Windows, и он ближе всего к основному кластеру серии: пул остаётся с инкапсуляцией VXLAN, только обёртка включена между любыми узлами.

Цена — 50 байт заголовков VXLAN и работа по обёртке на каждом пакете между узлами, в том числе между Linux-узлами в одной подсети, которые в режиме CrossSubnet общались бы напрямую. MTU интерфейсов подов — 1450 в обоих режимах: Calico сам вычитает заголовок VXLAN из MTU сетевого адаптера узла, а в основном кластере режим CrossSubnet закладывал тот же запас (это видно в выводе ip addr в части 14). Отвергнутый вариант — оставить Linux на CrossSubnet, а Windows-узлам дать отдельный пул с VXLAN — не работает: BGP включается и выключается для всего кластера, а Calico для Windows с VXLAN требует, чтобы он был выключен.


kube-proxy в режиме winkernel

На Windows у kube-proxy один режим — kernelspace, в документации и коде его называют winkernel. Название историческое: «ядро» здесь — это HNS и VFP. kube-proxy так же следит за Service и EndpointSlice, но вместо таблицы nftables создаёт объекты HNS:

  • балансировщик на каждый порт сервиса: виртуальный адрес и порт (ClusterIP, NodePort, внешний адрес) → список конечных точек-бэкендов. VFP выбирает бэкенд для нового соединения и записывает выбор в единый поток — как numgen random и conntrack в nftables-режиме из части 15;
  • удалённые конечные точки (remote endpoints) для подов на других узлах. Балансировщик HNS может ссылаться только на конечные точки, поэтому для бэкенда 172.21.211.8 на k8s-lab-node-1 kube-proxy создаёт в HNS-сети «пустую» конечную точку с этим адресом и пометкой «удалённая». Пакет к ней VFP отправляет по политикам маршрутизации сети — в VXLAN к нужному узлу.

Source VIP. В overlay-режиме kube-proxy нужен адрес из подсети узла, от имени которого VFP отправляет трафик сервисов, если исходный адрес нужно подменить (например, когда запрос пришёл на NodePort снаружи и уходит к поду на другом узле). Это параметр sourceVip. С Calico скрипт запуска kube-proxy из sig-windows-tools ждёт появления в сети Calico служебной конечной точки Calico_ep и берёт её адрес как source VIP — это один из зарезервированных адресов блока.

DSR (Direct Server Return, прямой возврат ответа). Без DSR узел, выбравший бэкенд на другом узле, подменяет и адрес назначения, и адрес источника, чтобы ответ вернулся через него и прошёл обратное преобразование. С DSR балансировка происходит на узле клиента, а обратное преобразование ответа делает VFP на узле пода: ответ идёт клиенту напрямую, а под видит настоящий адрес клиента. DSR на Windows стабилен с Kubernetes 1.34 и заблокирован во включённом состоянии: feature gate WinDSR нельзя выключить, а значение, заданное явно, игнорируется. Нужен он не только ради производительности: externalTrafficPolicy: Local на Windows работает только с DSR (флаг --enable-dsr=true). Аннотация сервиса preserve-destination: "true" идёт ещё дальше — пропускает DNAT, и под получает пакет с виртуальным адресом сервиса в поле назначения.

Привязка сессий (sessionAffinity: ClientIP) работает с Windows Server 2022, так что на Windows Server 2025 нашего Windows-узла доступна.

Конфигурация. В KubeProxyConfiguration для Windows есть раздел winkernel: networkName (HNS-сеть, где kube-proxy создаёт объекты), sourceVip, enableDSR, rootHnsEndpointName и forwardHealthCheckVip. DaemonSet kube-proxy-windows из sig-windows-tools передаёт всё флагами: start.ps1 запускает kube-proxy.exe с --proxy-mode=kernelspace, --source-vip, --enable-dsr=true и feature gates WinDSR=true,WinOverlay=true (оба стабильны, указание лишь подтверждает значение по умолчанию), а имя сети Calico передаёт переменной KUBE_NETWORK. Из общей ConfigMap kube-proxy он берёт только kubeconfig, поэтому mode: nftables для Linux-узлов Windows-поду не мешает. Перед стартом скрипт удаляет старые политики HNS: согласовывать их с оставшимися от прошлого запуска kube-proxy не умеет.


Ограничения сети Windows-узлов

Список из документации Kubernetes, с объяснением, откуда каждое ограничение:

  • Нет hostNetwork для обычных подов. У Windows-пода всегда свой отсек. Альфа-функция WindowsHostNetwork, которая это меняла, отозвана, и её feature gate с 1.33 объявлен устаревшим. В сети узла работают только HostProcess-поды — так устроены calico-node-windows и kube-proxy-windows.
  • NodePort недоступен с самого узла. Обращение к localhost:30080 или к своему адресу на порт NodePort с Windows-узла не работает; с других узлов и снаружи — работает.
  • Не больше 64 бэкендов на сервис. Балансировщик VFP держит не больше 64 уникальных адресов назначения. Сервис с сотней подов на Windows-узлах не поместится в одно правило.
  • Исходящий ICMP через win-overlay, win-bridge и Azure CNI — ограничение преобразований VFP, разобранное выше; на свежих сборках Windows Server 2025 может и не проявляться, но проверять связность наружу всё равно лучше по TCP.
  • externalTrafficPolicy: Local — только с DSR.
  • Нет IPv6. С Calico (и вообще в overlay/VXLAN) IPv6 на Windows-узлах не поддерживается.
  • Короткие имена с точкой не разрешаются. Среди поддерживаемых на Windows обращений документация называет «под → сервис по частичному имени, только если в нём нет точки». Имя hello из того же неймспейса и полное hello.demo.svc.cluster.local работают, а hello.demo — нет: резолвер Windows не дописывает к такому имени суффиксы поиска так, как это делает ndots:5 на Linux (часть 16). В конфигурации Windows-приложений имена сервисов из других неймспейсов лучше писать полностью.
  • Эталонные плагины без CHECK и ограничения Flannel VXLAN, о которых выше.

Где запускать Windows-узлы: новый кластер или перевод существующего

Основной учебный кластер серии сейчас работает не так, как нужно Windows-узлу. Пул default-ipv4-ippool — в режиме VXLANCrossSubnet, BIRD на каждом узле держит BGP-сессии со всеми остальными, хотя маршруты к блокам в ядро пишет не он, а Felix (proto 80), strictAffinity выключена. Windows-узлу нужны VXLAN Always, выключенный BGP и strictAffinity; VNI 4096 и порт 4789 — те же, что сейчас. Прийти к этому можно двумя путями: собрать для Windows-воркеров отдельный тестовый кластер, сразу в нужном режиме, или перевести существующий кластер на работающих подах. Рекомендуем первый путь; второй — альтернатива, и его тоже разберём целиком.

Рекомендуемый путь: отдельный тестовый кластер

Почему отдельный кластер, а не перевод основного:

  • Смена сети на работающем кластере затрагивает все поды. Инкапсуляция меняется на всех узлах сразу, маршруты между узлами перестраиваются, соединения, которые идут в этот момент, могут оборваться. Откат — такая же операция на всём кластере.
  • Calico на Windows ставит условия всему кластеру. VXLAN без CrossSubnet, выключенный BGP, strictAffinity, один блок на Windows-узел, только IPv4, на Windows — без eBPF и WireGuard. Проще заложить эти условия с первого дня, чем переделывать кластер, который вырос без них.
  • Windows-узлы — отдельная зона ответственности. Ежемесячные обновления, совпадение сборки образов и хоста из части 36, доменные учётные записи и сам домен (часть 40) — всё это лучше осваивать на кластере, где ошибка не заденет основные сервисы.
  • Основной кластер остаётся как был — VXLANCrossSubnet и BIRD, — и всё, что построено на нём в предыдущих частях, продолжает работать. С ним же работает и часть 41.

Тестовый кластер — минимальный гибридный: Linux control plane, два Linux-воркера и один Windows-воркер. Linux-воркеры обязательны: на них работают CoreDNS, Tigera operator и Typha, вебхуки и контроллеры CSI — всё, что существует только в виде Linux-образов, — а Calico для Windows требует хотя бы один Linux-воркер с Calico. Второй воркер нужен, чтобы любой из них можно было вывести на обслуживание, как в основном кластере.

Основной кластер Тестовый кластер
control plane k8s-master-1, 192.168.10.17 k8s-lab-master-1, 192.168.10.23
Linux-воркеры k8s-node-1 и k8s-node-2, 192.168.10.20 и .21 k8s-lab-node-1 и k8s-lab-node-2, 192.168.10.24 и .26
Windows-воркеры нет k8s-lab-win-1, 192.168.10.25, Windows Server 2025 Server Core
имя API k8s-api.example.com k8s-lab-api.example.com
сеть подов 172.20.0.0/16 172.21.0.0/16
сеть сервисов 10.96.0.0/12 10.96.0.0/12
Calico VXLANCrossSubnet, BGP через BIRD VXLAN Always, BGP выключен
strictAffinity выключена включена

Сеть подов тестового кластера выбрана отличной от основного, чтобы адреса в выводе команд не путались и чтобы по адресу пода сразу было видно, из какого он кластера. Сеть сервисов может совпадать: ClusterIP за пределы своего кластера не выходят.

Calico ставится в тестовый кластер Tigera operator, как в основной, но сразу в нужном режиме — без всякой миграции. Ресурс Installation:

apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    bgp: Disabled
    linuxDataplane: Nftables
    windowsDataplane: HNS
    ipPools:
    - name: default-ipv4-ippool
      cidr: 172.21.0.0/16
      encapsulation: VXLAN
      natOutgoing: Enabled
      blockSize: 26
  serviceCIDRs:
  - 10.96.0.0/12
  • bgp: Disabled — BIRD и confd в calico-node не запускаются с самого начала, маршруты к блокам соседей прописывает Felix;
  • encapsulation: VXLAN — оператор создаёт пул с vxlanMode: Always; VNI 4096 и порт 4789 — значения по умолчанию, их не задаём;
  • linuxDataplane: Nftables — как в основном кластере;
  • windowsDataplane: HNS — включает DaemonSet calico-node-windows; без этого поля оператор Windows-узлы не обслуживает;
  • serviceCIDRs — сеть сервисов: Calico для Windows не может узнать её из API, а на Windows-узле она нужна, например, для списка исключений OutBoundNAT, о котором шла речь выше.

Сразу после установки, до появления Windows-узла, включается strictAffinity — той же командой, что в шаге 1 альтернативного пути ниже:

$ kubectl patch ipamconfigurations default --type merge -p '{"spec":{"strictAffinity":true}}'
ipamconfiguration.projectcalico.org/default patched

И последнее, что отличает установку Calico для Windows: оператору нужен прямой адрес API-сервера. Обычно компоненты Calico ходят в API через ClusterIP сервиса kubernetes, но на Windows-узле calico-node-windows стартует раньше, чем kube-proxy настроит балансировку, поэтому адрес передают ConfigMap в неймспейсе оператора:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kubernetes-services-endpoint
  namespace: tigera-operator
data:
  KUBERNETES_SERVICE_HOST: k8s-lab-api.example.com
  KUBERNETES_SERVICE_PORT: "6443"

Сама сборка — в части 38: три Linux-машины так же, как в части 4, только с отличиями, Calico с этими ресурсами, второй контекст в kubeconfig, чтобы с рабочей станции работать с обоими кластерами, и затем Windows-воркер.

Альтернатива: перевод существующего кластера

Перевод имеет смысл, когда Windows-приложениям нужно жить в том же кластере, что и остальные сервисы (общие Ingress, хранилище, мониторинг), а держать второй кластер негде. Цена и риски:

  • перевод затрагивает все поды на всех узлах: в момент замены маршрутов соединения между узлами могут оборваться, поэтому в рабочем кластере его делают в окно обслуживания;
  • после перевода весь трафик подов между любыми двумя узлами идёт через VXLAN: UDP 4789 должен быть открыт между всеми узлами, а процессы в сети узла начинают ходить к подам с туннельного адреса — правила NetworkPolicy с ipBlock по адресам узлов придётся дополнить (подробнее в шаге 4);
  • выключенный BGP — это и отказ от всего, что на нём построено: пиринга узлов с маршрутизатором и анонса адресов сервисов по BGP;
  • откат возможен, только пока в кластере нет Windows-узлов; после присоединения первого возвращаться некуда.

Цель — VXLAN Always, BGP выключен, strictAffinity включена, VNI 4096 и порт 4789 остаются прежними. Делается это до присоединения Windows-узла, на работающем кластере, без пересоздания подов. После перевода в Installation остаётся добавить то же, что тестовый кластер получает при установке, — windowsDataplane: HNS и serviceCIDRs, — и создать ConfigMap kubernetes-services-endpoint; эти изменения на Linux-узлах ничего не перестраивают, но ConfigMap заставит оператор перезапустить calico-node с прямым адресом API.

Все изменения — через ресурс Installation, а не правкой IPPool: пул создан оператором, и документация Calico предупреждает, что оператор вернёт прямые правки пула к тому, что записано в Installation. Calico после части 35 — версии 3.33, вместе с Calico API server (он виден в kubectl get tigerastatus), поэтому ресурсы Calico доступны и через kubectl, и через calicoctl той же версии.

 сейчас                                       после перевода
 ┌────────────────────────────────────┐       ┌────────────────────────────────────┐
 │ пул: vxlanMode CrossSubnet         │       │ пул: vxlanMode Always              │
 │ Installation: bgp Enabled          │       │ Installation: bgp Disabled         │
 │ BIRD: полная сетка BGP, TCP 179    │  ──►  │ BIRD и confd не запускаются        │
 │ маршруты к блокам: proto 80,       │       │ маршруты к блокам: mtu 1450,       │
 │   via адрес узла dev ens18         │       │   via VTEP dev vxlan.calico        │
 │ strictAffinity: false              │       │ strictAffinity: true               │
 └────────────────────────────────────┘       └────────────────────────────────────┘

Шаг 0. Что есть сейчас

$ kubectl get installation default -o jsonpath='{.spec.calicoNetwork}' | jq '{bgp, ipPools: [.ipPools[] | {name, cidr, encapsulation, natOutgoing, blockSize}]}'
{
  "bgp": "Enabled",
  "ipPools": [
    {
      "name": "default-ipv4-ippool",
      "cidr": "172.20.0.0/16",
      "encapsulation": "VXLANCrossSubnet",
      "natOutgoing": "Enabled",
      "blockSize": 26
    }
  ]
}
user@k8s-node-1:~$ sudo calicoctl node status | head -n 9
Calico process is running.

IPv4 BGP status
+---------------+-------------------+-------+------------+-------------+
| PEER ADDRESS  |     PEER TYPE     | STATE |   SINCE    |    INFO     |
+---------------+-------------------+-------+------------+-------------+
| 192.168.10.17 | node-to-node mesh | up    | 2026-10-09 | Established |
| 192.168.10.21 | node-to-node mesh | up    | 2026-10-09 | Established |
+---------------+-------------------+-------+------------+-------------+

Таблица маршрутов k8s-node-1 — та же, что в части 14: блоки соседей через их адреса на ens18, proto 80. Перед изменениями стоит убедиться, что между всеми узлами, включая адрес будущего Windows-узла, открыт UDP 4789: если на узлах или между ними есть фильтр, после перевода через него пойдёт весь трафик подов. TCP 179 после перевода, наоборот, больше не нужен.

Шаг 1. strictAffinity

$ kubectl patch ipamconfigurations default --type merge -p '{"spec":{"strictAffinity":true}}'
ipamconfiguration.projectcalico.org/default patched
$ calicoctl ipam show --show-configuration
+--------------------+-------+
|      PROPERTY      | VALUE |
+--------------------+-------+
| StrictAffinity     | true  |
| AutoAllocateBlocks | true  |
| MaxBlocksPerHost   |     0 |
+--------------------+-------+

Это изменение ничего не делает с существующими адресами: оно запрещает будущие заимствования. Проверить, что заимствованных адресов в кластере нет и сейчас, можно командой calicoctl ipam check: она сверяет блоки, привязки и адреса подов и сообщает о расхождениях. То же самое делает calicoctl ipam configure --strictaffinity=true, если под рукой нет Calico API server. Поле MaxBlocksPerHost (сколько блоков может получить один узел) не трогаем: оно действует на все узлы, а Windows-узел и так берёт один блок.

Шаг 2. Инкапсуляция VXLAN во всех направлениях

$ kubectl patch installation default --type=json \
    -p '[{"op":"replace","path":"/spec/calicoNetwork/ipPools/0/encapsulation","value":"VXLAN"}]'
installation.operator.tigera.io/default patched
$ kubectl get ippools -o custom-columns=NAME:.metadata.name,CIDR:.spec.cidr,VXLAN:.spec.vxlanMode,IPIP:.spec.ipipMode,NAT:.spec.natOutgoing
NAME                  CIDR            VXLAN    IPIP    NAT
default-ipv4-ippool   172.20.0.0/16   Always   Never   true

Оператор переписал vxlanMode пула в Always. Дальше действует Felix на каждом узле: он видит, что блоки соседей теперь в пуле с постоянной инкапсуляцией, и заменяет свои маршруты к ним — шлюзом вместо адреса соседа на ens18 становится его туннельный адрес на vxlan.calico. BIRD в этом не участвует: маршруты пула с VXLAN он в ядро не писал и раньше, фильтр в его конфигурации оставляет их Felix. BGP-сессии при этом ещё живут:

user@k8s-node-1:~$ ip route | grep vxlan
172.20.70.192/26 via 172.20.70.192 dev vxlan.calico onlink mtu 1450
172.20.172.0/26 via 172.20.172.0 dev vxlan.calico onlink mtu 1450

Поменялись шлюз и интерфейс, а с ними и вид маршрута. Метки proto 80, которой Felix помечал прямые маршруты к блокам до перевода, у маршрутов через vxlan.calico в выводе нет — её Felix оставляет только на blackhole своего блока. Зато у каждого такого маршрута свой MTU 1450: на 50 байт меньше, чем у ens18, — место под заголовки VXLAN. Шлюз — туннельный адрес соседа (первый адрес его блока, как в части 14), onlink говорит ядру считать его доступным прямо через интерфейс. Пакет к 172.20.172.6 теперь уходит в vxlan.calico, ядро по ARP-записи туннельного адреса находит MAC VTEP соседа, по записи FDB — адрес узла, к которому этот MAC относится, и отправляет UDP-датаграмму на 192.168.10.21:4789. Обе записи Felix ставит статически: VXLAN-интерфейс Calico создан с nolearning и ничего не узнаёт сам.

Что происходит с подами в этот момент: ничего. Адреса, блоки, интерфейсы cali…, правила политик и natOutgoing не меняются, перезапусков нет. Меняется только способ доставки между узлами, и в момент замены маршрута пакеты между узлами могут кратко теряться; документация Calico предупреждает, что смена режима инкапсуляции может разорвать соединения, которые идут в этот момент. На учебном кластере это доли секунды, но в рабочем кластере такое делают в окно обслуживания.

Шаг 3. Выключаем BGP

$ kubectl patch installation default --type=merge -p '{"spec":{"calicoNetwork":{"bgp":"Disabled"}}}'
installation.operator.tigera.io/default patched
$ kubectl -n calico-system rollout status ds/calico-node
Waiting for daemon set "calico-node" rollout to finish: 1 out of 3 new pods have been updated...
Waiting for daemon set "calico-node" rollout to finish: 2 out of 3 new pods have been updated...
daemon set "calico-node" successfully rolled out
$ kubectl get tigerastatus
NAME        AVAILABLE   PROGRESSING   DEGRADED   SINCE
apiserver   True        False         False      12d
calico      True        False         False      34s
ippools     True        False         False      12d
tiers       True        False         False      12d

Оператор меняет шаблон DaemonSet calico-node: бэкенд сети — vxlan вместо bird, проверка готовности — только Felix, без BIRD:

$ kubectl -n calico-system get ds calico-node -o json | jq -r '.spec.template.spec.containers[0] | (.env[] | select(.name=="CALICO_NETWORKING_BACKEND") | .value), (.readinessProbe.exec.command | join(" "))'
vxlan
/usr/bin/calico component node health --felix-ready

и перезапускает calico-node по одному узлу. Перезапуск агента не трогает датаплейн: маршруты и таблицы nftables остаются в ядре, новый Felix читает их, сверяет с желаемым состоянием и исправляет только расхождения. Поды продолжают работать; запуск нового пода на узле в те секунды, пока его calico-node перезапускается, просто подождёт CNI. После перезапуска BIRD и confd в calico-node не стартуют; таблицу маршрутов это не меняет — маршруты к блокам соседей и blackhole на собственный блок Felix прописывал и до этого.

Откат, пока Windows-узлов в кластере нет, — те же два патча в обратном порядке: bgp: Enabled, затем encapsulation: VXLANCrossSubnet. После присоединения Windows-узла откатываться некуда: с BGP и CrossSubnet он работать не будет.

Шаг 4. Проверка

Таблица маршрутов k8s-node-1 после перевода:

user@k8s-node-1:~$ ip route | grep 172.20
172.20.70.192/26 via 172.20.70.192 dev vxlan.calico onlink mtu 1450
172.20.172.0/26 via 172.20.172.0 dev vxlan.calico onlink mtu 1450
blackhole 172.20.211.0/26 proto 80
172.20.211.1 dev cali01e594701c5 scope link metric 1024
172.20.211.43 dev calia68edcf6ff3 scope link metric 1024
172.20.211.53 dev cali4d7612d46be scope link metric 1024

Сравните с частью 14: маршруты к подам своего узла и blackhole не изменились, а блоки соседей идут теперь не через их адреса на ens18, а через vxlan.calico. BGP больше нет:

user@k8s-node-1:~$ sudo calicoctl node status
Calico process is running.

None of the BGP backend processes (BIRD or GoBGP) are running.

Пакеты. Под net с busybox из части 14 на k8s-node-1 пингует под hello на k8s-node-2, а на ens18 ловим VXLAN:

$ kubectl -n demo exec net -- ping -c1 172.20.172.6
64 bytes from 172.20.172.6: seq=0 ttl=62 time=0.517 ms

user@k8s-node-1:~$ sudo tcpdump -ni ens18 udp port 4789
10:52:13.204511 IP 192.168.10.20.48213 > 192.168.10.21.4789: VXLAN, flags [I] (0x08), vni 4096
IP 172.20.211.53 > 172.20.172.6: ICMP echo request, id 23, seq 0, length 64
10:52:13.204896 IP 192.168.10.21.41377 > 192.168.10.20.4789: VXLAN, flags [I] (0x08), vni 4096
IP 172.20.172.6 > 172.20.211.53: ICMP echo reply, id 23, seq 0, length 64

Теперь и между соседями в одной подсети — внешний UDP с адресами узлов, внутри — пакет подов, VNI 4096. ttl=62 тот же: на пути по-прежнему два маршрутизатора, ядро каждого узла. MTU пода не изменился:

$ kubectl -n demo exec net -- ip link show eth0 | head -1
2: eth0@if173: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue qlen 1000

Сервисы работают как прежде: kubectl -n demo exec net -- wget -qO- http://hello/ отвечает с разных подов, правила kube-proxy из части 15 перевод не трогал. Одно изменение стоит запомнить: процессы в сети узла (hostNetwork), обращаясь к подам на других узлах, теперь выходят через vxlan.calico, и под видит источником туннельный адрес узла (172.20.211.0), а не 192.168.10.20. Если в NetworkPolicy из части 20 есть правила ipBlock по адресам узлов, их нужно дополнить туннельными адресами. Таблицы ARP и FDB после перевода устроены так же, как в тестовом кластере, который мы соберём в части 38, только с адресами основного кластера.


Источники


Дальше — гибридный кластер на kubeadm. Сначала соберём тестовый кластер: две Linux-машины так же, как в части 4, только с отличиями (имена k8s-lab-*, сеть подов 172.21.0.0/16, имя API k8s-lab-api.example.com, сразу Kubernetes 1.37.2), Calico 3.33 оператором сразу в VXLAN без BGP и со strictAffinity, второй контекст в kubeconfig, metrics-server и cert-manager. Затем присоединим к нему Windows-воркер: подготовка Windows Server 2025 Server Core (роль Containers, обновления, имя, время), containerd, kubelet и kubeadm службами Windows, kubeadm join, Calico для Windows через Tigera operator и что после этого появляется на узле, DaemonSet kube-proxy для Windows в HostProcess, taint и RuntimeClass; проверка — веб-приложение на .NET в образе на основе Nano Server, Service и DNS между подами Linux и Windows, nodeSelector у Linux-DaemonSet'ов и что смотреть, если узел остаётся NotReady.

Оставить комментарий могут только зарегистрированные пользователи.

Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.