На Kubernetes-нодах (особенно с публичным IP на VDS) периодически всплывает неприятный набор симптомов: сервисы начинают «подвисать», часть соединений не устанавливается, в логах появляются таймауты, а в dmesg — сообщения вида nf_conntrack: table full, dropping packet и иногда Possible SYN flooding. Нередко рядом админы видят «dport scan» и делают вывод «нас сканируют, Kubernetes тут ни при чём».
На практике это часто комбинация фонового сканирования интернета и слишком маленьких (или неудачно подобранных) лимитов conntrack под реальную модель трафика k8s: Service NAT, NodePort, пробы, метрики, частые рестарты.
Ниже — пошаговая диагностика и тюнинг: как понять, что переполняется именно conntrack, как выбрать nf_conntrack_max и nf_conntrack_buckets, когда трогать таймауты и как снизить «шум» от внешних сканеров, не ломая кластер.
Почему conntrack важен в Kubernetes (и почему на VDS это всплывает чаще)
nf_conntrack — подсистема ядра Linux (netfilter), которая ведёт таблицу состояний соединений. Она используется не только для NAT, но и для stateful-фильтрации. Когда таблица заполнена, ядро начинает дропать пакеты — и сеть «сыпется» каскадом: от случайных 5xx на ingress до плавающих проблем с DNS и readiness.
Что в Kubernetes увеличивает давление на conntrack:
Service-трафик и NAT. Правила
kube-proxy(iptables или IPVS) и маскарадинг часто подразумевают conntrack.Много коротких соединений. Пробы, метрики, сервис-меш/sidecar’ы, частые запросы без keep-alive быстро плодят записи.
Экспозиция NodePort/LoadBalancer. Если нода светит портами наружу, любой сканер «пробегается» по ним. Даже без успешного рукопожатия могут создаваться состояния на время таймаутов.
Плотная нагрузка на одной машине. На небольших инсталляциях одна-две ноды совмещают и ingress, и мониторинг, и workload, а дефолтные sysctl остаются «средними».
Как выглядит проблема: признаки и быстрые симптомы
Ключевой маркер — сообщение ядра:
nf_conntrack: table full, dropping packet
Это означает: достигнут net.netfilter.nf_conntrack_max, новые записи не помещаются. Дальше вы обычно видите хаотичный набор сетевых ошибок:
таймауты DNS внутри кластера (CoreDNS),
увеличение 499/502/504 на ingress,
падение успешности liveness/readiness (которые сами же добавляют соединений и усугубляют ситуацию),
всплески входящих попыток на разные порты, которые в логах иногда маркируются как «dport scan».
«dport scan» — не диагноз причины переполнения conntrack, а лишь частый источник большого числа новых короткоживущих попыток. В k8s достаточно и внутреннего всплеска (деплой, рестарт, «шторм» проб), чтобы при малых лимитах поймать table full.

Быстрая диагностика: что проверить в первую очередь
1) Текущие лимиты и фактическую загрузку
Начните с базовых значений:
sysctl net.netfilter.nf_conntrack_max
sysctl net.netfilter.nf_conntrack_buckets
sysctl net.netfilter.nf_conntrack_count
Если nf_conntrack_count близко к nf_conntrack_max в моменты проблем — вы нашли узкое место. На некоторых системах nf_conntrack_count может отсутствовать в sysctl — тогда смотрите через procfs:
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_buckets
cat /proc/sys/net/netfilter/nf_conntrack_count
2) Подтвердить переполнение по логам ядра
dmesg -T | grep -E "nf_conntrack|conntrack"
Сопоставьте время сообщений «table full» с временем пользовательских ошибок/алертов — это важно для доказательства причинно-следственной связи.
3) Понять, что именно «раздувает» таблицу
Если установлены conntrack-tools:
conntrack -S
conntrack -C
Если утилит нет, быстрый (но тяжёлый) способ оценить объём:
wc -l /proc/net/nf_conntrack
Не запускайте это слишком часто: чтение большого файла даёт заметную нагрузку.
4) Проверить режим kube-proxy (iptables или IPVS)
Уточните, в каком режиме работает kube-proxy (команда зависит от способа установки; часто можно увидеть параметры в списке процессов):
ps aux | grep kube-proxy | grep -E "proxy-mode|iptables|ipvs"
Переход на IPVS иногда уменьшает накладные расходы, но «магически» не убирает conntrack: при NAT и stateful-фильтрации он всё равно остаётся критичным.
Если вы активно используете L4-балансировку и внешний входящий трафик, полезно сверить общую схему: IPVS + keepalived для L4-балансировки.
Почему таблица переполняется: типовые причины в Kubernetes
Фоновое сканирование (dport scan) по публичным адресам
Любая нода с публичным IP получает постоянный «шум»: SYN на разные порты, UDP-пакеты «наугад», повторные попытки. Если у вас наружу выставлены NodePort’ы, либо LB пробрасывает на ноды, число новых попыток легко уходит в тысячи в секунду в пике. Каждая попытка может создать запись в conntrack и жить до таймаута.
Внутренние всплески: деплои, рестарты, «шторм» health-check
Непродуманные пробы + короткие таймауты + много реплик = лавина коротких TCP-сессий. Сюда же относятся ситуации, когда поды флапают и клиенты начинают активно ретраить.
Маскарадинг на узле из-за CNI/маршрутизации
Если CNI/топология приводят к тому, что заметная доля east-west трафика идёт через NAT, вы сильнее зависите от conntrack. Это не «неправильно», но требует адекватных лимитов и мониторинга.
Как подобрать nf_conntrack_max и nf_conntrack_buckets (без вреда по памяти и CPU)
nf_conntrack_max — верхний предел числа записей. nf_conntrack_buckets — размер хеш-таблицы, влияющий на стоимость поиска/вставки. Если поднять только nf_conntrack_max и оставить маленькие buckets, вы можете получить рост коллизий и лишнюю нагрузку на CPU.
Практическая отправная точка
Часто удобное правило: держать nf_conntrack_buckets около nf_conntrack_max / 4 (в среднем 4 записи на bucket). Это не «закон», но хорошая базовая точка.
Безопасная стратегия изменения
Поднимайте лимиты постепенно (например, в 2 раза), фиксируйте метрики и эффект.
Следите за памятью: conntrack расходует kernel memory, и на небольших VDS «вылечить table full» можно ценой давления на память.
Пример мягкого повышения (подставьте свои значения):
sysctl -w net.netfilter.nf_conntrack_max=262144
sysctl -w net.netfilter.nf_conntrack_buckets=65536
Чтобы сделать изменения постоянными, добавьте отдельный файл в /etc/sysctl.d/:
cat > /etc/sysctl.d/99-conntrack-k8s.conf << 'EOF'
net.netfilter.nf_conntrack_max = 262144
net.netfilter.nf_conntrack_buckets = 65536
EOF
sysctl --system
Если система не позволяет менять nf_conntrack_buckets «на лету», это нормально: параметр может задаваться при инициализации модуля. Тогда планируйте изменение через параметры модуля и перезагрузку в окно работ.
Таймауты conntrack: как «шум» превращается в переполнение
Переполнение — это не только «маленький max», но и «слишком долго живут записи». При сканировании портов создаются в основном короткие попытки (SYN, half-open, UDP без ответа). Если таймауты на такие состояния велики, таблица успевает забиться «мусором».
Посмотреть основные таймауты (набор зависит от ядра):
sysctl net.netfilter.nf_conntrack_tcp_timeout_syn_sent
sysctl net.netfilter.nf_conntrack_tcp_timeout_syn_recv
sysctl net.netfilter.nf_conntrack_tcp_timeout_time_wait
sysctl net.netfilter.nf_conntrack_udp_timeout
sysctl net.netfilter.nf_conntrack_udp_timeout_stream
Уменьшайте таймауты осторожно: слишком агрессивные значения могут ломать легитимные медленные клиенты и нестабильные сети. На практике чаще всего имеет смысл начинать не с радикальных значений, а с умеренного снижения для SYN/UDP и обязательной проверки на реальном трафике.
Меры против dport scan без «сломать Kubernetes»

1) Минимизируйте экспозицию NodePort наружу
Если нет прямой необходимости держать NodePort доступным из интернета — ограничьте доступ на уровне фаервола (в идеале: открыты только порты ingress/LB, а не диапазон NodePort). Это резко сокращает поток новых попыток и, как следствие, количество записей в conntrack.
Если нужен план «усилить периметр на VDS», посмотрите также: SYNPROXY и nftables для защиты на уровне узла.
2) Следите за стабильностью kube-proxy и endpoint’ов
Сам по себе IPVS-режим не является «лекарством от conntrack», но может снизить накладные расходы. Важнее другое: флапающие endpoint’ы и частые пересборки правил увеличивают ретраи и churn соединений, что напрямую раздувает таблицу.
3) Снижайте churn на уровне приложений
Keep-alive к upstream, пулы соединений к БД/кэшу, разумные интервалы проб и ограничение ретраев (с backoff) часто дают эффект сильнее, чем «просто поднять лимиты».
4) Мониторинг и алерты до «table full»
Минимум, который стоит мониторить на каждой ноде:
nf_conntrack_countи долю отnf_conntrack_max,частоту сообщений ядра про
nf_conntrack: table full,CPU softirq и сетевые прерывания (как индикатор сетевого шторма).
Практичный порог для реакции: 70–80% заполнения стабильно, либо быстрые пики до 95% в моменты деградации сервиса.
Runbook: что делать, если «conntrack table full» уже случилось
Зафиксируйте факт. Снимите
dmesgпо conntrack и текущие значения:dmesg -T | grep -E "nf_conntrack|conntrack" sysctl net.netfilter.nf_conntrack_max sysctl net.netfilter.nf_conntrack_countБыстро стабилизируйте. Если трафик падает прямо сейчас — умеренно поднимите
nf_conntrack_maxи проверьте, прекратились ли дропы.Срежьте входной шум. Временно ограничьте доступ к NodePort/лишним портам на периметре, если виден явный внешний поток новых попыток.
После стабилизации. Подберите постоянные значения
nf_conntrack_max/nf_conntrack_buckets, а затем разберите источники churn: пробы, ретраи, DNS, деплои, внешнюю экспозицию.
Частые ошибки при тюнинге conntrack
Поднять только
nf_conntrack_maxи забыть проnf_conntrack_buckets. Таблица перестаёт переполняться, но CPU и задержки растут из-за коллизий.Слишком агрессивно уменьшить таймауты. Потом появляются редкие обрывы и «неуловимые» сетевые баги.
Игнорировать экспозицию портов. Если нода «светит» миру широким набором портов, вы всегда будете платить за это conntrack-памятью и CPU.
Искать виноватого только в kubelet.
kubeletне управляет conntrack напрямую, но косвенно влияет через число подов/проб и сетевую активность.
Итог: что обычно работает лучше всего
Надёжный набор мер для Kubernetes на публичной VDS обычно такой:
сужаем внешнюю поверхность (минимум открытых портов; NodePort — только при необходимости),
подбираем адекватные
nf_conntrack_maxиnf_conntrack_bucketsпод реальный профиль соединений,при необходимости аккуратно оптимизируем таймауты для SYN/UDP,
добавляем мониторинг заполнения conntrack, чтобы реагировать до «table full».
Если вы один раз поймали nf_conntrack: table full на k8s-ноде — считайте это не случайностью, а сигналом: сетевой слой и параметры netfilter нужно привести в соответствие с нагрузкой и тем, что реально торчит наружу.


