docs: MSS-CLAMPING-PLAN v2 — исправлено после валидации Opus (underlay MTU, замер, рестарт)
Deploy drhider / validate (push) Waiting to run

This commit is contained in:
2026-07-13 17:29:12 +04:00
parent 322626a372
commit 0950b68649
2 changed files with 129 additions and 27 deletions
@@ -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 <ip_другой_ноды>` (уменьшать пока не пройдёт)
2. `kubectl rollout restart ds/cilium -n kube-system`
3. Пересоздать поды приложения (ingress, drhider)
4. Вернуть `externalTrafficPolicy: Cluster`
### 3. Как проверить?
```bash
# Измерить до:
ping -M do -s 1472 <ip_другой_ноды>
tracepath <ip_другой_ноды>
# После изменения:
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)
+51 -26
View File
@@ -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 Выставить корректный MTU в Cilium, чтобы пакеты с Geneve-заголовком всегда влазили.
# ConfigMap cilium-config
mtu: 1450 **Важно:** `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 <ip_другой_ноды> # 1472+28=1500; если не проходит — уменьшать
tracepath <ip_другой_ноды> # покажет pmtu на пути
```
Если 1500 не проходит — уменьшать шагами по 50 (1450, 1400...) пока не пройдёт. Результат = значение для `mtu`.
### Шаг 1: Выставить MTU в Cilium
```bash ```bash
kubectl edit configmap -n kube-system cilium-config kubectl edit configmap -n kube-system cilium-config
# mtu: 1450 # mtu: <измеренное значение>
``` ```
Или iptables (если Cilium не управляет MTU): ### Шаг 2: Применить изменения
```bash ```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 ```bash
kubectl patch svc -n ingress shturval-ingress-controller-controller \ kubectl patch svc -n ingress shturval-ingress-controller-controller \
-p '{"spec":{"externalTrafficPolicy":"Cluster"}}' -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 - F5 несколько раз — без ERR_TIMED_OUT
- Проверить другие сервисы (Keycloak, etc.) — без регрессий - Проверить Keycloak и другие сервисы
## Почему это грамотно ## Почему это грамотно
- Стандартная практика для любого туннельного CNI - Решает корневую причину (PMTU blackhole), не симптомы
- Решает корневую причину, не симптомы - Не трогает логику Штурвала (ingress остаётся на 2 репликах)
- Не трогает логику Штурвала - Работает для всего кластера
- Не требует DaemonSet, 4 реплик, cron-скриптов - Стандартная практика для туннельного CNI
- Работает для всего кластера, не только drhider
## Если MSS clamping невозможен ## Примечания
План Б: DaemonSet для ingress через Штурвал (`controller.kind: DaemonSet` в Helm values). - **iptables как fallback ненадёжен:** Cilium с eBPF может обходить netfilter FORWARD. Если нужно — правило на **всех 4 нодах**, но лучше через `cilium-config`.
- **Понижение MTU безопасно** (меньше = консервативнее). Максимум — микро-потеря throughput.
- **Не смешивать с проблемой реплик.** При `Cluster` 2 реплик достаточно — ручной scale не нужен.