# Проблема загрузки файлов: диагностика и решение **Дата:** 2026-07-16 **Версия приложения:** v0.0.29 **Кластер:** `iot-naeel` (4 ноды, Cilium Geneve, kube-vip, Штурвал) --- ## Проблема 1: 51-секундная задержка (MTU) ### Суть При передаче POST из внешней сети — пауза 51с на любом объёме данных. Внутри кластера — мгновенно. ### Причина Underlay MTU = 1450. Cilium Geneve добавляет 50 байт. Дефолтный MTU пода = 1500. Cross-node пакет = 1500+50 = 1550 → фрагментация → дроп → ядро ждёт повторной передачи 51с. ### Решение `cilium-config` → `mtu: 1400`. 1400+50 = 1450 = underlay. Задокументировано 2026-07-13, применено 2026-07-14. --- ## Проблема 2: ERR_CONNECTION_RESET после фикса MTU ### Суть curl с ВМ работает. Браузер — `ERR_CONNECTION_RESET` или `⏳ 100%`. После `rollout restart` ingress — работает 5-10 минут, потом снова RST. ### Ложные следы (опровергнуты) | Гипотеза | Почему неверна | |----------|---------------| | kube-vip ARP flapping | `kube-vip.io/vipHost: control-plane` — VIP жёстко на одной ноде | | hostPort на 2 из 4 нод | Трафик только на control-plane, не на все 4 | | upstream keepalive stale | `upstream-keepalive-connections: 0` не помог | | conntrack | ETPolicy Cluster не при чём — трафик на одну ноду | | MTU | Решено в проблеме 1 | | HTTP/2 | `ERR_HTTP2_PROTOCOL_ERROR` → отключили → `ERR_CONNECTION_RESET` — симптом тот же | ### Истинная причина **`keep-alive: 10`** — Штурвал ставил nginx `keep-alive: 10` (вместо дефолта 75). Сценарий: 1. Браузер грузит страницу — TCP открыт 2. Пользователь выбирает файлы (>10с) — nginx закрывает idle соединение 3. Браузер не замечает FIN (буферизация ОС) 4. POST 63KB летит в закрытый сокет → TCP RST ### Решение (применено в платформе Штурвала 2026-07-15) Через `ShturvalServiceConfig` (не kubectl — ArgoCD откатывает): ```yaml controller: config: keep-alive: "75" proxy-body-size: "1024m" client-body-timeout: "60" client-header-timeout: "30" hostPort: enabled: true replicaCount: 2 service: type: LoadBalancer ``` Также в коде — `fetch('/health')` при загрузке страницы (прогрев upstream). ### Результаты тестов (v0.0.29, 2026-07-15) | Тест | Результат | |------|-----------| | 10× POST 63KB (свежие страницы) | **10/10 OK:200** | | UI: 5 файлов + SSE + ZIP + CSV | ✅ полный цикл | | 5× POST через 75с (keep-alive окно) | **5/5 OK:200** | | 5MB PDF через curl | ✅ 200 OK, 0.62с | | **ИТОГО** | **25/25 успешно, 0 RST** | --- ## Итоговая конфигурация кластера ### Ingress (через платформу Штурвала, несбрасываемо ArgoCD) | Параметр | Дефолт nginx | Было (Штурвал) | Сейчас | |----------|-------------|----------------|--------| | `keep-alive` | 75 | **10** | **75** | | `proxy-body-size` | 8m | 8m | **1024m** | | `client-body-timeout` | 60 | **10** | **60** | | `client-header-timeout` | 60 | **10** | **30** | | `use-http2` | true | true | **false** | | `upstream-keepalive-connections` | 0 | 50 | 0 | | `error-log-level` | info | info | **debug** (вернуть info) | ### Cilium (через kubectl, не сбрасывается) | Параметр | Дефолт | Сейчас | |----------|--------|--------| | `mtu` | 1500 | **1400** | ### Приложение (drhider v0.0.29) ```python # site/app.py VERSION = "0.0.29" app.config["MAX_CONTENT_LENGTH"] = 200 * 1024 * 1024 # 200 MB ``` ```javascript // site/templates/index.html — warmup при загрузке window.addEventListener('load', () => { sf = []; fi.value = ''; rr(); fetch('/health').catch(() => {}); // прогрев upstream }); ``` --- ## Документация | Файл | Что | |------|-----| | `docs/ARCHITECTURE.md` | Архитектура + требования к Flask | | `docs/MIGRATION-GUIDE.md` | Инструкция переноса UI на Flask | | `History/2026-07-14-browser-rst-debug.md` | Полная история диагностики RST | | `History/2026-07-15-rst-root-cause.md` | Финальный диагноз | | `History/2026-07-15-cluster-dump.md` | Дамп кластера | | `STATE-2026-07-15.md` | Состояние проекта на 2026-07-15 |