Прим. перев.: Проблема DNS у Kubernetes, а точніше - налаштування параметра ndots, - На диво популярна, причому вже не першийрік. У черговій нотатці на цю тему її автор — DevOps-інженер з великої брокерської компанії в Індії — у простій і лаконічній манері розповідає, про що корисно знати колегам, які експлуатують Kubernetes.
Одна з головних переваг розгортання додатків у Kubernetes – безпроблемне виявлення додатків. Внутрішньокластерна взаємодія сильно спрощується завдяки концепції сервісу (Обслуговування), яка є віртуальним IP, що підтримує набір IP-адрес pod'ів. Наприклад, якщо сервіс vanilla хоче зв'язатися з сервісом chocolate, він може звернутися безпосередньо до віртуального IP для chocolate. Постає питання: хто в даному випадку дозволить DNS-запит до chocolate і як?
Дозвіл імен DNS налаштовується в кластері Kubernetes за допомогою CoreDNS. Kubelet прописує pod з CoreDNS як сервер імен у файлах /etc/resolv.conf всіх pod'ів. Якщо подивитися на вміст /etc/resolv.conf будь-якого pod'а, воно виглядатиме приблизно так:
Ця конфігурація використовується DNS-клієнтами для перенаправлення запитів на сервер DNS. У файлі resolv.conf міститься така інформація:
сервер імен: сервер, на який надсилатимуться DNS-запити. У нашому випадку це адреса сервісу CoreDNS;
пошук: визначає шлях пошуку певного домену Цікаво, що google.com або mrkaran.dev не є FQDN (повними доменними іменами). Згідно зі стандартною угодою, якою слідує більшість resolver'ів DNS, повними (FDQN) доменами вважаються тільки ті, які закінчуються точкою «.», що представляє кореневу зону. Деякі resolver'и вміють додавати крапку самостійно. Таким чином, mrkaran.dev. - повне доменне ім'я (FQDN), а mrkaran.dev - Ні;
точки: Найцікавіший параметр (ця стаття саме про нього) ndots задає граничне число точок в імені запиту, при досягненні якого воно розглядається як «повне» доменне ім'я. Докладніше про це ми поговоримо пізніше, коли аналізуватимемо послідовність DNS-пошуку.
Давайте подивимося, що відбувається, коли ми запитуємо mrkaran.dev у pod'є:
Для цього експерименту я встановив рівень логування CoreDNS на all (що робить його дуже багатослівним). Подивимося на логи pod'а coredns:
[INFO] 10.1.28.1:35998 - 11131 "A IN mrkaran.dev.hello.svc.cluster.local. udp 53 false 512" NXDOMAIN qr,aa,rd 146 0.000263728s
[INFO] 10.1.28.1:34040 - 36853 "A IN mrkaran.dev.svc.cluster.local. udp 47 false 512" NXDOMAIN qr,aa,rd 140 0.000214201s
[INFO] 10.1.28.1:33468 - 29482 "A IN mrkaran.dev.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.000156107s
[INFO] 10.1.28.1:58471 - 45814 "A IN mrkaran.dev. udp 29 false 512" NOERROR qr,rd,ra 56 0.110263459s
[INFO] 10.1.28.1:54800 - 2463 "AAAA IN mrkaran.dev. udp 29 false 512" NOERROR qr,rd,ra 68 0.145091744s
Фух. Дві речі тут привертають увагу:
Запит проходить по всіх етапах пошуку доти, доки відповідь не міститиме код NOERROR (DNS-клієнти його розуміють та зберігають як результат). NXDOMAIN означає, що для цього доменного імені запис не знайдено. Оскільки mrkaran.dev не є FQDN-іменем (відповідно до ndots=5), resolver дивиться на пошуковий шлях та визначає порядок запитів;
Записи А и АААА надходять паралельно. Справа в тому, що разові запити в /etc/resolv.conf за замовчуванням налаштовані таким чином, що здійснюється паралельний пошук за протоколами IPv4 та IPv6. Скасувати таку поведінку можна, додавши опцію single-request в resolv.conf.
Примітка: glibc можна налаштувати на послідовне надсилання цих запитів, а musl — ні, тому користувачам Alpine слід прийняти це до відома.
Експериментуємо з ndots
Давайте ще трохи поекспериментуємо з ndots і подивимося, як поводиться цей параметр. Ідея проста: ndots визначає, чи буде DNS-клієнт вважати домен абсолютним чи відносним. Наприклад, як у випадку простого Google DNS-клієнт дізнається, чи є цей домен абсолютним? Якщо поставити ndots рівним 1, клієнт скаже: «О, в google немає жодної точки; мабуть, пробігу по всьому списку пошуку». Однак якщо запитати google.com, список суфіксів буде цілком проігноровано, оскільки ім'я, що запрошується, задовольняє порога ndots (Є хоча б одна точка).
[INFO] 10.1.28.1:52495 - 2606 "A IN mrkaran.hello.svc.cluster.local. udp 49 false 512" NXDOMAIN qr,aa,rd 142 0.000524939s
[INFO] 10.1.28.1:59287 - 57522 "A IN mrkaran.svc.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.000368277s
[INFO] 10.1.28.1:53086 - 4863 "A IN mrkaran.cluster.local. udp 39 false 512" NXDOMAIN qr,aa,rd 132 0.000355344s
[INFO] 10.1.28.1:56863 - 41678 "A IN mrkaran. udp 25 false 512" NXDOMAIN qr,rd,ra 100 0.034629206s
оскільки в mrkaran немає жодної точки, пошук проводився у всьому списку суфіксів.
Примітка: на практиці максимальне значення ndots обмежено 15; за замовчуванням у Kubernetes воно дорівнює 5.
Застосування в production
Якщо програма виконує безліч зовнішніх мережевих дзвінків, DNS може стати вузьким місцем у разі активного трафіку, оскільки при дозволі імені виконується безліч зайвих запитів (перш ніж система дістанеться потрібного). Програми зазвичай не додають кореневу зону до доменних імен, проте це цілком тягне на хак. Тобто замість того, щоб вимагати api.twitter.com, ви можете за'hardcode'ити api.twitter.com. (З точкою) у додатку, що спонукає DNS-клієнтів виконувати авторитетний пошук відразу в абсолютному домені.
Крім того, починаючи з версії Kubernetes 1.14, розширення dnsConfig и dnsPolicy набули статусу стабільних. Таким чином, при розгортанні pod'а можна зменшити значення ndotsскажімо, до 3 (і навіть до 1!). Через це кожне повідомлення всередині вузла має включати повний домен. Це один із класичних компромісів, коли доводиться вибирати між продуктивністю та переносимістю. Мені здається, що переживати про це варто лише у випадку, якщо наднизькі затримки є життєво важливими для вашої програми, оскільки результати DNS також кешуються всередині.
Посилання
Вперше про цю особу я дізнався на K8s-meetup'е, що пройшов 25 січня. Там йшлося, зокрема, і про цю проблему.
Примітка: Я вважав за краще не використовувати dig в цій статті. dig автоматично додає точку (ідентифікатор кореневої зони), роблячи домен "повним" (FQDN), НЕ проганяючи його заздалегідь через список пошуку. Писав про це в однією з попередніх публікацій. Тим не менш, досить дивний той факт, що загалом для стандартної поведінки доводиться ставити окремий прапор.