Ось знайомий жарт: dig повертає правильну IP-адресу, ваші панелі DNS зелені, а додаток поводиться так, ніби він втратив звʼязок із цивілізацією. Запити таймаутяться. TLS-рукопотискання не вдаються. Повторні спроби накопичуються, поки балансувальник навантаження не починає потіти. Усі дивляться на DNS, бо це найпростіший підозрюваний.
Іноді DNS дійсно винен. Частіше DNS просто свідок — а справжній злочин відбувається в шарі кешування, про який ви забули, що сидить між вашим додатком і авторитетною відповіддю і впевнено подає правду вчорашнього дня.
Ментальна модель: «DNS працює» — це не кінець історії
Коли хтось каже «DNS працює», зазвичай мається на увазі: з мого ноутбука, прямо зараз, за допомогою мого улюбленого інструменту, я можу резолвнути імʼя. Це приємний момент. Це не означає завершення інциденту.
У продакшні DNS — це конвеєр. Ваш додаток викликає API резолвера (часто через libc), який може звертатися до локальних кешів, stub-резидентного резолвера, node-local кеша, кластерного DNS-сервісу, upstream рекурсивного резолвера і нарешті до авторитетних серверів. На кожному кроці хтось може вирішити кешувати. На кожному кроці таймаути й повторні спроби можуть множитися. На кожному кроці конфігурація може відрізнятися між середовищами.
Результат — класичний розрив картинки на дві частини:
- Люди: «Дивись,
digпрацює.» - Додатки: «Я не можу підключитися і тепер буду тримати застарілу IP-адресу в памʼяті доти, поки всесвіт не охолоне до теплової смерті.»
Ця невідповідність виникає тому, що DNS — це не один кеш. Це кілька кешів, кожен зі своїми правилами TTL, політикою витіснення та семантикою помилок. Ви не дебажите DNS, сперечаючись про записи A. Ви дебажите, знаходячи шар кешування, який брешe.
Шари кешування, з якими ви насправді маєте справу
1) Кеші на рівні додатка (кеш «мій код невинний»)
Багато рантаймів і бібліотек кешують результати DNS — іноді агресивно, іноді вічно, іноді так, що це не відповідає уважно встановленому TTL запису.
- JVM: кешування DNS відоме своєю «уважністю». Залежно від налаштувань безпеки і наявності SecurityManager (тепер рідше), вона може кешувати позитивні відповіді довго, а також негативні відповіді. Якщо ви запускаєте Java і не знаєте ефективних налаштувань TTL для DNS, ви граєте в рулетку.
- Go: шлях резолвера залежить від прапорців збірки й оточення. У багатьох Linux-настроях Go може використовувати системний резолвер через cgo (успадковуючи поведінку libc) або власний pure-Go резолвер з власним підходом до кешування та повторних спроб. Контейнери додають спецій.
- Node.js / Python / Ruby: поведінка залежить від бібліотек. Рантайм може мало кешувати, але клієнти HTTP вищого рівня, connection pool-и або SDK для service discovery часто кешують.
- HTTP-клієнти й пулли зʼєднань: Навіть якщо DNS оновився правильно, пул може продовжувати підключатися до старої IP, поки сокет не впаде. Те, що DNS «виправлений», не означає, що трафік переміщено.
Проблеми кешування на рівні додатка особливо жорсткі, бо вони невидимі для звичних інструментів DNS. JVM, що тримає IP в памʼяті, продовжуватиме падати, навіть якщо dig показує все гаразд. Це не коливання DNS. Це впертий процес.
2) libc і NSS (кеш «це залежить від /etc/nsswitch.conf»)
У Linux резолюція імен проходить через NSS (Name Service Switch). Це означає, що ваш додаток може звертатися до files (файл hosts), потім dns, потім mDNS, LDAP або чогось, що хтось налаштував три роки тому під час «швидкого фіксу». Порядок має значення. Поведінка при помилках має значення. Таймаути мають значення.
glibc сама по собі не зберігає великий постійний кеш DNS, як думають деякі. Але вона все одно може підвести через:
/etc/hostsпереваги (застарілі, забуті або запечені в образи).- модулі NSS, які кешують (наприклад, SSSD, nscd) або додають затримки.
- параметри
resolv.confякtimeout,attemptsіrotate, що можуть суттєво змінити режим помилок.
3) Локальні демони кешування: nscd, dnsmasq, systemd-resolved
Якщо у вас є systemd-resolved, він ймовірно запускає stub-резидент на 127.0.0.53 і кешує відповіді. Якщо на ноутбуках або нодах є dnsmasq, він кешує. Якщо у вас ще є nscd (він не помер скрізь), він може кешувати пошуки хостів.
Ці кеші зазвичай доброї волі: зменшують затримку, знижують навантаження на upstream, переживають тимчасові відмови резолверів. Але вони можуть стати місцем, де затримуються неправильні відповіді.
4) Node-local DNS кеші (особливо в Kubernetes)
Кластери Kubernetes часто запускають CoreDNS як сервіс. Багато команд додають NodeLocal DNSCache, щоб зменшити навантаження і покращити хвостову затримку. Це корисно — поки не стає проблемою. Тепер у вас є:
- Pod → node-local cache (iptables на локальний IP)
- Node-local cache → CoreDNS service
- CoreDNS → upstream рекурсивні резолвери
Більше шарів — більше шансів на застарілі записи, неконсистентну конфігурацію й заплутану телеметрію. Якщо кеш на одній ноді застряг, певна частина pod-ів впаде, тоді як інші виглядають нормально. Саме такі інциденти породжують довгі Slack-треди і короткі нерви.
5) Рекурсивні резолвери (кеш «ми за це платимо»)
Ваші upstream рекурсивні резолвери (корпоративні, від хмарного провайдера або керовані сервіси) кешують агресивно. Вони також можуть застосовувати політику TTL: мінімальні/максимальні TTL, префетчинг і подачу застарілих відповідей під час upstream-помилок.
Деякі резолвери повертають прострочені, але кешовані відповіді («serve stale»), щоб зберегти доступність. Це чудово, коли авторитетні сервери недоступні. Це жахливо, коли ви намагаєтеся вивести трафік із мертвої IP-адреси.
6) Авторитетний DNS (місце, куди ви постійно вносите зміни, а нічого не змінюється)
Авторитетний DNS — це місце, де живуть ваші налаштування TTL. Це також місце, де ви очікуєте контроль. Але ваша авторитетність має значення лише тоді, коли кожен шар кешування її поважає. Багато хто не буде. Багато хто «поважає» її технічно дозволеним, але операційно незручним способом.
7) Не-DNS кеші, що виглядають як DNS-помилки
Не кожна «DNS-проблема» — це DNS. Деякі проблеми викликані:
- Пулювання зʼєднань: клієнти продовжують використовувати існуючі сокети до старих бекендів.
- Happy Eyeballs / пріоритет IPv6: ваш додаток спочатку намагається AAAA, повільно падає і тільки потім переключається.
- Повторне використання TLS-сесій і невідповідність SNI: ви потрапляєте на неправильну IP і отримуєте невідповідний сертифікат; це виглядає як «DNS не такий», але насправді це маршрутизація плюс TLS.
- Затримки в поширенні стану здоровʼя балансувальника навантаження: DNS вказує на LB, який ще віддає трафік на зламані таргети.
Жарт №1: DNS — як фабрика чуток: коли дійде до всіх, це технічно точно, але операційно марно.
Факти та історичний контекст, що пояснюють сучасний хаос
- DNS був спроєктований на початку 1980-х щоб замінити розповсюдження HOSTS.TXT; кешування було функцією з самого початку, а не доповненням.
- Концепція TTL мала контролювати життя кешу, але багато рекурсивних резолверів застосовують політику: мінімальні/максимальні TTL, що переважають ваші наміри.
- Негативне кешування стандартизували пізніше: відповіді NXDOMAIN і «немає даних» теж можна кешувати, отже «не існувало» може зберігатися після того, як ви створили запис.
- Ранні інструкції для операторів припускали відносно стабільні записи. Сучасні мікросервіси й автоскейлінг породжують більше DNS-хаосу, ніж система соціально очікувала.
- Деякі резолвери реалізують поведінку «serve stale», щоб підвищити доступність під час upstream-збоїв, ціною повільнішого cutover-у.
- systemd-resolved (середина 2010-х) нормалізував stub-резидентні резолвери на localhost у багатьох дистрибутивах, змінивши шаблони дебагу і здивувавши тих, хто очікував побачити реальні upstream-и в
/etc/resolv.conf. - Kubernetes зробив DNS критичною площею управління для service discovery; CoreDNS став одним із найважливіших pod-ів у кластері, подобається вам це чи ні.
- CDN-и й глобальні менеджери трафіку зробили DNS частиною маршрутизації. Це потужно, але означає, що відповіді DNS іноді залежать від локації й політики.
- Split-horizon DNS широко використовується в підприємствах (внутрішні й зовнішні відповіді різняться), тому «працює на моєму ноутбуці» може відображати зовсім іншу картинку, ніж у вашого ворклоаду.
Три корпоративні міні-історії (анонімізовано, болісно реальні)
Міні-історія №1: Інцидент через неправильне припущення
Команда вела багаторегіональний API за DNS-іменем, яке повертало різні A-записи для регіонів. Під час міграції вони заздалегідь зменшили TTL і запланували cutover. Офіційний план був таким: оновити записи, зачекати хвилину, перевірити новий розподіл трафіку.
День cutover-а настав. dig з bastion-хоста показав нові таргети миттєво. Моніторинг, однак, показував вперту стрічку трафіку на старий регіон. Латентність зросла. Деякі запити таймаутнули. Інженери на чергуванні подумали, що зміни не розповсюдилися, і почали «ляпати по DNS» знову й знову, що нічого не дало, крім зайвої тривоги.
Справжній винуватець не був авторитетним DNS або рекурсивними резолверами. Це був шар на рівні додатка: сервіс на Java, який виконував DNS-запит один раз при старті для upstream-залежності і кешував результат у процесі. Це не було зловмисним — це була «оптимізація», написана роки тому, коли upstream-и ніколи не переміщувалися. Сервіс був стабільний так довго, що ніхто не памʼятав про нього.
Вони перезапустили деплой, щоб примусити свіжу резолюцію. Трафік перемістився миттєво. Постмортем був незручним: команда DNS зробила все правильно, а команда додатку зробила зрозумілу річ. Тривале виправлення полягало в тому, щоб прибрати кеш у процесі, дотримуватися TTL і додати перевірку під час деплою, яка доводить, що рантайм оновлює DNS без рестарту.
Міні-історія №2: Оптимізація, яка відпрацювала проти вас
Група платформи впровадила NodeLocal DNSCache, щоб зменшити навантаження на CoreDNS і виправити переривчасту латентність DNS при піковому трафіку. Роллаут виглядав успішним. CPU CoreDNS впав. P99 латентність резолюції покращилася. Команда оголосила перемогу.
Два місяці по тому на деяких нодах почали зʼявлятися загадкові локалізовані відмови: pod-и на певних нодах не могли резолвити щойно створені імена сервісів кілька хвилин. Інженери бачили NXDOMAIN у логах додатків. Водночас pod-и на інших нодах резолвили нормально. Така асиметрія змусила підозрювати Kubernetes, «мережу» або фазу місяця.
Node-local кеш негативно кешував NXDOMAIN для імені сервісу, яке зʼявилося незабаром після деплою. У послідовності деплою стався гон, через який ранні запити йшли ще до створення Service і отримували NXDOMAIN. Після кешування ті ноди продовжували вважати, що сервіс не існує. Авторитетна істина змінилася, але негативний кеш ще не оновився.
Вони виправили це, уточнивши порядок деплою (Service перед workloads), зменшивши TTL негативного кешу в конфігурації DNS-кеша і додавши алерт на рівень NXDOMAIN по ноді. NodeLocal DNSCache залишився — це все ще була хороша ідея — але команда навчилася, що покращення P99 може також пришвидшити кешування неправильних речей.
Міні-історія №3: Нудна, але правильна практика, що врятувала день
Платіжна платформа дотримувалася консервативної практики DNS: для кожної критичної залежності був запис у runbook із повним шляхом резолюції. App → libc → node stub → cluster DNS → upstream resolver → authoritative. Для кожного кроку вони документували, які логи існують, які метрики дивитись і як обійти шар.
Це була нудна робота. Ніхто не отримав підвищення за «задокументував ланцюг резолверів». Але це означало, що під час відмови, коли upstream рекурсивний резолвер почав періодично таймаутитися, вони не витрачали години на сперечання з ноутбуками одне одного.
Вони одразу відтворили відмову всередині постраждалого pod-а, потім на ноді, потім напряму проти IP upstream резолвера. Це ізолювало проблему: bottleneck був upstream резолвером, а не CoreDNS чи додатком. Вони тимчасово переналаштували ноди на вторинний пул резолверів і відновили сервіс.
Пізніше вони використали існуючі дашборди, щоб показати латентність запитів і рівень таймаутів по резолверах. Вони ескалували до власника рекурсивного резолвера з доказами замість відчуттів. Інцидент був коротким. Постмортем — спокійним. Нудна практика окупилася.
Швидка плейбука діагностики: що перевіряти першим/другим/третім
Цей робочий процес економить години. Мета — визначити який шар кешування бреше і чи проблема у резолюції, маршрутизації чи повторному використанні зʼєднань.
Перше: відтворіть із того самого неймспейсу мережі, що й падаючий додаток
- Якщо це Kubernetes: exec у pod (або debug pod на тій самій ноді).
- Якщо це VM: запускайте з хоста, а не з вашого ноутбука.
- Якщо це контейнер: запускайте зсередини контейнера.
Якщо не вдається відтворити з того ж місця, ви дебажите відчуття, а не проблему.
Друге: підтвердіть, який резолвер насправді використовує ворклоад
- Перевірте
/etc/resolv.confвсередині ворклоаду. - Перевірте, чи вказує він на
127.0.0.53(stub systemd-resolved), node-local IP або кластерний DNS-сервіс. - Перевірте search-домени і
ndots. Вони можуть перетворити один запит на пʼять.
Третє: визначте, «неправильна відповідь» чи «повільна відповідь»
- Неправильна відповідь: повернена IP застаріла, вказує на мертву ціль або відрізняється по клієнтах.
- Повільна відповідь: таймаути, довгі повторні спроби, поодинокі SERVFAIL. Додатки часто трактують це як відмову залежності.
Четверте: навмисно обходьте шари
- Запитайте налаштований резолвер.
- Запитайте рекурсивний резолвер upstream напряму.
- Запитайте авторитетний (або відомо-робочий рекурсивний) напряму.
Кожен обхід — це тест, що усуває один шар кешування.
Пʼяте: перевірте налаштування кешування в додатку/рантаймі
- TTL та негативний TTL у JVM.
- DNS refresh rate і поведінка при помилках у proxy sidecars (Envoy).
- Клієнти service discovery (Consul, etcd-based, кастомні SDK), що кешують ендпоїнти.
Шосте: підтвердіть, що зʼєднання дійсно перемістилися
- Якщо DNS оновився, але трафік не перемістився, зазвичай причина — connection pooling або поведінка LB.
- Перевірте існуючі сокети, keep-alive і логи повторних спроб.
Парафразована ідея (приписують): Werner Vogels наголошував, що все ламається, тому системи повинні бути розроблені, щоб очікувати й обробляти відмови.
Практичні завдання: команди, що означає вивід і яке рішення прийняти
Ось практичні кроки, які я хочу, щоб інженери справді виконали. Кожне завдання містить команду, репрезентативний вивід, що він означає і яке рішення прийняти.
Завдання 1: Подивіться, як виглядає resolv.conf всередині проблемного середовища
cr0x@server:~$ cat /etc/resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
search svc.cluster.local cluster.local
Значення: Ви використовуєте локальний stub-резидент (127.0.0.53), і до імен буде додаватися search-домен. Поведінка резолюції залежить від systemd-resolved, а не від «того nameserver-а, про який ви думали».
Рішення: Не витрачайте час на запити випадковим upstream-ам. Спочатку опитайте systemd-resolved і підтвердіть, куди він форвардить.
Завдання 2: Перевірте порядок NSS і чи можуть джерела поза DNS перекривати
cr0x@server:~$ grep -E '^\s*hosts:' /etc/nsswitch.conf
hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname
Значення: /etc/hosts перевіряється першим. mDNS може коротко замкнути шлях. DNS не обовʼязково перша зупинка.
Рішення: Якщо симптом «працює на одній машині, але не на іншій», порівняйте /etc/hosts і NSS-конфігурації. Ваша «DNS-проблема» може бути локальним овердрайвом.
Завдання 3: Підтвердіть статус systemd-resolved, upstream-сервери і статистику кеша
cr0x@server:~$ resolvectl status
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 10.0.0.2
DNS Servers: 10.0.0.2 10.0.0.3
Значення: Stub форвардить на 10.0.0.2 і 10.0.0.3. Якщо вони повільні або отруєні, всі шари вище страждають.
Рішення: Тестуйте ці upstream IP напряму далі. Якщо прямі запити повільні, ескалюйте до власників резолверів.
Завдання 4: Скиньте кеш systemd-resolved (для контрольного тесту)
cr0x@server:~$ sudo resolvectl flush-caches
Значення: Ви видалили локальні кеш-записи. Якщо поведінка змінилася одразу, ви знайшли брехливий шар.
Рішення: Якщо скидання вирішує проблему, зосередьтеся на причинах подачі застарілих записів (політика TTL, serve-stale, негативне кешування або upstream-несумісність).
Завдання 5: Запитайте через налаштований резолвер і поміряйте час
cr0x@server:~$ dig +tries=1 +time=2 api.internal.example A
;; ANSWER SECTION:
api.internal.example. 30 IN A 10.40.12.19
;; Query time: 3 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
Значення: Локальний stub відповів швидко з TTL 30. Це добре, але це лише один шар.
Рішення: Якщо додаток все ще падає, підозрюйте кешування на рівні додатка або повторне використання зʼєднань. Також порівняйте з прямим запитом до upstream.
Завдання 6: Запитайте upstream рекурсивний резолвер напряму (обхід stub)
cr0x@server:~$ dig @10.0.0.2 api.internal.example A +tries=1 +time=2
;; ANSWER SECTION:
api.internal.example. 30 IN A 10.40.12.19
;; Query time: 210 msec
;; SERVER: 10.0.0.2#53(10.0.0.2)
Значення: Upstream повільніший за stub. Це може бути нормально (локальний кеш хит), або попереджувальний знак (upstream перевантажений).
Рішення: Якщо upstream постійно повільний або таймаутиться, виправте його ємність, шлях мережі або здоровʼя резолвера. Не налаштовуйте спочатку повторні спроби в додатку; це лише сховає біль.
Завдання 7: Перевірте негативне кешування, запитавши імʼя, яке ви щойно створили
cr0x@server:~$ dig newservice.svc.cluster.local A +tries=1 +time=2
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 1122
;; Query time: 4 msec
Значення: NXDOMAIN можна кешувати. Якщо сервіс тепер існує, але деякі клієнти продовжують бачити NXDOMAIN, ви маєте негативне кешування.
Рішення: Перевірте порядок створення в деплої і налаштуйте TTL негативного кешу, де це можливо (CoreDNS, node-local кеші). Якщо не можна налаштувати, змініть rollout, щоб уникати запитів до запису до того, як він зʼявиться.
Завдання 8: Спостерігайте розширення search-доменів і поведінку ndots (поширена пастка Kubernetes)
cr0x@server:~$ cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5 timeout:1 attempts:2
Значення: З ndots:5 імʼя на кшталт api.internal.example (два крапки) може вважатися «відносним» і спочатку пробуватися з search-доменами, породжуючи кілька запитів і затримки.
Рішення: Для зовнішніх імен використовуйте FQDN із кінцевою крапкою (api.internal.example.) в конфігураціях, де це підтримується, або обережно налаштуйте ndots (зрозумівши дефолт кластера).
Завдання 9: Використайте getent, щоб побачити те, що ймовірно бачить додаток через libc/NSS
cr0x@server:~$ getent hosts api.internal.example
10.40.12.19 api.internal.example
Значення: getent використовує NSS, що краще відповідає шляхам резолюції багатьох додатків, ніж dig.
Рішення: Якщо dig працює, а getent не — або повертає інший результат — зосередьтеся на NSS-конфігурації, hosts-файлі і локальних демонах кешування, а не на авторитетному DNS.
Завдання 10: Перевірте, чи не перекриває /etc/hosts ваше імʼя
cr0x@server:~$ grep -n "api.internal.example" /etc/hosts
12:10.20.1.99 api.internal.example
Значення: Хтось захардкодив. Це перекриватиме DNS, якщо NSS перевіряє files першим (поширено).
Рішення: Видаліть овердрайв, перебудуйте образи без нього і додайте CI-перевірки, щоб заборонити фіксацію hosts-файлів для production-імен сервісів.
Завдання 11: У Kubernetes опитайте CoreDNS напряму і порівняйте відповіді
cr0x@server:~$ kubectl -n kube-system get svc kube-dns -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP 2y k8s-app=kube-dns
Значення: IP сервісу CoreDNS — 10.96.0.10.
Рішення: Опитайте його напряму з pod-а, щоб обійти node-local кеші або stub-и при ізоляції вини.
Завдання 12: Проінспектуйте конфіг CoreDNS на предмет кешування і stub-доменів
cr0x@server:~$ kubectl -n kube-system get configmap coredns -o yaml | sed -n '1,120p'
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
forward . 10.0.0.2 10.0.0.3
cache 30
loop
reload
loadbalance
}
Значення: CoreDNS форвардить на upstream-и і кешує 30 секунд. Це не «погано», але пояснює часи розповсюдження і застарілість під час cutover-ів.
Рішення: Якщо вам потрібен швидший cutover для певних записів, розгляньте нижчі TTL end-to-end і перевірте політики резолверів. Не ставте cache на 0 бездумно — ви отримаєте DDOS запитами.
Завдання 13: Шукайте помилки і таймаути CoreDNS
cr0x@server:~$ kubectl -n kube-system logs -l k8s-app=kube-dns --tail=20
[ERROR] plugin/errors: 2 api.internal.example. A: read udp 10.244.1.10:45712->10.0.0.2:53: i/o timeout
[ERROR] plugin/errors: 2 api.internal.example. AAAA: read udp 10.244.1.10:46891->10.0.0.2:53: i/o timeout
Значення: CoreDNS таймаутить до upstream-резолвера 10.0.0.2. Додатки побачать переривчасті відмови резолюції або затримки.
Рішення: Виправте здоровʼя/ємність upstream-резолвера або маршрут. Як міра помʼякшення, додайте/змініть upstream-и і зменшіть timeout/attempts, щоб відмовлятися швидше, але не прикидайтеся, що це «тільки Kubernetes».
Завдання 14: Підтвердіть, до якої IP ваш додаток фактично підключений (DNS vs пул зʼєднань)
cr0x@server:~$ sudo ss -tnp | grep -E ':(443|8443)\s' | head
ESTAB 0 0 10.244.3.21:48712 10.40.12.10:443 users:(("java",pid=2314,fd=214))
Значення: Процес підключений до 10.40.12.10, яка може бути старою IP, навіть якщо DNS зараз повертає 10.40.12.19.
Рішення: Якщо DNS правильний, але сокети показують старі таргети, ваша проблема — повторне використання зʼєднань. Зменшіть lifetime keep-alive, реалізуйте періодичну повторну резолюцію або проведіть ротацію pod-ів/клієнтів під час cutover-ів.
Завдання 15: Швидко виміряйте латентність резолюції і рівень відмов
cr0x@server:~$ for i in {1..10}; do dig +tries=1 +time=1 api.internal.example A | awk '/Query time/ {print $4}'; done
3
4
1002
2
1001
3
4
1001
2
3
Значення: Деякі запити займають ~1с (таймаут) і потім вдаються на шляху повторів, що отруює хвостову латентність.
Рішення: Трактуйте це як відмову залежності: виправіть повільний резолверний хоп, зменшіть attempts і уникайте множення повторів на кількох шарах.
Жарт №2: Кешування DNS — єдине місце, де «згодом узгоджено» означає «згодом вас піднімуть на чергування».
Поширені помилки: симптом → причина → виправлення
1) Симптом: dig працює, але додаток все ще звертається до старої IP
Причина: Пулювання зʼєднань або кешування DNS у процесі (JVM, SDK, кастомний кеш). DNS змінився, але додаток не перерезольвив або не перепідключився.
Виправлення: Забезпечте, щоб рантайм дотримувався TTL і періодично перерезольвив; обмежте lifetime keep-alive; під час cutover-ів безпечно перезапустіть клієнтів. Перевірте ss і налаштування рантайму.
2) Симптом: Деякі pod-и падають, інші в порядку (той самий деплой)
Причина: Node-local DNS кеш застряг, специфічний для ноди маршрут до резолвера або проблеми зі stub-резолвером на ноді.
Виправлення: Порівняйте /etc/resolv.conf і шар кешу для кожної ноди; скиньте кеші; перезапустіть node-local DNS pod-и; виправте доступність upstream з nоди.
3) Симптом: Щойно створене імʼя сервісу повертає NXDOMAIN кілька хвилин
Причина: Негативне кешування у node-local кешах або рекурсивних резолверах; запити перед створенням запису в deploy-послідовності.
Виправлення: Створюйте DNS-обʼєкти перед тим, як клієнти почнуть запитувати; зменшуйте TTL негативного кешу, де можливо; додавайте readiness-gates у rollout, що перевіряють резолюцію.
4) Симптом: Повільний перший запит, потім швидко
Причина: Таймаути/attempts у резолвері занадто великі, розширення search-доменів або спроби AAAA перед A.
Виправлення: Налаштуйте timeout/attempts резолвера; виправте доступність IPv6 або змініть політику адресних сімейств; уникайте непотрібного розширення search-доменів, використовуючи абсолютні FQDN.
5) Симптом: Працює на ноутбуці, падає в продакшні
Причина: Split-horizon DNS, інший ланцюг резолверів, VPN/корпоративні резолвери або внутрішні зони, невидимі з продакшн-мережі.
Виправлення: Тестуйте з того самого неймспейсу мережі і з тими самими резолверами, що й ворклоад; документуйте, яке «видіння» (internal/external) використовує кожне середовище; не покладайтесь на DNS з ноутбука як на доказ.
6) Симптом: Випадкові сплески SERVFAIL
Причина: Проблеми upstream рекурсивних резолверів, помилки DNSSEC в деяких шляхах, втрата пакетів (UDP-фрагментація) або перевантаження CoreDNS.
Виправлення: Перевірте логи CoreDNS і латентність upstream-запитів; протестуйте fallback на TCP; зменшіть розмір EDNS-пакета, якщо потрібно; масштабовуйте ємність резолверів і додайте різноманітність.
7) Симптом: Рівень запитів DNS вибухає після «невеликої» зміни конфігу
Причина: Відключення кешування, глобальне встановлення занадто низького TTL або створення багатьох унікальних імен (наприклад, hostnames на запит).
Виправлення: Повторно увімкніть кешування з розумними TTL; уникайте імен на запит; використовуйте патерни service discovery, що не перетворюють DNS на гарячий цикл.
8) Симптом: Canary успішний; масовий трафік падає
Причина: Інший стек рантайму: canary використовує інший клієнт, конфіг sidecar-а або прапорці JVM; масовий трафік використовує pooling або має застарілу резолюцію.
Виправлення: Переконайтеся, що canary і маса збігаються за ланцюгом резолверів і налаштуваннями рантайму; порівняйте прапорці процесів і конфіги sidecar; запустіть getent і інспекцію сокетів в обох випадках.
Контрольні списки / покроковий план
Чекліст A: Під час інциденту (15–30 хвилин)
- Відтворіть з ворклоаду (pod/container/host). Зафіксуйте часову мітку і імʼя ноди.
- Зберіть докази ланцюга резолверів:
/etc/resolv.conf,resolvectl status(якщо релевантно) та/etc/nsswitch.conf. - Запустіть одночасно
digіgetentдля проблемного імені. Якщо вони відрізняються — пріоритет для дебагу NSS/локального кешу. - Виміряйте розподіл часу запитів (loop dig 10–20 разів). Шукайте переривчасті спайки 1с/2с.
- Обходьте шари: опитайте налаштований резолвер, потім upstream IP напряму.
- Перевірте негативне кешування: чи бере участь NXDOMAIN; чи був запис створений нещодавно.
- Підтвердіть реальні зʼєднання: використайте
ss, щоб побачити, куди процеси підключені. DNS може бути вірним, а сокети — застряглими. - Мʼяко помʼякшіть: перезапускайте шар кеша (stub/node-local/CoreDNS) лише якщо розумієте радіус ураження; інакше переключіться на здорові резолвери.
Чекліст B: Після інциденту (щоб цього не повторилось)
- Документуйте ланцюг резолверів для кожного середовища. Вкажіть, хто відповідає за кожен крок.
- Встановіть явну політику кешування в рантаймах для JVM і sidecar-ів. Не покладайтеся на дефолти.
- Уніфікуйте інструменти:
getentдля «що бачить додаток»,digдля «що каже DNS». Навчіть різниці. - Узгодьте TTL з операційною реальністю: якщо потрібен cutover за 30 секунд, переконайтеся, що кеші не навʼязують мінімум 5 хвилин.
- Додайте спостережуваність: латентність запитів, SERVFAIL/NXDOMAIN-ставки, здоровʼя кешів по нодах у Kubernetes.
- Практикуйте cutover-и: виконайте планову зміну запису в непро- прод середовищі і перевірте, чи клієнти дійсно переміщуються без рестартів.
Чекліст C: Перш ніж додавати новий шар кешування (будь чесним)
- Визначте, навіщо він потрібен: хвостова латентність, навантаження на резолвери, стійкість. Оберіть одну головну мету.
- Визначте власника і як його моніторитимуть. «То просто DNS» — не модель відповідальності.
- Вирішіть політику негативного кешування явно.
- Заплануйте обхід і аварійні контролі: як швидко переключити клієнтів на інший резолвер.
- Протестуйте режими відмов: upstream таймаут, SERVFAIL, NXDOMAIN, втрата пакетів і зміни авторитетності.
FAQ
1) Чому dig працює, а додаток не може резолвити?
dig запитує DNS напряму і обходить частини системного шляху резолюції. Ваш додаток ймовірно використовує NSS/libc (або поведінку рантайму) плюс кеші. Використайте getent hosts name, щоб наблизити результат до того, що бачить додаток.
2) Якщо я встановлю TTL 30 секунд, чому клієнти все ще використовують старі відповіді хвилинами?
Бо деякі шари кешування застосовують мінімальні/максимальні TTL, політику serve-stale або додаток кешує незалежно. Також, навіть при правильній оновленій DNS-резолюції, існуючі TCP-зʼєднання не перемістяться на нові IP автоматично.
3) Чи є скидання кешу DNS реальним виправленням?
Це діагностичний крок і інколи аварійна міра. Якщо скидання вирішує проблему — ви знайшли шар кешування, що подає застарілі/неправильні дані. Реальне виправлення — узгодити політику TTL, здоровʼя резолверів і поведінку рантаймів.
4) Чому тільки деякі Kubernetes pod-и падають з DNS?
Часто тому, що резолюція залежить від ноди (node-local кеш, шлях мережі до резолвера, iptables-редіректи або stub-резолвер на ноді). Підтвердіть ноду і протестуйте з іншого pod-а, розгорнутого на тій самій ноді.
5) Що таке негативне кешування і чому воно важливе?
Негативне кешування — це кешування відповідей «не існує» (NXDOMAIN/no data). Якщо ваш деплой робить запит до імені до його створення, кеши можуть запамʼятати NXDOMAIN і продовжувати повертати помилку після того, як імʼя створено.
6) Чи кешує glibc результати DNS?
glibc в основному слідує NSS і конфігурації резолвера; постійне кешування зазвичай здійснюють зовнішні демони (systemd-resolved, nscd, dnsmasq) або вищі шари (рантайм додатка). Не робіть припущення про «glibc cache» без доказів.
7) Як визначити, це DNS чи пулювання зʼєднань?
Якщо відповіді DNS правильні, але процес все ще підключений до старої IP — це пулювання/повторне використання зʼєднань. Перевірте активні зʼєднання з ss -tnp і порівняйте з поточними DNS-відповідями.
8) Чи варто вимикати кешування DNS, щоб уникнути застарілості?
Ні, не як загальне правило. Вимкнення кешування перемістить навантаження upstream, збільшить латентність і може створити каскадні відмови під час проблем резолвера. Краще налаштувати TTL, негативне кешування і забезпечити правильну поведінку клієнтів.
9) Чому всередині кластерів затримки при резолюції коротких імен?
Search-домени і ndots можуть спричиняти багато запитів на один lookup. Імʼя може спочатку пробуватися як name.namespace.svc.cluster.local і варіанти, перш ніж потрапити на потрібний FQDN, і таймаути накопичуються.
10) Яка найкорисніша метрика для надійності DNS?
Латентність запитів резолвера та рівень таймаутів/SERVFAIL на кожному хопі (node-local, CoreDNS, upstream рекурсивний). «Швидкість запитів» сама по собі вводить в оману; вам потрібно знати, коли резолюція стає повільною або нестабільною.
Висновок: практичні кроки
Якщо ваш DNS «працює», але додатки все одно відмовляють — припиніть трактувати DNS як одиничний компонент. Розглядайте його як ланцюг кешів і політик. Ваше завдання — знайти хоп, який бреше або повільний, і зробити його нудно надійним.
- Уніфікуйте базу для дебагу: завжди збирайте
/etc/resolv.conf,/etc/nsswitch.confі результатgetentз ворклоаду. - Інструментуйте ланцюг резолверів: латентність і ставки відмов CoreDNS/node-local кеш/upstream. Якщо ви цього не бачите — ви не можете це експлуатувати.
- Зробіть кешування в рантаймах явним: JVM, проксі та SDK. Дефолти — не стратегія.
- Плануйте cutover-и з урахуванням зʼєднань: DNS-зміни не зливають існуючі сокети. Включіть час або безпечно примусьте перепідключення.
- Напишіть runbook, який вам потрібен: шлях резолверів, команди обходу та власність. Це нудно. Але це те, що допоможе уникнути імпровізації о 3:00 ранку.