Исправление времени ожидания DNS в Docker с кешем DNS

Слабые тесты в вашем CI — это кошмар.

Вы не можете сказать, что ваш новый код кто-то сломал или просто эти тесты снова не работают. Поэтому в любое время, когда мы видим странные случайные сбои в CI для нашего проекта с открытым исходным кодом, Adapt, мы пытаемся найти виновника как можно скорее. Это история о том, как мы обнаружили, что (случайно) наводнили наш DNS-сервер трафиком и как мы использовали DNS-кеш в Docker для решения этой проблемы.

Фон

Один из проектов с открытым исходным кодом, над которым я работаю, AdaptJS может развертывать приложения в нескольких облаках и технологиях, поэтому существует множество системных тестов и сквозных тестов с Docker, Kubernetes, AWS, Google Cloud и другими подобными технологиями.
Мы интенсивно используем Docker в наших тестах, поэтому в итоге мы создали множество недолговечных контейнеров, которые запускаются, выполняют некоторую работу, например, создают или устанавливают приложение, а затем удаляются. И по мере того, как мы добавляли все больше и больше этих тестов, мы начали видеть, что ранее стабильные системные тесты случайно проваливались в CI.

Симптом: время ожидания теста

Первые симптомы, которые мы увидели, были тайм-ауты теста У нас достаточно короткие тайм-ауты во многих наших сквозных тестах, поэтому мы можем определить, вдруг ли новый код заставляет конечных пользователей работать дольше. Но теперь тест, который обычно занимает полсекунды,  иногда  занимает 5,5 секунд.
Дополнительные 5 секунд были отличной подсказкой — 5 секунд звучали так, будто это могло быть какое-то время. Вооружившись этой догадкой, мы оглянулись назад на все кажущиеся случайными неудачи тестов и нашли общий поток: все они были тестами, которые инициировали сетевые запросы. Мы также заметили несколько тестов, которые потерпели неудачу еще дольше … всегда с шагом 5 секунд.
Здесь не было слишком много сетевых протоколов, которые могли бы быть задействованы, поэтому некоторое быстрое поиск в Google указало нам правильное направление. Тайм-аут по умолчанию для запросов DNS-сервера в Linux  составляет 5 секунд .
Чтобы увидеть, что происходит с DNS, мы нашли, пожалуй, самый важный инструмент для отладки сетевых проблем в Linux:  tcpdump . (Или, если вы предпочитаете версию с графическим интерфейсом,  wireshark также хорош  .) Мы запустили tcpdump на хост-системе (экземпляр Amazon Workspaces Linux) и использовали фильтр для просмотра трафика DNS:

Первое, что мы заметили, было то, что мы генерировали огромный поток DNS-запросов к DNS-серверу AWS по умолчанию для нашего VPC. Выглядело, как будто все эти недолговечные контейнеры имели тенденцию делать кучу DNS-запросов при запуске по разным причинам. Далее мы заметили, что некоторые из этих DNS-запросов просто остались без ответа.
Общие DNS-серверы довольно часто применяют ограничения скорости, чтобы один пользователь не мог снизить производительность для всех остальных. Здесь мы подозревали, что DNS-серверы AWS делают именно это. Мы не смогли найти способ подтвердить, действительно ли мы достигли ограничения скорости AWS, но нам показалось разумным не делать DoS нашему DNS-серверу.

Решение: кеш Docker DNS, использующий dnsmasq

Чтобы изолировать DNS-трафик внутри хоста, нам нужен был локальный DNS-сервер, который выполнял бы функции кеша. Отличным выбором для такого кеша является  dnsmasq . Он надежен, широко используется и очень прост в настройке. И поскольку все наши тесты выполняются внутри контейнеров Docker, имеет смысл запускать DNS-сервер и в Docker.
Основная идея довольно проста: запустить контейнер dnsmasq в качестве DNS-кэша в сети хоста Docker, а затем запустить наши тестовые контейнеры с —dns опция,  указывающая на IP-адрес контейнера кэша.
Вот dns_cache  скрипт, который запускает контейнер кеша DNS:

Помимо запуска контейнера (если он еще не запущен), скрипт выводит IP-адрес контейнера кеша. Мы будем использовать это в командной строке любых других контейнеров, которые мы запускаем. Сценарий также гарантирует, что dnsmasq прослушивает только DNS-запросы в Docker (на интерфейсе моста Docker), так что есть небольшая дополнительная работа для определения IP-адреса для прослушивания.
Вот пример того, как запустить кэш DNS, запоминая IP-адрес в переменной DNS_IP  а затем запустить другой контейнер, который будет использовать кэш.

Проверка работоспособности кеша

После того, как мы начали использовать кеш в нашем тестировании, количество DNS-запросов, отправленных хост-системой на DNS-сервер AWS, сократилось до небольшого уровня. Мы также подтвердили, что кэш работает правильно, проверив статистику dnsmasq. Отправка SIGUSR1 dnsmasq заставляет его  печатать статистику в свой журнал :

И самое главное, мы увидели резкое сокращение времени ожидания системных тестов, и наши тесты CI стабилизировались.
Эта проблема заняла некоторое время, чтобы выследить. Но поддержание здорового состояния КИ чрезвычайно важно. Если у вас слишком много случайных неудачных тестов, разработчики склонны игнорировать результаты CI и выдвигать потенциально испорченный код.
Таким образом, несмотря на то, что отслеживание этих сбоев занимало много времени, учитывая простоту исправления, оно определенно стоило вложений.

Добавить комментарий

Войти с помощью: