infra
Platform

모듈 맵

[Linux] DNS 확인 과정과 resolv.conf, /etc/hosts 에러 트러블슈팅

0 / 37 완료

펼치기
0 / 37 완료0%

리눅스 서버 운영 · 19 / 37

[Linux] DNS 확인 과정과 resolv.conf, /etc/hosts 에러 트러블슈팅

IP로 ping은 되는데 도메인으로 curl이 안 될 때 — /etc/hosts부터 systemd-resolved까지 DNS 해석 경로를 추적하고 NXDOMAIN·SERVFAIL 오류를 구분해 해결합니다

🚨INCIDENT ALERT
HIGH

서버에 배포 직후 ping 93.184.216.34는 응답이 옵니다. 그런데 curl https://api.example.com을 실행하면 Could not resolve host: api.example.com이 뜨고 바로 실패합니다. 네트워크 자체는 정상인데 이름 해석이 안 되는 것입니다. /etc/resolv.conf를 열어보면 심볼릭 링크입니다.

DNS 해석이 실제로 어느 경로를 거치는지 알고 있으면, 어느 단계에서 끊겼는지 5분 안에 특정할 수 있습니다.

DNS & 이름 해석 트러블슈팅

이번 챕터에서 배울 것
  • 1Linux DNS 해석 경로(/etc/hosts → nsswitch.conf → systemd-resolved → upstream)를 설명할 수 있다
  • 2Ubuntu와 RHEL의 DNS 설정 차이(systemd-resolved vs NetworkManager)를 구분할 수 있다
  • 3dig +trace, dig @8.8.8.8, resolvectl query로 DNS 조회 경로를 단계별로 추적할 수 있다
  • 4NXDOMAIN vs SERVFAIL vs timeout 오류를 구분하고 원인별로 대응할 수 있다
  • 5컨테이너·K8s 환경의 CoreDNS와 ndots 설정 문제를 진단할 수 있다
실습 환경 준비
DNS 조회 도구 설치 확인 (Ubuntu)
which dig resolvectl || sudo apt-get install -y dnsutils
현재 DNS 설정 확인
cat /etc/resolv.conf
systemd-resolved 상태 확인
systemctl is-active systemd-resolved
resolv.conf가 심볼릭 링크인지 확인
ls -la /etc/resolv.conf
💡개념

DNS 해석 경로 전체 — 요청이 어디를 거쳐 응답에 도달하는가

DNS 전체 해석 경로 — 앱에서 authoritative NS까지확대

curl https://api.example.com을 실행하면, 커널이 직접 DNS를 조회하는 게 아닙니다. glibc의 Name Service Switch(NSS)가 /etc/nsswitch.conf에 정의된 순서에 따라 여러 소스를 순차적으로 시도합니다. 이 경로를 모르면 "resolv.conf를 고쳤는데 왜 아직 안 되지"라는 상황이 생깁니다.

Linux DNS 해석 경로 — /etc/hosts → systemd-resolved → Upstream → Authoritative확대

Ubuntu 22.04 기준 해석 경로:

애플리케이션 (curl, wget, your-app)
    ↓  getaddrinfo() — glibc
/etc/nsswitch.conf  →  "hosts: files mdns4_minimal [NOTFOUND=return] dns"
    ↓  1순위: files
/etc/hosts          →  127.0.0.1 localhost, ::1 localhost ...
    ↓  없으면 다음
    ↓  2순위: dns
127.0.0.53:53       →  systemd-resolved (stub resolver)
    ↓  캐시 없으면
upstream DNS        →  /run/systemd/resolve/resolv.conf의 nameserver
    ↓  (보통 DHCP에서 받은 라우터 DNS 또는 회사 내부 DNS)
외부 DNS 서버        →  8.8.8.8, 1.1.1.1 등

nsswitch.conf가 중요한 이유: /etc/hosts가 먼저 확인됩니다. 테스트 목적으로 hosts 파일에 임시 항목을 추가했다가 지우지 않으면, DNS 응답과 다른 IP로 연결이 됩니다.

로컬 터미널
# 현재 hosts 순서 확인
grep "^hosts:" /etc/nsswitch.conf
# hosts: files mdns4_minimal [NOTFOUND=return] dns

# /etc/hosts 내용 확인 (엉뚱한 항목이 있을 수 있음)
cat /etc/hosts

systemd-resolved의 역할: Ubuntu 18.04 이후 기본 활성화된 로컬 DNS 캐시 데몬입니다. 127.0.0.53:53에서 리스닝하며 다음 역할을 합니다.

역할설명
DNS 캐싱TTL 내 반복 질의는 upstream 요청 없이 바로 응답
검색 도메인 처리search corp.example.com 접미사를 자동 추가
per-link DNS각 네트워크 인터페이스별로 다른 DNS 서버 사용 가능
DNSSEC 검증옵션으로 활성화 가능

실습 1 — Ubuntu vs RHEL DNS 설정 차이 파악

Ubuntu 22.04와 RHEL/CentOS 계열은 DNS 설정 관리 방식이 다릅니다. 같은 명령이 다르게 동작하는 이유를 이해하면 혼란이 사라집니다.

1Ubuntu 22.04 — systemd-resolved 기반 설정 확인

Ubuntu 22.04에서는 systemd-resolved가 DNS를 관리합니다.

로컬 터미널
# 전체 DNS 설정 상태 확인 (가장 먼저 실행)
resolvectl status

# 특정 인터페이스의 DNS 설정만 확인
resolvectl status eth0

출력 예시:

Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
      DNS Servers: 10.0.1.1
     DNS Domain: corp.example.com

Link 2 (eth0)
      Current Scopes: DNS
           Protocols: +DefaultRoute ...
  Current DNS Server: 10.0.1.1
         DNS Servers: 10.0.1.1 8.8.8.8
          DNS Domain: corp.example.com

읽는 법:

  • resolv.conf mode: stub/etc/resolv.conf127.0.0.53을 가리키는 정상 상태
  • Current DNS Server — 실제로 질의 중인 upstream DNS
  • DNS Domain — 검색 도메인 (단축 이름 apiapi.corp.example.com으로 확장)
로컬 터미널
# DNS 캐시 비우기 (설정 변경 후 또는 스테일 캐시 의심 시)
sudo resolvectl flush-caches

# 특정 도메인 질의 테스트 (systemd-resolved 경유)
resolvectl query api.example.com
resolvectl status
🔍실행 후 확인할 것
  • 먼저 dig example.com 의 ANSWER SECTION 에서 응답 IP를 확인한다 — 그 다음 TTL 숫자(초 단위)를 읽는다. TTL이 300이면 5분 캐시, 86400이면 24시간이다. TTL이 60 이하로 짧으면 DNS 전파 직후이거나 임시 설정일 가능성이 높다
  • dig 결과 status가 NXDOMAIN이면 → 도메인 자체가 없거나 오타. SERVFAIL이면 → DNS 서버가 응답했지만 처리 실패(방화벽 차단, 내부 DNS 장애, DNSSEC 실패 중 하나). NOERROR이지만 ANSWER 0이면 → 도메인은 있지만 해당 레코드 타입이 없는 것
  • dig @8.8.8.8 도메인 이 성공하고 dig 도메인 이 실패하면 → systemd-resolved 또는 내부 DNS 문제. 반대로 둘 다 실패하면 → 네트워크 자체 또는 도메인 문제다
2RHEL/CentOS 8+ — NetworkManager 기반 DNS 설정

RHEL 8+, CentOS Stream, Rocky Linux는 NetworkManager가 DNS를 관리합니다. systemd-resolved는 기본 비활성화입니다.

로컬 터미널
# 네트워크 인터페이스별 DNS 설정 확인
nmcli dev show | grep DNS

# 현재 연결(connection)의 DNS 설정 확인
nmcli con show $(nmcli -t -f NAME,DEVICE con show --active | head -1 | cut -d: -f1)

# DNS 서버 변경 (RHEL/CentOS)
sudo nmcli con mod eth0 ipv4.dns "8.8.8.8 1.1.1.1"
sudo nmcli con up eth0

Ubuntu vs RHEL 비교:

항목Ubuntu 22.04RHEL 8+
DNS 관리 주체systemd-resolvedNetworkManager
로컬 stub127.0.0.53:53없음 (직접 resolv.conf)
resolv.conf심볼릭 링크실제 파일
DNS 캐시 비우기resolvectl flush-cachessystemctl restart NetworkManager
DNS 설정 확인resolvectl statusnmcli dev show | grep DNS
nmcli dev show | grep DNS
💡개념

dig 실전 사용법 — 어디서 막혔는지 정확히 찾기

dig 실전 사용법 — DNS 응답 해독과 장애 지점 찾기확대

DNS 문제 진단에서 dig는 가장 신뢰할 수 있는 도구입니다. nslookup보다 출력이 상세하고 옵션도 풍부합니다. 세 가지 패턴만 알면 대부분의 상황을 커버할 수 있습니다.

패턴 1: 공용 DNS로 직접 질의 — systemd-resolved 우회

로컬 터미널
# 로컬 DNS(systemd-resolved)를 완전히 우회하고 구글 DNS에 직접 질의
dig @8.8.8.8 api.example.com

# 응답 섹션만 간결하게 (스크립트에서 유용)
dig @8.8.8.8 api.example.com +short

이 명령이 성공하고 dig api.example.com이 실패하면 → 로컬 DNS 문제입니다.

패턴 2: 재귀 추적 — Root부터 Authoritative까지 전체 경로

로컬 터미널
# Root NS부터 Authoritative까지 전체 위임 경로 추적
dig +trace api.example.com

출력 예시 (요약):

.                       518400  IN  NS  a.root-servers.net.
com.                    172800  IN  NS  a.gtld-servers.net.
example.com.            172800  IN  NS  ns1.example.com.
api.example.com.        300     IN  A   93.184.216.34

Root → .com TLD → example.com Authoritative 순서로 위임되는 흐름이 보입니다. 특정 단계에서 응답이 없으면 그 구간이 문제입니다.

패턴 3: 특정 레코드 타입 조회

로컬 터미널
# A 레코드 (IPv4 주소)
dig api.example.com A

# AAAA 레코드 (IPv6 주소)
dig api.example.com AAAA

# MX 레코드 (메일 서버)
dig example.com MX

# SOA — 도메인 권한 정보 (NXDOMAIN 의심 시 권한 네임서버 확인)
dig example.com SOA

# PTR — 역방향 조회 (IP → 도메인)
dig -x 93.184.216.34

응답 status 값 해석:

Status의미다음 행동
NOERROR성공 (레코드 없어도 NOERROR 가능)ANSWER SECTION 확인
NXDOMAIN도메인이 존재하지 않음오타 확인, Authoritative에 레코드 등록 여부 확인
SERVFAIL서버 처리 오류DNS 서버 상태, 방화벽 UDP 53, DNSSEC 설정 확인
REFUSED서버가 질의 거부해당 DNS 서버가 재귀 질의를 허용하지 않음
DNS 진단 수치·시간 판단 — dig 출력에서 무엇을 읽나
Query time이 크다캐시 히트는 0~1ms, 재귀 조회는 수십~수백ms. 같은 질의를 두 번 해 첫 번째만 느리면 캐시 미스(정상). 매번 수백ms면 리졸버·상위 서버 지연 — 'Query time으로 캐시 여부 판별'
변경했는데 옛 값이 나온다TTL만큼 캐시 잔존 — dig 응답의 TTL 숫자가 매 조회마다 줄다가 0에서 갱신. 'TTL 3600이면 최대 1시간'. 변경 전 TTL을 미리 낮추는 게 정석
dig는 되는데 앱(브라우저)만 실패dig는 resolv.conf를 우회해 직접 질의하기도 함 — getent hosts <도메인>으로 NSS 경로(앱이 실제 쓰는 길)를 확인. '/etc/hosts·nsswitch가 가로채는지'
응답이 2~5초 걸린 뒤 성공1순위 nameserver 무응답 → timeout 후 폴백. resolv.conf options timeout:1 attempts:2로 단축 + 죽은 서버 제거. '지연 폴백=죽은 nameserver'
@8.8.8.8은 되고 기본은 안 됨내 리졸버 문제로 확정 — resolv.conf의 nameserver 또는 systemd-resolved 상태. 'dig @외부 비교로 내 리졸버 vs 전체 구분'
컨테이너에서만 이름 해석 실패ndots 설정으로 search 도메인을 과도하게 붙여 조회 폭증·실패. ndots:5 기본값 함정 — FQDN 끝에 점(.)을 붙이거나 ndots 조정. 'K8s DNS 지연의 단골'

실습 2 — /etc/resolv.conf 심볼릭 링크 vs 실제 파일

3/etc/resolv.conf 상태 파악
로컬 터미널
# resolv.conf가 링크인지 실제 파일인지 확인
ls -la /etc/resolv.conf

Ubuntu 22.04 (정상 상태):

lrwxrwxrwx 1 root root 39 Jan 01 00:00 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf

RHEL 8+ / 링크가 깨진 경우:

-rw-r--r-- 1 root root 73 Jan 01 00:00 /etc/resolv.conf

Ubuntu에서 심볼릭 링크 대상이 두 가지인 이유:

링크 대상내용특징
/run/systemd/resolve/stub-resolv.confnameserver 127.0.0.53기본값. systemd-resolved 캐싱 활용
/run/systemd/resolve/resolv.conf실제 upstream DNS 목록systemd-resolved 우회, 직접 연결
로컬 터미널
# stub-resolv.conf 내용 확인
cat /run/systemd/resolve/stub-resolv.conf
# nameserver 127.0.0.53
# options edns0 trust-ad
# search corp.example.com

# 실제 upstream DNS 확인
cat /run/systemd/resolve/resolv.conf
# nameserver 10.0.1.1
# nameserver 8.8.8.8
ls -la /etc/resolv.conf
4링크가 끊겼을 때 복원

이미 /etc/resolv.conf가 실제 파일로 교체된 경우, 또는 링크가 잘못된 대상을 가리키는 경우 복원 방법입니다.

로컬 터미널
# 현재 링크 대상 확인
readlink -f /etc/resolv.conf

# 링크가 깨진 경우: 올바른 stub으로 재연결
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

# 즉시 적용 확인
cat /etc/resolv.conf
# nameserver 127.0.0.53

# systemd-resolved 재시작 (설정 변경 후)
sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches

# DNS 해석이 정상화됐는지 확인
resolvectl query google.com

주의: 직접 /etc/resolv.confnameserver 8.8.8.8을 추가하고 싶을 때가 있습니다. Ubuntu에서는 이 파일이 재부팅이나 네트워크 재연결 시 덮어쓰여집니다. 영구 변경은 systemd-resolved 설정 파일을 통해 합니다.

로컬 터미널
# 영구적으로 upstream DNS 추가 (Ubuntu 22.04)
sudo mkdir -p /etc/systemd/resolved.conf.d/
cat <<EOF | sudo tee /etc/systemd/resolved.conf.d/dns.conf
[Resolve]
DNS=8.8.8.8 1.1.1.1
FallbackDNS=8.8.4.4
EOF
sudo systemctl restart systemd-resolved
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
💡개념

오류 유형 구분 — NXDOMAIN vs SERVFAIL vs connection timed out

DNS 오류 유형 3종 — NXDOMAIN · SERVFAIL · timed out 원인과 dig 출력 비교확대

DNS 오류 메시지를 보고 바로 원인 카테고리를 좁히면 진단 시간이 크게 줄어듭니다.

NXDOMAIN — 도메인이 없다

로컬 터미널
$ dig api.internal.corp
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 12345
  • Authoritative 서버까지 도달했는데 해당 레코드가 등록되어 있지 않습니다.
  • 원인: 오타, 도메인 만료, DNS 레코드 미등록, 검색 도메인(search domain) 문제
  • 확인: dig +trace api.internal.corp로 Authoritative 서버까지 도달하는지 봅니다.
로컬 터미널
# 검색 도메인 문제인지 확인 — 절대 이름으로 조회
dig api.internal.corp.   # 끝에 점(.) = 절대 이름, 검색 도메인 미적용

SERVFAIL — 서버가 처리하지 못했다

로컬 터미널
$ dig @10.0.1.53 api.internal.corp
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 67890
  • DNS 리졸버가 응답을 받아왔지만 처리 중 오류가 발생했습니다.
  • 원인: 내부 DNS 서버 장애, Authoritative 서버 비응답, DNSSEC 검증 실패, 방화벽이 DNS 응답 패킷을 차단
  • 확인: 다른 DNS 서버로 시도 → dig @8.8.8.8 api.internal.corp

connection timed out — 패킷이 도달하지 못했다

로컬 터미널
$ dig api.example.com
;; connection timed out; no servers could be reached
  • DNS 서버로의 UDP 53 패킷 자체가 차단됐거나 DNS 서버가 완전히 다운됐습니다.
  • 원인: 방화벽이 UDP 53을 차단, /etc/resolv.conf의 nameserver IP가 잘못됨, systemd-resolved 다운
  • 확인 순서:
서버 터미널
# 1. systemd-resolved가 살아있는지 확인
systemctl status systemd-resolved

# 2. 127.0.0.53 포트가 열려있는지 확인
ss -ulnp | grep 53

# 3. resolv.conf의 nameserver로 ping
ping -c 3 $(grep nameserver /etc/resolv.conf | head -1 | awk '{print $2}')

# 4. UDP 53 트래픽 직접 확인
sudo tcpdump -i any -n port 53 &
dig google.com

오류별 요약:

오류DNS 서버 도달레코드 존재주요 원인
NXDOMAINOX오타, 미등록, 만료
SERVFAILO확인 불가내부 DNS 장애, DNSSEC, 방화벽 응답 차단
timed outX확인 불가방화벽 UDP 53 차단, DNS 서버 다운

증상: 다음과 같은 오류가 발생합니다.

로컬 터미널
$ curl https://api.internal.corp/health
curl: (6) Could not resolve host: api.internal.corp

$ dig api.internal.corp
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 28371
;; ANSWER SECTION: (empty)

1단계: /etc/hosts 확인 — 엉뚱한 항목이 먼저 매칭될 수 있다

로컬 터미널
grep api.internal.corp /etc/hosts
# 출력이 없으면 hosts는 정상

2단계: 검색 도메인 문제인지 확인

로컬 터미널
# 현재 검색 도메인 확인
resolvectl status | grep "DNS Domain"

# 절대 이름으로 조회 (끝에 점)
dig api.internal.corp.

# 공용 DNS로도 같은 결과인지 확인
dig @8.8.8.8 api.internal.corp

3단계: 내부 DNS 서버가 이 도메인을 담당하는지 확인

로컬 터미널
# corp 도메인의 Authoritative 서버 찾기
dig SOA internal.corp

# 내부 DNS 서버에 직접 질의
dig @10.0.1.53 api.internal.corp

4단계: systemd-resolved가 내부 도메인을 올바른 DNS 서버로 보내는지 확인

로컬 터미널
# per-link DNS 설정 확인
resolvectl status eth0

# 내부 도메인용 DNS 서버가 설정됐는지 확인
# (VPN 연결 시 corp.example.com 도메인을 내부 DNS로 보내야 함)

해결 — per-domain DNS 라우팅 설정:

로컬 터미널
# 내부 도메인을 내부 DNS 서버로 보내도록 설정
sudo mkdir -p /etc/systemd/resolved.conf.d/
cat <<EOF | sudo tee /etc/systemd/resolved.conf.d/internal.conf
[Resolve]
DNS=10.0.1.53
Domains=~internal.corp ~corp.example.com
EOF
sudo systemctl restart systemd-resolved

# 적용 확인
resolvectl status | grep -A5 "DNS Domain"

Domains=~internal.corp 에서 ~ 접두사는 "이 도메인은 반드시 이 DNS 서버로"라는 라우팅 규칙입니다.


심화 — DNS가 UDP를 넘어설 때

💡개념

심화: DNS는 UDP만 쓰지 않는다 — 응답이 커지면 TCP로 넘어간다

지금까지 DNS를 '질의와 응답'으로만 다뤘지만, 가장 헷갈리는 간헐적 장애 몇 가지는 그 아래 전송 계층에서 벌어집니다. DNS가 어떤 전송을 언제 고르는지 알면, "다른 도메인은 다 되는데 유독 이 도메인만 가끔 안 되는" 상황을 설명할 수 있습니다.

  • DNS의 기본은 UDP 53이지만, 응답이 한 패킷에 안 들어가면 TCP로 넘어갑니다. 서버는 응답 헤더에 TC(truncated) 비트를 세워 "잘렸으니 TCP로 다시 물어보라"고 알리고, 리졸버는 같은 질의를 TCP 53으로 재시도합니다. 즉 TCP 53은 예외 상황용이 아니라 정상 프로토콜의 일부입니다.
  • 응답이 커지는 경우: A 레코드가 많은 도메인(로드밸런싱), 큰 TXT(SPF/DKIM), 그리고 특히 DNSSEC 서명(RRSIG·DNSKEY)입니다. DNSSEC 응답은 쉽게 UDP 한 패킷을 넘깁니다.
  • EDNS0가 UDP 버퍼를 키웁니다. 예전 512바이트 한계를 EDNS0가 4096바이트 등으로 확장해, 큰 응답도 TCP 없이 UDP로 받게 해줍니다(dig 출력의 ; EDNS: version: 0 ... udp: 4096). 하지만 그 큰 UDP 패킷은 IP 단편화(fragmentation)를 유발하고, 중간 장비가 단편을 떨구면 다시 TC→TCP 폴백이 필요해집니다.
  • 여기서 고전적 함정이 생깁니다. "DNS는 UDP만 쓴다"는 오해로 방화벽이 UDP 53만 열고 TCP 53을 막아두면, 작은 응답은 통과하는데 큰 응답(DNSSEC·많은 레코드)만 실패합니다. 전면 장애가 아니라 특정 도메인만 간헐적으로 깨지기 때문에 진단이 어렵습니다.
로컬 터미널
# 응답이 잘렸는지(플래그에 tc), TCP 폴백이 되는지 확인
dig +dnssec example.com          # 큰 응답을 유도 (flags에 tc가 뜨는지)
dig +tcp example.com             # TCP 53으로 강제 질의 — 무응답이면 TCP 차단 의심

정리하면, DNS 장애를 볼 때 "이름이 있느냐/없느냐"(NXDOMAIN·SERVFAIL) 다음으로 "응답이 어느 전송으로 오느냐"를 의심 목록에 넣어야 합니다. 특히 DNSSEC 도입, 레코드 급증, EDNS 큰 패킷은 TCP 53과 경로 MTU를 함께 점검할 신호입니다.

상황: 같은 리졸버로 다른 도메인은 멀쩡한데, 유독 어떤 외부(또는 사내) 도메인 하나만 간헐적으로 이름 해석이 실패합니다. dig를 몇 번 재시도하면 되기도 하고 안 되기도 해서, 캐시나 서버 부하로 오해하기 쉽습니다.

원인: 그 도메인의 응답이 UDP 한 패킷을 넘겨 TC(truncated) 비트가 서고, 리졸버가 TCP 53으로 폴백해야 완성됩니다. 그런데 경계 방화벽·보안그룹이 UDP 53만 허용하고 TCP 53을 차단하고 있어(또는 큰 EDNS UDP 단편을 중간에서 드롭해), 작은 응답은 통과하고 큰 응답만 실패합니다. DNSSEC이 응답을 키우는 대표 원인이라 DNSSEC 도메인에서 먼저 증상이 드러납니다.

진단: dig +short DOMAIN은 실패하는데 응답이 작은 다른 도메인은 되는지 대조합니다. dig +tcp DOMAIN이 timeout이면 TCP 53 차단이 강하게 의심됩니다. dig +dnssec DOMAIN 출력 헤더의 flagstc가 보이면 응답이 잘려 TCP가 필요하다는 증거입니다. 확정하려면 sudo tcpdump -i any -n port 53을 켜고 질의했을 때, TCP 53 SYN에 응답(SYN-ACK)이 돌아오지 않는지 관찰합니다.

해결: 근본 처방은 경계 방화벽·보안그룹에서 TCP 53도 UDP 53과 함께 허용하는 것입니다("DNS=UDP만"이라는 정책을 교정). 큰 EDNS UDP 패킷이 단편화로 드롭되는 환경이라면, 리졸버의 EDNS 버퍼 크기를 낮춰(예: 1232바이트) 조기에 TCP 폴백을 유도하거나 경로 MTU 문제를 해결합니다. 캐시 플러시나 nameserver 교체로는 이 문제가 사라지지 않는다는 점이 핵심입니다.


💼
실무 맥락컨테이너·K8s 환경의 DNS 문제 — CoreDNS와 ndots 설정으로 이름 해석 실패 디버깅
현업 패턴

컨테이너·K8s 환경의 DNS 문제 — CoreDNS와 ndots 설정

컨테이너 환경에서는 DNS 문제가 더 복잡해집니다. 호스트 OS의 DNS 설정이 아니라 컨테이너 런타임과 K8s 내부 DNS(CoreDNS)가 별도로 동작합니다.

Docker 컨테이너 DNS 확인

Docker
# 컨테이너 내부에서 /etc/resolv.conf 확인
docker exec -it my-container cat /etc/resolv.conf
# nameserver 127.0.0.11   ← Docker 내부 DNS
# options ndots:0

# 컨테이너 안에서 DNS 질의 테스트
docker exec -it my-container nslookup google.com
docker exec -it my-container dig api.internal.corp

# 컨테이너의 DNS 서버 직접 지정 (런타임 옵션)
docker run --dns 8.8.8.8 --dns 8.8.4.4 my-image

K8s에서 자주 만나는 ndots 문제

K8s Pod의 /etc/resolv.conf에는 기본으로 options ndots:5가 설정됩니다. ndots:5는 도메인에 .(점)이 5개 미만이면 검색 도메인을 먼저 붙여 시도한다는 뜻입니다.

# K8s Pod 내부 /etc/resolv.conf 예시
nameserver 10.96.0.10        ← CoreDNS ClusterIP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

api.example.com을 조회하면 점이 2개라서 5개 미만 → 먼저 아래를 순서대로 시도합니다:

  1. api.example.com.default.svc.cluster.local
  2. api.example.com.svc.cluster.local
  3. api.example.com.cluster.local
  4. 실패 후 api.example.com (원래 이름)

외부 도메인 조회마다 불필요한 CoreDNS 질의가 3~4번 추가로 발생합니다. 고트래픽 서비스에서 CoreDNS 부하 원인이 됩니다.

Kubernetes
# K8s에서 CoreDNS 상태 확인
kubectl -n kube-system get pods -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50

# Pod DNS 설정 확인
kubectl exec -it my-pod -- cat /etc/resolv.conf

# ndots 줄이기 (Pod spec에서)
# dnsConfig:
#   options:
#     - name: ndots
#       value: "2"

# 외부 도메인을 절대 이름으로 조회 (ndots 우회)
# 코드에서 api.example.com. 처럼 끝에 점을 붙이거나
# ndots:1 로 줄이면 불필요한 질의를 줄일 수 있음

CoreDNS가 특정 도메인을 못 찾을 때

Kubernetes
# CoreDNS 설정(ConfigMap) 확인
kubectl -n kube-system get configmap coredns -o yaml

# forward 플러그인: 클러스터 외부 도메인을 어디로 보낼지 확인
# forward . /etc/resolv.conf  → 노드의 DNS로 전달
# forward . 8.8.8.8           → 구글 DNS로 전달

컨테이너 DNS 문제는 대부분 세 가지 중 하나입니다: 호스트 DNS 설정 → Docker 데몬 DNS 설정 → K8s CoreDNS 설정. 어느 레이어인지 먼저 특정하고, 그 레이어에서 dignslookup으로 재현하면 빠르게 좁힐 수 있습니다.


명령어·단축키 빠른 참조

이 모듈에서 다룬 DNS 진단 명령을 실전 옵션과 함께 모았습니다.

명령어/단축키용도자주 쓰는 예
digDNS 조회 상세dig @8.8.8.8 api.example.com +short
dig +traceRoot→Authoritative 위임 추적dig +trace api.example.com
dig +tcp / +dnssecTCP 폴백·큰 응답 확인dig +tcp example.com(무응답이면 TCP 53 차단)
dig <타입> / -x레코드 타입·역방향 조회dig example.com MX, dig -x 93.184.216.34
resolvectl statussystemd-resolved DNS 설정resolvectl status eth0(per-link DNS)
resolvectl queryresolved 경유 이름 조회resolvectl query api.example.com
resolvectl flush-cachesDNS 캐시 비우기레코드 변경 후 스테일 캐시 제거
getent hostsNSS 경로(앱이 쓰는 길)로 조회getent hosts api.example.com
cat /etc/resolv.conf현재 리졸버 확인ls -la /etc/resolv.conf(stub 링크 여부)
grep ^hosts: /etc/nsswitch.conf해석 순서(files→dns) 확인/etc/hosts가 가로채는지 점검
nmcli dev showRHEL 계열 DNS 설정 확인nmcli dev show | grep DNS
ss -ulnp | grep 53127.0.0.53 리스닝 확인resolved 포트 열림 여부
tcpdump port 53DNS 패킷 실시간 확인sudo tcpdump -i any -n port 53
ln -sf / readlink -fresolv.conf 링크 복원·확인sudo ln -sf …/stub-resolv.conf /etc/resolv.conf

관련 모듈로 더 깊이:

다음 모듈에서는 포트와 네트워크 진단 — ss, netstat, lsof, nmap으로 열린 포트를 확인하고 서비스 연결 문제를 추적하는 방법을 다룹니다.

지식 확인

퀴즈 — 10문제

Q1

resolvectl query api.example.com 명령이 실패했지만 dig @8.8.8.8 api.example.com은 성공했다. 원인으로 가장 가능성 높은 것은?

Q2

dig api.internal.corp 결과가 'status: NXDOMAIN'일 때와 'status: SERVFAIL'일 때 의미하는 것의 차이는?

Q3

Ubuntu 22.04에서 /etc/resolv.conf가 심볼릭 링크인 이유와, 이 링크를 실제 파일로 교체할 때 발생하는 문제는?

Q4

ping myhost는 되는데 dig myhost는 NXDOMAIN이다. /etc/nsswitch.conf의 hosts가 'files dns'일 때 가능한 설명은?

Q5

DNS 레코드를 바꿨는데 앱이 여전히 옛 IP로 접속한다. systemd-resolved 환경에서의 1차 조치는?

Q6

dig api.example.com 출력에서 ANSWER SECTION이 비어 있고 AUTHORITY SECTION에 SOA 레코드만 있다. 의미는?

Q7

[심화] 대부분의 도메인은 잘 풀리는데 DNSSEC이 적용된 특정 도메인만 간헐적으로 실패합니다. DNS 전송 계층에서 그 원인이 될 수 있는 것은?

Q8

[심화] 특정 도메인만 이따금 SERVFAIL이나 timeout이 나고, dig +tcp 로 질의하면 아예 응답이 없습니다. 가장 가능성 높은 원인과 조치는?

Q9

[1급] IP 203.0.113.25의 역방향(PTR) 조회를 dig로 하려 합니다. 질의해야 할 이름과 레코드 타입으로 옳은 것은?

Q10

[1급] 도메인 최상위(apex, example.com)에 이미 MX·NS 레코드가 있는 상태에서 CNAME으로 CDN을 가리키게 하려 하자 영역(zone) 로드가 실패했습니다. 원인으로 옳은 것은?

0 / 10 답변

🧪 실습으로 확인하기

새 서버 인수인계 — 처음 30분

초급

낯선 Linux 서버를 인수받았을 때 OS, 서비스, 로그를 빠르게 파악하는 루틴을 직접 수행한다.

30📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요