Задача
К нам пришла финтех-компания — платёжный шлюз для e-commerce. Симптом звучал буднично: «иногда наш API недоступен, хотя серверы живы». Разбор показал классическую картину: весь DNS домена держался на паре nameserver'ов одного хостинга, тот периодически ловил DDoS по своей инфраструктуре — и вместе с ним «моргал» и клиентский домен. Для платёжного API минута недоступности DNS — это отклонённые транзакции и звонки от интеграторов.
Вторая боль была связана с первой: релизы. Деплой делался вручную по SSH раз в одну-две недели, каждый — с получасовым «окном тишины». Команда клиента боялась выкатывать чаще, потому что откат тоже был ручным.
Уговор зафиксировали так: DNS переживает полный отказ любого одного провайдера незаметно для пользователей; релизы становятся ежедневными и обратимыми одной командой; бюджет на инфраструктуру не растёт больше чем на €50/мес.
Что сделали
DNS перестроили по схеме hidden primary: авторитативный PowerDNS живёт в приватном контуре клиента и в делегировании домена не фигурирует вообще. Мир видит только секондари — два независимых anycast-провайдера, которые тянут зону по AXFR и получают NOTIFY при каждом изменении. Падение любого из них (или самого primary — хоть на сутки) пользователи не замечают.
Зону подписали DNSSEC прямо на primary — секондари раздают уже подписанную копию, им поддержка подписания не нужна. Правки зоны перевели в git: описание в YAML, применение через CI, ручное редактирование записей запретили процессом, а не только словами.
Деплой пересобрали на контейнерах: сборка и тесты в CI, выкатка через blue-green — новая версия поднимается рядом, получает трафик после health-check, откат — переключение балансировщика одной командой. Мониторинг закрыл обе системы: расхождение SOA-serial между primary и секондарями, срок жизни зоны, время ответа NS с четырёх точек мира, и алерты в Telegram дежурному. Именно из этого проекта потом вырос наш «Дозор» — теперь он несёт службу и у других клиентов.
Что пошло не так
Разделы «что пошло не так» студии обычно не пишут. Мы считаем иначе: без этой главы разбор — реклама, а не разбор.
- Секондари молча протухали. На третьей неделе заметили: serial на одном из провайдеров отстаёт на два дня. Причина — миграция скрипта правки зоны, после которой SOA-serial переставал инкрементироваться: primary считал, что зона «не менялась», и NOTIFY не слал. Молчаливая деградация — худший вид отказа. Лечение: сравнение serial'ов вынесли в отдельный внешний мониторинг, который не зависит ни от primary, ни от CI.
- DNSSEC чуть не уронил зону при смене ключа. Плановый rollover KSK сделали по инструкции реестра, но недооценили TTL старой DS-записи у резолверов — около часа часть валидирующих резолверов считала подписи битыми. Урон был мал (SERVFAIL у ~2% запросов), но урок запомнили: любые операции с DS теперь делаем с двойным запасом по TTL и в окно минимального трафика.
- Blue-green упёрся в миграции базы. Схема «две версии приложения рядом» прекрасна, пока обе версии совместимы с одной схемой БД. Первая же миграция с удалением колонки сломала «синюю» сторону. Пришлось вводить дисциплину expand–contract: сначала расширяющая миграция, релиз, и только через релиз — удаляющая. Это замедлило две выкатки, зато сделало откат честным всегда.
Цифры
Полгода наблюдений после сдачи:
За эти полгода один из DNS-провайдеров дважды переживал заметные инциденты в своей сети — клиентский домен оба раза продолжал резолвиться через второго. Собственно, ради этих двух «незамеченных» инцидентов всё и строилось.
Что бы сделали иначе
Внешний мониторинг serial'ов поставили бы в первый день, а не после инцидента — теперь это пункт номер один в нашем чек-листе любого DNS-проекта. И DNSSEC включали бы не в середине работ, а последним шагом, после двух недель стабильной работы связки: отлаживать трансферы и подписи одновременно — удовольствие ниже среднего.