"그냥 도메인을 IP로 바꿔주는 거 아니야?" — 이 한 문장으로 DNS를 설명하는 글을 여러 번 봤습니다. 이 글은 그 문장이 왜 DNS의 10%도 설명하지 못하는지에 대한 이야기입니다.
getaddrinfo() 호출은 시스템 콜 → 커널 네트워크 스택 → NIC DMA → 대륙 횡단 패킷 → 다단계 위임 → 응답 수신의 여정을 거칩니다.많은 분들이 DNS를 "도메인을 IP로 바꿔주는 전화번호부" 정도로만 알고 계십니다. 하지만 그 비유로는 DNS의 진짜 모습을 절반도 설명할 수 없는데요, DNS는 사실 전 지구 규모로 분산되어 있고, 계층적이며, 고가용성을 지녔고, 약한 일관성(eventual consistency)을 의도적으로 택한 데이터베이스 시스템입니다.
여러분이 브라우저에 google.com을 치는 순간, 무대 뒤에서는 수십 개의 네트워크 패킷이 대륙을 횡단하고, 여러 개의 서버가 릴레이처럼 질문을 넘기며, 커널의 네트워크 스택이 인터럽트를 발생시키고, NIC(Network Interface Card)의 DMA 버퍼에 데이터가 쓰여지는 일들이 몇십 밀리초 안에 벌어지는데요, 이 모든 과정의 지휘자가 바로 DNS입니다.
이 글에서는 DNS를 애플리케이션 계층의 추상적 개념으로만 보는 것이 아니라, 물리적 패킷이 구리선과 광섬유를 타고 흐르는 하드웨어 레벨까지 내려가서 살펴보겠습니다.
먼저 IP 주소가 무엇인지부터 짚고 가야 하는데요, IPv4 주소는 32비트(4바이트) 정수입니다.
142.250.207.46 → 10001110.11111010.11001111.00101110 → 0x8EFACF2E
142.250.207.46 같은 표기는 인간이 읽기 쉽게 하려고 8비트씩 끊어서 점으로 구분한 것일 뿐, 내부적으로는 0x8EFACF2E라는 하나의 32비트 숫자입니다. IPv6는 이것을 128비트로 확장한 것이고요.
💡 이 32비트 숫자는 "한 컴퓨터"가 아니라 "한 인터페이스"를 식별합니다. 노트북에 이더넷과 WiFi가 각각 다른 IP를 가질 수 있는 이유가 여기 있습니다.
인간의 작업 기억은 밀러의 법칙(Miller's Law)에 따라 대략 7±2개의 청크(chunk)만 동시에 유지할 수 있는데요, 142.250.207.46을 외우는 것과 google.com을 외우는 것 사이에는 인지 부하의 차원이 다릅니다.
게다가 IP는 언제든 바뀔 수 있습니다. 서버를 교체하거나 CDN을 바꾸거나 다른 데이터 센터로 마이그레이션하면 IP가 달라지는데, 만약 사람이 IP를 외워서 쓰고 있었다면 세상이 마비됩니다.
그래서 "이름(name)"과 "주소(address)"의 분리라는 시스템 설계 원칙이 등장하는데요, 이건 컴퓨터 과학의 거의 모든 영역에서 반복되는 패턴입니다.
| 분리 패턴 | 이름 역할 | 주소 역할 |
|---|---|---|
| 포인터 시스템 | 변수명 | 메모리 주소 |
| 파일 시스템 | 심볼릭 링크 | inode 번호 |
| 컴파일러 | 심볼 | 레지스터/오프셋 |
| 인터넷 | 도메인 이름 | IP 주소 |
1970년대 ARPANET 시절에는 DNS가 없었습니다. 대신 스탠포드 연구소(SRI-NIC)가 HOSTS.TXT라는 파일 하나를 관리했는데요, 전 세계(라기보다 미국의 몇몇 대학)의 모든 호스트 이름과 IP 매핑이 이 파일 하나에 다 들어 있었습니다. 각 기관은 주기적으로 FTP로 이 파일을 다운로드해서 자기 시스템의 /etc/hosts에 덮어쓰는 방식이었죠.
그런데 1980년대 들어 호스트가 기하급수적으로 늘어나면서 이 방식은 세 가지 이유로 붕괴합니다.
mail이라는 이름을 쓰면 문제가 생깁니다.이 세 가지 문제를 한 번에 해결한 게 1983년 Paul Mockapetris가 제안한 RFC 882/883(나중에 RFC 1034/1035로 발전)의 DNS였습니다.
DNS의 이름 공간은 루트(root)를 최상위로 하는 뒤집힌 나무 모양인데요, 여러분이 평소에 쓰는 www.google.com은 사실 생략된 표기이고, 정식 FQDN(Fully Qualified Domain Name)은 www.google.com.입니다.
. (root)
/ | \
com net kr
/ | \
google netflix co
/ \
www naver
맨 끝의 점(.)이 바로 루트를 가리키는 레이블입니다. 이 트리를 해석할 때는 오른쪽에서 왼쪽으로 읽습니다.
📏 각 레이블은 최대 63바이트, 전체 FQDN은 최대 255바이트로 제한됩니다. 이 제한은 뒤에서 볼 DNS 메시지의 압축 기법과 깊이 연관돼 있습니다.
흔히 "루트 DNS 서버는 전 세계에 13개밖에 없다"고 알려져 있는데요, 이건 반은 맞고 반은 틀린 이야기입니다.
| 구분 | 숫자 |
|---|---|
| 논리적 IP 주소 | 13개 (a.root-servers.net ~ m.root-servers.net) |
| 실제 물리 서버 | 1,500개 이상 |
어떻게 13개의 IP가 1,500개 서버에 대응될까요? 그 비밀이 바로 Anycast라는 네트워크 라우팅 기법입니다.
동일한 IP 주소를 여러 지리적 위치의 서버에 할당해 놓고, BGP(Border Gateway Protocol) 라우팅 테이블이 요청자에게 가장 가까운(홉 수가 적은) 서버로 자동으로 패킷을 보내는 방식인데요, 쉽게 말하면 "서울에서 198.41.0.4(a 루트 서버)로 패킷을 보내면 서울 혹은 도쿄 인스턴스가 응답하고, 뉴욕에서 같은 IP로 보내면 뉴욕 인스턴스가 응답하는" 겁니다.
🛡️ 이 Anycast 덕분에 DNS 루트 서버는 DDoS 공격에 강합니다. 2002년과 2007년의 대규모 루트 서버 공격에도 인터넷이 멈추지 않은 이유가 여기 있습니다.
루트 서버는 com, net, kr, jp 같은 TLD(Top-Level Domain)가 누구 관할인지만 알고 있습니다. 실제 google.com의 IP는 모릅니다. 대신 "com에 대해서는 Verisign의 TLD 서버들에게 물어봐라"라고 알려주는데요, 이것이 위임(delegation)입니다.
그래서 DNS 해석은 계층을 따라 내려가는 과정입니다.
[Resolver] "google.com의 IP 뭐야?"
│
├─▶ [Root] "com은 Verisign한테 물어봐"
│
├─▶ [com TLD] "google.com은 ns1.google.com이 관리해"
│
└─▶ [google.com 권한 서버] "142.250.207.46 이야"
이 중 어느 한 단계라도 막히면 전체가 실패합니다.
여러분이 브라우저에서 google.com을 입력하면, 가장 먼저 일어나는 일은 애플리케이션이 getaddrinfo()라는 시스템 콜을 호출하는 것입니다.
이 함수는 POSIX 표준 라이브러리가 제공하는 인터페이스로, 내부적으로 Stub Resolver라는 OS의 경량 DNS 클라이언트를 호출하는데요,
glibc의 nss_dns 모듈 혹은 systemd-resolvedDNS Client Service(Dnscache)mDNSResponderStub Resolver는 직접 루트부터 묻지 않습니다. 대신 /etc/resolv.conf(Linux) 또는 네트워크 어댑터 설정(Windows)에 지정된 Recursive Resolver(재귀 해석기)에게 한 번만 묻고 답을 받아옵니다. "나 대신 다 알아내 와"라고 위임하는 거죠.
Recursive Resolver는 Stub Resolver로부터 "google.com의 A 레코드 알려줘"라는 요청을 받으면, Iterative Query(반복 질의) 과정을 수행합니다.
1단계 — Resolver가 하드코딩으로 가지고 있는 루트 힌트(root hints) 파일에서 루트 서버 IP(가령 198.41.0.4)를 골라 UDP 패킷을 보냅니다. 루트 서버는 답을 주지 않고 "com TLD 서버들은 여기야"라면서 NS 레코드와 Glue 레코드(TLD 서버들의 IP)를 돌려주는데요, 이게 Referral(위임 응답)입니다.
2단계 — Resolver가 받은 com TLD 서버(가령 a.gtld-servers.net)에게 같은 질문을 던집니다. TLD 서버는 "google.com의 권한 서버는 ns1.google.com이야"라고 또 다른 Referral을 돌려줍니다.
3단계 — 비로소 google.com의 권한 서버에게 물어보고, 거기서 실제 A 레코드를 얻어냅니다.
이 세 단계가 순차적으로 일어나는 동안 최소 3번의 왕복(RTT, Round-Trip Time)이 발생하는데요, 각 RTT는 수 밀리초에서 수백 밀리초까지 다양합니다.
❓ "Recursive Resolver라는 이름은 왜 Recursive인데 내부 동작은 Iterative인가?"
이름은 클라이언트 관점의 것입니다. Stub Resolver 입장에서는 한 번 요청하면 모든 답이 재귀적으로 해결되어 돌아오니까 Recursive고, 실제 Resolver가 루트·TLD·권한 서버를 차례로 돌아다니는 행위는 Iterative인 겁니다.
DNS는 기본적으로 UDP(User Datagram Protocol) 53번 포트를 사용하는데요, 왜 TCP가 아니라 UDP일까요?
| 이유 | 설명 |
|---|---|
| ⚡ 속도 | TCP는 3-way handshake로 1.5 RTT를 낭비합니다. UDP는 쏘면 끝. |
| 💾 상태 비유지 | 초당 수십만 건 처리 시 TCP 연결 상태 유지는 리소스 폭발을 부릅니다. |
| 🎯 간결성 | DNS 질의/응답은 대부분 512바이트 안에 들어갑니다. |
다만 응답이 512바이트를 초과하거나, AXFR(존 전송)처럼 대용량 데이터를 주고받아야 할 때는 TCP 53번 포트로 폴백(fallback)합니다. 이 512바이트 제한은 과거 IP MTU 제약과 UDP 단편화 회피를 위한 것인데, 현대에는 EDNS(0)라는 확장으로 4,096바이트까지 UDP로 주고받을 수 있게 되었습니다.
DNS 메시지는 고정 12바이트 헤더로 시작하는데요, 구조는 이렇습니다.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ID (16 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| QDCOUNT (16 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ANCOUNT (16 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NSCOUNT / ARCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Transaction ID(16비트)는 질의와 응답을 매칭하는 식별자입니다. 공격자가 이 ID를 추측할 수 있으면 캐시 포이즈닝이 가능하기 때문에, 2008년 Kaminsky 공격 이후로는 UDP 출발 포트까지 무작위화해서 엔트로피를 늘리게 되었습니다.
플래그 비트들 중 특히 중요한 것은:
RD (Recursion Desired) — 클라이언트가 재귀 해석을 원한다RA (Recursion Available) — 서버가 재귀 해석을 지원한다AA (Authoritative Answer) — 내가 이 도메인의 권한 서버라서 확신 있게 답한다TC (Truncated) — 응답이 512바이트를 넘어서 잘렸으니 TCP로 다시 물어라DNS가 다루는 정보는 전부 RR(Resource Record)이라는 단위로 표현되는데요, 주요 타입은 다음과 같습니다.
| 타입 | 용도 |
|---|---|
A | IPv4 주소 (32비트) |
AAAA | IPv6 주소 (128비트), "쿼드A"로 읽습니다 |
CNAME | 별칭 — "이 이름은 사실 저 이름이야" |
MX | 메일 교환 서버 |
NS | 권한 서버 |
PTR | 역방향 조회 (IP → 이름) |
SOA | 존 관리 정보 |
TXT | 임의 텍스트 (SPF, DKIM, 도메인 소유 증명 등) |
각 RR에는 TTL(Time To Live)이라는 필드가 있는데요, "이 정보를 몇 초 동안 캐시해도 된다"를 의미합니다. CDN 같은 자주 바뀌는 서비스는 TTL을 60초 이하로 짧게 두고, 거의 안 바뀌는 TLD 정보는 며칠 단위로 깁니다.
getaddrinfo()가 호출되면 어떤 일이 벌어지는지 커널 레벨로 내려가 보겠습니다.
먼저 Stub Resolver는 socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) 시스템 콜로 UDP 소켓을 만듭니다. 이 시스템 콜은 syscall 인스트럭션으로 CPU를 유저 모드에서 커널 모드로 전환시키고, 커널은 내부에 struct sock 구조체를 할당해서 소켓 파일 디스크립터를 반환합니다.
다음으로 sendto() 시스템 콜로 DNS 질의 패킷을 보내는데요, 커널은 이 바이트열을 받아 계층적으로 캡슐화합니다.
[DNS 메시지]
↓ UDP 헤더 (8 B) 추가
[UDP 세그먼트]
↓ IP 헤더 (20 B, IPv4) 추가, 게이트웨이 MAC 조회
[IP 패킷]
↓ 이더넷 헤더 (14 B) 추가
[이더넷 프레임]
↓ NIC로 전달
이 캡슐화 과정이 OSI 7계층 모델의 L5→L4→L3→L2 하강 그 자체입니다.
패킷이 완성되면 커널은 NIC(Network Interface Card) 드라이버에게 전달하는데요, 현대 NIC는 DMA(Direct Memory Access) 엔진을 가지고 있어서 CPU를 거치지 않고 시스템 메모리에서 직접 패킷을 읽어갑니다.
드라이버는 송신 링 버퍼(TX ring buffer)의 디스크립터에 패킷 버퍼의 물리 주소를 써 넣고, NIC의 MMIO(Memory-Mapped I/O) 레지스터에 "보낼 게 있다"고 신호를 보내는 doorbell write를 수행합니다.
NIC는 DMA로 패킷을 자기 내부 FIFO에 복사한 뒤, PHY 칩을 통해 물리 신호로 변환해서 송출합니다.
🌏 이 순간 여러분의 DNS 질의는 전기 신호 혹은 광 펄스가 되어 ISP의 어딘가로 떠나는 겁니다.
응답이 돌아오면 반대 순서로 일어납니다. NIC가 프레임을 수신하면 DMA로 시스템 메모리의 RX 링 버퍼에 복사하고, 하드웨어 인터럽트(IRQ)를 발생시켜 CPU에게 "일 생겼다"고 알리는데요, 현대 Linux는 인터럽트 폭풍을 막기 위해 NAPI(New API)라는 하이브리드 방식을 씁니다. 첫 인터럽트만 받고 그 후로는 폴링 모드로 전환해서 여러 패킷을 한 번에 처리하는 겁니다.
커널 네트워크 스택은 이더넷 헤더 → IP 헤더 → UDP 헤더를 차례로 벗기고, 페이로드만 남겨서 해당 소켓의 수신 큐에 넣습니다. 이때 epoll 혹은 select 같은 이벤트 통지 메커니즘이 해당 소켓을 대기 중이던 사용자 프로세스를 깨우고, Stub Resolver가 recvfrom()으로 데이터를 읽어갑니다.
이 전체 과정이 보통 수 마이크로초에서 수십 밀리초 안에 끝납니다.
DNS가 전 세계 수십억 기기의 요청을 감당할 수 있는 건 공격적인 다층 캐싱 덕분인데요, 하나의 질의는 다음 계층을 차례로 거칩니다.
[애플리케이션]
↓ (브라우저 캐시 — Chrome은 chrome://net-internals/#dns)
[OS Stub Resolver 캐시]
↓ (ipconfig /displaydns, resolvectl statistics)
[Recursive Resolver 캐시]
↓ (통신사 DNS, 8.8.8.8, 1.1.1.1)
[권한 서버]
TTL은 캐시의 유효 기간을 의미하는데, 레코드가 캐시에 올라온 시점부터 초 단위로 감소하다가 0이 되면 만료됩니다. 만료된 뒤 다시 요청이 오면 Resolver는 상위에 다시 물어봐야 합니다.
재미있는 건 부정 응답도 캐시한다는 점인데요, 존재하지 않는 도메인에 대해 NXDOMAIN 응답을 받으면 그것도 SOA 레코드의 MINIMUM 필드에 명시된 시간만큼 캐시합니다.
이게 없으면 누군가 asdfasdfasdf.com 같은 이름을 반복 질의할 때마다 전체 해석 체인을 타야 하니 엄청난 낭비가 됩니다.
캐시는 성능의 원천이지만 보안의 약점이기도 합니다. 만약 공격자가 Resolver의 캐시에 가짜 응답을 주입할 수 있다면, 그 Resolver를 쓰는 모든 사용자가 가짜 사이트로 유도됩니다.
2008년 Dan Kaminsky가 발표한 공격은 이 취약점을 실용적으로 현실화시킨 사건이었는데요, 그 대응으로 Source Port Randomization(UDP 출발 포트 무작위화)과 DNSSEC(DNS Security Extensions)이 널리 퍼지게 되었습니다.
DNSSEC은 각 DNS 응답에 디지털 서명을 붙여서 위변조를 탐지하는 체계입니다.
[Root KSK] ─서명─▶ [Root ZSK]
│
▼
[TLD KSK] ─서명─▶ [TLD ZSK]
│
▼
[Domain KSK] ─서명─▶ [Domain ZSK]
루트의 KSK(Key Signing Key) → TLD의 ZSK(Zone Signing Key) → 도메인의 ZSK로 이어지는 신뢰 체인(chain of trust)을 통해 검증하는데요, RRSIG, DNSKEY, DS, NSEC 같은 새로운 레코드 타입들이 이를 위해 정의되어 있습니다.
⚠️ DNSSEC은 기밀성(confidentiality)은 제공하지 않습니다. 서명만 할 뿐 암호화하지 않아서, 중간자는 여전히 누가 어떤 도메인을 조회하는지 엿볼 수 있습니다.
이 기밀성 문제를 해결하기 위해 등장한 것이:
| 프로토콜 | 포트 | 특징 |
|---|---|---|
| DoT (DNS over TLS, RFC 7858) | TCP 853 | TLS 세션 안에서 DNS 메시지 교환 |
| DoH (DNS over HTTPS, RFC 8484) | TCP 443 | HTTPS에 DNS를 얹음 — 일반 웹 트래픽과 구분 어려움 |
| DoQ (DNS over QUIC, RFC 9250) | UDP 443 | QUIC의 0-RTT 재개와 멀티플렉싱 활용 |
DoH는 방화벽이 일반 HTTPS 트래픽과 구분하기 어려워서 검열 우회에 특히 효과적입니다.
기업이나 교육기관 네트워크는 거의 예외 없이 Split-Horizon DNS(분할 지평 DNS) 구조를 채택하는데요, 이건 같은 도메인에 대해 내부에서 보는 IP와 외부에서 보는 IP가 다르게 응답하는 구성입니다.
외부에서 gitlab.company.com 조회 → 공인 IP (예: 203.0.113.10)
내부에서 gitlab.company.com 조회 → 사설 IP (예: 10.20.30.10)
이 구성을 가능하게 하려면 내부 전용 DNS 서버가 있어야 하고, 단말들은 이 내부 서버를 DNS로 고정해서 써야 합니다.
내부 DNS 서버는 자기가 관리하는 도메인(*.company.com 같은)만 직접 답하고, 나머지(google.com, kakao.com 등 외부)는 상위 Forwarder에게 넘기는데요, 이 포워더가 또 다른 내부 보안 장비(프록시 DNS, DNS 방화벽)를 거치는 구조면 지연이 계단식으로 쌓입니다.
[단말] ─▶ [내부 DNS] ─▶ [보안 DNS 방화벽] ─▶ [상위 포워더] ─▶ [공용 DNS] ─▶ [권한 서버]
게다가 상위 포워더 중 하나가 응답이 느리거나 죽어 있다면, Resolver는 기본 타임아웃(보통 5초) 만큼 기다렸다가 다음 후보 서버로 재시도합니다. /etc/resolv.conf에 DNS 서버가 3개 등록돼 있고 첫 번째가 죽어 있으면, 매 질의마다 5초씩 낭비되는 거죠.
🔍 어떤 작업이 유독 40초, 18초 같은 이상한 지연을 보인다면, 거의 확실하게 다중 타임아웃이 누적된 패턴입니다.
최신 앱의 로그인 과정은 한 번의 DNS 조회로 끝나지 않습니다.
여러 도메인을 연달아 조회해야 하는데, 이 각각이 느린 DNS 체인을 타면 전체 지연이 도메인 개수만큼 배수로 커집니다.
더구나 DNS 해석 후에도 TCP 3-way handshake + TLS handshake(1.2는 2-RTT, 1.3은 1-RTT)가 추가로 필요합니다. DNS에서 이미 몇 초씩 까먹으면 체감 지연이 폭발적으로 느껴지죠.
집 공유기는 DHCP가 주는 DNS(보통 ISP DNS나, 공유기 내장 DNS 프록시가 위임하는 8.8.8.8)를 쓰는데요, 이 DNS들은 초거대 캐시와 짧은 네트워크 경로를 가지고 있어서 대부분의 유명 도메인은 이미 캐시돼 있습니다.
응답이 수 밀리초 안에 오니 전체 체감 속도가 다른 겁니다.
Linux/macOS에서 다음을 실행하면 Resolver 없이 직접 루트부터 내려가는 전체 과정을 관찰할 수 있습니다.
dig +trace google.com
각 단계의 응답 시간까지 찍혀 나오니 어디서 병목이 생기는지 명확히 보입니다. Windows에서는 nslookup이 비슷한 역할을 하지만 기능이 더 제한적이어서, WSL을 통해 dig를 쓰는 걸 권장합니다.
특정 DNS 서버를 명시해서 비교도 가능합니다.
dig @8.8.8.8 google.com # Google Public DNS
dig @1.1.1.1 google.com # Cloudflare
dig @<내부 DNS IP> google.com # 내부망 DNS
내부 DNS와 외부 DNS의 응답 시간을 직접 비교하면, 병목이 어디인지 바로 드러납니다.
정말 바닥까지 내려가서 보고 싶다면 Wireshark를 켜 놓고 DNS 쿼리를 캡처하면 됩니다.
udp.port == 53
UDP 53번 포트 필터를 걸면 패킷 하나하나의 헤더, 플래그, RR까지 다 들여다볼 수 있는데요, 타임아웃 재시도가 일어나고 있다면 여기서 명확히 보입니다. 동일한 Transaction ID의 질의가 5초 간격으로 반복 발사되는 패턴이 보일 거예요.
정리하면, DNS는 단순한 "이름→IP 변환기"가 아니라 전 지구 규모의 계층적 분산 데이터베이스이며, 수십 년에 걸친 엔지니어링 누적의 결정체입니다.
한 번의 getaddrinfo() 호출 뒤에는:
일들이 동시에 벌어집니다.
관리되는 네트워크에서 겪는 수십 초의 지연은 사실 이 거대한 시스템 어딘가에서 타임아웃 몇 번이 쌓인 결과일 뿐인데요, 이런 증상을 볼 때마다 "DNS는 어느 계층에서 어떤 형태로 동작하고 있는가"를 떠올릴 수 있다면, 대부분의 네트워크 지연 문제는 스스로 진단할 수 있게 됩니다.
백엔드 개발자로서 DNS를 깊이 이해한다는 건, 단순히 네트워크 엔지니어의 영역을 침범하는 게 아니라, 분산 시스템의 이름 해석과 서비스 디스커버리의 근원을 이해한다는 뜻입니다.
Kubernetes의 CoreDNS, AWS의 Route 53, Service Mesh의 이름 기반 라우팅, Spring Cloud의 서비스 디스커버리 — 이 모든 현대적 인프라의 뿌리에 DNS의 개념이 살아 있습니다.
오늘 글은 여기서 마치겠습니다.