Усю серію ми робили відмовостійким сам DNS: реплікація бази, два NS за dnsdist, захист від флуду, підпис. Але була одна сліпа зона: записи статичні. www віддає умовний 203.0.113.20 - і якщо цей вебсервер ляже, DNS незворушно шле на нього людей далі. Resolver не знає, що там уже нікого немає.
PowerDNS уміє це виправити - health-check прямо в DNS. Через LUA-записи сервер сам опитує бекенди і віддає в відповіді лише ті, що насправді живі. Відмовостійкість спускається на рівень самого DNS.
Що потрібно зробити?#
Навчити www.example.com вказувати на два вебсервери так, щоб PowerDNS сам перевіряв кожен (HTTP-запитом) і прибирав із відповіді той, що не відповідає. Поставити LUA-запис з ifurlup, подивитись, як трафік балансується між живими, а тоді вимкнути один бекенд і переконатися, що він зникає з відповіді сам - і на майстрі, і на репліці незалежно.
З чим працюю?#
Той самий стенд: ns1 (майстер) + ns2 (репліка), зона example.com з DNSSEC. Додаю два простих вебсервери - web1 і web2 (слухають :8080):
| |
Ключова ідея: health-check виконує сам авторитативний сервер, фоновим потоком. Тож і майстер, і репліка стежать за бекендами кожен окремо - жодної спільної точки, яка вирішує «живий / мертвий».
Весь процес - у записі (ліворуч ns1, праворуч - вузол із web1):
Далі те саме по кроках, уже з поясненнями.
Вмикаємо LUA-записи#
За замовчуванням PowerDNS LUA-записи не обробляє - їх треба явно ввімкнути. Оскільки health-check робитимуть обидві ноди, вмикаємо на кожній (ns1 і ns2):
| |
⚠️ LUA-запис - це код, який виконується на вашому DNS-сервері. Глобальний
enable-lua-records=yesдозволяє його для всіх зон. У проді безпечніше вмикати точково - через метадані лише для довірених зон:
1pdnsutil set-meta example.com ENABLE-LUA-RECORDS 1Тоді чужа (наприклад, делегована клієнтові) зона не зможе виконувати Lua на вашому сервері.
Запис із health-check#
Міняємо статичний www A на LUA-запис. У полі даних - тип відповіді (A) і Lua-вираз, що її обчислює. Для перевірки живучості беремо ifurlup - вона робить HTTP-запит до кожного бекенда й лишає тих, хто відповів 200 (а з опцією stringmatch - ще й з потрібним вмістом на сторінці):
| |
Важлива деталь: LUA-записи не можна додати через API - PowerDNS їх навмисно блокує (update of Lua records is not allowed), бо це виконуваний код. Тож і веб-панель через API ними не керуватиме - тільки pdnsutil або пряма база. Найзручніше - edit-zone (не треба воювати з лапками):
| |
Еквівалент одним рядком -
pdnsutil add-record example.com www.example.com LUA 30 '...'. Але Lua-вираз сам повний лапок ('всередині,"зовні), тож у шеліedit-zoneпростіший. І не забувайте FQDN: PowerDNS 5.x хочеwww.example.com, а не простоwww.
Невеликий TTL (тут 30) тут доречний: що менший, то швидше резолвери підхоплять зміну складу живих бекендів.
Обидва живі - балансуємо#
Питаємо www напряму в pdns (:5300, повз кеш dnsdist). Обидва бекенди відповідають, тож PowerDNS віддає то один, то інший - виходить заразом ще й балансування навантаження:
| |
Гасимо бекенд - він зникає сам#
Вимикаємо web1 (10.10.60.104):
| |
І за кілька секунд (інтервал перевірки - 5 с) www перестає його віддавати - лишається тільки живий web2:
| |
Ніхто руками нічого не правив - PowerDNS сам побачив, що бекенд не відповідає, і прибрав його з відповіді. Повертаємо web1 (systemctl start lab-web) - і так само сам, за кілька секунд, він повертається в ротацію.
Репліка перевіряє незалежно#
Найкраще для нашої схеми: на ns2 ми нічого окремо не налаштовували - LUA-запис приїхав реплікацією бази, а enable-lua-records=yes ми ввімкнули на обох нодах. Тож репліка опитує бекенди самостійно і теж віддає лише живі:
| |
Жодної спільної точки, яка вирішує за всіх. Якщо впаде навіть сам ns1 - ns2 однаково віддає коректну, перевірену відповідь.
А якщо лягли всі?#
ifurlup за замовчуванням fail-open: якщо живих не лишилось, вона віддає випадковий IP із пулу, а не порожнечу. Логіка проста - краще відправити на «можливо, живий» сервер, ніж повернути NXDOMAIN і гарантовано зламати сайт:
| |
Бонус: відповідь підписана DNSSEC#
LUA-запис синтезує A на льоту - і PowerDNS тут же підписує його нашим ключем DNSSEC (той самий тег 56910). Health-check і криптопідпис не конфліктують:
| |
Граблі й нюанси#
- Кеш dnsdist маскує зміни. Через
:53(dnsdist) packet cache віддає закешовану відповідь до свого TTL - тому для демонстрації ми питаємо pdns напряму (:5300). У проді тримайте TTL LUA-запису низьким, щоб і кеш, і резолвери швидко підхоплювали failover. - Інтервал і «засинання». Перевірки йдуть кожні
lua-health-checks-intervalсекунд (дефолт 5). Аlua-health-checks-expire-delay(дефолт 3600) зупиняє перевірку записів, яких ніхто не питав годину - перша після паузи відповідь може бути ще за старим станом. ifurlupvsifportup.ifportup(443, {...})- простіша перевірка: лише чи відкритий TCP-порт.ifurlupчесніша: робить HTTP-запит і може звіряти вміст (stringmatch), тобто ловить «порт відкритий, а застосунок віддає 500».- Пули й пріоритет. Адреси в
ifurlup- це список пулів:{{'основний1','основний2'}, {'резерв'}}. Поки живий хоч хтось у першому пулі - резерв мовчить; усі впали - вмикається наступний. Зручно для «основний ЦОД / запасний». - Безпека понад усе. Ще раз: LUA-запис виконується на сервері. Глобально вмикайте лише там, де всі зони свої; для хостингу з чужими зонами - тільки точкові метадані.
- HTTPS теж можна. У проді health-check робіть на бойовий
https://www.example.com/(:443) -ifurlupвміє TLS; ми в лабі взяли:8080, щоб не чіпати решту сервісів на стенді.
Що далі#
Відмовостійкість ми довели до рівня окремого запису: DNS більше не шле на мертві бекенди. Відкрите питання з DNSSEC-частини - DS у реєстратора як єдиний ручний крок - напрошується закрити автоматизацією (CDS/CDNSKEY, RFC 7344/8078), щоб батьківська зона підхоплювала зміну ключа сама. А хто хоче «справжньої» промислової відмовостійкості - далі лежить anycast (один IP на обидва NS, маршрутизація через BGP).
Підсумок#
Звичайний DNS віддає фіксовані адреси й не знає, живі вони чи ні. PowerDNS із LUA-записами перетворює DNS на активного учасника відмовостійкості: ifurlup сам опитує бекенди й лишає у відповіді лише ті, що працюють, - з балансуванням, fail-open і підписом DNSSEC «з коробки». А оскільки перевіряє кожна нода окремо, схема не має спільної точки відмови навіть у самому health-check. Єдине, про що варто памʼятати, - LUA-запис це код: вмикайте його свідомо й лише для довірених зон.



