У меня есть для тебя загадка сегодня. На Azure мы запускаем небольшой трехузловой кластер Elasticsearch на основе CoreOS (2023.5.0 / Linux 4.19.25-coreos). Elasticsearch запускается внутри док-контейнера в режиме хост-сети. После почти годовой работы без обслуживания мы видим, что машины находятся в очень интересном состоянии.
Обновить
Эта проблема была решена путем исправления драйвера в ядре Linux . Смотрите ответ ниже.
симптомы
По сути, связь между уязвимой машиной и двумя другими узлами прекращается. Все они находятся в одной виртуальной сети и одной подсети и обычно могут общаться друг с другом. Уязвимый узел все еще может быть доступен из других подсетей (я могу подключиться к нему по ssh) и из другой одноранговой виртуальной сети. Машина также имеет (очень нечеткое) подключение к Интернету, но большинство запросов просто прерываются.
Мы наблюдали, что на затронутом узле число «используемых сокетов», о которых сообщается, /proc/net/sockstat
очень велико (~ 4.5k вместо ~ 300 на исправном узле). Мониторинг показывает, что это число быстро увеличивается с того момента, как узел становится недоступным.
Самое интересное, что мы не можем определить источник этих используемых сокетов:
# cat /proc/net/sockstat
sockets: used 4566
TCP: inuse 2 orphan 0 tw 2 alloc 98 mem 4
UDP: inuse 1 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
# cat /proc/net/sockstat6
TCP6: inuse 98
UDP6: inuse 1
UDPLITE6: inuse 0
RAW6: inuse 1
FRAG6: inuse 0 memory 0
В остальном машина выглядит нормально. Подозрительные процессы не выполняются, загрузка процессора минимальна, а доступной памяти недостаточно.
Pinging в «недоступный» VM в одних и тех же результатах подсетей в нескольких EAGAIN
ответов , recvmsg
а затем пересекая , чтобы получить ENOBUFS
обратно от sendmsg
. вывод пинга здесь
Я собрал некоторые дополнительные данные (до того, как были внесены какие-либо изменения в систему) и разместил их в этом списке: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c
Анализ
Мы попытались отключить все, что только можем придумать на сервере, с упругим поиском, который был первым подозреваемым. Но закрытие контейнера с эластичным поиском не освобождает использованные розетки. То же самое для всех процессов, связанных с CoreOS (update-engine, locksmithd, ...) или даже для всей среды выполнения Docker или специфических для Azure вещей. Ничто не помогло.
Но теперь это становится еще более странным: мы попытались запустить tcpdump
машину, чтобы увидеть, что происходит. И вот: проблема решилась сама собой, связь была восстановлена. Наша теория состояла в том, что tcpdump выполняет своего рода системный вызов, который разрешает его. Мы запустили tcpdump с gdb и установили точки останова на всех системных вызовах. Пройдя через множество точек останова, мы наконец обнаружили, что установка смешанного режима на сокете захвата (в частности, на эту строку в libpcap ) - это то, что сбрасывает счетчик используемых сокетов и возвращает нас в нормальное состояние.
Дополнительные выводы
- Мы убедились, что работа
tcpdump
с-p/--no-promiscuous-mode
флагом не очищает счетчик используемых сокетов и возвращает машину в рабочее состояние. - Запуск
ifconfig eth0 txqueuelen 1001
сбрасывает счетчик используемых сокетов, но связь не восстанавливается. - Установка режима Promisc вручную
ip link set eth0 promisc on
также не восстанавливает связь.net.ipv4.xfrm4_gc_thresh
установлен на 32768, и его небольшое увеличение не решает проблему.
Мы связались с Azure, который так же озадачен этим, как и мы. Я понимаю, что это, скорее всего, не проблема, а просто симптом. Но это единственная ощутимая вещь, которую я нашел до сих пор. Я надеюсь, что, поняв симптом, я смогу приблизиться к основной причине. Сетевые интерфейсы в Azure запускаются с этим сетевым драйвером .
Может CoreOS / Kernel виноват?
С точки зрения временной шкалы, проблемы начались 2019-11-11, когда CoreOS автоматически обновился до последней версии. Согласно примечаниям к выпуску , это обновление содержало обновление ядра с 4.15.23 до 4.19.25 . Я все еще изучаю журналы изменений, чтобы понять, не может ли что-нибудь быть там. До сих пор я обнаружил только то, что драйвер гипервосети получил довольно много обновлений в последние месяцы , не все из которых, кажется, являются частью 4.19.25. Набор патчей, который CoreOS применил к 4.19.25, не так впечатляет , но патч, представляющий поддельный модуль nf_conntrack_ipv4, является новым.
Обновление: возможный связанный входящий патч ядра?
Помогите!
Пока что у нас есть следующие вопросы:
Что может привести к тому, что метрика «использованные сокеты» взлетит до небес? Я прочитал исходные коды ядра для этой метрики, и это, кажется, просто счетчик без ссылки на то, что это за сокеты на самом деле или что их создало.
Почему номер ровный около 4,5к? Какой лимит будет причиной этого?
Что-то существенно изменилось между ядром 4.14.96 и 4.19.25?
Почему
setsockopt()
вызов в libpcap сбрасывает состояние?
Связанная ошибка CoreOS: https://github.com/coreos/bugs/issues/2572
источник
Ответы:
Прежде всего, спасибо за очень хорошо написанный вопрос!
Поскольку уровень детализации, который вы описали, очень высок, и вы уже находитесь на уровне GDB, я предполагаю, что мой ответ не будет для вас особенно полезен. Во всяком случае, вот попытка:
ss -ae
иlsof -n
?dmesg
что-нибудь интересное, когда это произойдет?ip link set [interface] promisc on
), это также решит проблему?Надеюсь, это поможет.
источник
ss
,lsof
аnetstat
не от «розеток используются» в/proc/net/sockstat
. Только общее количество (которое кажется только что прочитанным из этого файла) одинаково.iptables
работает, но не имеет специальных правил (см. суть), я не пробовал сам устанавливать режим смешанного режима или постоянно запускать tcpdump. Сделаем это в следующий раз.ss -aepi
своей коллекции выходных данных: gist.github.com/privatwolke/… - К сожалению, dmesg ничего не возвращает, когда это происходит. На самом деле самой последней записи до инцидента 5 дней.dmesg / journalctl -k
вывод.ip link set eth0 promisc on
само по себе не восстанавливает машину в работоспособное состояние.xfrm4_gc_thresh - INTEGER
The threshold at which we will start garbage collecting for IPv4
destination cache entries. At twice this value the system will
refuse new allocations.
насколько я могу судить, он связан с IPsec, который, похоже, здесь тоже не работает.Это было вызвано ошибкой в драйвере hv_netsvc в ядре Linux. Мы могли бы решить эту проблему с разработчиком Microsoft и смогли применить исправление в апстриме.
Я процитирую здесь сообщение о коммите, так как оно довольно хорошо подводит итог проблемы:
Для дальнейшего использования, фиксация, исправляющая это, - https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .
источник