Тонкая настройка маршрутизации для MetalLB в режиме L2

  • Tutorial


Не так давно я столкнулся с весьма нестандартной задачей настройки маршрутищации для MetalLB. Всё бы ничего, т.к. обычно для MetalLB не требуется никаких дополнительных действий, но в нашем случае имеется достаточно большой кластер с весьма нехитрой конфигурацией сети.


В данной статье я расскажу как настроить source-based и policy-based routing для внешней сети вашего кластера.


Я не буду подробно останавливаться на установке и настройке MetalLB, так как предполагаю вы уже имеете некоторый опыт. Предлагаю сразу перейти к делу, а именно к настройке маршрутизации. Итак мы имеем четыре кейса:


Случай 1: Когда настройка не требуется


Разберём простой кейс.



Дополнительная настройка маршрутизации не требуется, когда выдаваемые MetalLB адреса находятся в той же подсети что и адреса ваших нод.


Например вы имеете подсеть 192.168.1.0/24, в ней имеется маршрутизатор 192.168.1.1, и ваши ноды получают адреса: 192.168.1.10-30, тогда для MetalLB вы можете настроить рейндж 192.168.1.100-120 и быть уверенным что они будут работать без какой либо дополнительной настройки.


Почему так? Потому что ваши ноды уже имеют настроенные маршруты:


# ip route
default via 192.168.1.1 dev eth0 onlink 
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10

И адреса из того же рейджа будут переиспользовать их без каких-либо дополнительных телодвижений.


Случай 2: Когда требуется дополнительная настройка



Вам следует настроить дополнительные маршруты всякий раз тогда, когда ваши ноды не имеют настроенного IP-адреса или маршрута в подсеть для которой MetalLB выдаёт адреса.


Объясню чуть подробней. Всякий раз когда MetalLB выдёт адрес, это можно сравнить с простым назначением вида:


ip addr add 10.9.8.7/32 dev lo

Обратите внимание, на:


  • a) Адрес назначается с префиксом /32 то есть маршрут в подсеть для него автоматически не добавится (это просто адрес)
  • b) Адрес вешается на любой интерфейс ноды (например loopback). Здесь стоит упомянуть, об особенности сетевого стека Linux. Не важно на какой интерфейс вы добавите адрес, ядро всегда будет обрабатывать arp-запросы и отправлять arp-ответы на любой из них, это поведение считается коректным и, кроме того, достаточно широко используется в такой динамической среде как Kubernetes.

Данное поведение можно настраивать, например включив strict arp:


echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

В этом случае arp-ответы будут отправляться только в том случае, если интерфейс явно содержит конкретный IP-адрес. Данная настройка является обязательной в случае если вы планируете использовать MetalLB и ваш kube-proxy работает в режиме IPVS.


Тем не менее MetalLB не использует ядро для обработки arp-запросов, а делает это самостоятельно в user-space, таким образом данная опция не повлияет на работу MetalLB.


Вернёмся к нашей задаче. Если маршрута для выдаваемых адресов на ваших нодах не существует, добавьте его заранее на все ноды:


ip route add 10.9.8.0/24 dev eth1

Случай 3: Когда понадобится source-based routing


Source-based routing вам потребуется настроить тогда, когда вы получаете пакеты через отдельный gateway, не тот что настроен у вас по умолчанию, соответственно ответные пакеты также должы уходить через этот же gateway.


Например, у вас есть всё таже подсеть 192.168.1.0/24 выделенная для ваших нод, но вы хотите выдавать внешние адреса с помощью MetalLB. Предположим, у вас есть несколько адресов из подсети 1.2.3.0/24 находящихся во VLAN 100, и вы хотите использовать их для доступа Kubernetes-служб извне.



При обращении на 1.2.3.4 вы будете совершать запросы из другой подсети нежели 1.2.3.0/24 и ожидать ответ. Нода, которая в данный момент является мастером для выданного MetalLB адреса 1.2.3.4, получит пакет от маршрутизатора 1.2.3.1, но ответ для него обязательно должен уйти тем же маршрутом, через 1.2.3.1.


Так как наша нода уже имеет настроенный default gateway 192.168.1.1, то по умолчанию ответ пойдёт к нему, а не к 1.2.3.1, через который мы получили пакет.


Как же справиться с данной ситуацией?


В этом случае вам необходимо подготовить все ваши ноды таким образом, чтобы они были готовы обслуживать внешние адреса без дополнительной настройки. То есть для вышеприведённого примера вам нужно заранее создать VLAN-интерфейс на ноде:


ip link add link eth0 name eth0.100 type vlan id 100
ip link set eth0.100 up

А затем добавить маршруты:


ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100

Обратите внимание маршруты мы добавляем в отдельную табицу маршрутизации 100 она будет содержать только два маршрута необходимых для отправки ответного пакета через гейтвей 1.2.3.1, находящийся за интерфейсом eth0.100.


Теперь нам нужно добавить простое правило:


ip rule add from 1.2.3.0/24 lookup 100

которое явно говорит: если адрес источника пакета находится в 1.2.3.0/24, то нужно использовать табицу маршрутизации 100. В ней у нас уже описан маршрут который отправит его через 1.2.3.1


Случай 4: Когда понадобится policy-based routing


Топология сети как и в предыдущем примере, но допустим вы хотите также иметь возиможность обращаться к внешним адресам пула 1.2.3.0/24 из ваших подов:



Особенность заключается в том что при обращении к любому адресу в 1.2.3.0/24, ответный пакет попадая на ноду и имея адрес источника в диапазоне 1.2.3.0/24 будет послушно отправлен в eth0.100, но мы-то хотим чтобы Kubernetes перенаправил его в наш первый под, который и сгенерировал изначальный запрос.


Решить данную проблему оказалось непросто, но это стало возможным благодаря policy-based routing.


Для начала, как и в предыдущем примере, создадим дополнительную таблицу маршрутизации:


ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100

Метод предложенный amarao

Уже после публикации этой статьи мне предложили более простой и изящный метод решения данной проблемы, для этого нам всего-лишь нужно добавить два правила:


ip rule add from 1.2.3.0/24 lookup 100
ip rule add from 1.2.3.0/24 to 10.112.0.0/12 lookup main

где:


  • 1.2.3.0/24 — внешняя подсеть
  • 10.112.0.0/12 — ваша podNetwork

Второе правило обязательно должно быть объявленно после первого, чтобы получило наивысший приоритет.


Метод с маркировкой соединения

Для большего понимания процесса приведу блок схему netfilter:


Теперь добавим несколько правил в iptables:


iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN
iptables -t mangle -A PREROUTING -i bond0.100 -j MARK --set-mark 0x100
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark

Эти правила будут маркировать входящие подключения на интерфейс eth0.100, помечая все пакеты тэгом 0x100, этим же тэгом будут помечены и ответы в рамках одного подключения.


Теперь мы можем добавить правило роутинга:


ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100

То есть все пакеты с адресом источника 1.2.3.0/24 и тэгом 0x100 должны быть смаршрутизированны используя таблицу 100.


Таким образом другие пакеты, полученные на другой интерфейс, под это правило не попадают, что позволит им быть смаршрутизированными стандартными средствами Kubernetes.


Есть ещё одно но, в Linux существует так называемый reverse path filter, который портит всю малину осуществляет простую проверку: для всех входящих пакетов он меняет адрес источника пакета с адресом отправителя и проверяет может-ли пакет уйти через тот-же интерфейс на который был получен, если нет, то отфильтровывет его.


Проблема в том что в нашем случае он будет работать некорректно, но мы можем отключить его:


echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filter

Обратите внимание, первая команда котролирует глобальное поведение rp_filter, если его не отключить, то вторая команда не будет иметь никакого эфекта. Тем не менее остальные интерфейсы останутся со включённым rp_filter.


Чтобы не ограничивать работу фильтра полностью мы можем воспользоваться реализацией rp_filter для netfilter. Используя rpfilter в качестве модуля iptables можно настроить достаточно гибкие правила, например:


iptables -t raw -A PREROUTING -i eth0.100 -d 1.2.3.0/24 -j RETURN
iptables -t raw -A PREROUTING -i eth0.100 -m rpfilter --invert -j DROP

включат rp_filter на интерфейсе eth0.100 для всех адресов кроме 1.2.3.0/24.

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 44

    0

    очень круто! Но не рассмотрена одна из проблем — что будет с Real IP клиента после попадания в кластер. Даже в дефолтной инсталляции MetalLB с ней есть нюансы.

      0

      Если использовать externalTrafficPolicy=Local то IP-адрес клиента передаётся в workload без изменений это работает из коробки like a charm.


      Подробности: https://kubernetes.io/docs/tutorials/services/source-ip/

        +1

        И… ломаешь балансировку трафика на поды, не ?


        The downside of this policy is that incoming traffic only goes to some pods in the service. Pods that aren’t on the current leader node receive no traffic, they are just there as replicas in case a failover is needed.

        https://metallb.universe.tf/usage/

      +1

      Комбинация iptables с рутингом (когда iptables влияет на маршрут) — это всегда 'code smell'. Вы уверены, что вам надо использовать iptables, если можно обойтись ip rule?


      Объясняю, почему это code smell. У вас есть две сущности: iptables и рутинг. iptables идеологически определяет "можно или нет" пакету пройти сетевой стек. рутинг говорит "куда идти" пакету. Вы создаёте патологическую связность между двумя разными сущностями, решающими разные задачи.


      На выходе — хрупкая архитектура, которая "но у меня всё работает" (а у меня нет), в которой трудно разобраться, трудно отладить и которая содержит в себе добротную порцию WTF для любого пришедшего (все косвенные признаки паталогической связности).

        0

        Спасибо за отзыв, смею с ним согласиться.
        Но в моём кейсе обойтись простым ip rule не удалось, по этому пришлось маркировать пакеты и принимать решение о маршрутизации в зависимости от интерфейса на который они были получены.

          +1

          Мне лениво в бездны докера нырять. Скажите, что вы хотели от ip rule? (Будем считать интересным админским упражнением).

            +1

            Ох, ну если вам правда интересно, то изначальная задача была такая:


            Имеется n физических нод, на каждой из них есть несколько интерфейсов и IPVS, скажем:


            • bond0 (10.10.0.0/16) — внутренняя сетка
            • kube-bridge — бридж с контейнерами на ноде
            • kube-dummy-if — dummy интерфейс для IPVS, сюда вешаются все сервисные IP из куба (как внешние так и clusterIP), по сути это выглядит следующим образом:

            Котейнеры получают адреса из podSubnet: 10.112.0.0/12, на каждую ноду выделяется свой рейдж из этого диапазона.
            Есть ещё serviceSubnet: 10.96.0.0/12 (специальная сеть для сервисов Kubernetes, считайте это сетью для virtualserver-адресов в IPVS)


            Скрытый текст

            strict arp включён:


            echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
            echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

            но на MetalLB он не влияет.


            (вывод изменён)


            # ip addr
            1: bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP group default qlen 1000
                link/ether 94:f1:28:c6:87:39 brd ff:ff:ff:ff:ff:ff
                inet 10.10.130.182/16 brd 10.10.255.255 scope global bond0
            
            2: kube-dummy-if: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
                link/ether 22:71:5f:ff:3a:05 brd ff:ff:ff:ff:ff:ff
                inet 1.2.3.4/32 brd 1.2.3.4 scope link kube-dummy-if
                   valid_lft forever preferred_lft forever
                inet 10.96.221.9/32 brd 10.96.221.9 scope link kube-dummy-if
                   valid_lft forever preferred_lft forever
                inet 10.96.113.129/32 brd 10.96.113.129 scope link kube-dummy-if
                   valid_lft forever preferred_lft forever
            
            3: bond0.100@bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP group default qlen 1000
                link/ether 94:f1:28:c6:87:39 brd ff:ff:ff:ff:ff:ff
                inet6 fe80::96f1:28ff:fec6:8739/64 scope link 
                   valid_lft forever preferred_lft forever
            
            4: kube-bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
                link/ether 5e:79:2d:c4:d3:e9 brd ff:ff:ff:ff:ff:ff
                inet 10.113.63.1/24 scope global kube-bridge
                   valid_lft forever preferred_lft forever
                inet6 fe80::5c79:2dff:fec4:d3e9/64 scope link 
                   valid_lft forever preferred_lft forever
            
            5: veth11694f93@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master kube-bridge state UP group default 
                link/ether e2:66:16:a9:fd:25 brd ff:ff:ff:ff:ff:ff link-netnsid 4
                inet6 fe80::e066:16ff:fea9:fd25/64 scope link 
                   valid_lft forever preferred_lft forever
            6: vethe332a950@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master kube-bridge state UP group default 
                link/ether e6:1b:9a:1b:d8:a2 brd ff:ff:ff:ff:ff:ff link-netnsid 5
                inet6 fe80::e41b:9aff:fe1b:d8a2/64 scope link 
                   valid_lft forever preferred_lft forever

            # ipvsadm -L -n
            TCP  10.96.113129:9000 rr
              -> 10.112.58.28:9000            Masq    1      0          0      
            TCP  10.96.221.9:80 rr
              -> 10.112.147.25:80             Masq    1      0          0         
              -> 10.113.14.200:80             Masq    1      0          0         
              -> 10.113.63.39:80              Masq    1      0          0     
            TCP  1.2.3.4:80 rr
              -> 10.112.147.25:80             Masq    1      0          0         
              -> 10.113.14.200:80             Masq    1      0          0         
              -> 10.113.63.39:80              Masq    1      0          0     

            Таблица маршрутизации внутри кластера сторится с помощью kube-router (BGP):


            # ip route
            # дефолтный гейтвей во внутренней сети
            default via 10.10.0.1 dev bond0 proto static
            # маршрут в локальный контейнер
            10.113.63.0/24 dev kube-bridge proto kernel scope link src 10.113.63.1 
            # маршруты к контейнерам на других нодах
            10.113.14.0/24 via 10.10.130.1 dev bond0 proto 17 
            10.113.14.0/24 via 10.10.130.1 dev bond0 proto 17
            10.113.58.0/24 via 10.10.130.186 dev bond0 proto 17

            есть также vlan интерфейс с внешней сеткой


            • bond0.100 (1.2.3.0/24)

            Особенность MetalLB в том что он кофигурит роутинг от слова "никак", то есть механика его работы заключается тупо в том, чтобы в нужный момент добавить внешний 1.2.3.4/32 адрес на ноду.
            Соответсвенно все роуты должны должны быть настроенны на ноде заранее, включая роут во внешнюю подсеть, т.к. нода не имеет IP-адреса из таковой.


            задача:


            1. Настроить чтобы ответ с source ip 1.2.3.0/24 уходил через bond0.100 (по умолчанию он, ожидаемо, идёт в default gateway внутренней сети)
            2. В тоже время нужно оставить возможность обращаться из контейнеров к внешней подсети 1.2.3.0/24, эти пакеты не должны уходить через bond0.100, а должны попадать на ноду, чтобы быть отмаршрутизированными в друие контейнеры средствами IPVS.

            если перая задача может быть легко решена дополнительной таблицей маршрутизации со своим gateway и правилом типа:


            ip rule add from 1.2.3.0/24 lookup 100

            и это работает даже без переключения rp_filter


            то со второй задачей возникает проблема:
            когда контейнеры генерируют пакеты к 1.2.3.4 они уходят в bond0.100, а должны попадать на dummy интерфейс чтобы быть перенаправленными через IPVS

              +1

              (спасибо, challenge accepted, я сегодня вечером ей займусь).

                +2

                Обрезаю задачу до минимальной. У вас опечатки. eth0.100? Я предполагаю, что речь про bond0.100.


                Моё понимание задачи:
                На сервере три интерфейса:
                bond0 — 10.10.x.x/16, default gateway
                bond0.100 — 1.2.3.x/24 — internet, куда надо маршуртизировать тарфик от 1.2.3.х/24. Я предполагаю, что где-то там есть шлюз 1.2.3.1.
                есть dummy интерфейс kube-dummy-if, который содержит много адресов из 1.2.3.х/24.
                ....


                Дальше, конейнеры локальные или трафик через bond0 может прилетать? Я вижу дополнительные роуты на контейнеры, но из описания я не понял, трафик на 1.2.3.х идёт только из "своих" контейнеров или может приходить с bond0?


                Я предполагаю, что может приходить снаружи (bond0). В этом случае у нас:


                Есть адреса из 10.112.х.х сетей, как на локальном бридже, так и за bond0 (куда настроены дополнительные машруты на них).


                Задача: обеспечить маршрутизацию между контейнерами и kube-dummy-if, плюс обеспечить отправку трафика от kube-dummy-if для посторонних адресов (т.е. для интернета) в bond0.100.


                ip rule add from {{ external_ips }} to {{ container_net }} table 0 # default gateway
                ip rule add from {{ external_ips }} table 1 #source_based

                дальше


                ip route add default via 1.2.3.1/24 dev bond0.100 table 1

                Или я что-то пропустил?

                  0
                  Дальше, конейнеры локальные или трафик через bond0 может прилетать?

                  Да всё верно, трафик из контейнеров может идти как локально из kube-bridge, так и с других нод через bond0.


                  Хорошая попытка, но к сожалению ip rule to у меня не заработало, как ни крути ответные пакеты всегда уходят в bond.100:



                  в не зависимости от того какие правила я добавил бы на ноду, последнее всегда стреляет:


                  # ip rule
                  0:      from all lookup local
                  32762:  from all to 10.112.0.0/12 lookup local
                  32764:  from 1.2.3.0/24 lookup 100

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

                    0

                    Т.е. вы утверждаете, что в списке правил всегда применяется последнее matched? man с вами не согласен.


                    Each policy routing rule consists of a selector and an action predicate. The RPDB is scanned in order of decreasing priority (note that lower number means higher priority, see the description of PREFERENCE below). The selector of each rule is applied to {source address, destination address, incoming interface, tos, fwmark} and, if the selector matches the packet, the action is performed. The action predicate may return with success. In this case, it will either give a route or failure indication and the RPDB lookup is terminated. Otherwise, the RPDB program continues with the next rule.


                    Т.е. правило может либо вернуть success (с route'ом или с failure), либо lookup продолжится.
                    И у нас есть action unicast — the rule prescribes to return the route found in the routing table referenced by the rule..


                    Мне кажется, вы просто недочитали ip rule. Может быть я тоже не дочитал, но пока то, что вы говорите, не звучит как "не подходит как решение". После этого становятся применимы мои аргументы по поводу путать iptables с ip route.


                    Где вы ошиблись: пытались отладить ip rule на боевой настройке, а не в уютной виртуалке с тремя интерфейсами. Minimal viable case, как stackoverflow требует. В процессе изготовления обычно много тумана из головы уходит и появляется два-три правильных вопроса, ответы на которые и содержат решение.

                      0

                      Пардон, я не так выразился, я всего-лишь хотел сказать что правило


                      ip rule add to 10.112.0.0/12 lookup local

                      в моём случае не работало и вместо него выполнялось следующее попадающее под условие.


                      Разобрался, проблема оказалось в глупой ошибке, нужно использовать таблицу main, а не local


                      Теперь о хорошем, ваш метод работает:


                      ip rule add from 1.2.3.0/24 lookup 100
                      ip rule add from 1.2.3.0/24 to 10.112.0.0/12 lookup main

                      где 10.112.0.0/12 — сеть подов в Kubernetes.


                      Но правило to должно добавляться после, что бы имело наивысший приоритет.


                      Заметным плюсом данного подхода является также то что не нужно шаманить с rp_filter, всё и так работает с дефолтными настройками.


                      Огромное спасибо за содействие, я собираюсь обновить статью чтобы описать данный метод как рекомендованный.

            0

            А еще у нас есть sysctl ) уже надо три сущности настраивать ))

              +1

              Ну kube-proxy и так sysctls правит и кучу iptables-правил генерит, с маркировкой и прочим винегретом, а если добавить к этому делу ещё CNI-планин, то вообще можно свихнуться:





              BTW, мы перешли на kube-router в качестве CNI и service-proxy. Он активно юзает ipset, так что это уже не выглядит так страшно.


              Что касается правил и настройки маршрутизации для MetalLB, это всего-лишь небольшой скрипт запускающийся как init-контейнер для спикеров MetalLB, это небольшая плата за возможность автоматически выдавать внешние IP-адреса через Kubernetes.

                0

                Дело не в количестве вещей для настройки. Изменение sysctl при рутинге — это нормально (вы рутинг-то включаете sysctl'ом). А вот правила iptables, которые влияют на ip rule — это уже начало спагетти в зависимостях.

              0

              А режим l3 не решает таких проблем?

                0

                У MetalLB есть два режима работы: Layer2 и BGB.


                • BGP решает проблему маршрутизации при доставке IP-адреса на ноду, но требут поддержки BGP со стороны вашей сети.
                  В нашем случае это плоская L2-сеть которая доставляется на ноду обычным VLAN.


                • Layer2 можно сравнить с тем, как работает VRRP. Но в отличии от VRRP преимущество данного подхода заключается в том, что изначально ноды не имеют назначенных публичных IP-адресов, а получают их только в момент присвоения адреса MetalLB.



                Интересный факт, что полученный IP-адрес является виртуальным (его не видно в выводе ip addr). Но побочным эфектом от этого, что маршрутизация для этого IP-адреса осуществляется только в рамках запущенного workload.


                То есть имея адрес, назначенный таким образом, попасть на ноду невозможно, а на ваш workload всегда пожалуйста. Это валидно для IPVS, но не уверен что это будет работать также, если kube-proxy настроен в режиме iptables, т.к. не проверял.

                  0
                  я про BGP и имел ввиду, моя оплошность. Помню ваше выступление на highload и вы описывали плоскую сеть без ротинга как примещуство. А получается, чтобы добиться гибкости маршрутизации в такой схеме, приходится добавлять статику, PBR, красить роуты на нодах. И это, ИМХО конечно, сложнее обслуживать чем динамику, где бгп за тебя анонсит маршруты соседям и дальше магия сетевиков (главное чтобы сеть не офигела от количества маршрутов которые бедет генерить куб). Я не критикую вас. Так мысли в слух. И понять для себя как лучше
                    0

                    Мне кажется, что нужно начать с того, что MetalLB — это вариант для бедных. От безысходности. Хотите нормально? Покупайте F5 и ставьте его впереди кластера. Или любое аналогичное решение с внешним LB

                      0

                      Не согласен, MetalLB — это просто софт который решает конкретную задачу, к слову он и BGP-роуты анонсить может.


                      Основная задача которую он решает: выдача ExternalIP-адресов LoadBalancer-сервисам.


                      Вариант с L2 более специфичен, но при должном подходе остаётся достаточно востребованным даже в больших кластерах как наш.

                        0

                        del

                          0
                          F5 предоставляет провайдер для кубернетс, что бы нормально отрабатывался type: loadBalancer?
                            0

                            Извините, пожалуйста, за встречный вопрос — а зачем вам вообще type: loadBalancer? Мы, например, смирились с тем, что мы в кубернетес затаскиваем или разработческие среды (и тогда не проблема telepresence/port-forward и затащить сервис на машину разработчика без публикации наружу), или кидать в кубернетес только http/rest приложения. Ну, действительно — там целая прорва проблем с БД и stateful нагрузками, так что решайте сами. А раз у нас все через ингресс, то теоретически можно внешних клиентов вменяемо отбалансировать по узлам даже без провайдера.


                            Отвечая на исходный вопрос — не оно — https://clouddocs.f5.com/containers/v2/kubernetes/ ?

                              0
                              Отвечая на исходный вопрос — не оно — clouddocs.f5.com/containers/v2/kubernetes ?

                              Нет, не оно. Там речь об ингресс, но тоже вариант.

                              А для тайп ЛБ есть куче кейсов, кроме стейтфула и бд
                                0

                                Давайте обсудим. Может я в этой жизни что-то не понимаю просто напросто ))) и Вы откроете мне какую-то очередную истину.

                                  0
                                  Истины не существует, а кейс — по выделенному ингресс контроллеру для каждого неймспейса, где хочется что бы svc для него был тайп лоадбалансер, это удобно для всяких автоматизаций и тестовых окружений.
                                    0
                                    по выделенному ингресс контроллеру для каждого неймспейса, где хочется что бы svc для него был тайп лоадбалансер, это удобно для всяких автоматизаций и тестовых окружений.

                                    живем с единым ingress — брат жив. Могу представить, что разным пользователям кластера могут понадобиться разные ингресс-контроллеры (принципиально), но это странное решение. Если же речь за безопасность… То в любом случае нужно писать какие-то хуки или политики, которые будут запрещать возможность потрогать чужой неймспейс или забиндиться на чужое доменное имя (а с этим реально пока в кубе проблемы)

                                      +2
                                      Это не странное решение, а в saas варианте сплошь и рядом. Плюс, тут как раз тот момент, когда пользователь должен сказать тайп лоадбалансер и все, в итоге увидеть айпи, желательно что бы оно еще автоматом создало запись в каком-то клоуд днс. в итоге получить окружение c точкой входа, для примера, api-tiket02.example.com, для тестирования и тп. После мерджа — это окружение так же, должно, легко быть выпилино одной командой.
                                      Так что, покупка вендорской железки, это не решение проблемы, ибо, зачастую, у нее отсутствуют нужные интграции для кубера, а автоматизировать это с боку — лишняя работа.
                                      Да, и вообще, кубер очень сильно завязан на то, что у него снизу есть слой IaaS, который ему и сторедж предоставит, и нетворкинг, и лб, и кучу другого
                                        0
                                        Да, и вообще, кубер очень сильно завязан на то, что у него снизу есть слой IaaS, который ему и сторедж предоставит, и нетворкинг, и лб, и кучу другого

                                        +


                                        Плюс, тут как раз тот момент, когда пользователь должен сказать тайп лоадбалансер и все, в итоге увидеть айпи, желательно что бы оно еще автоматом создало запись в каком-то клоуд днс. в итоге получить окружение c точкой входа, для примера, api-tiket02.example.com, для тестирования и тп.

                                        самое простое решение — не строить свой кубер, а взять в облаке. К чему нас и толкают. Вы серьезно хотите он-премис куб? Касательно SaaS не совсем понял. Если Вы условный слак — Вы клиентам предоставляете единую точку входа вроде api.slack.com, а где .slack.com по большому счету не так важно.

                                        Так что, покупка вендорской железки, это не решение проблемы, ибо, зачастую, у нее отсутствуют нужные интграции для кубера, а автоматизировать это с боку — лишняя работа.

                                        Если *.example.com на нее направить, то проблемы будто нет (развожу руками)

                                          0
                                          я не люблю он-преймс, но они тоже присутствуют в моей жизни, часто, это связанно с рынком и законодательством на нем
                                          Если *.example.com на нее направить, то проблемы будто нет (развожу руками)

                                          Вы же понимаете это всего лишь пример, и доменов может быть больше, и не всегда вэйлкард прокатит)
                                    0

                                    Простой вопрос: как ещё можно пустить внешний трафик в кластер на ingress-контроллер, чтобы это было удобно и отказоусточиво?


                                    А если таких ingress-контроллеров много?

                                      0

                                      Я же сказал вроде — внешний балансировщик, не? Вы же все равно наверняка с WAF там или Qrator интегрируетесь. Как минимум это "отказоустойчиво". Насчет "удобно" — зависит от наличия интеграций, как правильно заметил, P6i. Но тут варьируется от того насколько динамичная среда нужна и какие типы нагрузок (в условном кейсе только web-сервисов наружу — все ок).


                                      К тому же в том же OpenShift как-то тоже ведь решали проблему отказоустойчивости "точки входа приложений в кластер", нет? Не могу, к сожалению, вспомнить точно, но вроде там магия с keepalived была и haproxy.

                                        +1
                                          +1
                                          Это с оператором. А можно «внекуба», например поднять кластер haproxy, а тот уже будет балансировать на игнресс ноды, а те в свою очередь через ингресс балансировать на поды. Если для нужд хватает 80/443 портов. И будет очень даже отказоусточиво, да.
                                          А можно даже заанонсить Service, и балансировать на них через haproxy (а дальше магия куба, но это тот еще костыль). Но в этом случае нужно отслеживать, чтобы при деплое не поменялся IP у сервиса или сообщать об этом haproxy, ну и фичи теряешь LB. Хотя можно поставить externalTrafficPolicy=Local и Affinity… крч много вариантов
                                            0

                                            Реквестирую обзор всех возможностей для нубов

                                              +2
                                              Я хотел это сделать, даже начал писать статью. Но потом понял, что получается лонгрид, и никто это читать не будет))))
                                              +1
                                              Не ингрессом единым, плюс, что будет автоматизировать конфигурацию haproxy? Но тут чуть лучше, вроде как, со вторйо версии он стал нативно поддерживать api kubernetes

                                              Да я видел варианты, где народ юзает external ip, ввиде навешенных на всех нодах на lo интерфейсах пачкой апи и анонса их через ospf на бордер. Ну и табличка в конфлюенсе, какой айпи за каким сервисов закреплен)
                                                +1
                                                на балансер повесить wildcard, а с него балансить на ingress nodes. Т.е. в этом случае автоматизация — добавить новые ingress nodes в ротацию. Но это любым ансиблом можно сделать. Если про первый вариант мной описаный. Если про второй — то это вообще не продовая вещь. там много костылей.
                                                  +2
                                                  Вы не поняли кейса, у вас в каждом неймспейсе свой ингресс котроллер, со своей пачкой доменов, не все они домен третьего уровня, эти окружения (я про неймспейсы) — ондеманд, создаются динамически по запросу, так же удаляются. Помимо всего этого, еще через тот же external-dns плагин делает записи в днс провайдере.

                                                  Плюс, не должно быть доп телодвижений для конфигурации, или это должно быть спрятано от пользователя, и тп. Да это все прекрасно автоматизируется, оборачивается в ci/cd. Но зачем мне плюс одна сущность в виде ансибла или другой системы, когда я могу обойтись и без нее)

                                                  Я вообще больше скажу, тут речь идет как раз об динамических окружениях, коих будет много, создаваться они будут часто и, так же часто, будут удаляться.

                                                  Да, если у вас прод кластер, в котором задеплоены сервисы, для них созданы ингресы и другие методы выставить их наружу, раз настроен хапрокси тот же, то да, можно и так жить, и так даже будет хорошо, меньше движущихся частей — меньше мест где сломается.
                                                  Но жизнь многогранна. Тем более, у автора поста, своего рода публичный «клауд» (ну почти так)
                              0

                              Я ничуть не спорю, BGP хорошо, и я с радостью юзал бы его, но так вышло, что у нас такая топология сети. Основное преимущество же заключалось в том что стоимость L2-оборудования значительно ниже чем умного L3.


                              И да, BGP решит проблему настройки роутинга, но не спасёт вас от маркировки пакетов. Вам всегда придётся как-то выкручиваться если на вашей ноде более одного default gateway.

                          0
                          Вот только зачем L2? Я, как сетевой инженер, постоянно вижу как люди постоянно пытаются использовать L2, там, где это на самом деле не требуется, потому что «так проще», но в итоге напарываются на кучу проблем.
                          Мой всем совет, используйте везде L3 где это возможно, нет острой необходимости в L2.

                          p.s. я пробовал MetalLB c BGP, мне понравилось.
                            +1
                            согласен насчет л2. Но автор ответил на этот вопрос. А вы пробовали на ноде, например с CNI калико, которая установила пиринг по БГП со свичом/роутером поднять MetalLB спикера и подружить с темже свичем? (Необходимы костыли, пару из которых описаны здесь)
                              0
                              Как-то они там все усложнили, очевидный воркэрунд же — повесить второй ip на лупбек лифа и пирить metallb с ним.
                                0
                                можно и так тоже да. или второй ip на интерфейс ноды =)

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое