CoreDNS Pod가 Running인데 이름 해석이 안 된다면, 내부와 외부를 먼저 가른다
DNS 실패는 “CoreDNS가 죽었나”보다 “무엇을 해석하다 실패했나”로 갈라야 빠르다. 클러스터 내부 이름과 외부(업스트림) 이름은 경로가 완전히 다르다.
kubectl run dnstest --rm -it --image=busybox:1.36 --restart=Never -- sh -c \
'nslookup kubernetes.default; echo ---; nslookup example.com'
- 내부(kubernetes.default)만 실패 → CoreDNS 서비스/설정 문제.
- 외부(example.com)만 실패 → 업스트림(forward) 또는 노드 DNS 문제.
- 둘 다 느리거나 간헐 실패 → 아래 ndots 함정을 먼저 의심한다.
가장 많이 밟는 함정: ndots:5와 search 도메인
Pod의 /etc/resolv.conf에는 보통 options ndots:5와 여러 search 도메인이 들어간다. 그래서 api.example.com처럼 점이 5개 미만인 이름은 외부로 나가기 전에 api.example.com.<ns>.svc.cluster.local 등 search 도메인부터 차례로 시도한다. 이 헛질의 때문에 해석이 느려지거나, 그 조합이 우연히 응답하면 엉뚱한 곳으로 간다. 확실한 외부 도메인은 끝에 점을 붙여(api.example.com.) FQDN으로 만들면 search를 건너뛴다.
업스트림(forward) 확인
kubectl -n kube-system get configmap coredns -o yaml # Corefile 의 forward . ... 확인
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100
Corefile의 forward . /etc/resolv.conf는 노드의 resolv.conf를 따라간다. 노드 자체 DNS가 흔들리면 클러스터 전체 외부 해석이 같이 흔들린다. NodeLocal DNSCache를 쓴다면 그 캐시 경로도 함께 본다.
막힘이 정책이라면
NetworkPolicy가 kube-system의 kube-dns로 가는 53번(UDP·TCP 둘 다)을 막고 있지 않은지 확인한다. UDP만 열고 TCP를 막으면 응답이 큰 질의에서만 실패하는, 재현이 까다로운 형태가 된다.
정리
내부/외부 분리 → ndots·search(FQDN 끝점) → forward 업스트림 → 53/UDP·TCP 정책. “CoreDNS가 Running”이라는 사실은 진단의 시작이지 결론이 아니다.
빠른 진단 체크리스트
- 내부(kubernetes.default)와 외부(example.com) 해석을 나눠 테스트한다
- 내부만 실패면 CoreDNS 서비스·Corefile, 외부만 실패면 업스트림이다
- 느리거나 간헐 실패면 ndots·search 도메인을 먼저 의심한다
- 확실한 외부 도메인은 끝에 점을 붙여 FQDN으로 search를 건너뛴다
- Corefile의 forward가 노드 resolv.conf를 따르는지 확인한다
- NodeLocal DNSCache를 쓰면 그 캐시 경로도 본다
- NetworkPolicy가 kube-dns 53/UDP·TCP를 막는지 확인한다
- UDP만 열고 TCP를 막으면 큰 응답에서만 실패한다