✻ Урок 2.3 · Тема 2: Сеть, HTTP, DNS, nginx и TLS
DNS: как имя становится адресом
Содержание урока
Зачем это нужно
Люди помнят имена, сети работают с адресами. Между ними стоит DNS (Domain Name System, «система доменных имён»). Это как телефонная книга интернета: ты знаешь имя notes.example.com, а компьютеру нужен IP-адрес вроде 192.0.2.10 (что такое IP-адрес, мы разбирали в уроке 2.1). Домен (domain) это и есть такое имя: example.com, notes.example.com. Читается справа налево: com это «верхний уровень», example это имя, которое кто-то зарегистрировал, а notes это его поддомен, отдельное имя внутри домена. Без DNS пришлось бы помнить и вводить числа вместо имён и менять их у всех клиентов при каждом переезде сервера.
На работе про DNS вспоминают в первую очередь, когда «всё сломалось и непонятно почему»:
- сервис переехал на новый IP, а часть клиентов всё ещё ходит на старый;
- в контейнере (изолированной «коробке» с программой, внутри которой может быть свой набор сетевых настроек; подробно в уроке 4.1) не находится имя базы данных;
- сертификат (электронное удостоверение сайта для защищённого соединения HTTPS, выдаётся на конкретное имя; разберём в уроке 2.6) выпущен, а домен смотрит не туда;
- приложение пишет
Temporary failure in name resolution, и никто не понимает, что это значит.
Половина странных отказов это DNS, и проверяется он за десять секунд, если знаешь, какую команду запустить и как прочитать ответ.
В этом уроке ты научишься читать ответ программы dig (она задаёт DNS вопросы и показывает ответы), понимать, кто именно отвечает на вопрос, и отличать три разные беды: «такого имени нет», «DNS-сервер молчит» и «ответ просто устарел».
Шаг проекта: имя notes.lab в файле /etc/hosts на клиенте и на сервере, и «Заметки» открываются по имени, а не по адресу. Код app.py не меняется, остаётся версия v2.2.
Что нужно знать
- Урок 2.1: адреса и маршруты - IP-адрес, шлюз и подсеть. DNS отдаёт именно адреса, а дойдёт ли до них пакет, решает маршрут. Адрес
127.0.0.1и сетьlo(loopback) тоже оттуда. - Урок 2.2: порты, TCP и SSH - порт, разница между TCP и UDP, ошибки
Connection refusedиtimed out. Они случаются уже после DNS, и здесь ты научишься отличать их от ошибок имени. - Урок 1.2: текст, потоки и конвейеры -
grep,awk,headи|нужны, чтобы разбирать выводdig. - Урок 1.8: systemd и редакторы - «Заметки» работают как сервис
notes, а сама система разрешения имён на Ubuntu тоже сервис,systemd-resolved, который смотрим черезsystemctl.
Картина целиком
Представь, что тебе нужно позвонить в пиццерию «Маргарита». Номера ты не помнишь. Что ты делаешь?
- Сначала заглядываешь в свою записную книжку. Если номер там есть, звонишь сразу.
- Если нет, звонишь в справочную службу. Оператор либо помнит номер (недавно уже спрашивали), либо сам обзванивает нужные инстанции и находит его.
- Номер, который тебе сказали, ты записываешь на бумажку и пользуешься ею какое-то время, чтобы не звонить в справочную снова.
DNS устроен точно так же:
- записная книжка это файл
/etc/hostsна твоей машине (обычный текстовый файл, в котором каждая строка связывает адрес с именем; подробно ниже); - справочная служба это рекурсивный резолвер (recursive resolver): сервер, которому твоя машина задаёт вопрос «какой адрес у этого имени?»;
- обзвон инстанций это цепочка серверов: корневые, потом «зоны верхнего уровня» (
com,ru), потом сервер самого домена. Зона это участок имён, за который отвечает один владелец, а запись (record) это одна строка в его справочнике вида «имя такое-то, адрес такой-то». Подробно о зонах и записях ниже; - бумажка с номером это кэш (cache): запомненный ответ, который живёт ограниченное время, TTL (time to live, «время жизни»: число секунд, сколько ответ можно считать верным, не спрашивая заново). Кэш нужен, чтобы не гонять один и тот же вопрос по всему интернету; минус в том, что после смены адреса часть клиентов какое-то время видит старый.
flowchart TD
P["Твоя программа (curl, браузер, ssh)<br>«какой адрес у notes.example.com?»"] --> H["1. Файл /etc/hosts<br>есть запись? берём её, конец"]
H -->|"нет"| L["2. Локальный резолвер systemd-resolved<br>слушает 127.0.0.53, в кэше есть? отвечает"]
L -->|"нет"| R["3. Рекурсивный резолвер<br>у роутера, провайдера или 8.8.8.8"]
R -->|"в его кэше нет"| ROOT["4. Корневой сервер<br>«за com отвечают вот эти»"]
ROOT --> TLD["5. Сервер зоны com<br>«за example.com отвечают вот эти»"]
TLD --> AUTH["6. Авторитетный сервер example.com<br>«notes.example.com это 192.0.2.10»"]
Шаги 1 и 2 происходят на твоей машине, шаг 3 у провайдера или публичного резолвера, шаги 4-6 это обход цепочки, который резолвер делает за тебя.
За урок ты разберёшь каждый шаг этой схемы: как устроено имя, кто отвечает на каждом шаге, какие бывают записи и что такое TTL, как читать ответ dig, как операционная система решает, куда идти первым, и какие ошибки что означают.
Теория
Зачем нужен DNS и что было до него
Компьютеры находят друг друга по IP-адресам. Запомнить 140.82.121.4 вместо github.com человеку трудно. Хуже другое: адрес сервера меняется. Компания переехала в другой ЦОД (центр обработки данных, здание с серверами), купила новый сервер, перенесла сайт, и адрес стал другим. Если бы все ходили по адресам, каждому пользователю пришлось бы сообщать новый. Имя даёт слой косвенности: имя остаётся, а адрес за ним можно менять.
Раньше вся «телефонная книга» была одним файлом HOSTS.TXT, который люди скачивали с одного компьютера. Когда сеть выросла, единый файл перестал работать: его невозможно обновлять для миллионов имён и раздавать миллионам машин. DNS заменил его распределённой базой: каждый владелец имени сам хранит его записи на своих серверах, а найти нужный сервер помогает иерархия. Файл /etc/hosts до сих пор существует как маленький локальный остаток той эпохи.
Похоже на справочную службу города, где у каждой улицы свой отдел. Ты спрашиваешь у общей справочной «Ленина, 5», и тебя перенаправляют в отдел нужного района, а там дают номер. Никто не хранит номера всего мира: каждый знает только свой участок и то, к кому отправить дальше. Где аналогия перестаёт работать: живая справочная отвечает по телефону одному человеку, а DNS-серверы отвечают миллионам запросов в секунду, и ответ, который получил один клиент, полезен всем следующим (поэтому существует кэш).
Программа не ходит по цепочке сама: она спрашивает одного помощника, резолвера, и получает готовый адрес. Всё остальное происходит без неё. DNS-вопросы и ответы идут по сети как обычные пакеты: чаще всего по UDP на порт 53 (вспомни урок 2.2: UDP это «открытка» без рукопожатия, для короткого вопроса и короткого ответа она подходит). Если ответ не помещается в один пакет или UDP не проходит, DNS переключается на TCP, тоже на порт 53.
Осторожно: что DNS «находит сервер». Он ничего не проверяет: он лишь говорит «у этого имени записан вот такой адрес». Работает ли сервер по этому адресу, слушает ли он нужный порт, дойдёт ли до него пакет, DNS не знает и знать не должен. Поэтому после успешного DNS всё равно бывают Connection refused и timed out.
Прикинь сам: Сервер переехал на новый адрес. Если бы не было DNS, что пришлось бы сделать каждому, кто ходит на сайт?
Узнать новый адрес и поменять его у себя везде, где он записан. Имя в DNS решает это одной правкой записи у владельца.
Главное: DNS превращает имя в адрес, но ничего не проверяет: после успешного ответа всё ещё возможны
Connection refusedиtimed out.
Проверь понимание: DNS вернул адрес, а
curlпишетConnection refused. Ошибка в DNS?
Ответ
Нет. Раз адрес получен, DNS свою работу сделал. Connection refused это уже следующий шаг: пакет дошёл до машины, но на этом адресе и порту никто не слушает (урок 2.2). Искать надо на сервере: работает ли сервис и на каком адресе он слушает.
Мы увидели, зачем нужен DNS и как он вырос из одного файла. Теперь разберём, как устроено само имя: именно его структура позволяет поделить работу между многими серверами.
Имя домена: как оно читается и кто за что отвечает
Плоский список имён («notes», «shop», «mail») на весь мир невозможен: имена бы совпадали, а хранить список пришлось бы в одном месте. Поэтому имена организованы деревом: каждый уровень принадлежит тому, кто им управляет, и может сам раздавать имена внутри себя.
Сравни с почтой. Почтовый адрес читается от большого к малому: страна, город, улица, дом. Имя в DNS читается так же, только справа налево: сначала самая крупная часть, потом всё мельче.
Возьмём имя notes.example.com. и разберём его.
flowchart TD
R[". (корень, root)<br>невидимая точка в конце имени"] --> C["com<br>домен верхнего уровня (TLD)"]
C --> E["example<br>домен второго уровня, его купил владелец"]
E --> N["notes<br>поддомен, владелец создал его сам"]
Имя notes.example.com. читается справа налево: корень, потом com, потом example, потом notes.
- В конце имени стоит точка. Она обычно не пишется, но она есть: это корень (root), вершина всего дерева. Имя, записанное вместе с этой точкой, называется полным (FQDN, fully qualified domain name):
notes.example.com.. Программаdigвсегда показывает имена именно так, с точкой на конце. comэто домен верхнего уровня (TLD, top-level domain). Бываютcom,org,ru,рфи другие. Каждым TLD управляет своя организация.exampleэто домен второго уровня. Его ты (или твоя компания) покупаешь у регистратора (registrar): компании, которая от твоего имени записывает в базу «example.comпринадлежит такому-то, а его записи хранят вот эти серверы».notesэто поддомен. Его владелецexample.comсоздаёт сам, бесплатно и без всяких регистраторов.
Слово зона (zone) означает кусок дерева, за который отвечает один владелец. Владелец зоны example.com решает, какие в ней записи, и хранит их на своих серверах. Он может отдать поддомен другому: например, cloud.example.com может вести отдельная команда со своими серверами. Такая передача называется делегированием (delegation): в родительской зоне пишется «за cloud.example.com отвечают вот эти серверы».
Проверим на нашем имени: чей это адрес, notes.example.com.? Идём справа налево:
- Корень знает, кто ведёт
com. - Серверы
comзнают, кто ведётexample.com. - Серверы
example.comзнают, какой адрес уnotes.example.com.
Никто из них не хранит всего дерева, каждый знает только свой уровень и к кому отправить дальше. Ниже, в разделе про трёх участников, это будет с настоящими именами серверов.
Осторожно: Домен и адрес сайта. example.com это имя в дереве, а не «сайт». У одного имени может быть сайт, почта, ничего или всё сразу: что именно, определяют записи, о них ниже. И второе: точка в конце не опечатка. notes.example.com (без точки) программа при некоторых настройках может достроить, о чём мы поговорим в разделе про resolv.conf, а notes.example.com. (с точкой) всегда значит именно это имя целиком.
Прикинь сам: В имени
notes.example.com.какая часть самая крупная, если читать по правилам DNS?
Корень, невидимая точка в конце. Дальше идут com, потом example, потом notes: читать имя нужно справа налево.
Главное: имя это дерево: корень, домен верхнего уровня (
com), домен второго уровня (example) и поддомен (notes); каждый уровень принадлежит тому, кто им управляет.
Проверь понимание: какой домен верхнего уровня у имени
api.shop.example.co.uk, и кто «выше»:shopилиexample?
Ответ
Верхний уровень читается справа: uk. Выше (левее в дереве это правее в записи) стоит example, потому что читаем справа налево: uk, потом co, потом example, потом shop, потом api. example выше, чем shop: shop это поддомен внутри example.co.uk.
Имя делится на уровни, и за каждый уровень кто-то отвечает. Теперь посмотрим, какие серверы за это отвечают и как вопрос доходит до нужного.
Три роли серверов: корневые, авторитетные и рекурсивные
Нужно, чтобы вопрос «какой адрес у имени?» можно было задать любому серверу и получить ответ, при этом чтобы никто не хранил всё. Для этого работа разделена на три роли, и путаница между ними причина половины ошибок в понимании DNS.
Ты приходишь в большой торговый центр искать магазин. У входа стоит информационная стойка (корневые серверы): она не знает, где конкретный магазин, но знает, на каком этаже какой отдел. Ты идёшь на нужный этаж, там администратор отдела (серверы зоны верхнего уровня) знает, какой магазин где. А сам магазин (авторитетный сервер) знает всё про себя. И есть твой помощник-консьерж (рекурсивный резолвер): он ходит по всем этим стойкам за тебя и приносит готовый ответ. Где аналогия не работает: консьерж запоминает всё, что узнал, и отдаёт следующим посетителям, пока сведения не устарели.
Разберём роли по одной, в том порядке, в каком по ним идёт вопрос.
Корневые серверы (root servers) стоят первыми. Они знают только, кто отвечает за com, ru, org и другие домены верхнего уровня (последняя часть имени). Их 13 имён (от a.root-servers.net до m.root-servers.net), но за каждым именем стоят сотни машин по всему миру. Адреса корневых серверов «зашиты» во все резолверы.
Дальше вопрос доходит до авторитетных серверов (authoritative servers). Они хранят настоящие записи зоны (своей части имён) и отвечают «это моё, вот ответ». «Авторитетный» значит «главный источник по этой зоне». Их имена записаны в записях NS (name server, «сервер имён») зоны.
Но сам ты по этой цепочке не ходишь. За тебя её проходит рекурсивный резолвер (recursive resolver), та машина, которую ты спрашиваешь. Он обходит цепочку от корня до авторитетного сервера, возвращает готовый ответ и запоминает его на время TTL. Слово «рекурсивный» здесь значит «доведёт до конца сам». Это может быть твой домашний роутер, DNS провайдера, публичные 8.8.8.8 (Google) или 1.1.1.1 (Cloudflare) или корпоративный сервер.
Есть и ещё один участник, у тебя на машине: stub resolver («заглушка»). Это маленький кусочек операционной системы, который принимает вопрос от программы и отправляет его рекурсивному резолверу из настроек. Сам по цепочке он не ходит. На Ubuntu его роль играет systemd-resolved, о нём ниже.
sequenceDiagram
participant S as Твоя машина<br>curl и stub resolver (127.0.0.53)
participant R as Рекурсивный резолвер<br>например 8.8.8.8
participant Root as Корневой сервер
participant T as Сервер зоны com
participant A as Авторитетный сервер<br>example.com
S->>R: вопрос: адрес notes.example.com?
R->>Root: спрашивает
Root->>R: «за com спроси у них»
R->>T: спрашивает
T->>R: «за example.com спроси у них»
R->>A: спрашивает
A->>R: «notes... = 192.0.2.10»
Note over R: запоминает ответ (кэш) на время TTL
R->>S: готовый ответ
Твоя машина задаёт один вопрос и получает готовый ответ, а весь обход делает рекурсивный резолвер.
Весь обход можно увидеть своими глазами. Вот настоящий результат dig +trace example.com A: команда сама проходит цепочку и показывает каждый шаг (запуск и разбор в практике, задание 2). Ниже сокращённо, с настоящими значениями:
. 4502 IN NS a.root-servers.net. <- шаг 0: список корневых серверов
;; Received 239 bytes from 127.0.0.53#53(127.0.0.53) in 3 ms
com. 172800 IN NS a.gtld-servers.net. <- шаг 1: корень ответил, кто ведёт com
;; Received 836 bytes from 192.203.230.10#53(e.root-servers.net) in 259 ms
example.com. 172800 IN NS hera.ns.cloudflare.com. <- шаг 2: com ответил, кто ведёт example.com
example.com. 172800 IN NS elliott.ns.cloudflare.com.
;; Received 359 bytes from 192.54.112.30#53(h.gtld-servers.net) in 247 ms
example.com. 300 IN A 104.20.23.154 <- шаг 3: сам авторитетный сервер ответил
example.com. 300 IN A 172.66.147.243
;; Received 72 bytes from 108.162.195.228#53(elliott.ns.cloudflare.com) in 235 ms
Читаем сверху вниз. Строка Received ... from говорит, кто дал именно этот блок. Сначала у локального резолвера (127.0.0.53) взят список корневых серверов. Затем один из них, e.root-servers.net, на вопрос про example.com не ответил адресом, а сказал: «за com отвечают серверы *.gtld-servers.net». Дальше h.gtld-servers.net сказал: «за example.com отвечают hera и elliott у Cloudflare». И только эти серверы дали настоящий ответ: два адреса. На каждом шаге спрашивают следующего, пока не дойдут до того, кто знает ответ сам. Числа 172800 и 300 это TTL в секундах, о нём чуть ниже.
Адреса и имена серверов у тебя будут другие: владелец example.com может сменить хостинг DNS, и тогда вместо Cloudflare здесь будет другая компания.
Осторожно: Авторитетный сервер и рекурсивный резолвер. Авторитетный хранит записи только своих зон и на чужие вопросы отвечает «не знаю» (или вообще не отвечает на рекурсивные вопросы). Рекурсивный сам ничего не хранит навсегда: он ищет и запоминает на время. В настройках сети ты всегда указываешь рекурсивный резолвер.
Прикинь сам: Сколько серверов нужно спросить твоей программе, чтобы узнать адрес
notes.example.com, если рядом есть рекурсивный резолвер?
Один: резолвер. Обход корня, зоны com и авторитетного сервера он делает сам и возвращает готовый ответ.
Главное: корневые серверы знают, кто ведёт
comи другие зоны верхнего уровня, авторитетные хранят настоящие записи, а рекурсивный резолвер ходит по цепочке за тебя и запоминает ответ.
Проверь понимание: ты хочешь узнать, что записано у самого владельца домена, минуя чужие кэши. К какому серверу нужно обратиться?
Ответ
К авторитетному серверу зоны. Его имя видно в записях NS домена, а спросить его напрямую можно командой dig @имя_сервера имя_домена. Рекурсивный резолвер может отвечать из кэша, то есть показать устаревшее.
Мы знаем, кто отвечает на вопрос. Теперь выясним, что именно лежит под именем и какие бывают типы записей.
Записи и их типы: что можно хранить под именем
Под одним именем нужно хранить разное: адрес сервера, куда доставлять почту, подтверждение владения доменом. Поэтому запись в DNS имеет тип.
Запись напоминает карточку организации в справочнике: под одним названием («Пиццерия Маргарита») хранятся разные поля: адрес, телефон, почта, сайт. Тип записи это название поля. Оговорка: в отличие от карточки, у одного поля в DNS может быть несколько значений (два адреса у example.com), и это нормально.
Запись (resource record) это строка из пяти частей: имя TTL класс тип значение. Например, example.com. 300 IN A 104.20.23.154: имя example.com., время жизни 300 секунд, класс IN (Internet, единственный, который ты будешь встречать, просто пропускай), тип A, значение это адрес. Главные типы:
| Тип | Что значит | Пример |
|---|---|---|
A |
имя в IPv4-адрес | notes.example.com -> 192.0.2.10 |
AAAA |
имя в IPv6-адрес (то же, но для нового протокола, урок 2.1) | notes.example.com -> 2001:db8::10 |
CNAME |
имя-псевдоним: «это то же самое, что другое имя» | www.github.com -> github.com |
MX |
куда доставлять почту домена (число это приоритет, меньше значит важнее) | 10 mail.example.com |
TXT |
произвольный текст: подтверждение владения, защита почты (SPF) | "v=spf1 -all" |
NS |
какие серверы авторитетны для зоны | hera.ns.cloudflare.com. |
SOA |
служебная запись зоны: серийный номер, таймеры, контакт владельца; одна на зону | см. ниже |
PTR |
обратное: адрес в имя | 8.8.8.8 -> dns.google |
Каждый тип можно запросить отдельно. Всё это настоящие ответы, полученные при подготовке урока:
$ dig +noall +answer www.github.com A
www.github.com. 4435 IN CNAME github.com.
github.com. 15 IN A 140.82.121.4
Резолвер сначала вернул CNAME: «www.github.com это всего лишь другое имя для github.com», а затем сразу адрес для настоящего имени. Поэтому у CNAME есть цена: лишний шаг при поиске.
$ dig +short example.com MX
0 .
$ dig +short example.com TXT
"v=spf1 -all"
У example.com в MX записано 0 .: точка вместо имени сервера значит «почту сюда не принимают». А v=spf1 -all в TXT это SPF: «с этого домена не отправляет почту никто». Так почтовые серверы отсекают подделку писем от твоего имени.
$ dig +noall +answer -x 8.8.8.8
8.8.8.8.in-addr.arpa. 4502 IN PTR dns.google.
Флаг -x спрашивает обратное: чьё это имя. Для этого адрес записывается наоборот и добавляется .in-addr.arpa., и получается обычное имя, у которого есть PTR.
$ dig +noall +answer example.com SOA
example.com. 1874 IN SOA elliott.ns.cloudflare.com. dns.cloudflare.com. 2415949263 10000 2400 604800 1800
В SOA по порядку: главный сервер зоны; контакт администратора (dns.cloudflare.com. значит адрес dns@cloudflare.com, точка вместо @); серийный номер (растёт при каждой правке зоны, по нему серверы понимают, что появилась новая версия); четыре таймера в секундах. Тебе пока важно последнее число, 1800: оно определяет, как долго запоминается ответ «такого имени нет» (об этом в разделе про TTL).
Осторожно: Два частых заблуждения.
Первое: CNAME можно поставить на «корень» домена (example.com без поддомена). Нельзя: на корне уже лежат SOA и NS, а CNAME означает «у этого имени нет своих записей, всё как у другого имени», и соседей терпеть не может. Поэтому «голый» домен обычно получает A, а CNAME ставят только на поддомены (www, shop).
Второе: CNAME указывает на имя, а не на адрес. Если написать CNAME на 192.0.2.10, получится ошибка, для адреса нужен A.
Прикинь сам: Какую запись нужно создать, чтобы
www.example.comвёл туда же, кудаexample.com, а самexample.comполучил адрес?
Для example.com запись A с адресом, для www запись CNAME на example.com. На корень домена CNAME ставить нельзя.
Главное: запись это
имя TTL класс тип значение;Aэто адрес,CNAMEпсевдоним на другое имя,MXпочта,TXTтекст,NSсерверы зоны,PTRобратный поиск.
Проверь понимание: у
example.comдва адреса вA. Это ошибка или так и задумано?
Ответ
Так задумано. У имени может быть несколько записей одного типа. Резолвер отдаёт их все, а клиент обычно пробует по порядку. Так владельцы распределяют нагрузку между несколькими серверами (за одним именем стоят разные машины). Но это не настоящая балансировка: DNS не проверяет, жив ли сервер по каждому адресу (подробнее в вопросах для собеседований).
Записи хранятся не вечно: у каждой есть срок жизни. Дальше разберём, как он вместе с кэшем определяет, почему изменение появляется не сразу.
TTL и кэш: почему запись меняется не сразу
Если бы каждая программа при каждом запросе шла от корня до авторитетного сервера, корневые серверы утонули бы в запросах, а открытие сайта занимало бы десятки миллисекунд лишних на каждый шаг. Поэтому любой ответ запоминается (кэшируется), и повторный вопрос получает ответ мгновенно. Но запомненное устаревает: адрес поменяли, а кэш ещё помнит старый. Чтобы это было управляемо, у каждой записи есть срок годности: TTL (time to live, «время жизни») в секундах.
Кэш работает как молоко в холодильнике с датой на пакете. Пока срок не вышел, пользуешься тем, что есть, и не бежишь в магазин. Вышел срок, идёшь и покупаешь свежее. Оговорка: в DNS «пакет» не знает, что его заменили. Владелец записи не может выбросить молоко из чужих холодильников, он может только ждать, пока сроки выйдут.
Пошагово это выглядит так:
- Резолвер получает от авторитетного сервера запись с TTL 300 и запоминает: «адрес такой, годен 300 секунд».
- Пока идут эти секунды, на каждый вопрос он отвечает из памяти. Число TTL в ответе уменьшается: через 100 секунд он скажет 200, потому что рассказывает, сколько осталось.
- Когда TTL дошёл до нуля, запись выбрасывается, и следующий вопрос снова уходит выше.
Кэши стоят на каждом шаге: в браузере, в приложении, в systemd-resolved, в рекурсивном резолвере провайдера. Они независимы, у каждого свои часы.
Пример 1, TTL вживую. Настоящие ответы dig +noall +answer example.com A с паузой 5 секунд между запросами:
example.com. 171 IN A 172.66.147.243 <- первый запрос: осталось 171 секунда
example.com. 166 IN A 104.20.23.154 <- через 5 секунд: 171 - 5 = 166
А тот же вопрос авторитетному серверу напрямую всегда даёт полный TTL:
example.com. 300 IN A 104.20.23.154 <- у источника всегда 300
Значит, локальный кэш получил запись где-то 129 секунд назад (300 - 171 = 129), и ещё 171 секунду будет отвечать из памяти, даже если владелец уже поменял адрес.
Пример 2, переезд сервиса. У записи TTL 3600 (час). Ты хочешь в 14:00 переключить её на новый сервер, и чтобы почти никто не заметил.
- Если поменять запись в 14:00 и ничего больше не делать: клиент, спросивший в 13:59, запомнил старый адрес до 14:59. Почти час часть пользователей ходит на старый сервер.
- Правильно: заранее, скажем в 12:00 (за время, не меньшее старого TTL), снизить TTL записи до 300. К 13:00 все кэши со старым TTL 3600 истекли и получили запись с TTL 300. В 14:00 меняешь адрес: худший случай это 5 минут, пока последний кэш не обновится. После переезда TTL возвращают обратно.
Именно поэтому в вопросе «когда снижать TTL?» правильный ответ «заранее, а не в момент переезда».
Ещё один кэш: отрицательный. Резолвер запоминает и ответ «такого имени нет» (об этом ответе ниже, NXDOMAIN). Срок хранения задаёт последнее число в SOA (в примере выше 1800, то есть полчаса). Поэтому бывает так: ты создал запись, а клиент, который спрашивал имя минуту назад, ещё полчаса получает «нет такого». Это не сбой, а чужой кэш.
Осторожно: «Я поменял запись, значит, всё поменялось». Поменялся только источник. Клиенты увидят изменение не раньше, чем истечёт TTL в каждом кэше по цепочке. И обратное: «TTL 0 значит, что кэша нет» не совсем так, многие резолверы всё равно держат запись несколько секунд.
Прикинь сам: TTL записи 3600, а переехать нужно в 14:00 почти без простоя. Когда снижать TTL?
Заранее, не позже чем за старый TTL до переезда: в 12:00 снизить до 300, к 13:00 все кэши получат короткий срок, а в 14:00 менять адрес. После переезда TTL возвращают.
Главное: ответ живёт в каждом кэше по цепочке до конца своего TTL, и число TTL в ответе уменьшается; поменять запись у источника значит не поменять её у всех сразу.
Проверь понимание: ты сменил A-запись, TTL был 3600. Через 10 минут коллега всё ещё попадает на старый сервер. Ошибка в записи?
Ответ
Скорее всего нет. Его рекурсивный резолвер (или система, или браузер) хранит старый ответ до конца TTL, то есть до часа. Сначала проверь авторитетный сервер напрямую (dig @сервер имя): если там новый адрес, запись верна. Тогда остаётся ждать или сбросить кэш на клиенте.
Когда понятны записи и TTL, нужен инструмент, который показывает всё это в ответе. Это dig.
Как читать ответ dig
dig (domain information groper) это инструмент для DNS, как ping для доступности. Он спрашивает сервер и печатает ответ целиком, поэтому по нему видно, что именно ответил DNS, а не что «додумала» твоя программа. Умение читать этот вывод главный навык урока.
Вывод dig напоминает квитанцию с полным разбором: кто спрашивал, кого, что спросили, что ответили, сколько это заняло. Обычно мы смотрим только на сумму, но при споре читаем все строки.
Общий вид команды: dig [@сервер] имя [тип] [+опции]. Если сервер не указан, берётся из /etc/resolv.conf. Если тип не указан, это A. Опции с плюсом меняют вывод: +short печатает только значения, +noall +answer показывает только строки ответа, +trace проходит цепочку от корня.
Вот полный вывод dig example.com A со всеми полями:
; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> example.com A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18928
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 172 IN A 104.20.23.154
example.com. 172 IN A 172.66.147.243
;; Query time: 77 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Wed Sep 30 12:00:37 UTC 2026
;; MSG SIZE rcvd: 72
Разбор по строкам:
- Первая строка: версия
digи то, что ты спросил (example.com A). Строки, начинающиеся с;, это комментарии, часть из них служебные. opcode: QUERY: обычный вопрос. Других значений ты почти не увидишь.status: NOERROR: главная строка. Это код результата:NOERRORзначит «вопрос понятен и обработан». Другие значения (NXDOMAIN,SERVFAIL) разберём в разделе про ошибки.id: 18928: случайный номер вопроса, чтобы клиент мог сопоставить ответ с вопросом. Ничего не значит для диагностики.flags: qr rd ra: флаги ответа.qr(query response) значит «это ответ».rd(recursion desired) значит «клиент просил довести поиск до конца».ra(recursion available) значит «сервер умеет доводить поиск до конца», то есть это рекурсивный резолвер. Ещё бываетaa(authoritative answer): «ответил сам авторитетный сервер, не из кэша». Ты увидишь его в задании 2.QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1: сколько записей в каждом разделе ниже. Ответа две записи, поэтомуANSWER: 2.OPT PSEUDOSECTION: технический раздел о расширении протокола (EDNS). Для диагностики его можно пропускать.QUESTION SECTION: что спрашивали: имяexample.com., классIN, типA.ANSWER SECTION: ответ, по одной записи на строку: имя, TTL (здесь 172 секунды осталось), класс, тип, значение. Два адреса значит две строки.Query time: 77 msec: сколько ушло на вопрос. Первый раз 77 миллисекунд, потому что запрос шёл по сети, повторный придёт из кэша за 0.SERVER: 127.0.0.53#53(127.0.0.53) (UDP): кто ответил. Форматадрес#порт. Здесь отвечал локальныйsystemd-resolved, а не резолвер провайдера. Это тоже часть диагностики: если ты думал, что спрашиваешь8.8.8.8, а тут127.0.0.53, вывод про другой сервер.WHEN: время,MSG SIZE rcvd: 72: размер ответа в байтах.
Осторожно: Читают только ответ и не смотрят на SERVER и flags. Между тем одно и то же имя может давать разные ответы у разных серверов, и только SERVER говорит, чьё мнение ты видишь. И второе: пустой ANSWER не всегда ошибка, это зависит от status (см. ниже).
Прикинь сам: В выводе
digстрокаSERVER: 127.0.0.53#53. Кто ответил на вопрос, провайдер или твоя машина?
Твоя машина: это локальный systemd-resolved. Если ты думал, что спрашиваешь 8.8.8.8, вывод относится к другому серверу.
Главное: в выводе
digсмотриstatus(результат),flags(кто ответил и как),ANSWER SECTION(записи с TTL) иSERVER(чьё это мнение).
Проверь понимание: в ответе
status: NOERROR,flags: qr aa rd, TTL равен 300, и это же число ты видишь при каждом повторе через минуту. Что это говорит о том, кто ответил?
Ответ
Флаг aa значит, что ответил авторитетный сервер, то есть первоисточник, а не кэш. У источника TTL всегда полный (300), он не убывает. Отсутствие флага ra тут тоже нормально: авторитетный сервер не занимается рекурсией для чужих.
dig спрашивает DNS напрямую, но обычные программы ходят другим путём. Разберём, как система сама превращает имя в адрес.
Как система превращает имя в адрес: hosts, nsswitch, resolv.conf
Разные программы (curl, ssh, браузер, Python) все хотят одного: имя в адрес. Если бы каждая делала это по-своему, на одной машине у разных программ были бы разные представления о мире. Поэтому всё вынесено в общую библиотеку операционной системы (библиотека это набор готовых функций, которые подключают к себе все программы). Библиотека называется libc, а нужная функция getaddrinfo(): «дай адрес для этого имени».
Вспомни порядок поиска номера из первого примера: сначала записная книжка, потом справочная. У тебя есть правило «где искать и в каком порядке», и оно одно на всех.
Путь имени в системе определяют три файла:
/etc/nsswitch.conf(name service switch, «переключатель служб имён») задаёт порядок источников. Нас интересует строкаhosts:. Значениеfiles dnsзначит: сначалаfiles, то есть файл/etc/hosts, и только потомdns, то есть DNS-запрос./etc/hosts: простой текстовый файл, где на каждой строке адрес и одно или несколько имён:127.0.0.1 notes.lab. Он локальный: действует только на этой машине./etc/resolv.conf: говорит, куда слать DNS-запрос, если файлhostsне помог. Строкаnameserver 127.0.0.53значит «к серверу на этом адресе». Другие строки:searchэто список суффиксов, которые система дописывает к короткому имени (приsearch corp.localзапросssh dbпревратится вdb.corp.local; так же работают короткие имена внутри Kubernetes, об этом в уроке 5.3);optionsэто дополнительные настройки.
На Ubuntu есть ещё один слой. nameserver 127.0.0.53 это не настоящий DNS-сервер провайдера, а адрес программы systemd-resolved на твоей же машине (помнишь 127.0.0.0/8, loopback? Это он). Он принимает вопросы, кэширует ответы и уже сам ходит к настоящим серверам, которые получил при подключении к сети. Эти настоящие серверы обычно выдаёт сама сеть: по протоколу DHCP (он раздаёт машинам адрес, шлюз и адреса DNS-серверов, урок 2.1). Файл /etc/resolv.conf на Ubuntu это не обычный файл, а симлинк (символическая ссылка, «ярлык» на другой файл), ведущий к /run/systemd/resolve/stub-resolv.conf.
flowchart TD
A["curl notes.lab"] --> B["getaddrinfo()<br>читает /etc/nsswitch.conf: «hosts: files dns»"]
B -->|"1"| C["/etc/hosts<br>нашлось? берём, конец"]
B -->|"2, если не нашлось"| D["/etc/resolv.conf<br>«nameserver 127.0.0.53»"]
D --> E["systemd-resolved (127.0.0.53)<br>свой кэш, читает и /etc/hosts"]
E -->|"серверы из DHCP (resolvectl status)"| F["Рекурсивный резолвер<br>корень, ..., авторитетный сервер"]
Здесь видно, почему curl находит имя из /etc/hosts, а dig @8.8.8.8 нет: dig сразу идёт в DNS и первый шаг пропускает.
Вот как это выглядит на деле: настоящие файлы с учебного стенда:
$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 Sep 30 11:52 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
Первая буква l значит, что это симлинк, а после стрелки -> указано, куда он ведёт. Содержимое без комментариев:
nameserver 127.0.0.53
options edns0 trust-ad
search .
nameserver 127.0.0.53 это stub systemd-resolved. options edns0 trust-ad это технические настройки протокола, они тебе не понадобятся. search . значит «суффиксов нет».
$ grep '^hosts' /etc/nsswitch.conf
hosts: files dns
Сначала файл, потом DNS.
Главная ловушка урока: dig и программы видят разное. dig не читает /etc/hosts сам, он просто отправляет DNS-запрос по адресу из resolv.conf. А curl, ssh и браузер идут через getaddrinfo(), то есть проходят все три шага сверху, и запись в /etc/hosts для них главнее DNS. Поэтому можно получить: dig говорит одно, а curl открывает другое, и оба «правы». Команда, которая честно показывает то, что увидит приложение, это getent hosts имя (getent от get entries, «получить записи» из баз имён системы; она вызывает ту же getaddrinfo()). Если dig и getent hosts дают разное, разбираться нужно именно с этим.
Есть нюанс, который сбивает с толку: на Ubuntu systemd-resolved сам умеет читать /etc/hosts и отвечать по нему на DNS-запросы. Поэтому dig notes.lab (который идёт к 127.0.0.53) иногда покажет адрес из /etc/hosts: ответ придёт с флагом aa и TTL 0. А вот dig @8.8.8.8 notes.lab (напрямую к Google) /etc/hosts уж точно не видит. Чтобы проверять «есть ли имя в настоящем DNS», задавай вопрос конкретному внешнему серверу.
Осторожно: «Файл /etc/hosts это DNS». Нет, это отдельный локальный источник, у него нет TTL, иерархии и записей типа MX. Он действует только на той машине, где лежит, и никто другой о нём не узнает. И второе: «dig показывает то, что видит приложение». Нет, по причинам выше.
Прикинь сам: В
nsswitch.confстоитhosts: files dns. Что проверитcurlпервым:/etc/hostsили DNS?
/etc/hosts: files стоит первым. DNS-запрос уйдёт, только если там имени не нашлось.
Главное: программы идут через
getaddrinfo(): сначала/etc/hosts, потом DNS поresolv.conf;digберёт только DNS, поэтому «что видит приложение» проверяй черезgetent hosts.
Проверь понимание: в
/etc/hostsзаписано127.0.0.1 notes.lab, аdig @8.8.8.8 notes.labвозвращаетNXDOMAIN.curl notes.labпри этом работает. Почему так?
Ответ
curl идёт через getaddrinfo(), где по nsswitch.conf первым стоит files, и находит запись в /etc/hosts. Публичный сервер 8.8.8.8 о твоём локальном файле не знает и честно отвечает, что имени нет (NXDOMAIN). Проверять «что видит приложение» нужно через getent hosts.
Теперь известен весь путь от программы до ответа. Пора понять, как он ломается и чем различаются типичные ошибки.
Ошибки DNS: NXDOMAIN, SERVFAIL, тишина и как их отличать
DNS ломается по-разному, и чинится каждый вариант в своём месте. Если не различать их, будешь менять адрес там, где сломан резолвер, и наоборот. Разделить их можно за одну команду.
Звонишь в справочную. Три исхода: оператор отвечает «такой организации нет» (имя не существует), оператор отвечает «у нас сбой, не могу проверить» (сломан поиск), или трубку вообще не берут (справочная недоступна). И лечатся они по-разному: в первом случае проверяй, правильно ли ты назвал организацию, во втором ждёшь и пробуешь другую справочную, в третьем проверяешь, работает ли телефон.
Случаев четыре, и в dig первые три видны в строке status: заголовка:
| Что видишь | Что значит | Где искать |
|---|---|---|
NOERROR и в ANSWER есть записи |
всё хорошо | нигде |
NOERROR и ANSWER: 0 |
имя существует, но записи такого типа нет | запросил не тот тип (например, AAAA у имени только с IPv4) |
NXDOMAIN |
такого имени не существует | опечатка, запись не создана, не та зона |
SERVFAIL |
сервер не смог получить ответ | сломана зона, не отвечают её серверы, сломана подпись DNSSEC |
connection timed out; no servers could be reached |
резолвер вообще не отвечает | сеть, файрвол, неверный nameserver в resolv.conf |
Про DNSSEC: это система цифровых подписей, которая позволяет проверить, что ответ DNS не подменили. Если подпись у домена сломана, проверяющий резолвер (например, 8.8.8.8) вместо неверного ответа возвращает SERVFAIL. Ты встретишь RRSIG и DS в выводе +trace: это подписи, при чтении их можно пропускать.
А сама программа, которая пытается открыть имя, сообщает об этом своими словами. Настоящие тексты ошибок:
$ curl -sS http://nonexistent-abc123.example.com/
curl: (6) Could not resolve host: nonexistent-abc123.example.com
$ ping -c 1 example.com # при недоступном резолвере
ping: example.com: Temporary failure in name resolution
$ ping -c 1 example.com # если имя не нашли ни в одном источнике
ping: example.com: Name or service not known
Could not resolve host (curl, код выхода 6) значит «не смог превратить имя в адрес», причину curl не уточняет. Temporary failure in name resolution значит, что резолвер не ответил вовсе (временная неудача), а Name or service not known значит «источники ответили или пропустили: такого имени нет». Точную причину всё равно устанавливают через dig.
Три класса в одной проверке выглядят так. Настоящие ответы:
$ dig no-such-host.invalid | grep status
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 61126
$ dig @8.8.8.8 dnssec-failed.org | grep status # домен со специально сломанной подписью
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 50077
$ dig @192.0.2.53 +time=2 +tries=1 example.com # такого сервера нет
;; communications error to 192.0.2.53#53: timed out
;; no servers could be reached
Первый: резолвер работает, просто имени no-such-host.invalid нет (домен .invalid зарезервирован под «заведомо несуществующие» имена). Второй: резолвер работает, но не смог довести поиск. Третий: ответа нет вообще, потому что по адресу 192.0.2.53 никто не слушает (этот диапазон отведён под примеры в документации). Флаги +time=2 +tries=1 говорят dig ждать две секунды и пробовать один раз, иначе он ждёт пятнадцать секунд.
Как понять, что виновата именно DNS, а не сеть или сервис. Задай один вопрос напрямую: dig +short shop.example.com. Если адрес пришёл, а curl всё равно не открывает сайт, проблема не в DNS: ищи дальше по цепочке, в порте, файрволе или самом сервисе. Если dig молчит, отвечает NXDOMAIN или SERVFAIL, а curl по IP-адресу (curl http://192.0.2.10/) работает, значит, сеть цела, а ломается именно разрешение имени.
Осторожно: NXDOMAIN и «DNS не работает». NXDOMAIN как раз означает, что DNS работает и честно ответил. Сломан DNS в случае тишины (timed out) или SERVFAIL. И ещё: пустой ANSWER при NOERROR не ошибка, это «нет записи такого типа».
Прикинь сам:
digвернулstatus: NOERROR, но разделANSWERпуст. Ошибка ли это?
Нет: имя существует, но записи запрошенного типа у него нет (например, спросили AAAA у имени только с IPv4).
Главное:
NXDOMAINзначит «имени нет» (DNS работает),SERVFAILзначит «сервер не смог довести поиск», аtimed outзначит «резолвер молчит»; лечатся они в разных местах.
Проверь понимание:
curlпишетCould not resolve host: shop.example.com. Какие два принципиально разных случая надо разделить первой же командой?
Ответ
Резолвер отвечает, но имени нет (NXDOMAIN, проблема с записью), либо резолвер не отвечает вовсе (проблема с сетью или с resolv.conf). Различает их dig shop.example.com: в первом случае увидишь status: NXDOMAIN, во втором timed out.
Ошибки различать научились. Теперь применим знания к проекту: дадим «Заметкам» своё имя без настоящего домена.
Имя для учебного проекта: /etc/hosts и домен notes.lab
Настоящий домен стоит денег, а регистрация занимает время. Для учёбы и для проверки на своей машине нужно имя, которое работает только у тебя. Для этого и нужен /etc/hosts: вписал строку, и имя работает на этой машине.
Файл /etc/hosts работает как свои сокращения в записной книжке: «Мама» вместо полного номера. Только ты знаешь, что это значит, и никакая справочная о них не знает.
Строка в /etc/hosts: адрес, пробел, имя (можно несколько имён через пробел). Например, 127.0.0.1 notes.lab. Изменения действуют сразу для программ, которые ходят через getaddrinfo() (systemd-resolved подхватывает файл в течение пары секунд).
Почему домен .lab, а не любой:
.localнельзя: он зарезервирован под mDNS (multicast DNS, протокол поиска соседей в локальной сети без DNS-сервера), и на нём резолвер может вести себя непредсказуемо;.labв настоящем DNS не существует:dig @8.8.8.8 notes.labвозвращаетNXDOMAIN, поэтому запросы не улетают в интернет и не попадают к чужим владельцам;- для внутренних имён в настоящих проектах ICANN (организация, которая управляет доменами верхнего уровня) с 2024 года зарезервировала
.internal, но в курсе остаётсяnotes.lab, чтобы имя везде было одинаковым.
Клиент и сервер могут быть разными машинами. Пусть сервер с «Заметками» имеет адрес 192.168.64.5, а ты работаешь с ноутбука.
- На ноутбуке строка
192.168.64.5 notes.lab(клиенту нужен настоящий адрес сервера). - На самом сервере строка
127.0.0.1 notes.lab(сервер обращается к самому себе, и сервис слушает127.0.0.1, урок 2.1).
Имя одно, а адрес зависит от того, откуда смотришь. В настоящем DNS такого «зависит от того, кто спрашивает» обычно нет: там одно имя даёт один и тот же ответ всем. Это одно из отличий /etc/hosts от DNS.
Про порт: имя даёт только адрес. Порт 8080 по имени не определяется, поэтому пока перед «Заметками» нет nginx (он появится в уроке 2.5 на порту 80, который браузер подставляет сам), адрес пишется с портом: http://notes.lab:8080/.
Осторожно: что запись в /etc/hosts «зарегистрирует» домен. Нет, она работает только на этой машине. Если её забыть и через месяц адрес сервера изменится, будет тихая поломка: DNS уже знает новый адрес, а машина упорно ходит по старому, потому что файл побеждает DNS. Такие записи «залипают» надолго, и в сломай-и-почини ты с этим встретишься.
Прикинь сам: Сервер «Заметок» имеет адрес
192.168.64.5. Какую строку дляnotes.labнаписать на ноутбуке, а какую на самом сервере?
На ноутбуке 192.168.64.5 notes.lab, на сервере 127.0.0.1 notes.lab: имя одно, а адрес зависит от того, откуда смотришь.
Главное:
/etc/hostsдаёт имя только этой машине и без порта (http://notes.lab:8080/); домен.labне существует в настоящем DNS, поэтому запросы никуда не улетают.
Проверь понимание: ты вписал
10.0.0.5 notes.labв/etc/hostsна своём ноутбуке. Увидит ли это имя коллега на своём?
Ответ
Нет. Файл /etc/hosts работает только на той машине, где лежит. Коллеге нужна такая же запись у него или настоящая запись в DNS, которую видят все.
Имя для проекта мы задали локально. Теперь вернёмся к настоящему DNS и посмотрим, по какому транспорту ходит его вопрос.
Как DNS-вопрос едет по сети: UDP, TCP и порт 53
Вопрос «какой адрес у имени?» короткий, ответ тоже. Устанавливать TCP-соединение (тройное рукопожатие из урока 2.2) ради одного вопроса дорого: три пакета только на знакомство, потом сам вопрос. Поэтому DNS по умолчанию использует UDP: клиент отправляет один пакет с вопросом и ждёт один пакет с ответом.
Сравни открытку и телефонный звонок. Открытку с вопросом бросил в ящик и ждёшь ответную. Звонок требует, чтобы сначала оба сняли трубки. Оговорка: открытка может потеряться, и никто тебе об этом не скажет, поэтому клиент сам повторяет вопрос, если ответа нет.
Обмен идёт в несколько шагов.
- Клиент выбирает случайный порт отправителя и шлёт UDP-пакет на порт
53резолвера. - Если ответ не пришёл за несколько секунд, клиент повторяет вопрос, а после нескольких попыток пробует следующий
nameserverиз списка. Именно поэтому при неверном адресе вresolv.confвсё «висит» секунд десять и только потом падает. - Если ответ не влез в один UDP-пакет, сервер ставит в ответ флаг
tc(truncated, «обрезан»). Клиент видит его и повторяет вопрос по TCP на тот же порт53. Так же бывает с большими ответами: например, с длинным списком записей или с подписями DNSSEC. - Через TCP ходят и переносы зон между серверами, и опция
dig +tcp, которую ты применяешь в практике.
Всё это видно в выводе dig. В строке SERVER: 127.0.0.53#53(127.0.0.53) (UDP) из вывода dig три части: кто ответил (127.0.0.53), порт (53) и протокол в скобках (UDP). С опцией +tcp в конце будет (TCP). Размер ответа тоже виден: MSG SIZE rcvd: 72 значит, что пришло 72 байта, а это сильно меньше границы, после которой сервер обрежет ответ (порядка 1200 байт при современных настройках).
Осторожно: «DNS работает только по UDP». Нет, TCP тоже нужен, и если файрвол (урок 2.7) закрыл TCP на порту 53, всё будет работать на коротких ответах и вдруг сломается на длинных. Такие поломки трудно ловить, потому что «иногда работает».
Прикинь сам: Ответ DNS не помещается в один UDP-пакет. Что сделает клиент?
Увидит флаг tc (обрезано) и повторит вопрос по TCP на тот же порт 53.
Главное: DNS обычно идёт по UDP на порт 53, а по TCP на тот же порт ходят большие ответы и переносы зон; закрыть TCP/53 значит получить поломку «иногда работает».
Проверь понимание: файрвол пропускает только UDP на порту 53. Какие запросы начнут падать и по какому признаку это заметишь?
Ответ
Те, где ответ большой и не влезает в один UDP-пакет: клиент получает обрезанный ответ, пытается повторить по TCP и не может. dig покажет ;; Truncated, retrying in TCP mode и потом таймаут. Короткие ответы будут идти как обычно.
Транспорт ясен. Остался бытовой приём, из-за которого короткое имя вдруг превращается в полное: список search.
Короткие имена и search: как ssh db становится db.corp.local
Внутри компании десятки серверов с именами вроде db.corp.local, app1.corp.local. Печатать .corp.local каждый раз неудобно. Поэтому система умеет дописывать суффикс сама.
В своём городе ты говоришь «улица Ленина, 5», а не «Россия, Новосибирск, улица Ленина, 5»: город подразумевается сам. Оговорка: если такой улицы в твоём городе нет, система не догадается, что ты имел в виду другой город, а честно вернёт «не найдено».
В /etc/resolv.conf строка search corp.local задаёт список суффиксов. Когда ты просишь имя без точек (db), система пробует по очереди:
db.corp.local(имя плюс суффикс изsearch);- если не нашлось,
dbкак есть.
Число точек в имени тоже влияет: за это отвечает опция ndots (по умолчанию 1). Имя, в котором точек меньше, чем ndots, система сначала пробует с суффиксами. В Kubernetes ndots равен 5, и поэтому обычный запрос example.com там сначала превращается в несколько лишних запросов (example.com.notes.svc.cluster.local и так далее), пока не дойдёт до настоящего (подробнее в уроке 5.3).
Посмотрим на стенд. В нашем лабораторном resolv.conf стоит search .: суффиксов нет. Поэтому короткое имя notes не превратится ни во что, и getent hosts notes ничего не найдёт, в то время как getent hosts notes.lab найдёт запись из /etc/hosts. Если бы у тебя на работе было search corp.local, ssh db дошло бы до db.corp.local.
Осторожно: Короткое имя и полное имя с точкой в конце. db. (с точкой) система никогда не дополняет суффиксами, это уже полное имя от корня. Без точки система вправе достроить.
Прикинь сам: В
resolv.confстоитsearch corp.local. Во что превратитсяdbи что будет сdb.(с точкой)?
db система сначала попробует как db.corp.local, потом как есть. db. с точкой в конце это уже полное имя, его суффиксами не дополняют.
Главное:
searchдописывает суффикс к коротким именам; точка в конце имени отключает дописывание, а в Kubernetes из-заndots 5лишних попыток бывает много.
Проверь понимание: в
resolv.confsearch corp.local. Ты пишешьping db, а пинг идёт на неожиданный адрес. Что проверишь?
Ответ
Что вернёт getent hosts db.corp.local: скорее всего, именно это имя и получилось из db. Если такая запись есть, ping пошёл туда. Чтобы обратиться к другому имени db, пиши его полностью с точкой на конце.
Теперь картина DNS собрана. Осталось увидеть, где она пригодится в следующих уроках.
Где DNS встретится дальше
- В Docker Compose контейнеры находят друг друга по имени сервиса (
db,notes): внутри Docker есть свой маленький DNS (тема 4). - В Kubernetes у каждого сервиса появляется DNS-имя, а вопросы обслуживает внутрикластерный DNS-сервер CoreDNS (урок 5.3). Там же работает
searchизresolv.conf. - Для TLS-сертификатов (урок 2.6) имя решает всё: сертификат выдаётся на имя, а не на адрес.
- В диагностике «сайт не открывается» (урок 2.8) DNS проверяется первым слоем: сначала имя, потом адрес, потом порт.
Практика
Все задания выполняются на твоей учебной ВМ (или на компьютере) с Ubuntu 26.04 LTS или 24.04 LTS из урока 1.1 и доступом в интернет. Если ты работаешь в контейнере или очень урезанном образе, systemd-resolved может отсутствовать: тогда задания 3 и 4 читай как справку.
Установим dig. Пакет dnsutils содержит dig, nslookup и host. apt-get install -y ставит пакет без вопроса «продолжить?», а -y от «yes»:
sudo apt-get update
sudo apt-get install -y dnsutils
dig -v
Как читать вывод: dig -v печатает версию. На Ubuntu 24.04 у нас получилось DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu, у тебя номер сборки может отличаться.
DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu
Если сеть у тебя закрывает исходящий UDP на порт 53 (в некоторых офисах и облаках так бывает), команды, которые обращаются к внешнему серверу напрямую (dig @8.8.8.8 ..., dig +trace), будут виснуть. Добавь опцию +tcp: dig пойдёт по TCP, содержимое ответа будет то же. В примерах ниже так и указано там, где это пригодилось при подготовке урока.
Задание 1. Разбери ответ dig по строкам
Цель: научиться читать вывод dig и находить в нём статус, TTL, тип записи и сервер, который ответил.
Предскажи: сколько секунд TTL будет у записи example.com при втором запросе через 5 секунд: такой же, как в первом, или меньше? Ответь до запуска.
Ответ
Меньше, примерно на 5. Второй ответ придёт из кэша локального резолвера, а TTL в кэше убывает с течением времени. Так виден кэш в действии.
Шаги:
-
Задай запрос типа A с полным выводом. Команда
dig example.com Aзначит «спроси у системного резолвера, какие у имениexample.comзаписи типаA»:dig example.com A -
Теперь только строки ответа, дважды с паузой. Опции:
+noallвыключает все разделы вывода,+answerвключает обратно только раздел ANSWER.sleep 5ждёт 5 секунд:dig +noall +answer example.com A sleep 5 dig +noall +answer example.com A -
Оставь только адреса, как это нужно скриптам. Опция
+shortпечатает только значения записей:dig +short example.com A -
Покажи TTL в привычных единицах,
+ttlunits:dig +noall +answer +ttlunits example.com A
Что должно получиться: у первой команды весь вывод из раздела теории «Как читать ответ dig» (числа и время у тебя другие):
; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> example.com A
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18928
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 172 IN A 104.20.23.154
example.com. 172 IN A 172.66.147.243
;; Query time: 77 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Wed Sep 30 12:00:37 UTC 2026
;; MSG SIZE rcvd: 72
Второй и третий шаги:
example.com. 171 IN A 172.66.147.243
example.com. 171 IN A 104.20.23.154
example.com. 166 IN A 104.20.23.154
example.com. 166 IN A 172.66.147.243
172.66.147.243
104.20.23.154
example.com. 2m46s IN A 104.20.23.154
example.com. 2m46s IN A 172.66.147.243
Как читать вывод:
- Первый блок расшифрован строка за строкой выше, в теории. Первым делом смотри на
statusиSERVER. - В шаге 2 между запросами прошло 5 секунд, и TTL стал меньше на 5 (171 и 166): ответ пришёл из кэша
systemd-resolved, и он честно показывает, сколько осталось. Если у тебя между двумя запросами TTL вырос, а не упал, значит, кэш обновился: срок истёк, и резолвер запросил запись заново. - Порядок адресов между запросами может меняться (в шаге 3 он другой, чем в шаге 1): DNS не обещает порядок, и клиентам нельзя на него полагаться.
2m46sэто те же 166 секунд: 2 × 60 + 46 = 166.- Адреса и TTL у тебя будут другие, а само имя
example.comможет смотреть на других серверов: у него два адреса, потому что за именем стоит несколько машин.
Объясни себе:
- Что означают флаги
qr rd ra, и какого флага не хватает, чтобы понять, что ответил сам авторитетный сервер? - Почему у
example.comдва адреса, и какой из них выберетcurl? (Подсказка: обычно первый работающий по списку, но порядок непостоянный.) - Что бы изменилось, если бы
SERVERбыл8.8.8.8, а не127.0.0.53?
Типичные ошибки:
bash: dig: command not found: не установлен пакет; поставьsudo apt-get install -y dnsutils.;; communications error to 127.0.0.53#53: timed out:systemd-resolvedне работает или в сети нет доступа; смотриsystemctl status systemd-resolvedи задание 3.- Вместо цифр TTL прочерки или очень большие значения: ты спросил авторитетный сервер напрямую (
@...), там TTL всегда полный и не убывает. Это нормально.
Задание 2. Пройди цепочку от корня и спроси авторитетный сервер
Цель: увидеть иерархию DNS своими глазами: корень, зона com, авторитетные серверы домена. И отличить ответ авторитетного сервера от кэшированного.
Предскажи: в какой последовательности появятся серверы в выводе dig +trace example.com: сначала example.com, потом com, потом корень, или наоборот?
Ответ
От корня к домену: сначала корневые серверы (.), потом com., потом авторитетные серверы example.com.. Каждый отвечает не итогом, а «спроси вот у них», кроме последнего.
Шаги:
-
Пройди цепочку целиком.
+traceзаставляетdigне спрашивать резолвер, а самому пройти шаги от корня.+nodnssecпрячет подписи, которые здесь только мешают:dig +trace +nodnssec example.com A -
Спроси записи других типов и сравни. Тут
+short(только значения), а тип идёт последним словом:dig +short example.com NS dig +short example.com MX dig +short example.com TXT -
Спроси авторитетный сервер напрямую, минуя кэш. Разберём команду по частям.
NS=$(...)запускает команду внутри скобок и записывает её вывод в переменнуюNS(в терминале это переменная оболочки, ты работал с ними в теме 1).dig +short example.com NSдаёт список серверов имён,| head -n 1оставляет из него первую строку. Потом@"$NS"говоритdig: «спрашивай не системный резолвер, а вот этот сервер»:NS=$(dig +short example.com NS | head -n 1) echo "$NS" dig +noall +answer @"$NS" example.com A dig @"$NS" example.com A
Что должно получиться: в trace три блока, каждый заканчивается строкой ;; Received ... bytes from .... У нас пример получился такой (строки корневых серверов и серверов com сокращены: их по 13, а вывод в трейсе полностью они печатаются все):
; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> +tcp +trace +nodnssec example.com A
;; global options: +cmd
. 4502 IN NS a.root-servers.net.
. 4502 IN NS b.root-servers.net.
... (ещё 11 строк с корневыми серверами)
;; Received 239 bytes from 127.0.0.53#53(127.0.0.53) in 3 ms
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
... (ещё 11 строк с серверами com)
;; Received 836 bytes from 192.203.230.10#53(e.root-servers.net) in 259 ms
example.com. 172800 IN NS hera.ns.cloudflare.com.
example.com. 172800 IN NS elliott.ns.cloudflare.com.
;; Received 359 bytes from 192.54.112.30#53(h.gtld-servers.net) in 247 ms
example.com. 300 IN A 104.20.23.154
example.com. 300 IN A 172.66.147.243
;; Received 72 bytes from 108.162.195.228#53(elliott.ns.cloudflare.com) in 235 ms
(В этом прогоне стояло ещё +tcp, потому что стенд не выпускает UDP наружу. Без него содержимое то же.)
Записи разных типов:
hera.ns.cloudflare.com.
elliott.ns.cloudflare.com.
0 .
"v=spf1 -all"
"_k2n1y4vw3qtb4skdx9e7dxt97qrmmq9"
Прямой вопрос авторитетному серверу (в этом прогоне тоже с +tcp):
hera.ns.cloudflare.com.
example.com. 300 IN A 104.20.23.154
example.com. 300 IN A 172.66.147.243
А полный вывод последней команды:
; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> +tcp @hera.ns.cloudflare.com. example.com A
; (3 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64204
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65535
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 300 IN A 104.20.23.154
example.com. 300 IN A 172.66.147.243
;; Query time: 228 msec
;; SERVER: 172.64.32.162#53(hera.ns.cloudflare.com.) (TCP)
;; WHEN: Wed Sep 30 12:00:43 UTC 2026
;; MSG SIZE rcvd: 72
Как читать вывод:
- В trace ищи строки
;; Received ... from ...: они показывают, какой сервер дал блок над ней. Три шага (.,com.,example.com.) это те самые три уровня цепочки из теории. Не удивляйся, если у тебя будут другие серверыNS, уexample.comможет смениться хостинг DNS. - TTL корня и
comбольшие (172800это 48 часов): эти данные почти не меняются, и их можно держать в кэше сутками. У итогового адреса TTL короткий (300, 5 минут): адреса меняют, и держать их долго опасно. Первое число4502(не 518400, как у тебя, может быть) это остаток TTL из кэша локального резолвера. - В последнем выводе
flags: qr aa rd: естьaa(ответил авторитетный сервер), нетra(он не занимается рекурсией). СтрокаWARNING: recursion requested but not availableэто как раз об этом:digпросил довести поиск до конца (rd), а авторитетный сервер так не умеет. Это нормально, не ошибка.SERVERв конце показывает, что отвечал сервер Cloudflare, а не твой локальный. И TTL 300 полный, не убывает. MXвернул0 .: уexample.comнет почты. Так выглядит намеренное «почту не принимаем» (записей нет вообще было бы просто пустым выводом).
Объясни себе:
- Почему у корня и
comTTL двое суток, а у итоговой A-записи пять минут? - Зачем ходить к авторитетному серверу напрямую, когда есть резолвер? (Подсказка: чтобы отличить «запись в источнике неверна» от «кэш устарел».)
- Чем
+traceотличается от обычногоdig: кто ходит по цепочке?
Типичные ошибки:
;; communications error to ...#53: timed outи в конце;; no servers could be reached: сеть блокирует UDP на порт 53 наружу; попробуйdig +tcp +trace example.comили другую сеть.- Пустой вывод на
MXилиAAAA: у домена нет такой записи. Это нормально,digпри этом пишетNOERRORс пустым ответом. dig: couldn't get address for '': no address: переменнаяNSпуста,dig +short example.com NSничего не вернул. Проверь сам запрос отдельно.
Нейросеть не видит твой DNS и легко придумает «типичный» ответ
dig. Вставляй ей настоящий вывод целиком, а выводы проверяй своей командой:digиgetent hostsмогут дать разные ответы.
Задание 3. Кто мой резолвер, и что видит приложение
Цель: отличать то, что говорит DNS, от того, что видит программа, и понимать путь запроса на своей машине.
Предскажи: resolvectl status покажет 127.0.0.53 как DNS-сервер? Ответь до запуска.
Ответ
Нет. 127.0.0.53 это локальный stub, его видно в /etc/resolv.conf. А resolvectl status показывает настоящие серверы, которые выдал DHCP или которые прописаны вручную.
Шаги:
-
Посмотри, что лежит в
resolv.confи куда он ведёт.ls -lпокажет, симлинк ли это.grep -v '^#'печатает все строки, кроме тех, что начинаются с#(комментарии):-vзначит «инвертировать», а^в шаблоне значит «начало строки»:ls -l /etc/resolv.conf grep -v '^#' /etc/resolv.conf -
Узнай настоящие серверы.
resolvectl status(клиент кsystemd-resolved) рассказывает о его настройках, аhead -n 12оставляет первые 12 строк:resolvectl status | head -n 12 -
Посмотри порядок источников имён:
grep '^hosts' /etc/nsswitch.conf -
Сравни ответ системного резолвера, публичного резолвера и «что видит приложение».
getent hosts(неdig) идёт путём приложения, аdig @8.8.8.8спрашивает Google напрямую:dig +noall +answer example.com A dig +tcp +noall +answer @8.8.8.8 example.com A getent hosts example.com -
Спроси систему как она сама:
resolvectl queryпоказывает, откудаsystemd-resolvedвзял ответ:resolvectl query example.com
Что должно получиться:
lrwxrwxrwx 1 root root 39 Sep 30 11:52 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
search .
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Current DNS Server: 192.168.65.7
DNS Servers: 192.168.65.7
Link 2 (tunl0)
Current Scopes: none
Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
hosts: files dns
example.com. 372 IN A 104.20.23.154
example.com. 372 IN A 172.66.147.243
example.com. 300 IN A 104.20.23.154
example.com. 300 IN A 172.66.147.243
104.20.23.154 example.com
172.66.147.243 example.com
example.com: 104.20.23.154
172.66.147.243
-- Information acquired via protocol DNS in 733us.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: cache network
Как читать вывод:
- В
resolv.conf(пустая строка передnameserverэто то, что осталось от вырезанных комментариев)nameserver 127.0.0.53значит: все DNS-вопросы идут в локальныйsystemd-resolved, а не напрямую наружу. resolvectl status: строкаresolv.conf mode: stubподтверждает, чтоresolv.confуказывает на stub.Current DNS ServerиDNS Serversэто настоящие сервера, кудаsystemd-resolvedотправляет вопросы дальше. У нас в лабораторном контейнере это внутренний DNS Docker (192.168.65.7), и он указан в разделеGlobal. У тебя на настоящей ВМ адреса будут другие (адрес шлюза или DNS провайдера), и чаще всего они окажутся в разделе своей сетевой карты (Link 2 (ens3)или похоже): именно туда их положил DHCP. ОстальныеLinkв нашем выводе это пустые технические интерфейсы контейнера, у тебя их не будет.- В четвёртом блоке первые две строки это ответ системного резолвера, TTL
372(у Docker-резолвера кэш свой), следующие две это ответ Google, TTL300. У двух серверов разный кэш, поэтому и число разное. Здесь показан именно такой случай: адреса одинаковые, а TTL нет.getent hostsпечатает адрес и имя в другом формате (без TTL), потому что это уже итог для приложения: в формате «адрес имя», как в/etc/hosts. resolvectl query: строкаData from: cache network(в первый разnetwork, потомcache) показывает, из кэша ответ или свежий. Есть и вариантsynthetic: ответ собрала сама система, например из/etc/hosts(мы увидим его в задании 5).
Объясни себе:
- Почему в
nameserverстоит127.0.0.53, а не адрес роутера, и кто стоит за этим адресом? - Что именно означает
files dnsвhosts:? - В каких случаях
digиgetentдадут разные ответы?
Типичные ошибки:
resolvectl: command not foundилиFailed to get global data: Unit dbus-org.freedesktop.resolve1.service not found:systemd-resolvedне установлен или не запущен (минимальный образ, контейнер); смотриcat /etc/resolv.confнапрямую, а на обычной ВМ включиsudo systemctl enable --now systemd-resolved.resolv.conf mode: foreignвместоstub:/etc/resolv.confперестали быть симлинком на stub, кто-то (или что-то) записал туда обычный файл. Так выглядит поломка из раздела «Сломай и почини».
Задание 4. TTL и кэш вживую
Цель: увидеть, как кэш ускоряет и одновременно прячет изменения, и сбросить его.
Предскажи: после resolvectl flush-caches первый запрос быстрее или медленнее второго? Сколько это примерно в миллисекундах?
Ответ
Медленнее: локальный кэш пуст, и запрос уходит выше по сети, десятки миллисекунд. Повторный придёт из кэша за 0-1 мс. Но если и вышестоящий резолвер уже держит имя в кэше, разница будет меньше: кэши независимы и стоят по цепочке.
Шаги:
-
Посмотри счётчики кэша
systemd-resolved. Нуженsudo, иначе получишьPermission denied.grep -E 'Cache (Hits|Misses)'выбирает две строки:-Eвключает расширенные регулярные выражения, скобки с|значат «или»:sudo resolvectl statistics | grep -E 'Cache (Hits|Misses)' -
Сбрось кэш и посмотри, как изменились счётчики.
flush-cachesочищает кэшsystemd-resolved(это не удаляет никаких файлов):sudo resolvectl flush-caches dig www.iana.org A | grep 'Query time' dig www.iana.org A | grep 'Query time' sudo resolvectl statistics | grep -E 'Cache (Hits|Misses)' -
Сравни разные кэши: запросы к локальному резолверу и напрямую к Google (
+noall +answerиз задания 1):dig +noall +answer example.com A | head -n 1 dig +tcp +noall +answer @8.8.8.8 example.com A | head -n 1
Что должно получиться: у нас на первой команде и после сброса вышло:
Cache Hits: 50
Cache Misses: 56
;; Query time: 74 msec
;; Query time: 0 msec
Cache Hits: 55
Cache Misses: 59
example.com. 365 IN A 104.20.23.154
example.com. 300 IN A 104.20.23.154
Как читать вывод:
Cache Hitsэто сколько раз ответ взят из кэша,Cache Missesсколько раз в кэше ничего не нашлось и пришлось идти дальше. После твоих запросов оба числа растут: первый запросwww.iana.orgэто промах (Misses+1) и74 msec, второй попадание (Hits+1) и0 msec. Числа у тебя будут другие, важно, как они меняются.- Если после сброса первый запрос всё равно быстрый (единицы миллисекунд), значит, имя уже лежит в кэше выше: у роутера или провайдера. Это как раз пример «кэшей несколько». Для честного эксперимента возьми имя, которое ты давно не спрашивал.
- Последний блок: у локального резолвера остаток TTL 365 (он получил запись раньше и убывает), а Google говорит 300. Тот же ответ, разные часы.
Объясни себе:
- Какие ещё кэши, кроме
systemd-resolved, могут держать старый ответ (браузер, приложение, Java с собственным кэшем)? - Почему при переезде TTL снижают заранее, а не в день переезда?
- Что нужно сделать клиенту, чтобы увидеть новый адрес немедленно, не дожидаясь конца TTL?
Типичные ошибки:
Failed to get statistics: Access deniedилиPermission deniedприresolvectl statistics: нуженsudo.sudo: systemd-resolve: command not found: старое имя команды (до Ubuntu 21.10); теперь толькоresolvectl.- После
flush-cachesчислоCache Hitsне сбросилось в ноль: сбрасывается содержимое кэша, а счётчики накопительные, они растут до перезапуска службы.
Задание 5. Шаг проекта: notes.lab в /etc/hosts
Цель: дать «Заметкам» имя notes.lab на клиенте и на сервере и открыть их по имени.
Предскажи: curl по имени notes.lab без записи в /etc/hosts сработает? А dig @8.8.8.8 notes.lab вернёт адрес?
Ответ
Нет и нет. curl не найдёт имя ни в /etc/hosts, ни в DNS и напишет Could not resolve host. Публичный DNS не знает про .lab и вернёт NXDOMAIN. После правки файла curl начнёт работать, а публичный DNS по-прежнему будет отвечать NXDOMAIN.
Шаги:
-
Убедись, что «Заметки» запущены (как сервис из урока 1.8) и слушают порт 8080.
systemctl is-active notesпечатаетactive, если сервис работает. Затемcurlпроверяет, что приложение отвечает. Флаг-Sпоказывает ошибку,-sубирает индикатор загрузки:systemctl is-active notes curl -sS http://127.0.0.1:8080/healthz -
Проверь, что имени ещё нет (это «до»):
getent hosts notes.lab; echo "код выхода: $?" curl -sS http://notes.lab:8080/healthz -
Добавь имя. Если клиент и сервер это одна машина, адрес
127.0.0.1. Если сервер это ВМ, а ты работаешь с ноутбука, на ноутбуке пиши адрес ВМ (посмотреть его можно командойip -4 addr, урок 2.1), а на самом сервере127.0.0.1. Разберём команду:echo '...'печатает строку,|передаёт её следующей команде,sudo tee -a /etc/hostsдописывает (-aэто append, «добавить в конец») эту строку в файл и заодно выводит на экран.teeздесь нужен потому, чтоsudo echo ... >> /etc/hostsне сработает: перенаправление>>выполняет твоя обычная оболочка, а неsudo, и ей писать в/etc/hostsнельзя.echo '127.0.0.1 notes.lab' | sudo tee -a /etc/hosts -
Проверь разными способами.
sleep 3даётsystemd-resolvedвремя подхватить файл:sleep 3 getent hosts notes.lab dig +tcp @8.8.8.8 notes.lab | grep -E 'status|SERVER' curl -sS http://notes.lab:8080/healthz -
Останови сервис и посмотри, как выглядит ошибка после успешного DNS. Потом запусти обратно:
sudo systemctl stop notes curl -sS http://notes.lab:8080/healthz sudo systemctl start notes -
Если ты в WSL2:
/etc/hostsтам пересоздаётся при каждом запуске, и твоя запись пропадёт. Добавь в/etc/wsl.confблок и перезапусти WSL командойwsl --shutdownиз PowerShell:[network] generateHosts = false
Что должно получиться:
active
ok
код выхода: 2
curl: (6) Could not resolve host: notes.lab
127.0.0.1 notes.lab
127.0.0.1 notes.lab
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 51598
;; SERVER: 8.8.8.8#53(8.8.8.8) (TCP)
ok
curl: (7) Failed to connect to notes.lab port 8080 after 0 ms: Couldn't connect to server
Как читать вывод:
- Шаг 1:
active(сервис работает) иok(ответ/healthz, без перевода строки, поэтому следующий текст может «прилипнуть»). - Шаг 2:
getentничего не напечатал, а код выхода2значит «не найдено».curl: (6)это ошибка имени, ещё до соединения. - Шаг 3:
teeэхом печатает добавленную строку. - Шаг 4:
getent hostsпоказывает адрес из файла. ВdigстатусNXDOMAINи сервер8.8.8.8: публичный DNS проnotes.labничего не знает, как мы и предсказывали. Иcurlдаётok: приложение получило адрес из/etc/hosts. Эти три строки вместе и есть «dig говорит одно, curl делает другое». - Шаг 5: главное отличие ошибок. Раньше было
Could not resolve host(имени нет). ТеперьFailed to connect ... Couldn't connect to server: имя превратилось в адрес, а по этому адресу и порту никто не слушает. В новых версиях curl (8.18 в Ubuntu 26.04) текст немного другой:Could not connect to server, смысл тот же. Это ошибка следующего слоя (урок 2.2), и чинится она не в DNS. - Если ты запустишь
dig +short notes.labбез@8.8.8.8, на Ubuntu можно увидеть адрес: локальныйsystemd-resolvedсам читает/etc/hosts(ответ сData from: syntheticвresolvectl query). Это не ошибка: спрашивай внешний сервер, если хочешь знать, что в настоящем DNS.
Файлы проекта в ~/notes не менялись, версия app.py остаётся v2.2.
Объясни себе:
- Почему пришлось указывать порт
:8080, ведь имя уже есть? (Имя даёт только адрес, порт это отдельная часть, nginx на порту 80 появится в уроке 2.5.) - Чем плохо держать в
/etc/hostsдесятки записей на реальном проекте? - Что произойдёт, если через месяц адрес сервера изменится, а запись останется?
Типичные ошибки:
curl: (6) Could not resolve host: notes.lab: записи нет или опечатка; проверьgetent hosts notes.labиgrep notes /etc/hosts.curl: (7) Failed to connect to notes.lab port 8080 after 0 ms: Couldn't connect to server: имя разрешилось, но сервис не слушает или адрес не тот; смотриsudo ss -tlnp | grep 8080(урок 2.2).bash: /etc/hosts: Permission denied: ты написалsudo echo '...' >> /etc/hosts;sudoотносится только кecho, а запись файла делает оболочка без прав. Используй| sudo tee -a.- Имя работает на сервере, а на ноутбуке нет: запись нужна на каждой машине отдельно.
Сломай и почини
В этом разделе ты тренируешь главный навык дежурного: по симптому найти причину. Скрипт сам ломает окружение, не заглядывай в него: диагностика и есть упражнение. Скрипт меняет /etc/resolv.conf, /etc/hosts и /etc/nsswitch.conf, поэтому запускай его только на своей учебной ВМ. Для работы нужна запись notes.lab из задания 5.
Скачай скрипт. У curl флаг -f означает «при ошибке сервера не сохраняй страницу с ошибкой», -L разрешает переходить по перенаправлениям, -o задаёт имя файла:
curl -fsSL -o /tmp/break-2.3.sh https://raw.githubusercontent.com/distinguished-sre/learning/main/devops/project/notes/break/2.3/break.sh
sudo bash /tmp/break-2.3.sh 1
Сценарии: 1, 2 и 3. Проходи по одному: запусти, найди причину, почини сам или командой sudo bash /tmp/break-2.3.sh fix, потом бери следующий. В конце выполни fix и удали скрипт: rm /tmp/break-2.3.sh.
Симптом
- Сценарий 1.
dig example.comдолго висит и заканчивается;; no servers could be reached,ping example.comпишетTemporary failure in name resolution, аping -c 3 8.8.8.8при этом проходит. Странность:curl http://notes.lab:8080/healthzработает. - Сценарий 2. Сервис активен,
curl http://127.0.0.1:8080/healthzотвечаетok, аcurl http://notes.lab:8080/healthzпишетFailed to connect ... Couldn't connect to server. Хотя запись в/etc/hostsвроде бы есть. - Сценарий 3.
dig +short example.comвозвращает адреса, аcurl http://example.com/пишетCould not resolve host: example.com. Сеть работает,notes.labоткрывается.
Гипотезы
Перед проверками выпиши минимум три причины. Подсказка по слоям: что читает getaddrinfo() и в каком порядке, куда смотрит resolv.conf, какой файл побеждает DNS, какой кэш держит ответ. Подумай, чем «имя не найдено» отличается от «имя найдено, но ошибка при соединении». Таблица ошибок из теории подскажет.
Проверки
Иди от простого к сложному, каждая команда отсекает целый класс причин:
getent hosts notes.lab # что видит приложение
grep notes /etc/hosts # нет ли лишних и старых записей
ls -l /etc/resolv.conf # симлинк на stub или обычный файл
grep -v '^#' /etc/resolv.conf # куда уходят DNS-запросы
resolvectl status | head -n 6 # настоящие серверы и режим resolv.conf
grep '^hosts' /etc/nsswitch.conf # порядок источников имён
dig +time=2 +tries=1 example.com # отвечает ли DNS вообще
dig +tcp +short @8.8.8.8 example.com # то же в обход системных настроек
getent hosts example.com # то же глазами приложения
Разбор и исправление
Сценарий 1: неверный resolv.conf. ls -l /etc/resolv.conf показывает обычный файл (-rw-r--r--), а не симлинк, в нём одна строка nameserver 192.0.2.53, и resolvectl status пишет resolv.conf mode: foreign. Запросы уходят на несуществующий сервер. Вот настоящий вывод:
$ dig +time=2 +tries=1 example.com
;; communications error to 192.0.2.53#53: timed out
; <<>> DiG 9.18.39-0ubuntu0.24.04.7-Ubuntu <<>> +time=2 +tries=1 example.com
;; global options: +cmd
;; no servers could be reached
$ ping -c 1 -W 3 example.com
ping: example.com: Temporary failure in name resolution
$ curl -sS http://example.com/
curl: (6) Could not resolve host: example.com # после примерно 10 секунд ожидания
Значит, сеть есть, сломан именно резолвер: dig +tcp +short @8.8.8.8 example.com отвечает. Почему notes.lab работает? Потому что он записан в /etc/hosts, а files стоит раньше dns, и до сломанного резолвера дело не доходит. Починка: вернуть симлинк и перезапустить службу.
sudo ln -sf ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
Сценарий 2: старая запись в /etc/hosts. getent hosts notes.lab даёт 127.0.0.2, а не 127.0.0.1, и grep notes /etc/hosts показывает строку 127.0.0.2 notes.lab # старый сервер. Сервис слушает 127.0.0.1 (урок 2.1), а адрес 127.0.0.2 это другой адрес loopback, на нём никто не слушает, поэтому быстрый отказ, а не тишина. Вот вывод:
$ getent hosts notes.lab
127.0.0.2 notes.lab
$ curl -sS --max-time 3 http://notes.lab:8080/healthz
curl: (7) Failed to connect to notes.lab port 8080 after 0 ms: Couldn't connect to server
$ curl -sS http://127.0.0.1:8080/healthz
ok
Имя разрешилось, но в неверный адрес. Так выглядит забытая запись после переезда сервера. Урок: /etc/hosts побеждает DNS, поэтому забытая запись «залипает» навсегда, и в настоящем DNS ты этого не увидишь (dig @8.8.8.8 тут бессилен). Починка: править или удалить строку. Например, заменить адрес:
sudo sed -i 's/^127\.0\.0\.2 notes\.lab.*/127.0.0.1 notes.lab/' /etc/hosts
Разбор sed: -i правит файл на месте, s/шаблон/замена/ заменяет, ^ привязывает к началу строки, обратная косая перед точкой значит «именно точка» (без неё точка означала бы «любой символ»), .* в конце шаблона это «до конца строки».
Сценарий 3: сломан nsswitch.conf. В grep '^hosts' /etc/nsswitch.conf стоит hosts: files, слова dns нет. Значит, getaddrinfo() ищет имена только в /etc/hosts и никогда не спрашивает DNS. dig при этом работает, потому что ходит в DNS сам, а не через getaddrinfo(). Вот вывод:
$ dig +short example.com
104.20.23.154
172.66.147.243
$ curl -sS --max-time 5 http://example.com/
curl: (6) Could not resolve host: example.com
$ getent hosts example.com; echo "код выхода: $?"
код выхода: 2
$ ping -c1 -W2 example.com
ping: example.com: Name or service not known
Это та самая «главная ловушка»: dig говорит «всё есть», а приложения не находят имя. Именно поэтому в диагностике второй командой после dig идёт getent hosts. Починка: вернуть dns в строку.
sudo sed -i 's/^hosts:.*/hosts: files dns/' /etc/nsswitch.conf
Правило для дежурного:
digработает, а программа нет: сравниdigиgetent hosts; расхождение ищи в/etc/hostsи/etc/nsswitch.conf.digтоже молчит (timed out): проверьresolv.confиresolvectl status, потомdig @8.8.8.8; если он отвечает, виноват адрес резолвера.- Имя есть, но соединения нет: это уже не DNS, а порт, сервис или файрвол (урок 2.2).
- Ответ устарел (адрес поменяли, а клиент видит старый): сравни TTL и ответ авторитетного сервера, подожди срок жизни или сбрось кэш (
sudo resolvectl flush-caches).
ИИ в помощь
Нейросеть хорошо объясняет вывод dig построчно, но не видит твой резолвер и кэши, а в сроках TTL и в разнице между dig и приложением часто ошибается. Общие правила работы с ней: ИИ-помощник.
Задача: разобрать вывод dig.
Я учу DNS. Вот полный вывод dig с моей Ubuntu-машины:
<вставь вывод целиком>.
Объясни по строкам: status, flags, секции, TTL, кто ответил (SERVER).
Скажи, это ответ из кэша или от авторитетного сервера, и откуда ты это знаешь.
Проверь ответ: сверь с разбором строк в теме про dig: по флагу aa и по тому, что TTL не уменьшается, видно авторитетный ответ. Типичная ошибка нейросети: путает NXDOMAIN с SERVFAIL или говорит, что пустой ANSWER при NOERROR это ошибка.
Задача: найти, почему имя «то работает, то нет».
У меня curl не может открыть <имя сайта>: Could not resolve host.
Вот вывод: dig <имя>: <вставь>; getent hosts <имя>: <вставь>; cat /etc/resolv.conf: <вставь>.
Предложи план проверки по шагам, от самого вероятного, и для каждого шага команду.
Ничего не меняй, только предлагай проверки.
Проверь ответ: убедись, что в плане есть разделение «резолвер отвечает» против «резолвер молчит» и что проверка идёт через getent hosts, а не только dig. Типичная ошибка: советует перезапустить службы или поменять resolv.conf вручную, хотя файл на Ubuntu управляется systemd-resolved.
Задача: спланировать переезд сервиса на новый IP.
Мой сервис живёт на <IP>, TTL записи A сейчас <число> секунд. Нужно переехать в <время> с минимальным простоем.
Распиши по часам, когда менять TTL, когда адрес и когда вернуть TTL, и как проверить каждый шаг через dig.
Проверь ответ: сверь с разобранным примером про переезд: снижать TTL надо заранее, не позже чем за старый TTL. Типичная ошибка: предлагает менять запись и TTL одновременно.
Словарик урока
| Термин | Простыми словами |
|---|---|
| DNS (Domain Name System) | Распределённая «телефонная книга» интернета: превращает имя в адрес |
| Домен, зона | Часть дерева имён и кусок дерева, за который отвечает один владелец |
| TLD | Домен верхнего уровня: com, ru, org |
| Корень (root) | Вершина дерева имён, невидимая точка в конце имени |
| FQDN | Полное имя с точкой на конце: notes.example.com. |
| Поддомен | Имя, созданное владельцем внутри своего домена: notes в notes.example.com |
| Регистратор | Компания, через которую ты покупаешь домен |
| Делегирование | Передача поддомена другим серверам: «за него отвечают вот эти» |
| Корневые серверы | Серверы, которые знают, кто отвечает за каждый TLD |
| Авторитетный сервер | Сервер, хранящий настоящие записи зоны; первоисточник |
| Рекурсивный резолвер | Сервер, который сам обходит цепочку от корня и возвращает готовый ответ |
| Stub resolver | Маленький посредник на твоей машине, передающий вопрос рекурсивному резолверу |
systemd-resolved |
Служба Ubuntu: stub на 127.0.0.53 с кэшем |
| Запись (resource record) | Строка DNS: имя, TTL, класс, тип, значение |
| A, AAAA | Имя в IPv4-адрес, имя в IPv6-адрес |
| CNAME | Псевдоним: «это то же, что другое имя»; нельзя на корне зоны |
| MX | Куда доставлять почту домена |
| TXT | Текстовая запись: подтверждения, SPF |
| NS | Какие серверы авторитетны для зоны |
| SOA | Служебная запись зоны: серийный номер, таймеры |
| PTR | Обратная запись: адрес в имя |
| TTL | Сколько секунд ответ можно хранить в кэше; в кэше он убывает |
| Кэш | Запомненный ответ, чтобы не спрашивать снова |
| Отрицательный кэш | Запомненный ответ «такого имени нет»; срок задаёт последнее число SOA |
| DNSSEC | Цифровые подписи DNS-ответов, чтобы их нельзя было подменить |
getaddrinfo() |
Функция системы, которой пользуются программы, чтобы получить адрес по имени |
/etc/nsswitch.conf |
Файл с порядком источников имён (строка hosts:) |
/etc/hosts |
Локальный файл «адрес имя», главнее DNS, действует только на этой машине |
/etc/resolv.conf |
Файл, где указано, куда слать DNS-вопросы (nameserver) |
| Симлинк | Файл-ссылка на другой файл, «ярлык» |
| DHCP | Служба сети, которая выдаёт машине адрес, шлюз и адреса DNS-серверов |
dig |
Программа, которая задаёт DNS вопросы и показывает ответ целиком |
getent hosts |
Показывает, какой адрес получит приложение (через getaddrinfo()) |
NOERROR, NXDOMAIN, SERVFAIL |
Коды результата: всё хорошо; имени нет; сервер не смог получить ответ |
search-домен |
Суффикс, который система дописывает к короткому имени |
.lab |
Учебный домен курса: в настоящем DNS не существует, описан в /etc/hosts |
Вопросы с собеседований
Раздел для повторения: ответь вслух, потом открой ответ. Короткие вопросы с пометкой [на скорость] тренируй на время: ответ за 30 секунд.
1. [junior] [часто] Что происходит, когда ты вводишь в браузере notes.example.com?
Ответ
Программа просит у операционной системы адрес для этого имени. Система сначала смотрит файл /etc/hosts и локальный кэш, потом отправляет вопрос рекурсивному резолверу из настроек. Тот, если в кэше нет ответа, идёт от корневых серверов к серверам зоны com, затем к авторитетному серверу домена и возвращает адрес. Только после этого браузер открывает TCP-соединение по этому адресу. Ответ запоминается на время TTL.
Что хотят услышать: локальный резолвер (stub) и рекурсивный, кэш и TTL, порядок files, dns, что DNS идёт до TCP и TLS.
Красный флаг: «браузер спрашивает у DNS-сервера сайта» без упоминания резолвера и кэша.
2. [junior] [часто] [на скорость] В чём разница между A и CNAME и почему CNAME нельзя на корень домена?
Ответ
A даёт адрес, CNAME перенаправляет имя на другое имя, и резолверу нужен ещё один запрос. На корне зоны уже лежат SOA и NS, а CNAME не может сосуществовать с другими записями того же имени, поэтому для корня ставят A, а у DNS-провайдеров бывают собственные аналоги ALIAS или ANAME.
Что хотят услышать: «CNAME исключает другие записи того же имени», лишний запрос, ALIAS у DNS-провайдеров.
Красный флаг: «CNAME быстрее, чем A».
3. [middle] [часто] Планируется переезд сервиса на новый IP с минимальным простоем. Что сделаешь с DNS?
Ответ
Заранее, не меньше чем за старый TTL до переезда (например, при TTL 3600 за час и больше), снижу TTL записи до 60-300 секунд. Когда старый TTL истечёт, все кэши будут держать короткий срок. Переключаю адрес: клиенты уйдут на новый сервер за минуты. Старый сервер оставляю работающим на время окна, потом возвращаю TTL.
Что хотят услышать: снижение TTL заранее, ожидание старого TTL, параллельная работа обоих серверов, откат.
Красный флаг: «меняю запись, а TTL не важен» или снижение TTL в момент переезда.
4. [junior] Сайт открывается у тебя, но не открывается у коллеги. Ты только что поменял A-запись. Что проверишь?
Ответ
Смотрю, что вернёт авторитетный сервер (dig @сервер имя), и что возвращает резолвер коллеги. Если авторитетный отдаёт новый адрес, а резолвер старый, дело в TTL: коллега увидит изменение, когда срок в его кэше истечёт. Ещё проверю /etc/hosts у него и кэш браузера.
Что хотят услышать: сравнение ответа авторитетного сервера и кэшированного, TTL, локальные кэши, /etc/hosts.
Красный флаг: «пересоздам запись» или «подожду, само пройдёт» без проверки.
5. [junior] curl пишет Could not resolve host. Как разберёшься?
Ответ
Отделяю «имени нет» от «DNS недоступен»: dig имя. NXDOMAIN значит запись не создана или опечатка. timed out значит резолвер молчит: тогда смотрю resolvectl status, /etc/resolv.conf и проверяю dig @8.8.8.8 имя. Если dig работает, а curl нет, сравниваю с getent hosts имя и смотрю /etc/hosts и nsswitch.conf.
Что хотят услышать: разделение NXDOMAIN и таймаута, getent, сравнение с публичным резолвером.
Красный флаг: сразу перезагружать сервер или менять DNS «на 8.8.8.8» без диагностики.
6. [middle] dig показывает новый адрес, а приложение ходит на старый. Почему?
Ответ
dig ходит в DNS сам и не использует getaddrinfo(), поэтому он не видит /etc/hosts и порядок из nsswitch.conf. Приложение может брать адрес из /etc/hosts, где записан старый, или держать его у себя в кэше (пул соединений, кэш в самом приложении, например в JVM: виртуальная машина Java, свой кэш имён). Проверяю getent hosts, /etc/hosts, перезапускаю приложение или сбрасываю кэш.
Что хотят услышать: getaddrinfo против прямого DNS-запроса, nsswitch.conf, кэш внутри приложения.
Красный флаг: «dig не может врать, значит проблема в сети».
7. [middle] В логах Temporary failure in name resolution у части подов или сервисов, у остальных нет. Что делаешь?
Ответ
Проверяю с проблемной машины dig и resolvectl status: доступен ли резолвер и какой указан. Сравниваю resolv.conf больных и здоровых узлов, смотрю нагрузку на резолвер и таймауты. Под (pod) это наименьшая единица запуска в Kubernetes, и внутри кластера DNS обслуживает CoreDNS: DNS-сервер, работающий в самом кластере (подробнее в теме 5). Начало то же: кто именно не отвечает и на каком узле.
Что хотят услышать: локализация (узел, резолвер), сравнение конфигов, dig @ip напрямую, UDP и TCP.
Красный флаг: «перезапущу приложение» без выяснения, отвечает ли резолвер.
8. [middle] Что такое DNS round-robin и почему это не настоящая балансировка?
Ответ
У имени несколько A-записей, резолвер отдаёт их в разном порядке, и клиенты распределяются между серверами. Но DNS не знает о состоянии серверов: упавший продолжит получать долю трафика, пока запись не уберут, а кэши и TTL замедляют изменения. Настоящий балансировщик (программа, распределяющая запросы) проверяет здоровье серверов и убирает упавшие мгновенно.
Что хотят услышать: нет проверки здоровья, роль TTL, замена: балансировщик или DNS с проверкой здоровья.
Красный флаг: «это полноценная балансировка с отказоустойчивостью».
9. [junior] [на скорость] Ответ у dig NOERROR, но раздел ANSWER пуст. Что это значит?
Ответ
Имя существует, но записи запрошенного типа у него нет. Например, спросили AAAA для имени, у которого только IPv4. Это не ошибка, в отличие от NXDOMAIN, где не существует само имя.
Что хотят услышать: различие NOERROR с пустым ANSWER, NXDOMAIN и SERVFAIL.
Красный флаг: «сервер сломан».
10. [middle] Почему DNS часто причина крупных инцидентов, и как ты подстрахуешься?
Ответ
Он на пути почти каждого запроса, кэши прячут изменения, а сбой выглядит как «сервис недоступен». Страхуюсь несколькими резолверами в настройках, разумным TTL, мониторингом резолвинга и времени ответа, а в диагностике «сайт не открывается» проверяю DNS первым слоем.
Что хотят услышать: зависимость всего от DNS, мониторинг, несколько резолверов, план отката TTL.
Красный флаг: «DNS надёжный, он не ломается».
11. [junior] Чем dig отличается от getent hosts и когда они дают разные ответы?
Ответ
dig спрашивает DNS напрямую и показывает подробный ответ сервера. getent hosts идёт тем же путём, что и приложения: через getaddrinfo(), в порядке из nsswitch.conf, то есть сначала /etc/hosts, потом DNS. Ответы расходятся, если имя есть в /etc/hosts (файл побеждает DNS), если в nsswitch.conf убран источник dns или если приложение и dig спрашивают разные резолверы.
Что хотят услышать: getent показывает «глазами приложения», dig показывает ответ DNS-сервера, роль /etc/hosts и nsswitch.conf.
Красный флаг: «dig показывает то, что видит приложение».
12. [junior] Чем рекурсивный резолвер отличается от авторитативного DNS-сервера?
Ответ
Авторитативный сервер хранит записи своей зоны и отвечает за них окончательно. Рекурсивный резолвер - это сервер, к которому обращается клиент: он сам обходит иерархию (корневые серверы, TLD, авторитативный сервер домена), собирает ответ и кеширует его на время TTL. На Linux-клиенте резолвер указан в /etc/resolv.conf (часто это локальный systemd-resolved). Проверить, кто что отвечает: dig @8.8.8.8 имя для конкретного резолвера и dig +trace имя для прохода по цепочке. «Не у всех сразу» обычно объясняется кешами разных резолверов.
Что хотят услышать: авторитативный хранит зону, рекурсивный ищет и кеширует, TTL, resolv.conf, dig @сервер, dig +trace.
Красный флаг: «Это одно и то же, просто DNS-сервер».
13. [junior] [на скорость] Для чего нужны записи MX, TXT, NS и PTR?
Ответ
MX указывает почтовые серверы домена с приоритетом. NS перечисляет авторитативные серверы зоны. TXT хранит произвольный текст: на нём держатся SPF, DKIM, DMARC и проверка владения доменом. PTR - обратная запись из IP в имя, нужна, например, почтовым серверам для репутации. Смотрю так: dig MX example.org, dig TXT example.org, dig -x 192.0.2.10. Адреса имён хранят A (IPv4) и AAAA (IPv6).
Что хотят услышать: MX - почта с приоритетом, NS - серверы зоны, TXT - SPF/DKIM/проверки, PTR - обратная запись, примеры dig.
Красный флаг: «TXT - это комментарии, ни на что не влияют».
14. [middle] Что такое split-horizon DNS и с какими проблемами ты можешь столкнуться?
Ответ
Split-horizon (split DNS) - когда одно и то же имя даёт разные ответы в зависимости от того, откуда спрашивают: изнутри сети внутренний адрес, снаружи публичный. Это удобно, чтобы сотрудники ходили к сервису напрямую, а не через интернет. Проблемы: на разных машинах разное поведение («у меня открывается, у тебя нет»), забытая внутренняя зона, когда снаружи запись поменяли, а внутри нет, и при VPN клиент может использовать не тот резолвер. Диагностика: спросить имя у обоих резолверов через dig @внутренний имя и dig @внешний имя и сравнить.
Что хотят услышать: разные ответы для внутренних и внешних клиентов, расхождение зон, VPN и выбор резолвера, dig @ у обоих.
Красный флаг: «Такого не бывает, DNS отдаёт везде одинаково».
15. [junior] [на скорость] Что такое FQDN и чем он отличается от короткого имени?
Ответ
FQDN (fully qualified domain name) это полное имя узла со всеми уровнями от корня DNS: notes.prod.example.com., точка в конце обозначает корень. Короткое имя notes неоднозначно, и резолвер достраивает его по search из /etc/resolv.conf. Внутри Kubernetes полное имя сервиса такое: notes.default.svc.cluster.local. FQDN нужен для сертификатов, записей DNS и настроек, которые должны вести в одно место из любой сети. Ограничения: метка до 63 символов, всё имя до 253.
Что хотят услышать: полное имя от корня, search и достройка коротких имён, пример с svc.cluster.local.
Красный флаг: «FQDN это просто адрес сайта в браузере».
Проверено на версиях
- Ubuntu 24.04 LTS (образ с systemd, процессор aarch64):
dig9.18.39-0ubuntu0.24.04.7 (dnsutils),systemd-resolvedиresolvectlиз systemd 255.4-1ubuntu8.17, curl 8.5.0. Все задания 1-5 и три сценария поломок прогнаны на нём. - «Заметки»:
app.pyv2.2 (эталон изproject/notes/versions), порт 8080,Python 3.12.3. В этом уроке код не менялся. - Ubuntu 26.04 LTS: проверены в контейнере без systemd только
dig9.20.24-1ubuntu0.3, curl 8.18.0 (текстCould not resolve host, тот же формат ответа), строкаhosts: files dnsвnsswitch.conf. Командыresolvectlиsystemd-resolvedна 26.04 не прогонялись (там пакетsystemd-resolvedставится отдельно): проверь на своей ВМ. - Внешние серверы на нашем стенде не пропускали исходящий UDP на порт 53, поэтому
dig +traceи запросы@8.8.8.8,@имя_авторитетного_серверапрогнаны с+tcp. Содержимое ответов при UDP то же. Имена и адресаexample.com(hera.ns.cloudflare.comи так далее) на момент прогона 30 сентября 2026: они могут смениться. - Не проверялось: правка
/etc/wsl.confдля WSL2, выводresolvectl statusна ВМ с настоящим DHCP (в стенде DNS-сервер задан вGlobal, а не вLink), командаsudo apt-get install -y dnsutils(в образе она была выполнена, но вывод в урок не вставлен). - Скрипт
project/notes/break/2.3/break.sh:shellcheckбез замечаний, сценарии1,2,3иfix(в том числе повторный запускfix) прогнаны на Ubuntu 24.04 в контейнере с systemd.
Итог урока: ты умеешь
- назвать цепочку от приложения до авторитетного сервера и роль каждого звена: stub, рекурсивный резолвер, корень, TLD, авторитетный сервер
- разобрать имя
notes.example.com.по уровням и объяснить, что такое зона и делегирование - прочитать ответ
dig:status,flags,ANSWER, TTL,SERVER - пройти цепочку
dig +traceи спросить авторитетный сервер напрямую - объяснить, для чего каждый тип записи (
A,AAAA,CNAME,MX,TXT,NS,SOA,PTR) и почемуCNAMEнельзя на корне - рассчитать, когда снижать TTL перед переездом, и объяснить, почему запись меняется не сразу
- отличить
NXDOMAINотSERVFAILи от недоступного резолвера - показать, что видит приложение:
getent hosts, а неdig, и объяснить, почему они расходятся - найти настоящие DNS-серверы (
resolvectl status) и сбросить кэш - дать проекту имя
notes.labчерез/etc/hostsи проверить его
Дальше: Урок 2.4: HTTP: запросы, заголовки, коды ответов, curl
Проверь себя
Короткий тест по уроку: 5 вопросов из банка в 30. Засчитывается только полностью правильный ответ, порог 60%. Каждая новая попытка даёт другие вопросы, пока банк не закончится. Ответы видны после проверки.
Тест работает с включённым JavaScript.