diff --git a/History/2026-07-13-opus-response-mss-clamping.md b/History/2026-07-13-opus-response-mss-clamping.md new file mode 100644 index 0000000..ba2ebe3 --- /dev/null +++ b/History/2026-07-13-opus-response-mss-clamping.md @@ -0,0 +1,77 @@ +# Opus: валидация MSS Clamping плана + +**Дата:** 2026-07-13 + +--- + +## Ключевое исправление + +В плане ошибка: `mtu: 1450` в cilium-config — это MTU **underlay-сети**, не туннеля. Cilium сам вычитает 50 байт на Geneve: + +``` +mtu: 1450 → tunnel MTU = 1450 − 50 = 1400 +``` + +По умолчанию Cilium автодетектит underlay 1500 → туннель 1450. Если stall всё равно есть — underlay реально < 1500. **Число надо измерить, не гадать.** + +--- + +## Ответы на вопросы + +### 1. Корректно ли решение? + +Да, направление верное. Но: +- ConfigMap сам не применяется — нужен `rollout restart ds/cilium` +- Число 1450 — гипотеза, нужен замер между нодами +- `mtu` глобален на весь кластер +- Существующие TCP-соединения не поменяют MSS — только новые + +### 2. Что ещё нужно? + +1. Измерить underlay MTU: `ping -M do -s 1472 ` (уменьшать пока не пройдёт) +2. `kubectl rollout restart ds/cilium -n kube-system` +3. Пересоздать поды приложения (ingress, drhider) +4. Вернуть `externalTrafficPolicy: Cluster` + +### 3. Как проверить? + +```bash +# Измерить до: +ping -M do -s 1472 +tracepath + +# После изменения: +kubectl -n kube-system exec ds/cilium -- cilium-dbg status | grep -i mtu +ip link show | grep -E 'cilium|geneve' +tcpdump -ni any 'tcp[tcpflags] & tcp-syn != 0' -vv | grep mss + +# Функционально: файл >5 MB без паузы +``` + +### 4. Риск для других сервисов? + +Понижение MTU безопасно (меньше = консервативнее). Небольшой рост числа пакетов, микро-потеря throughput. Функционально ничего не ломает. Рестарт агентов — возможны короткие блипы, лучше в окно. + +### 5. iptables равноценен? + +**Нет.** Cilium с eBPF обходит netfilter FORWARD — правило может не видеть пакеты. Надёжнее `cilium-config`. Если iptables — то на всех 4 нодах (kube-vip раздаёт VIP на все). + +### 6. Вердикт + +Путь правильный. Уточнённый план: +1. Измерить path MTU между нодами +2. Выставить `mtu` = измеренное значение (вероятно < 1500) +3. Рестарт агентов + подов +4. Вернуть `Cluster` policy + +При `Cluster` проблема реплик исчезает сама (2 хватает). + +--- + +## Моё мнение + +Opus прав. План нужно дополнить **замером**. Без замера `1450` — пальцем в небо. Обновлю `MSS-CLAMPING-PLAN.md` с учётом: +- Добавить шаг 0: измерение path MTU +- Исправить формулу: `mtu` = underlay, туннель = `mtu - 50` +- Добавить `rollout restart ds/cilium` + рестарт подов +- Убрать iptables как основной вариант (ненадёжен с Cilium) diff --git a/docs/MSS-CLAMPING-PLAN.md b/docs/MSS-CLAMPING-PLAN.md index 771cb6c..94c2ed4 100644 --- a/docs/MSS-CLAMPING-PLAN.md +++ b/docs/MSS-CLAMPING-PLAN.md @@ -1,7 +1,8 @@ -# Корневое решение: MSS clamping вместо externalTrafficPolicy: Local +# Корневое решение: MSS clamping через Cilium -**Дата:** 2026-07-13 -**Статус:** План для девопса +**Дата:** 2026-07-13 (обновлено после валидации Opus) +**Статус:** План для девопса +**Валидация:** [Opus response](../History/2026-07-13-opus-response-mss-clamping.md) --- @@ -11,54 +12,78 @@ ## Корень проблемы -Geneve-туннель добавляет ~50 байт к пакету → превышение MTU (1500) → ICMP Frag Needed блокируется → TCP stall 51 секунда при передаче больших файлов. +Geneve-туннель добавляет ~50 байт → превышение underlay MTU → ICMP Frag Needed блокируется → TCP stall 51с. -## Решение: MSS clamping через Cilium +## Решение -```yaml -# ConfigMap cilium-config -mtu: 1450 +Выставить корректный MTU в Cilium, чтобы пакеты с Geneve-заголовком всегда влазили. + +**Важно:** `mtu` в cilium-config — это MTU **underlay-сети** (физической/VM-сети между нодами). Cilium сам вычитает 50 байт на Geneve: +``` +mtu: X → туннель = X − 50 → поды = X − 50 ``` - -Cilium режет MSS (Maximum Segment Size) у TCP SYN-пакетов так, чтобы итоговый пакет с Geneve-заголовком всегда влазил в MTU. - -**Эффект:** никаких stall, никаких cross-node проблем. ## Что сделать девопсу -### Шаг 1: MSS clamping +### Шаг 0: Измерить реальный underlay MTU + +```bash +# С одной ноды на IP другой ноды (DF-бит, подбираем размер) +ping -M do -s 1472 # 1472+28=1500; если не проходит — уменьшать +tracepath # покажет pmtu на пути +``` + +Если 1500 не проходит — уменьшать шагами по 50 (1450, 1400...) пока не пройдёт. Результат = значение для `mtu`. + +### Шаг 1: Выставить MTU в Cilium ```bash kubectl edit configmap -n kube-system cilium-config -# mtu: 1450 +# mtu: <измеренное значение> ``` -Или iptables (если Cilium не управляет MTU): +### Шаг 2: Применить изменения + ```bash -iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu +# Перезапустить агенты Cilium (ConfigMap сам не применяется) +kubectl rollout restart ds/cilium -n kube-system + +# Пересоздать поды приложения (ingress, drhider — чтобы veth получили новый MTU) +kubectl rollout restart deploy -n ingress shturval-ingress-controller-controller ``` -### Шаг 2: Вернуть Cluster policy +### Шаг 3: Вернуть Cluster policy ```bash kubectl patch svc -n ingress shturval-ingress-controller-controller \ -p '{"spec":{"externalTrafficPolicy":"Cluster"}}' ``` -### Шаг 3: Верификация +### Шаг 4: Верификация -- Загрузить файл > 5 MB через drhider — должно быть без 51-сек паузы +```bash +# Проверить что Cilium применил MTU +kubectl -n kube-system exec ds/cilium -- cilium-dbg status | grep -i mtu +ip link show | grep -E 'cilium|geneve' + +# Проверить MSS в SYN-пакетах +tcpdump -ni any 'tcp[tcpflags] & tcp-syn != 0' -vv | grep mss +``` + +Функционально: +- Загрузить файл > 5 MB через drhider — без паузы 51с - F5 несколько раз — без ERR_TIMED_OUT -- Проверить другие сервисы (Keycloak, etc.) — без регрессий +- Проверить Keycloak и другие сервисы ## Почему это грамотно -- Стандартная практика для любого туннельного CNI -- Решает корневую причину, не симптомы -- Не трогает логику Штурвала -- Не требует DaemonSet, 4 реплик, cron-скриптов -- Работает для всего кластера, не только drhider +- Решает корневую причину (PMTU blackhole), не симптомы +- Не трогает логику Штурвала (ingress остаётся на 2 репликах) +- Работает для всего кластера +- Стандартная практика для туннельного CNI -## Если MSS clamping невозможен +## Примечания -План Б: DaemonSet для ingress через Штурвал (`controller.kind: DaemonSet` в Helm values). +- **iptables как fallback ненадёжен:** Cilium с eBPF может обходить netfilter FORWARD. Если нужно — правило на **всех 4 нодах**, но лучше через `cilium-config`. +- **Понижение MTU безопасно** (меньше = консервативнее). Максимум — микро-потеря throughput. +- **Не смешивать с проблемой реплик.** При `Cluster` 2 реплик достаточно — ручной scale не нужен.