Отказоустойчивый Kubernetes на BGP. Часть 5: Calico с eBPF и рабочие узлы
Три мастера собраны, VIP работает, но кластер без сети. В этой части устанавливаем Calico, переводим его на eBPF вместо kube-proxy и присоединяем рабочие узлы.
Серия «Отказоустойчивый Kubernetes на BGP»
- Схема и план
- Готовим узлы Ubuntu 24.04
- BGP на роутере (FRR)
- kube-vip в режиме BGP и первый мастер
- Calico с eBPF и рабочие узлы (эта статья)
- Адреса LoadBalancer из Calico по BGP
- Traefik за BGP и externalTrafficPolicy Local
- Проверка отказоустойчивости и разбор полётов
Почему Calico, и почему eBPF
Calico в моём кластере выполняет сразу три задачи:
- CNI — сеть подов (VXLAN в режиме CrossSubnet: между узлами одной подсети пакеты идут без инкапсуляции);
- сервисы — в режиме eBPF Calico сам обслуживает
ClusterIP,NodePortиLoadBalancer, иkube-proxyне нужен; - адреса LoadBalancer по BGP (часть 6).
Режим eBPF я выбрал по двум причинам. Первая — исчезает целый слой правил iptables, которые надо чем-то обновлять: однажды kube-proxy не подхватил смену адреса сервиса на части узлов, и именно это стало главной задержкой переезда. Вторая — eBPF сохраняет адрес клиента для соединений, которые принял другой узел.
Требования: ядро 5.10+ (Ubuntu 24.04 — 6.8), cgroup v2 и смонтированный bpffs — на Ubuntu 24.04 всё это есть из коробки.
Установка оператора
Calico ставится через tigera-operator: он разворачивает и обслуживает все компоненты, а настройка сводится к нескольким ресурсам.
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.2/manifests/operator-crds.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.2/manifests/tigera-operator.yaml
(Файл operator-crds.yaml есть в версиях 3.30 и новее; для старых — достаточно одного tigera-operator.yaml. Именно create, не apply: у CRD слишком большая аннотация.)
Адрес API без kube-proxy
Здесь есть курица и яйцо. Оператор и calico-node — поды с hostNetwork, и в поисках API они обращаются к сервису kubernetes (10.96.0.1). Но этот адрес превращается в адрес мастера только благодаря kube-proxy — которого у нас нет. А eBPF-датаплейн Calico, который должен его заменить, сам требует доступа к API, чтобы запуститься.
Решение из документации Calico — сказать оператору настоящий адрес API через ConfigMap. Указываем имя VIP:
apiVersion: v1
kind: ConfigMap
metadata:
name: kubernetes-services-endpoint
namespace: tigera-operator
data:
KUBERNETES_SERVICE_HOST: control.k8s.example.com
KUBERNETES_SERVICE_PORT: "6443"
kubectl apply -f kubernetes-services-endpoint.yaml
kubectl -n tigera-operator rollout restart deploy/tigera-operator
Рестарт нужен, чтобы под перечитал переменные окружения.
Installation
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
linuxDataplane: BPF
bgp: Disabled
ipPools:
- name: default-ipv4-ippool
cidr: 172.20.0.0/16
blockSize: 26
encapsulation: VXLANCrossSubnet
natOutgoing: Enabled
nodeSelector: all()
disableBGPExport: true
---
apiVersion: operator.tigera.io/v1
kind: APIServer
metadata:
name: default
spec: {}
Что тут важно:
- Пул подов задан явно. Если его не указать, оператор создаст стоковый
192.168.0.0/16, который легко пересечётся с вашей домашней сетью. У насkubeadmне задавалpodSubnet, так что сеть подов известна только Calico. bgp: Disabledпока: сначала я хочу поднять сеть подов, а BGP включим в части 6 вместе с остальной настройкой. Иначе «из коробки» Calico начнёт строить полносвязную сетку BGP между всеми узлами, а нам она не нужна.disableBGPExport: trueна пуле подов: когда BGP будет включён, Calico не станет рассказывать роутеру про блоки172.20.x.x/26. Трафик подов идёт через VXLAN, роутеру про них знать незачем. (Роутер всё равно отбросил бы эти маршруты поprefix-list, но лучше не создавать ему лишней работы.)APIServerразворачиваетcalico-apiserver— агрегированный APIprojectcalico.org/v3. Без негоkubectlне умеет работать сBGPConfiguration,BGPPeerи обычнымиIPPoolв человекочитаемом виде. Правда, в Calico 3.32 этот компонент объявлен устаревшим: ему на смену идут нативные CRD, но на момент написания он нужен.
kubectl apply -f installation.yaml
kubectl get tigerastatus -w
Через пару минут все компоненты (calico, apiserver, ippools) должны стать Available=True, а три мастера — Ready. CoreDNS перейдёт в Running.
Рабочие узлы
Команду join мы сохранили из вывода kubeadm init. Если токен уже протух (он живёт 24 часа), создаём новый на любом мастере:
kubeadm token create --print-join-command
На каждом из пяти воркеров:
sudo kubeadm join control.k8s.example.com:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Воркеры обращаются к API через роутер: имя ведёт на VIP, VIP — в подсеть, которой нет рядом, и маршрут идёт через 192.168.10.1. Поэтому правило разворота из части 3 должно быть к этому времени на месте: без него join будет подвисать или обрываться.
kubectl get nodes -o wide
kubectl get pods -A -o wide
Проверка eBPF
kubectl -n kube-system get ds # kube-proxy нет
kubectl -n calico-system get pods -o wide
kubectl get installation default -o jsonpath='{.status.computed.calicoNetwork.linuxDataplane}'; echo # BPF
Что видит датаплейн:
kubectl -n calico-system exec ds/calico-node -c calico-node -- calico-node -bpf nat dump | head -20
Здесь все сервисы с их бэкендами. Обычные iptables-save про сервисы уже ничего не скажет.
Проверяем, что у подов работает DNS и доступ в интернет:
kubectl run -it --rm dnscheck --image=busybox:1.37 --restart=Never -- nslookup kubernetes.default
kubectl run -it --rm nettest --image=busybox:1.37 --restart=Never -- wget -qO- -T 5 http://example.com | head -3
Как управлять Calico с оператором
Новичку в оператор-режиме обычно нужно пережить два сюрприза.
Оператор возвращает всё на место. Он непрерывно приводит кластер к описанному состоянию. Редактировать руками daemonset/calico-node или deployment/calico-typha в calico-system бесполезно: оператор молча вернёт их к своему виду за секунды, без ошибки и без следа в логах. Параметры сети (MTU, инкапсуляция, пулы) меняются только через Installation.
Две группы API.
| Группа | О чём | Примеры |
|---|---|---|
operator.tigera.io/v1 |
как Calico развёрнут | Installation, APIServer, TigerStatus |
projectcalico.org/v3 |
как Calico настроен | IPPool, BGPConfiguration, BGPPeer, FelixConfiguration |
Ресурсы projectcalico.org/v3 правятся напрямую. Исключение — пул подов default-ipv4-ippool: им владеет оператор, он держит его копию в Installation и откатывает правки самого IPPool. Параметры пула меняем только в Installation, и патч должен быть JSON, а не merge: merge заменил бы список пулов целиком.
kubectl patch installation default --type=json \
-p '[{"op":"replace","path":"/spec/calicoNetwork/ipPools/0/disableBGPExport","value":true}]'
Ещё одна ловушка: IPPool виден через две группы сразу — ippools.projectcalico.org (через агрегированный API, с проверкой) и «сырой» ippools.crd.projectcalico.org. Данные одни и те же, но писать нужно в первую.
Диагностика. Здоровье — первое, что надо смотреть:
kubectl get tigerastatus
kubectl -n tigera-operator logs deploy/tigera-operator --tail=50
tigerastatus пишет что-то расплывчатое вроде «Waiting for Tigera API server», а настоящую причину дают логи оператора.
В логах calico-apiserver будет много level=error с пометкой «Timeout or abort while handling» на GET /apis/projectcalico.org/v3 — это не поломка. Каждые 30 секунд kube-aggregator проверяет доступность APIService и закрывает поток, не дочитав ответ. Если APIService в Available=True, а ошибки только на discovery, всё в порядке.
Память
calico-node в режиме eBPF занимает 200–300 МБ — в его cgroup учитываются карты BPF. Если у вас Hyper-V и вы не добавили nr_cpus (часть 2), сюда ещё добавятся гигабайты per-CPU памяти.
В части 6 включаем BGP в Calico и настраиваем выдачу адресов LoadBalancer.
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.