코드에서 https://api.example.com으로 요청을 보낼 때 컴퓨터는 api.example.com이 어느 서버인지 모른다. 실제 통신은 IP 주소로 이루어진다. DNS(Domain Name System)는 이 변환을 담당하는 분산 시스템이다.

조회 과정

api.example.com을 처음 조회하는 상황을 따라가면 이렇다.

클라이언트
  → 로컬 캐시 확인 (없으면)
  → 운영체제 리졸버 (/etc/resolv.conf에 적힌 DNS 서버)
  → 재귀 리졸버 (ISP 또는 8.8.8.8 같은 공용 DNS)
      → 루트 네임서버 (. 에 대한 응답: "com은 여기 물어봐")
      → TLD 네임서버 (com. 에 대한 응답: "example.com은 여기 물어봐")
      → 권위 네임서버 (example.com을 실제로 관리하는 서버)
          → "api.example.com = 1.2.3.4" 응답
  → 결과를 TTL 동안 캐시
  → 클라이언트에 IP 반환

재귀 리졸버(recursive resolver): 클라이언트를 대신해 루트부터 차례로 물어보고 최종 답을 돌려준다. 클라이언트는 재귀 리졸버에게만 물어보면 된다.

권위 네임서버(authoritative nameserver): 특정 도메인의 레코드를 실제로 보유한 서버다. Route 53, Cloudflare DNS 같은 서비스가 이 역할을 한다. “내가 정답이다"라고 최종 응답한다.

주요 레코드 타입

A 레코드: 도메인 → IPv4 주소

api.example.com.  300  IN  A  1.2.3.4
api.example.com.  300  IN  A  1.2.3.5   # 여러 개면 라운드로빈

AAAA 레코드: 도메인 → IPv6 주소

CNAME 레코드: 도메인 → 다른 도메인 (별칭)

www.example.com.  300  IN  CNAME  api.example.com.

www.example.com으로 오면 api.example.com을 다시 조회한다. 로드밸런서 DNS 이름처럼 IP가 유동적인 대상을 가리킬 때 쓴다. CNAME은 조회가 한 단계 더 생기므로 A 레코드보다 느리다. 루트 도메인(example.com)에는 CNAME을 쓸 수 없다 — RFC 제약이다. Route 53의 ALIAS 레코드는 이 제약을 우회하는 AWS 전용 확장이다.

MX 레코드: 이메일 수신 서버 지정

example.com.  300  IN  MX  10  mail.example.com.

TXT 레코드: 임의의 텍스트. 도메인 소유권 인증(Google, AWS Certificate Manager), SPF/DKIM 이메일 인증에 쓰인다.

NS 레코드: 이 도메인의 권위 네임서버가 어디인지 지정

SRV 레코드: 서비스의 호스트와 포트를 함께 지정. k8s의 CoreDNS가 _http._tcp.my-svc.my-ns.svc.cluster.local 형태로 서비스 포트 정보를 제공할 때 쓴다.

TTL — 캐시 유효 시간

TTL(Time To Live)은 이 레코드를 몇 초 동안 캐시해도 되는지 알려주는 값이다.

api.example.com.  300  IN  A  1.2.3.4
                  TTL = 300초 (5분)

재귀 리졸버와 클라이언트가 이 시간 동안 캐시를 쓴다. TTL이 지나면 다시 조회한다.

TTL이 배포에 미치는 영향: IP를 바꿔야 하는 상황(로드밸런서 교체, IP 변경)에서 TTL이 3600이면 최대 1시간 동안 일부 트래픽이 이전 IP로 계속 간다. 변경 전에 TTL을 60~300으로 낮춰두고, 변경 후 다시 높이는 것이 표준 절차다.

TTL이 낮으면: 변경이 빠르게 전파되지만 DNS 서버에 쿼리가 더 자주 간다. CDN이나 글로벌 서비스에서 지역별 IP를 빠르게 전환할 때 낮은 TTL을 쓴다.

클러스터 내부 DNS — CoreDNS

k8s 클러스터 안에서는 CoreDNS가 내부 DNS 서버 역할을 한다. 파드가 my-svc.my-namespace.svc.cluster.local로 조회하면 해당 Service의 ClusterIP를 반환한다.

my-svc.my-namespace.svc.cluster.local.  5  IN  A  10.96.0.10

파드의 /etc/resolv.confsearch my-namespace.svc.cluster.local svc.cluster.local cluster.local이 적혀 있어서, 코드에서 그냥 my-svc만 써도 풀네임으로 조회된다.

클러스터 외부 도메인(예: google.com)은 CoreDNS가 upstream DNS 서버로 포워딩한다. 이때 CoreDNS 파드에서 인터넷 DNS 서버로 나가는 UDP 53 포트가 열려 있어야 한다. NetworkPolicy로 egress를 막을 때 DNS 포트를 빠뜨리면 모든 외부 통신이 끊기는 이유다.

트레이드오프

DNS 캐시가 있어서 레코드를 수정해도 즉시 반영되지 않는다. 장애 상황에서 IP를 바꾸는 경우 TTL이 높으면 전파 지연이 생긴다. 반대로 TTL을 너무 낮게 잡으면 DNS 서버에 부하가 늘고 조회 지연이 누적된다. 평상시에는 TTL을 적당히 높게(300~3600) 유지하고, 변경 예정일 때만 낮추는 것이 현실적이다.

Route 53 같은 클라우드 DNS는 헬스체크와 연동해 비정상 엔드포인트를 자동으로 제외하는 DNS 페일오버 기능을 제공한다. 하지만 TTL 동안 캐시된 응답은 막을 수 없어 완전한 즉시 전환은 보장하지 못한다. 빠른 페일오버가 필요하면 로드밸런서 레벨에서 처리하는 것이 더 확실하다.