4.1 KiB
loadtest — загрузка файлов через Managed Flask (Shturval)
Тестовый проект для проверки Managed Flask на платформе Shturval 2.12.1. Задача: принять загрузку файлов 3-5 MB через веб-интерфейс стабильно и быстро.
Как работает
- Фронтенд: HTML + vanilla JS, выбор файлов, прогресс-бар, drag-and-drop
- Бэкенд: Flask 3.1 + flask-sock (WebSocket) + Gunicorn (gevent worker)
- Загрузка: WebSocket, 64KB чанки, один connection на все файлы
- Деплой: git push → Shturval auto-deploy
Проблема: 51-секундный TCP stall
Симптом
Файл 3.7 MB — 90% мгновенно, затем пауза ровно 51 секунда. В ~80% соединений.
Корень
externalTrafficPolicy: Cluster (дефолт) на LoadBalancer-сервисе shturval-ingress-controller-controller. Kube-vip в ARP-режиме форвардил трафик на ноды без локального ingress-пода → cross-node форвардинг через Geneve → TCP zero window oscillation → 51 секунда.
Исправление (платформа)
kubectl patch svc -n ingress shturval-ingress-controller-controller \
-p '{"spec":{"externalTrafficPolicy":"Local"}}'
kubectl scale deploy -n ingress shturval-ingress-controller-controller --replicas=4
С Local трафик идёт только на ноды с локальными ingress-подами. Cross-node форвардинг исключён.
Что НЕ помогло
- Flow control на клиенте (
bufferedAmount, ACK) - Gunicorn вместо Werkzeug
- nginx keepalive, buffering, таймауты
- nodeSelector, hostNetwork
- HTTP POST вместо WebSocket
Внутри кластера всё работало мгновенно — проблема была только при проходе через VIP извне.
Как юзать загрузку
- Открыть https://loadtest.pythonk8s.dev.nubes.ru/
- Нажать «Выбрать файлы» или перетащить файлы в зону загрузки
- Нажать «Загрузить»
- Прогресс-бар показывает реальный прогресс
- После загрузки — ✓ с временем и скоростью
Поддерживается множественная загрузка (несколько файлов подряд через один WebSocket).
Структура проекта
.
├── Dockerfile # Gunicorn CMD (не используется Shturval)
├── requirements.txt # flask, gunicorn, gevent, flask-sock
├── site/
│ ├── app.py # Flask: /, /health, /upload (HTTP), /ws-upload (WS)
│ ├── static/
│ │ └── app.js # Клиент: выбор файлов, WebSocket загрузка
│ └── templates/
│ └── index.html # UI
└── History/ # Полная история расследования
├── 2026-07-11-fix-externalTrafficPolicy.md # Финальный фикс
├── 2026-07-11-sonnet-review.md # Отчёт для ревью
└── 2026-07-11-review-response.md # Рецензия и выводы
Выводы для других проектов на Shturval
- Managed Flask может принимать большие файлы — после фикса платформы
- Всегда проверять «работает ли изнутри кластера» — это изолирует платформу от кода
- WebSocket через managed ingress работает — с правильным
externalTrafficPolicy - Если платформа не чинится — вынести загрузку на ВМ с родным nginx (как в проекте
contracts)
Версия
Текущая: 1.0.25 (baseline WebSocket + Gunicorn gevent)