Kubernetes Pod DNS 실패(CoreDNS) 5분 진단: can't resolve & Temporary failure
K8s_Troubleshooting_Guide 8편
"어제까지 멀쩡하던 Pod가 갑자기 서비스명도 외부 도메인도 못 푼다." 운영하다 보면 한 번쯤 만나는 장애입니다. 애플리케이션 로그에는 connection refused나 i/o timeout만 찍혀서 마치 네트워크/통신 장애처럼 보이지만, 실제 원인은 DNS 해석 실패인 경우가 의외로 많습니다. 이름을 IP로 못 바꾸니 그 다음 통신은 당연히 전부 실패하는 거죠.
이번 편은 DNS 계층 하나에만 집중합니다. 영문 에러 원문을 보고 "클러스터 내부 / 외부 도메인 / 부분 실패" 중 어디인지 즉시 분류하고, 복붙 가능한 5단계 명령어로 5분 안에 원인을 좁히는 것이 목표입니다.
1. 에러 원문부터 분류하자
DNS 실패는 에러 메시지만 봐도 의심 계층을 절반 이상 좁힐 수 있습니다.
| 에러 메시지 원문 | 의미 | 의심 계층 | 우선 점검 |
|---|---|---|---|
nslookup: can't resolve 'kubernetes.default' | 클러스터 내부 서비스조차 못 푼다 | CoreDNS 다운 / resolv.conf 잘못 / 53 차단 | 2~5단계 전부 |
server can't find <domain>: NXDOMAIN | 도메인이 실제로 없거나 search 도메인 오조합 | resolv.conf / ndots | 4단계 |
server can't find <domain>: SERVFAIL | upstream resolver가 응답 실패 | CoreDNS forward / upstream | 3·4단계 |
Temporary failure in name resolution | 애초에 DNS 서버에 도달조차 못함(소켓 레벨) | resolv.conf 없음 / 53 차단 / 노드 네트워크 | 4·5단계 |
| 내부는 되는데 외부만 느리거나 실패 | search list를 다 거치며 지연 | ndots:5 / upstream | 4단계 |
정리하면 내부 서비스까지 다 안 되면 CoreDNS 자체나 DNS 경로 문제, 외부만 안 되면 ndots/upstream, 특정 도메인만 안 되면 NetworkPolicy나 search 도메인 조합을 의심합니다.
2. 5단계 복붙 진단 명령어
① dnsutils 임시 Pod로 직접 조회
kubectl run -it --rm dnsutils \
--image=registry.k8s.io/e2e-test-images/agnhost:2.39 \
-- nslookup kubernetes.default정상 출력:
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1비정상 출력:
;; connection timed out; no servers could be reached
# 또는
nslookup: can't resolve 'kubernetes.default'Server: 10.96.0.10(kube-dns ClusterIP)이 응답하면 DNS 경로는 살아있는 겁니다. timed out이면 53 트래픽이 막혔거나 CoreDNS가 죽은 것.
② CoreDNS Pod 상태
kubectl get pods -n kube-system -o wide | grep corednsRunning에 READY 1/1이 보통 2개 이상이어야 정상입니다. CrashLoopBackOff, Pending, 0/1, 혹은 replica가 0이면 그게 곧 원인입니다.
③ CoreDNS 로그
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50[ERROR] plugin/errors ... SERVFAIL, i/o timeout이 upstream 쪽으로 찍히면 forward 설정/외부 resolver 문제입니다.
④ Pod의 resolv.conf 확인
kubectl exec -it dnsutils -- cat /etc/resolv.conf정상 예시:
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5nameserver가 비어 있거나 노드의 외부 DNS(예: 168.126.63.1)만 박혀 있으면 내부 서비스를 못 풉니다. 파일 자체가 없으면 Temporary failure in name resolution이 뜹니다.
⑤ NetworkPolicy 점검
kubectl get networkpolicy -Aegress를 제한하는 정책이 있는데 kube-system의 53/UDP를 허용하지 않았다면, DNS 패킷이 막혀 connection timed out이 납니다.
3. 왜 외부 도메인이 느릴까 — ndots:5와 search 5단계
Pod의 기본 options ndots:5는 "점(.)이 5개 미만인 이름은 일단 search 도메인을 붙여서 먼저 조회하라"는 뜻입니다. github.com(점 1개)을 조회하면 실제로 다음 순서로 쿼리가 나갑니다.
github.com.default.svc.cluster.local → NXDOMAIN
github.com.svc.cluster.local → NXDOMAIN
github.com.cluster.local → NXDOMAIN
github.com → 성공즉 외부 도메인 하나 푸는 데 쿼리가 4번 나가니 지연이 생기고, UDP 패킷 손실까지 겹치면 간헐적 실패로 보입니다. ClusterIP 서비스를 svc.namespace.svc.cluster.local FQDN(끝에 점 포함)으로 호출하면 search list를 건너뛰어 한 방에 끝납니다.
4. 원인별 해결 레시피
(a) CoreDNS 다운 / replica 0
kubectl scale deployment coredns -n kube-system --replicas=2
kubectl describe pod -n kube-system -l k8s-app=kube-dns # 리소스 부족/OOM 확인(b) ndots:5로 외부 조회가 느림 — Pod에 dnsConfig 추가:
spec:
dnsConfig:
options:
- name: ndots
value: "1"ndots를 1로 낮추면 점 있는 외부 도메인은 search 도메인을 거치지 않고 바로 조회합니다.
(c) NetworkPolicy가 53 차단 — DNS egress 허용 정책:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: my-app
spec:
podSelector: {}
policyTypes: ["Egress"]
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53(d) conntrack/iptables UDP race — 노드에서 conntrack -S로 insert_failed 증가를 확인. UDP는 race condition으로 5초 지연(use-vc/단일 요청 손실)이 잘 생깁니다. TCP 강제(options use-vc)나 NodeLocal DNSCache가 답입니다.
(e) CoreDNS upstream 오설정 — Corefile의 forward 확인:
forward . /etc/resolv.conf {
max_concurrent 1000
}사내망이라면 외부 resolver를 직접 지정합니다: forward . 10.0.0.2 8.8.8.8. 수정 후 kubectl rollout restart deployment/coredns -n kube-system.
5. 실무 한마디 + 근본 완화책
경험상 "DNS가 가끔 느리다"는 신고의 상당수는 (b) ndots와 (d) UDP race의 합작입니다. 한두 개 Pod만 패치하기보다 클러스터 전체 차원에서 NodeLocal DNSCache를 도입하는 걸 권합니다. 각 노드에 캐싱 DNS 에이전트를 띄워 Pod가 노드 로컬 캐시로 먼저 질의하게 만들면, conntrack 경합과 외부 다중 쿼리 부담이 크게 줄어 응답이 안정됩니다. eBPF 기반 CNI(Cilium)를 쓴다면 DNS-aware 정책으로 53 트래픽 제어가 더 깔끔해지니 같이 검토해 보세요.
한 장 요약 체크리스트
- 에러 원문 분류 → 내부 / 외부 / 부분 실패 구분
- dnsutils로
nslookup kubernetes.default→Server: 10.96.0.10응답 여부 - CoreDNS Pod
Running 1/1& replica 확인 - CoreDNS 로그에서 SERVFAIL/timeout 확인
- resolv.conf의 nameserver·ndots·search 점검
- NetworkPolicy 53/UDP 허용 확인
- 안정화는 NodeLocal DNSCache
자주 묻는 질문 (FAQ)
Q. nslookup kubernetes.default는 되는데 외부 도메인만 안 됩니다.
A. CoreDNS의 upstream forward 설정이나 ndots:5 문제일 가능성이 큽니다. CoreDNS 로그에서 SERVFAIL을 확인하고, Corefile의 forward 대상 resolver를 점검하세요. 외부 도메인을 FQDN(끝에 .)으로 조회하거나 dnsConfig로 ndots를 1로 낮추면 즉시 개선됩니다.
Q. Temporary failure in name resolution은 무슨 뜻인가요?
A. DNS 서버에 패킷이 도달조차 못 했다는 소켓 레벨 에러입니다. Pod의 /etc/resolv.conf에 nameserver가 없거나, NetworkPolicy가 kube-dns로 가는 53/UDP를 막았거나, 노드 네트워크/CoreDNS 다운을 의심하세요.
Q. 간헐적으로 DNS가 5초씩 지연됩니다.
A. UDP conntrack race condition이 전형적입니다. 노드에서 conntrack -S로 insert_failed를 확인하고, 근본 해결로 NodeLocal DNSCache 도입을 권장합니다.
다음 편(9편) 예고: "Service에 Endpoint가 안 붙는다 — Service/Endpoint 연결 실패와 selector 미스매치 진단"
이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.
댓글
불러오는 중...