OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

MetalLB и K3s на VDS: L2 vs BGP, healthchecks и устойчивые Service IP

Как получить стабильные публичные Service IP в K3s на VDS? Разбираем MetalLB в режимах layer2 и BGP: когда что выбирать, ограничения сетей провайдеров, healthchecks и BFD, strict ARP и sysctl, примеры CRD и Service, диагностика и подводные камни.
MetalLB и K3s на VDS: L2 vs BGP, healthchecks и устойчивые Service IP

Если вы поднимаете Kubernetes в компактной конфигурации на VDS, K3s — естественный выбор: минималистичный, экономный по памяти и времени. Но у него нет облачного провайдера, а значит, для Service типа LoadBalancer нужен внешний балансировщик. Самый логичный вариант — MetalLB. В этой статье разберем, как построить устойчивую схему с Service IP на VDS: режимы layer2 и BGP, healthchecks, BFD, sysctl и настройку kube-proxy.

Почему MetalLB в K3s на VDS — это не «поставил и забыл»

В K3s по умолчанию есть простой балансировщик (ServiceLB), но он не выдает «реальный» Service IP, доступный из внешней сети, — чаще это NodePort со снабженными iptables правилами. MetalLB же выделяет и анонсирует настоящие адреса из пула, обеспечивая привычный опыт «managed» LoadBalancer. На VDS это особенно востребовано: хочется иметь понятные публичные IP для Ingress-контроллера, API или TCP/UDP сервисов.

Подводные камни кроются в сетевых политиках провайдера. Для layer2 MetalLB отвечает на ARP (IPv4) или NDP (IPv6), «притягивая» Service IP к активному узлу. Многие провайдеры фильтруют ARP/NDP-спуфинг: это может сломать layer2. Тогда понадобится BGP: ваш кластер будет анонсировать префикс на граничный маршрутизатор, а тот — раздавать маршруты дальше. Не у всех провайдеров есть частный BGP-пиринг, поэтому иногда приходится ставить свой «пограничный» маршрутизатор (например, FRR) на отдельном VDS и строить eBGP от нод к нему.

Топология и выбор режима: layer2 или BGP

Коротко:

  • Layer2: просто и быстро, один активный держатель IP. Требования — провайдер не блокирует ARP/NDP для «чужих» IP, у вас есть пул адресов в той же L2-сети, где узлы кластера.
  • BGP: сложнее, но мощнее — ECMP, анонс с нескольких узлов, быстрая сходимость с BFD. Требования — пиринг к сетевому оборудованию (провайдера или вашему пограничному VDS с FRR/BIRD), выделенный префикс, фильтрация маршрутов, пароли BGP.

Правило большого пальца: если провайдер позволяет ARP-ответы для выделенного вам дополнительного префикса — начинайте с layer2. Если видите «немой» ARP и нулевой эффект от анонса IP — переезжайте на BGP (через eBGP к маршрутизатору или к своему FRR).

Схема топологии: MetalLB в режимах L2 (ARP/NDP) и BGP с ECMP

Подготовка K3s

Предположим, у нас несколько узлов (1 control-plane + 2 workers) на VDS. K3s по умолчанию использует flannel, чего достаточно. Нам важно отключить встроенный ServiceLB и, если хотим, включить kube-proxy в режиме IPVS со strict ARP. Сконфигурируем K3s через файл:

# /etc/rancher/k3s/config.yaml
write-kubeconfig-mode: "0644"
disable:
  - servicelb
kube-proxy-arg:
  - proxy-mode=ipvs
  - ipvs-strict-arp=true

Перезапустите K3s на всех узлах после изменения конфигурации. IPVS не обязателен, но в больших кластерах он предсказуемее под нагрузкой. Опция ipvs-strict-arp=true предотвращает ARP-флюкс и важна для корректной работы с MetalLB.

Полезные sysctl для сети

Дополнительно имеет смысл включить маршрутинг и ужесточить ARP-поведение:

# /etc/sysctl.d/99-k3s-metallb.conf
net.ipv4.ip_forward=1
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2

Примените: sysctl --system.

Если вы планируете Ingress, посмотрите наш обзор контроллеров и режимов публикации: Ingress в K3s: Traefik, NGINX, HAProxy.

Установка MetalLB

Создадим namespace и установим MetalLB (через Helm или манифест релиза MetalLB):

kubectl create namespace metallb-system
kubectl apply -n metallb-system -f metallb-native.yaml

Далее мы опишем CRD для пулов адресов и объявлений. Разделим сценарии на layer2 и BGP.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Layer2: минимальная живая схема

Требования: дополнительная подсеть/пул адресов в вашей L2-сети у провайдера. Часто это /29 или /28, маршрутизированная на один из ваших серверов. Уточните у провайдера, разрешены ли ARP-ответы с любых узлов (иначе layer2 может не сработать).

Пул адресов и объявление

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: public-pool
  namespace: metallb-system
spec:
  addresses:
    - 203.0.113.64-203.0.113.79
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: public-l2
  namespace: metallb-system
spec:
  ipAddressPools:
    - public-pool

В этом режиме MetalLB выберет один узел-«владельца» IP для каждого Service. При падении узла IP быстро переедет на другой.

Service типа LoadBalancer

apiVersion: v1
kind: Service
metadata:
  name: echo-lb
  namespace: default
  annotations:
    metallb.universe.tf/address-pool: public-pool
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: echo
  ports:
    - name: http
      port: 80
      targetPort: 8080

externalTrafficPolicy: Local важен для корректности исходных IP клиента и для «умного» анонса: MetalLB может ограничивать анонс узлами, на которых есть готовые Endpoints (см. раздел про healthchecks ниже). Если не используете Local, трафик может прилетать на любой узел и проксироваться дальше kube-proxy.

Ограничения layer2

  • Один активный узел на IP — не будет ECMP с внешней стороны.
  • Некоторые провайдеры фильтруют ARP — проверяйте заранее.
  • Failover зависит от таймингов ARP/NDP и обнаружения отказа узла.

BGP: гибкость, ECMP и быстрая сходимость

Если у вас есть пиринг к провайдерскому маршрутизатору — прекрасно. Если нет, поднимите «пограничный» VDS с FRR (или BIRD) в той же сети и сделайте eBGP от нод MetalLB к нему. Этот пограничный узел будет анонсировать ваш префикс дальше (статикой провайдера или, если договоритесь, через пиринг).

Пул адресов и объявления для BGP

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: public-pool
  namespace: metallb-system
spec:
  addresses:
    - 198.51.100.128/27
---
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
  name: edge-router
  namespace: metallb-system
spec:
  myASN: 65010
  peerASN: 65000
  peerAddress: 192.0.2.1
  holdTime: 180s
  keepAliveTime: 60s
  ebgpMultiHop: true
  password: "supersecret-md5"
  bfdProfile: fast-bfd
---
apiVersion: metallb.io/v1beta2
kind: BFDProfile
metadata:
  name: fast-bfd
  namespace: metallb-system
spec:
  receiveInterval: 50ms
  transmitInterval: 50ms
  echoInterval: 50ms
  passiveMode: false
  minimumTtl: 254
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
  name: public-adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - public-pool
  aggregationLength: 32

Пояснения:

  • myASN/peerASN — приватные AS для eBGP. В реальном пиринге используйте согласованные номера.
  • ebgpMultiHop: true — удобно, если peer не в одном L2-сегменте или вы строите пиринг через внешний хост.
  • password — BGP MD5 для базовой защиты сессии.
  • BFDProfile — быстрые детекторы отказов; проверьте поддержку на стороне соседа.

FRR на пограничном VDS (пример)

Если вы поднимаете собственный маршрутизатор, настройте eBGP с каждым рабочим узлом кластера и пропишите анонс префикса наружу. В FRR это проверяется командами:

vtysh -c "show ip bgp summary"
vtysh -c "show ip route 198.51.100.128/27"

Не забудьте firewall: TCP/179 для BGP, UDP/3784 для BFD (single-hop) или 4784 (multihop).

Диагностика BGP и BFD: команды kubectl, vtysh и tcpdump

Healthchecks: как MetalLB решает, где анонсировать IP

Есть два уровня «здоровья»:

  1. Здоровье узла и процесса speaker: если speaker на ноде не жив, анонс оттуда снимется.
  2. Наличие готовых Endpoints для конкретного Service.

Ключевая практика — использовать externalTrafficPolicy: Local для тех сервисов, где важен исходный клиентский IP и/или вы хотите, чтобы IP анонсировался только с узлов, где реально есть готовые Pod'ы для этого Service. Так MetalLB не будет привлекать «пустые» ноды для входящего трафика.

В layer2 это означает: активным держателем IP становится узел, на котором есть готовые Endpoints. При их исчезновении (например, Deployment масштабирован в 0 или все Pods неготовы) IP переедет на другой узел с рабочими Endpoints. В BGP это означает: только такие узлы будут анонсировать маршрут, и внешние роутеры перестанут слать трафик на ноды без готовых Endpoints (ECMP динамически уменьшится).

Для быстрого обнаружения отказов в BGP используйте BFD. Для layer2 обратите внимание на тайминги ARP/NDP и настройку kube-proxy/IPVS (strict ARP).

Readiness и PodDisruptionBudget

Чтобы healthchecks имели смысл, убедитесь, что ваши приложения правильно выставляют readinessProbe, а также пользовались PodDisruptionBudget, чтобы во время обновлений у вас не исчезали все Endpoints сразу (что вызовет миграции VIP или спад анонсов).

Проверка и диагностика

Проверяем CRD и состояние компонентов

kubectl -n metallb-system get pods,svc
kubectl -n metallb-system get ipaddresspools,l2advertisements,bgppeers,bgpadvertisements
kubectl -n metallb-system logs deploy/controller
kubectl -n metallb-system logs ds/speaker -c speaker

Layer2: ARP/NDP и соседние таблицы

ip a
ip neigh
arping -I eth0 203.0.113.70 -c 3
tcpdump -i eth0 arp or icmp6 and ip6[40] == 135

Если не видите ARP-ответа на Service IP, хотя спикер активен, вероятно, провайдер режет ARP. Проверьте логи MetalLB, строчки вида «layer2: announce»/«withdraw».

BGP: сессии и маршруты

# На ноде k3s с MetalLB (FRR-интеграция или нативный стек MetalLB)
ss -ntp | grep :179

# На пограничном FRR
vtysh -c "show ip bgp summary"
vtysh -c "show bgp ipv4 unicast 198.51.100.128/27"

# Трафик BFD
tcpdump -ni eth0 udp port 3784 or udp port 4784

Обратите внимание на ECMP: внешние маршрутизаторы могут балансировать трафик на несколько нод. Убедитесь, что MTU и обратные пути корректны.

Частые проблемы и их решение

  • В layer2 не пингуется Service IP: провайдер блокирует ARP/NDP. Решение — переход на BGP или запрос разрешений/вторичного маршрутизируемого префикса.
  • BGP up, но трафик не идет: на внешнем роутере нет статик/redistribute для вашего префикса, либо фильтрация по спискам соседей/префиксов. Проверьте политики импорта/экспорта.
  • Петли исходящих соединений от Pod'ов: проверьте policy routing, externalTrafficPolicy: Local, SNAT на egress, MTU внутри overlay (flannel) и на хостах.
  • Дребезг маршрутов при рестарте Pod'ов: настройте readinessProbe, maxUnavailable для Deployments, используйте PDB.
  • IPVS/ARP-флюкс: проверьте ipvs-strict-arp=true и sysctl arp_ignore/arp_announce.

IPv6: NDP и двойной стек

MetalLB поддерживает IPv6 и NDP. В layer2 это ответ на NDP-соседские запросы, в BGP — анонс IPv6-префиксов. На практике в VDS важно проверить RA/ND-фильтры у провайдера. Для dual-stack Service укажите порты и убедитесь, что у вас есть независимые пулы IPv4/IPv6.

Наблюдаемость: метрики и алерты

MetalLB controller и speaker экспонируют основные метрики: состояние пиров, количество объявленных префиксов, время сходимости. Подключите их к вашей системе мониторинга и заводите алерты на:

  • Падение BGP-пиров.
  • Исчезновение объявлений для критичных Service.
  • Аномальный рост переанонсов (flap) и перезапусков speaker.
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Практические рекомендации по дизайну

  • Разделяйте пулы по классам сервисов: публичные HTTP(S), гейм-сервисы/UDP, внутренние TCP. Для TCP/UDP см. также наш материал по stream-балансировке NGINX: балансировка TCP/UDP в NGINX.
  • В BGP используйте разные пулы/префиксы для изоляции и простоты фильтрации.
  • Для production обязательно MD5 на BGP и фильтр источников по IP, плюс ограничение TCP/179 на firewall.
  • В layer2 держите небольшой запас IP, чтобы миграции и масштабирование не упирались в потолок пула.
  • Обновите DNS: укажите A/AAAA на стабильные LoadBalancer IP. При необходимости используйте нашу регистрацию доменов и оформляйте SSL-сертификаты для HTTPS.

Чек-лист перед запуском

  • K3s установлен, ServiceLB отключен, kube-proxy настроен (IPVS и strict ARP по желанию).
  • MetalLB развернут, CRD применены: IPAddressPool, L2/BGP Advertisement, BGPPeer/BFDProfile при необходимости.
  • Firewall: открыт TCP/179 для BGP, UDP/3784 или 4784 для BFD; разрешены ARP/NDP при layer2.
  • Сервисы с type: LoadBalancer и externalTrafficPolicy: Local для корректного исходного IP и анонсов по Endpoints.
  • ReadinessProbe и PDB на приложениях, чтобы не провоцировать flap.
  • Наблюдаемость: метрики MetalLB, алерты на пиры и объявления.

Итоги

MetalLB делает K3s на VDS полноценной платформой с «настоящими» LoadBalancer Service IP: в layer2 режиме — просто и быстро, в BGP — мощно и масштабируемо. Заранее проверьте сетевые ограничения провайдера, определитесь с пулом адресов и подготовьте здравые healthchecks (readiness, PDB, externalTrafficPolicy: Local). С этими принципами ваш кластер выдержит отказы узлов и обновления, а входящий трафик всегда будет приходить по предсказуемым IP.

Поделиться статьей

Вам будет интересно

ACME tls-alpn-01 и порт 80: как правильно выпустить SSL за обратным прокси OpenAI Статья написана AI (GPT 5)

ACME tls-alpn-01 и порт 80: как правильно выпустить SSL за обратным прокси

Многие путают tls-alpn-01 с http-01 и запускают проверку на 80-м — валидация падает. Разбираем, почему челлендж обязателен на 443 ...
JWT в Nginx с njs: проверка HS256 и RS256 на реверс‑прокси OpenAI Статья написана AI (GPT 5)

JWT в Nginx с njs: проверка HS256 и RS256 на реверс‑прокси

Практическое руководство для админов и DevOps: как валидировать JWT прямо на уровне Nginx с помощью njs. Разберём HS256 и RS256, с ...
TimescaleDB на VDS: hypertable, compression и retention для быстрых time series OpenAI Статья написана AI (GPT 5)

TimescaleDB на VDS: hypertable, compression и retention для быстрых time series

Поднимем TimescaleDB на VDS и выжмем максимум из time series. Создадим hypertable, подберём интервал чанка, включим compression и ...