У частині 1 ми підняли PowerDNS із бекендом MariaDB і API, у частині 2 - зробили дані надійними через реплікацію. Дані живуть на обох серверах, але вхід у DNS - ще ні: запити йдуть прямо в pdns, без балансування й без захисту від того, що один pdns впаде чи захлинеться.
Ставимо перед кожним pdns dnsdist - спеціалізований DNS-балансувальник від тих самих авторів. Він бере на себе порт :53, балансує запити на локальний pdns, тримає сусідній сервер як резерв, перевіряє бекенди health-check-ом і сам виводить хворий з ротації.
Що потрібно зробити?#
Поставити dnsdist на обидві ноди, зсунути pdns на :5300 (щоб звільнити :53 для dnsdist), налаштувати dnsdist так, щоб він слав запити на локальний pdns, а якщо той недоступний - на сусідній pdns по приватній мережі. А тоді - перевірити наживо: вимкнути pdns на одній ноді й переконатися, що запити (навіть нові, не з кешу) далі резолвляться. Усе записав у двох панелях: ліворуч ns1, праворуч ns2.
З чим працюю?#
Дві ноди Debian 13 з частини 2 (pdns + MariaDB-реплікація). Тепер перед кожним pdns стає dnsdist:
| |
Резервний бекенд (сусідній pdns) dnsdist смикає по тій самій приватній мережі 10.20.0.0/24, що й реплікацію - inter-node трафік не світиться в публічній мережі.
Далі те саме, що в записі, тільки вже можна копіювати.
Встановлення dnsdist#
dnsdist - в окремому компоненті того самого репозиторію PowerDNS (гілка dnsdist-21 = dnsdist 2.1). Додаємо джерело й ставимо (ключ і pinning уже є з частини 1):
| |
| |
Звільняємо :53 - pdns на :5300#
Поки :53 займає pdns. Переносимо його на :5300, слухаючи localhost (для dnsdist) і приватну адресу (щоб сусідній dnsdist міг дістатися як до резерву). Файл /etc/powerdns/pdns.d/listen.conf на ns1:
| |
Грабля pdns 5.x: стара опція
local-portтут ігнорується - порт треба вписувати прямо вlocal-addressчерез двокрапку. На ns2, відповідно,10.20.0.2:5300.
| |
Конфіг dnsdist#
Головний файл - /etc/dnsdist/dnsdist.conf (мова Lua). На ns1:
| |
Ключові рядки:
newServer({... order=...})- два бекенди.order=1(локальний pdns) - основний,order=2(сусід по приватній адресі) - резерв.checkName/checkType- health-check. Важливо: типовий health-check питає кореневий домен, на який наш authoritative-сервер відповістьREFUSED- і dnsdist може вирішити, що бекенд живий, коли той насправді не обслуговує нічого потрібного. Тому питаємоSOAзони, яку pdns реально тримає (example.com) - так «живий» означає «справді віддає наші зони».setServerPolicy(firstAvailable)- завжди бери перший заorderбекенд, що зараз UP. Поки локальний живий - усе йде на нього; впав - на сусіда.newPacketCache- кеш однакових відповідей, щоб розвантажити pdns.
На ns2 конфіг такий самий, тільки резервний бекенд вказує на 10.20.0.1:5300.
controlSocket/setKeyпотрібні лише для консолі (dnsdist -c), якою зручно дивитися статус бекендів. Ключ згенеруйте так:openssl rand -base64 32(саме 32 байти - коротший консоль відкине).
Запускаємо:
| |
Перевірка#
Запит клієнта тепер іде на :53 (dnsdist) і далі на локальний pdns:
| |
Стан бекендів дивимось через консоль (нашою функцією status()):
| |
Failover наживо#
Найцікавіше - вимикаємо локальний pdns на ns1 і дивимось, що буде:
| |
Health-check за пару секунд помітив, що локальний pdns не відповідає, і вивів його з ротації. А запити - працюють далі, бо dnsdist шле їх на сусіда по приватній мережі. Перевіряємо новим запитом (щоб точно не з кешу):
| |
Відповідь прийшла - хоча локального pdns немає. Для клієнта нічого не змінилось. Повертаємо pdns:
| |
dnsdist сам побачив, що локальний бекенд ожив, і повернув його в роботу - знову все йде на нього.
А якщо впаде вся нода?#
Failover вище рятує, коли на ноді лягає pdns, а сама нода й dnsdist живі. Якщо ж падає вся ns1 - тут працює механізм рівня делегування, про який ми говорили в частині 2: у зоні вказані два NS-записи (ns1 і ns2 з різними IP), і резолвери самі перемикаються на той, що відповідає. Два шари разом - dnsdist на кожній ноді плюс два NS - покривають і «впав демон», і «впала нода».
Граблі#
- pdns 5.x ігнорує
local-port. Порт вказуйте прямо вlocal-address(127.0.0.1:5300), інакше pdns лишиться на:53і не пустить туди dnsdist. - Ключ консолі dnsdist - рівно 32 байти.
openssl rand -base64 32. Коротший (16 байт) консоль відкине з «console key is not valid», хоча сам dnsdist працюватиме. - Health-check для authoritative. Типовий health-check питає те, чого ваш сервер не обслуговує, і статус бекенда може бути оманливим. Задавайте
checkName/checkTypeна зону, яку pdns реально тримає. - У консолі
dnsdist -c -eвидно лише те, що функція ПОВЕРТАЄ.print()пише в лог демона, не клієнту - томуstatus()збирає рядок іreturn-ить його, а не друкує. - Кеш пакетів може маскувати failover. Якщо запит уже в кеші dnsdist, відповідь прийде з кешу, не торкаючись бекенда. Перевіряйте failover новим іменем, яке ще не кешувалось.
Що далі#
Тепер вхід у DNS відмовостійкий: балансування, health-check, резерв і два NS. Лишилось захистити його від перевантаження - коли резолвери починають заливати нас запитами. У наступній частині: тюнинг dnsdist проти флуду - обмеження запитів на один IP і динамічні блоки.
Підсумок#
dnsdist перетворив два окремі pdns на відмовостійкий вхід: клієнти стукають у :53, а балансувальник сам вирішує, куди слати - на локальний pdns чи, якщо той впав, на сусіда по приватній мережі. Health-check тримає картину актуальною, кеш розвантажує бекенди, а два NS-записи додають відмовостійкості на рівні делегування. Падіння pdns тепер - не подія для клієнта.



