6.3 KiB
Sonnet: найти точку отказа внутри k8s — загрузка >48KB падает
КОНТЕКСТ
Сервис: Flask loadtest (замер скорости загрузки) на Shturval managed k8s. POST /upload с base64-телом >48KB случайно обрывается (TimeoutError на TCP-коннекте). Мелкие файлы — всегда 100%.
Требование: починить ВНУТРИ k8s. Без ВМ, без внешнего роутера, без ретраев/костылей.
ИНФРАСТРУКТУРА
Shturval 2.12.1, Cilium CNI, 4 ноды:
- control-plane (10.10.102.2) — kube-vip ✅, ingress ❌
- worker-6f74n (10.10.102.3) — kube-vip ✅, ingress ❌
- worker-bhbvs (10.10.102.4) — kube-vip ✅, ingress ✅ (hostPort 443)
- worker-v8zq4 (10.10.102.5) — kube-vip ✅, ingress ✅ (hostPort 443)
kube-vip: DaemonSet, ARP mode, vip_leaderelection=false, hostNetwork=true
Все 4 ноды добавляют VIP 185.247.187.151 на интерфейс и шлют gratuitous ARP
nginx ingress: Deployment, 2 реплики, hostPort 443
Service type LoadBalancer, external IP = 185.247.187.151
Ингресс-аннотации: proxy-body-size=1024m, timeouts 120-600s, proxy-request-buffering=off
ModSecurity: OWASP CRS 4.10, SecRuleEngine DetectionOnly, SecRequestBodyNoFilesLimit=131072
Flask: dev-сервер (python app.py), порт 5000, НЕ Gunicorn
ВСЕ ТЕСТЫ
1. Базовые (изоляция компонентов)
| # | Источник | Цель | Размер | Результат |
|---|---|---|---|---|
| 1 | Под pythonk8s | свой localhost:5000 | 100KB base64 (136KB POST) | ✅ 10/10, ~4ms |
| 2 | Под pythonk8s | ingress ClusterIP:443 | 136KB POST | ✅ 10/10, ~2ms |
| 3 | Под pythonk8s | VIP 185.247.187.151:443 | 136KB POST | ✅ 10/10, 1-6ms |
| 4 | Мы (интернет) | VIP 185.247.187.151:443 | 136KB POST | ❌ 3-5/10, TimeoutError |
| 5 | Мы (интернет) | прямой IP ВМ 5.172.178.213:443 | 136KB POST | ✅ 0 таймаутов, но "no file" |
| 6 | ВМ (10.10.102.21) | VIP 185.247.187.151:443 | 136KB POST | ❌ 1/10 |
| 7 | ВМ | worker node :443 | любой | ❌ ConnectionRefused |
2. Бинарный поиск предела
| Размер | Результат (снаружи→VIP) |
|---|---|
| 1-48 KB | ✅ всегда |
| 50 KB | ❌ |
| 52 KB | ✅ |
| 55-80 KB | ❌ |
| 100 KB | иногда ✅, иногда ❌ |
Жёсткого предела НЕТ — случайность.
3. HTTP/1.1 keep-alive (одно соединение)
| Тест | Результат |
|---|---|
| 10 запросов на одном TCP-соединении | ✅ 8/10 (первые 2 таймаута при установке, остальные OK) |
4. Rapid-fire vs delayed (проверка ARP-стабильности)
Rapid (без пауз): сначала 5 таймаутов, потом 3 OK подряд 10s пауза: снова миксуется
ЧТО ПРОБОВАЛИ (внутри k8s)
| Действие | Результат |
|---|---|
proxy_request_buffering: off (ingress annotation) |
было 3/10 → стало 5/10 |
keep-alive: 10→75 (ingress ConfigMap) |
❌ ухудшило 5→2/10, откачено |
iptables TCPMSS --set-mss 1200-1360 на ноде |
❌ 3-4/10, откачено |
vip_leaderelection: true (kube-vip DS) |
❌ 5→3/10, откачено |
| ingress replicaCount 2→3 (scale) | ❌ 3/10, откачено |
| Dockerfile Gunicorn field_size | ❌ бесполезно (Gunicorn не используется) |
| conntrack проверка | ✅ чистый (54/262K), не проблема |
| ModSecurity | ✅ DetectionOnly, не проблема |
ЧТО НЕ ПРОБОВАЛИ
- kube-vip BGP вместо ARP
- NodePort/LoadBalancer вместо hostPort
- Убрать kube-vip с нод без ingress (nodeSelector/taints)
- Увеличить ARP-интервал в kube-vip
- Включить strict ARP (kube-vip only on leader node)
КЛЮЧЕВОЙ ВЫВОД
Внутри k8s ВСЁ работает идеально (тесты 1-3). Снаружи — нет (тест 4). Разница: внешний роутер получает ARP от ВСЕХ 4 нод (kube-vip без лидера), включая 2 ноды БЕЗ ingress. Когда роутер выбирает MAC ноды без ingress → connection timeout.
KUBE-VIP КОНФИГУРАЦИЯ (полностью)
# DaemonSet: shturval-vip (namespace: kube-vip)
Image: r.shturval.tech/kube-vip:v1.0.0
hostNetwork: true
env:
cp_enable: "false"
enable_endpointslices: "true"
enable_node_labeling: "true"
lb_enable: "true" # LoadBalancer включён
lb_port: "6443"
svc_election: "true" # выборы для сервисов
svc_enable: "true"
vip_arp: "true" # ARP-режим (не BGP)
vip_interface: "" # пусто = все интерфейсы
vip_leaderelection: "false" # ВСЕ ноды анонсят VIP
vip_leasename: "sht-uservip-cp-lock"
vip_subnet: "32"
vip_nodename: "" # из spec.nodeName
# ShturvalServiceConfig: shturval-vip
spec:
chart: shturval-vip
version: 2.12.1
mode: auto
iscritical: true
namespace: kube-vip
# Ingress Service (namespace: ingress)
type: LoadBalancer
externalTrafficPolicy: Cluster
status.loadBalancer.ingress.ip: 185.247.187.151
status.loadBalancer.ingress.ipMode: VIP
# Lease: kubevip-shturval-ingress-controller-controller (ingress ns)
holderIdentity: iot-naeel-workers-vqphm-v8zq4 (с 2026-04-20)
ВОПРОС
kube-vip v1.0.0 ARP mode, vip_leaderelection=false, DaemonSet на 4 нодах, ingress hostPort только на 2. Как заставить VIP 185.247.187.151 всегда вести на ноды с ingress?
vip_leaderelection: trueне применился через DaemonSet (Shturval не подхватил customvalues)svc_election: trueуже есть — почему не работает?- Есть ли способ через
customvaluesв ShturvalServiceConfig правильно включить лидера? - Или нужен
nodeSelectorна DaemonSet чтобы kube-vip был только на нодах с ingress?