Создание балансировщика из Kubernetes
В managed Kubernetes TatNet достаточно создать Service с type: LoadBalancer.
Встроенный cloud-controller-manager (CCM) создаст балансировщик TatNet в проекте
кластера и запишет его публичный IP в status.loadBalancer.ingress.
Отдельно устанавливать CCM или передавать API-ключ в манифест не нужно.
Один Service создаёт один балансировщик. Каждый порт Service становится
слушателем TCP, который отправляет трафик на NodePort узлов кластера, а Kubernetes
направляет его в поды по selector. Поддерживается TCP; UDP и SCTP не поддерживаются.
Для HTTPS можно передавать TCP-трафик на порт приложения или ingress-контроллера,
который сам завершает TLS.
Подготовка
Нужны работающий кластер TatNet с готовыми рабочими узлами, его kubeconfig,
kubectl и curl. Скачайте kubeconfig из панели и укажите путь к нему:
export KUBECONFIG="$HOME/Downloads/tatnet-kubeconfig.yaml"
kubectl config current-context
kubectl get nodes
Убедитесь, что выбрали нужный кластер. Пример ниже создаёт тестовые поды и платный балансировщик; после проверки удалите их. Узлы балансировщика оплачиваются отдельно от узлов Kubernetes.
1. Создайте приложение и Service
Сохраните следующий манифест в файл lb-demo.yaml. Namespace lb-demo
должен быть свободен: он используется только для этого примера.
apiVersion: v1
kind: Namespace
metadata:
name: lb-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: lb-demo
spec:
replicas: 2
selector:
matchLabels:
app: lb-demo-web
template:
metadata:
labels:
app: lb-demo-web
spec:
containers:
- name: nginx
image: nginx:stable-alpine
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
path: /
port: http
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: lb-demo
annotations:
tatnet/lb-node-count: "2"
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: lb-demo-web
ports:
- name: http
protocol: TCP
port: 80
targetPort: http
kubectl apply -f lb-demo.yaml
kubectl -n lb-demo rollout status deployment/web --timeout=300s
port: 80 — порт публичного балансировщика, targetPort: http — именованный
порт контейнера. Kubernetes сам выделяет nodePort: не отключайте
allocateLoadBalancerNodePorts и не задавайте loadBalancerClass, чтобы Service
обрабатывал встроенный CCM. В примере externalTrafficPolicy: Local
сохраняет IP клиента до пода. Балансировщик проверяет NodePort и направляет
новые соединения только на узлы с локальными готовыми endpoint. Обычный TCP
Service с CCM 0.6.0 использует нативный L4-путь без PROXY protocol.
2. Дождитесь внешнего IP
kubectl -n lb-demo wait service/web \
--for=jsonpath='{.status.loadBalancer.ingress[0].ip}' --timeout=600s
kubectl -n lb-demo get service web
Пока балансировщик создаётся, EXTERNAL-IP имеет значение <pending>.
CCM публикует адрес после перехода балансировщика в состояние active или
degraded. Наличие IP ещё не подтверждает готовность приложения: её проверим
HTTP-запросом. Балансировщик также появится в панели проекта с привязкой к кластеру.
3. Проверьте HTTP (смоук)
Запускайте проверку с компьютера, имеющего доступ к публичному IP:
LB_IP=$(kubectl -n lb-demo get service web \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}')
test -n "$LB_IP"
curl --noproxy '*' --fail --show-error --silent \
--connect-timeout 5 --max-time 15 \
--retry 12 --retry-delay 5 --retry-all-errors \
"http://${LB_IP}/" -o lb-demo-response.html
grep -F 'Welcome to nginx!' lb-demo-response.html
Ожидаемый результат — успешный HTTP-ответ и строка Welcome to nginx!.
Эта проверка проходит весь путь: публичный IP → балансировщик TatNet →
NodePort → Service → готовый под nginx. Для команды повтора нужен curl 7.71.0
или новее.
Внутренний балансировщик
Для второго ingress-контроллера с приватным адресом создайте отдельный Service
в его namespace. В отличие от обычного ClusterIP, это управляемый
балансировщик TatNet с нативным L4-путём и health checks OVN.
apiVersion: v1
kind: Service
metadata:
name: ingress-internal
namespace: ingress-internal
annotations:
tatnet/lb-scheme: "internal"
tatnet/lb-node-count: "2"
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: haproxy-internal
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
- name: https
port: 443
targetPort: 443
protocol: TCP
Namespace и поды HAProxy должны уже существовать; замените selector и
targetPort на значения своего Helm-чарта. Если чарт позволяет задавать
аннотации Service через values, передайте tatnet/lb-scheme: internal
там, чтобы Helm сохранял настройку при обновлениях.
В EXTERNAL-IP Kubernetes покажет приватный адрес из сети узлов кластера:
название столбца не означает доступность из интернета. Публичный IP не
выделяется и не оплачивается. Адрес доступен из сети этого кластера; в режиме
VPC балансировщик получает адрес из своей VPC. Правила доступа других сетей
этой аннотацией не открываются.
Для публичного ingress создайте другой Service с
tatnet/lb-scheme: "internet-facing". Без аннотации используется публичный
режим, чтобы сохранять поведение существующих Service.
Поддерживается и аннотация AWS
service.beta.kubernetes.io/aws-load-balancer-scheme с теми же значениями —
это удобно для переноса Helm values. Если заданы обе аннотации, значения
должны совпадать. Неверное или конфликтующее значение останавливает
создание: оно не заменяется публичным режимом.
Режим задаётся при создании. Чтобы поменять его, пересоздайте Service; приватный IP при этом может измениться. Для внутреннего HTTPS используйте TLS в ingress-контроллере, загруженный сертификат либо DNS-01. Проверка HTTP-01 через интернет для внутреннего балансировщика недоступна.
Проверку выполняйте из своего кластера, например из существующего пода с curl:
kubectl -n ingress-internal wait service/ingress-internal \
--for=jsonpath='{.status.loadBalancer.ingress[0].ip}' --timeout=600s
INTERNAL_IP=$(kubectl -n ingress-internal get service ingress-internal \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# Замените namespace, client-pod и имя внутреннего сайта на свои.
kubectl -n app exec client-pod -- curl --fail --show-error \
--connect-timeout 5 --max-time 15 \
-H 'Host: internal.example.com' "http://${INTERNAL_IP}/"
Убедитесь отдельно, что внутренний сайт недоступен из интернета. Учтите, что Cilium может направлять обращения подов к IP LoadBalancer прямо в Service: для проверки именно пути через OVN нужен клиент в той же приватной сети вне Kubernetes.
Метрики L4
В панели доступны активные соединения, новые соединения в секунду и входящий / исходящий трафик в байтах в секунду. Учёт ведётся на сетевом пути балансировщика, включает IP/TCP-заголовки и исключает служебные проверки доступности backend-узлов. HTTP-запросы и коды ответов доступны у балансировщиков, которые обрабатывают HTTP.
Если данные с одного из сетевых узлов отсутствуют или устарели, на графике появляется пропуск: неполная сумма не показывается как реальная нагрузка. История начинается с момента включения сбора метрик.
При первом включении учёта байтов существующие соединения продолжают работать. Пока они не завершатся, график трафика может показывать состояние прогрева; метрики соединений уже доступны. Новые балансировщики получают полный учёт с самого начала.
Аннотации Service
Все значения аннотаций задавайте строками. Они применяются ко всем портам данного Service.
| Аннотация | Значение | Действие |
|---|---|---|
tatnet/lb-scheme | "internal" или "internet-facing" | Приватный или публичный адрес. Режим неизменяемый; неверное значение блокирует создание. |
tatnet/lb-node-count | "1", "2", "3" | Число узлов балансировщика. По умолчанию CCM использует 2; аннотация позволяет изменить число и после создания. |
tatnet/lb-preserve-client-ip | "true" или "false" | Нативное сохранение адреса клиента; по умолчанию включено для TCP Service без PROXY. Для HTTP health checks и stickiness задайте "false". |
tatnet/lb-health-check-path | Например, "/healthz" | HTTP-проверка на NodePort вместо TCP-проверки в режиме прокси. Приложение должно отвечать по этому пути. |
tatnet/lb-proxy-protocol | "none", "v1" или "v2" | Передаёт PROXY protocol бэкенду. Включайте только если принимающий сервер настроен его читать; обычный nginx из примера этого не делает. |
tatnet/lb-stickiness | "source_ip" | Закрепляет соединения одного исходного IP за целью балансировщика. Это узел Kubernetes; привязка к конкретному поду этим не гарантируется. |
Путь проверки должен начинаться с / и содержать только символы,
разрешённые шаблоном ^/[A-Za-z0-9._~/=&?-]*$.
Неверное значение tatnet/lb-scheme блокирует создание балансировщика.
Неверные и противоречивые настройки сохранения IP и PROXY protocol
блокируют применение. Для остальных известных аннотаций CCM показывает
событие InvalidAnnotation и использует значение по умолчанию. Неизвестные имена аннотаций не настраивают
балансировщик. Используйте префикс tatnet/; прежний tatnet.ru/ больше
не поддерживается. Нативный режим доступен с CCM 0.6.0. Подробнее —
реальный IP клиента.
Например, изменить число узлов:
kubectl -n lb-demo annotate service web tatnet/lb-node-count="3" --overwrite
Если проверка не проходит
kubectl -n lb-demo describe service web
kubectl -n lb-demo get events --sort-by=.metadata.creationTimestamp
kubectl -n lb-demo get pods -l app=lb-demo-web -o wide
kubectl -n lb-demo get endpointslices -l kubernetes.io/service-name=web
EXTERNAL-IPостаётся<pending>. Проверьте события Service, готовность рабочих узлов и состояние балансировщика в панели. Во время создания CCM повторяет попытки; ошибки API или отсутствие подходящих узлов требуют диагностики.- IP есть, но HTTP не отвечает. Проверьте
selector,targetPort, готовность подов и адреса в EndpointSlice. ПриImagePullBackOffсначала устраните проблему скачивания образа. PROXY protocol должен быть выключен для этого примера. InvalidAnnotation. Исправьте значение аннотации согласно таблице.ConfigRejectedпри порте 80. Порт 80 допустим, но если к этому балансировщику вручную прикреплён сертификат HTTP-01, порт резервируется для ACME. Отсоедините этот сертификат, используйте DNS-01 либо измените порт Service. Одно ожидание повторной попытки конфликт не устранит.
4. Удалите тестовые ресурсы
Сначала удалите Service и дождитесь завершения: его finalizer позволяет CCM удалить связанный балансировщик. Затем удалите namespace с приложением.
kubectl -n lb-demo delete service web --wait=true --timeout=600s
kubectl delete namespace lb-demo --wait=true --timeout=300s
Удаление балансировщика в платформе асинхронное: после исчезновения Service
он может некоторое время оставаться в состоянии deleting.
В панели дождитесь, чтобы связанный балансировщик исчез. Если Service завис в
удалении, проверьте события и доступность CCM; не снимайте finalizer вручную,
иначе платный балансировщик может остаться без владельца в Kubernetes.
Удалять сам балансировщик через панель для этого примера не нужно: пока
Service существует, CCM может создать его заново с новым IP.