diff --git a/History/2026-07-15-rst-root-cause.md b/History/2026-07-15-rst-root-cause.md new file mode 100644 index 0000000..6de30ea --- /dev/null +++ b/History/2026-07-15-rst-root-cause.md @@ -0,0 +1,169 @@ +# DrHider — итоговая диагностика ERR_CONNECTION_RESET + +**Дата:** 2026-07-15 +**Версия:** v0.0.29 + +--- + +## Хронология + +| Дата | Событие | +|------|---------| +| 2026-07-11 | Исходный деплой | +| 2026-07-14 (день) | MTU fix (Cilium 1400) — решило 51с задержку | +| 2026-07-14 (вечер) | RST диагностика: keep-alive 75 + JS warmup — частично | +| 2026-07-15 (11:53) | Helm ревизия 9 — сброс ConfigMap на дефолты (keep-alive:10) | +| 2026-07-15 | podAffinity `required` на drhider (ручной kubectl edit) | +| 2026-07-15 (16:00) | Полная диагностика: hostPort vs cloud LB | + +--- + +## Две независимые проблемы + +### Проблема #1: MTU (решена 2026-07-14) + +**Симптом:** 51с задержка при POST любого размера через внешний VIP. +**Причина:** Geneve +50, underlay 1450, дефолт 1500 → фрагментация/дроп. +**Решение:** Cilium `mtu: 1400`. + +### Проблема #2: ERR_CONNECTION_RESET (хост порт, решена 2026-07-15) + +**Симптом:** Браузер получает TCP RST при POST 63KB через 5-10 мин после рестарта ingress. +**Ранее считалось:** keep-alive 10с или kube-vip conntrack. +**Реальная причина:** Штурвал балансирует трафик на **все 4 ноды**, но ingress стоит `replicas: 2` с **hostPort** — порт 80/443 открыт только на 2 нодах. + +``` +Browser → cloud LB → любая из 4 нод + ├── нода с ingress-подом → hostPort 80 → nginx → ✅ + └── нода БЕЗ ingress-пода → порт 80 не слушается → RST ❌ +``` + +**50% запросов попадает на пустую ноду → RST.** + +--- + +## Подтверждающие данные + +### Helm ревизии (дамп) + +| Ревизия | Время | replicaCount | Другие изменения | +|---------|-------|-------------|------------------| +| 1 (деплой) | 2026-07-11 | 2 | — | +| 8 | 2026-07-15 02:00 | **2** | — | +| 9 | 2026-07-15 11:53 | **2** | — | + +Helm **не менял** replicaCount. Всегда 2. Но ConfigMap сбрасывал на дефолты (keep-alive: 10, proxy-body-size: 8m и т.д.). + +### Ingress ConfigMap (последствия Helm upgrade) + +```yaml +# Было (ручные правки 2026-07-14) → Стало (после ревизии 9) +keep-alive: "75" → "10" # вернулось на дефолт Штурвала +proxy-body-size: "1024m" → "8m" # тоже сброшено +error-log-level: debug → info # сброшено +upstream-keepalive-connections: "0" → сохранилось +``` + +### kube-vip svc_election — мёртв + +```yaml +# Lease ingress/kubevip-shturval-ingress-controller-controller +holderIdentity: "" # пусто — никто не держит +leaseDurationSeconds: 1 # аномально короткий (норма 15-30) +renewTime: 2026-07-11T14:55:28Z # 4 дня назад не обновлялся +leaseTransitions: 17 # но было 17 переходов +``` + +svc_election никогда не работал. VIP назначен через `ipMode: VIP` в статусе сервиса, работает на уровне облака (BGP/маршрутизация). + +### hostPort + +```yaml +# В шаблоне пода ingress (Helm template) +hostPort: 80 +hostPort: 443 +``` + +Включён в ревизиях 8 и 9. hostPort = порт слушается ТОЛЬКО на нодах где стоит под. + +### podAffinity на drhider — временный костыль + +```json +{ + "podAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": [{ + "labelSelector": {"matchLabels": {"app.kubernetes.io/name": "shturval-ingress-controller"}}, + "namespaceSelector": {"matchLabels": {"name": "ingress"}}, + "topologyKey": "kubernetes.io/hostname" + }] + } +} +``` + +Добавлен через `kubectl edit`, НЕ через Helm. Привязывает drhider к ноде с ingress-подом. Это НЕ лечит RST (RST на уровне VIP→нода, не на уровне нода→drhider). При следующем `helm upgrade` — исчезнет. + +### Kube-vip DaemonSet — не участвует + +```yaml +vip_arp: true # ARP включён +vip_leaderelection: false # нет CP election +svc_election: true # должен быть — но lease мёртв +``` + +Даемоны не логгируют VIP `185.247.187.151`. Трафик распределяет облако, не kube-vip. + +--- + +## Решение + +**Единственное полное решение:** ingress-под на каждой ноде куда приходит трафик. + +### Вариант 1 (рекомендуемый): увеличить replicas + +```yaml +# Helm values +shturval-ingress-controller: + replicaCount: 4 +``` + +Или выяснить у DevOps сколько нод в LB-пуле Штурвала и поставить `replicaCount = число нод`. + +### Вариант 2 (если балансировка на все worker'ы): DaemonSet + +```yaml +# Helm values +shturval-ingress-controller: + kind: DaemonSet +``` + +--- + +## Что делать сейчас (ручной воркараунд) + +### 1. Починить ConfigMap (срочно) + +```bash +kubectl patch configmap -n ingress shturval-ingress-controller-controller --type merge \ + -p '{"data":{"keep-alive":"75","proxy-body-size":"1024m","client-body-timeout":"60","client-header-timeout":"30"}}' +``` + +### 2. Масштабировать ingress (временный фикс) + +```bash +kubectl scale deploy -n ingress shturval-ingress-controller-controller --replicas=4 +``` + +Поды раскидаются по всем 4 нодам → hostPort на всех → 0% RST. + +⚠️ **Предупреждение:** после следующего `helm upgrade`: +- ConfigMap сбросится (нужно править Helm values) +- replicas вернётся на 2 +- podAffinity на drhider исчезнет + +--- + +## Вопросы к DevOps + +1. **Сколько нод в LB-пуле Штурвала?** (на какие ноды облако направляет трафик ingress?) +2. **Можно ли увеличить `replicaCount` до числа нод?** +3. **Как правильно изменить Helm values для ingress?** (чтобы ConfigMap не сбрасывался при upgrade)