리눅스 네트워크 진단 · 이름 해석 · 이론
getent 와 dig 는 다른 길로 간다
한 줄 요약
getent 는 이름 서비스 스위치를 거치고 dig 는 거치지 않는다. 둘의 결과가 다르면 문제는 DNS 가 아니라 스텁 리졸버 구간이다.
왜 이게 필요했나
"DNS 가 안 됩니다"라는 신고를 받았다. 접속해서 dig api.example.com 을 쳐 보니 잘 나온다. 그런데 애플리케이션은 계속 이름을 못 찾는다고 한다.
여기서 "dig 가 되니까 DNS 는 정상"이라고 결론 내리면 몇 시간을 잃는다. dig 는 애플리케이션이 쓰는 길로 가지 않기 때문이다.
애플리케이션은 glibc 의 getaddrinfo() 를 부르고, glibc 는 /etc/nsswitch.conf 의 hosts: 줄을 보고 어떤 순서로 물어볼지 정한다. 보통 files dns 이므로 /etc/hosts 를 먼저 보고 그다음 DNS 다. 반면 dig 는 이 모든 것을 건너뛰고 /etc/resolv.conf 의 네임서버에 직접 물어본다.
그래서 /etc/hosts 에 잘못된 항목이 있으면 dig 는 정상인데 앱만 틀린 곳으로 간다. 반대로 hosts 에만 있는 이름은 앱은 되는데 dig 는 못 찾는다. 같은 이름을 물어도 두 도구의 답이 다를 수 있다는 사실 자체가 진단 도구다.
어떻게 동작하나
이름 해석은 하나의 시스템이 아니라 성격이 다른 다섯 구간이 이어 붙은 경로다.
1. 애플리케이션 + 스텁 리졸버 - /etc/hosts, /etc/nsswitch.conf, 런타임 자체의 캐시
2. 리졸버 선택 - /etc/resolv.conf
3. 재귀 리졸버 캐시 - 대부분의 질의가 여기서 끝난다
4. 위임 추적 - 루트 -> TLD -> 권한 서버
5. 권한 서버 응답
구간을 나누는 이유는 각 구간을 따로 물어볼 수 있기 때문이다. getent 는 1번을 포함해서 보고, dig 는 2번부터, dig @서버 +norecurse 는 그 리졸버의 캐시만, dig +trace 는 4번을 직접 걷는다. "+trace 는 정상인데 앱은 실패"면 범인은 권한 서버가 아니라 리졸버 구간이다.
/etc/resolv.conf 는 지연의 산수를 결정한다.
nameserver는 최대 3개까지만 쓰인다options timeout:n기본 5초,options attempts:n기본 2회options ndots:n- 이름에 점이 몇 개 이상이어야 검색 도메인 없이 절대 이름으로 먼저 질의할지의 임계값
여기서 두 가지 계산이 나온다. 첫 네임서버가 죽어 있으면 사용자는 기본값 기준 5초를 그대로 체감한다. 그리고 ndots 가 크면 외부 이름 하나를 푸는 데 실패 질의가 여러 번 앞서 나간다 - 컨테이너에서 이름 해석이 느린 전형적인 원인이다. 해결은 의외로 간단하다. 이름 끝에 점을 붙여 절대 이름으로 만드는 것이다.
TTL 과 네거티브 캐싱. DNS 에는 푸시가 없다. 변경이 퍼지는 것이 아니라 캐시가 만료되는 것이다. 그리고 "없다"는 답도 캐시된다. NXDOMAIN(이름 자체가 없음)과 NODATA(이름은 있는데 그 타입만 없음)는 다른 사건이고, 오타 난 레코드를 고쳤는데 한나절 동안 계속 실패하는 상황의 원인은 대개 네거티브 캐시 시간이다.
현장에서 만나는 모습
dig 의 status 를 먼저 읽어라. NOERROR 인데 답 구역이 비면 NODATA 다. SERVFAIL 은 "이름이 없다"가 아니라 "답을 만들지 못했다" 이고, 상위 도달 실패나 DNSSEC 검증 실패를 뜻한다. REFUSED 는 정책상 거부다.
flags 의 aa 한 글자. 이게 없으면 권한 있는 답이 아니라 캐시에서 온 답이다. 권한 서버는 항상 원래 TTL 을 주고, 리졸버는 남은 시간을 준다. 둘이 다른 것은 정상이다.
분할 지평. 사내 DNS 와 외부 DNS 가 같은 이름에 다른 답을 주는 구성에서는 어디서 물었느냐가 답을 바꾼다. 장애 신고를 받을 때 "VPN 에 접속한 상태인가"를 먼저 확인해야 하는 이유다.
마지막 원칙 하나. 이름이 정상적으로 풀리면 그 시점에서 DNS 조사를 종료하고 연결 계층으로 넘어간다. 이름 해석이 되는데 계속 DNS 를 파는 것이 시간 낭비의 대표적인 형태다.
다음 실습에서 할 것
/etc/resolv.conf 와 /etc/nsswitch.conf 를 직접 읽어 스텁 리졸버가 어떻게 동작하는지 확인하고, /etc/hosts 에 항목을 추가해 getent 는 찾고 dig 는 못 찾는 상황을 직접 만든다. 같은 이름을 두 줄로 적어 어느 쪽이 이기는지 확인하고, 마지막에는 이름 해석 결과를 종료 코드로 알려 주는 헬퍼를 작성한다.