/인프라/Kubernetes Pod DNS 실패(CoreDNS) 5분 진단: can't resolve & Temporary failure
인프라kubernetescoredns

Kubernetes Pod DNS 실패(CoreDNS) 5분 진단: can't resolve & Temporary failure

Kubernetes Pod의 nslookup can't resolve, Temporary failure in name resolution DNS 실패를 CoreDNS·resolv.conf·ndots·NetworkPolicy로 분류해 5단계 복붙 명령어로 진단하고 원인별 해결법까지 정리합니다.

Kubernetes Pod DNS 실패(CoreDNS) 5분 진단: can't resolve & Temporary failure

Kubernetes Pod DNS 실패(CoreDNS) 5분 진단: can't resolve & Temporary failure

K8s_Troubleshooting_Guide 8편

"어제까지 멀쩡하던 Pod가 갑자기 서비스명도 외부 도메인도 못 푼다." 운영하다 보면 한 번쯤 만나는 장애입니다. 애플리케이션 로그에는 connection refusedi/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 / ndots4단계
server can't find <domain>: SERVFAILupstream resolver가 응답 실패CoreDNS forward / upstream3·4단계
Temporary failure in name resolution애초에 DNS 서버에 도달조차 못함(소켓 레벨)resolv.conf 없음 / 53 차단 / 노드 네트워크4·5단계
내부는 되는데 외부만 느리거나 실패search list를 다 거치며 지연ndots:5 / upstream4단계

정리하면 내부 서비스까지 다 안 되면 CoreDNS 자체나 DNS 경로 문제, 외부만 안 되면 ndots/upstream, 특정 도메인만 안 되면 NetworkPolicy나 search 도메인 조합을 의심합니다.

2. 5단계 복붙 진단 명령어

① dnsutils 임시 Pod로 직접 조회

Bash
kubectl run -it --rm dnsutils \
  --image=registry.k8s.io/e2e-test-images/agnhost:2.39 \
  -- nslookup kubernetes.default

정상 출력:

CODE
Server:    10.96.0.10
Address:   10.96.0.10:53
Name:      kubernetes.default.svc.cluster.local
Address:   10.96.0.1

비정상 출력:

CODE
;; 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 상태

Bash
kubectl get pods -n kube-system -o wide | grep coredns

RunningREADY 1/1이 보통 2개 이상이어야 정상입니다. CrashLoopBackOff, Pending, 0/1, 혹은 replica가 0이면 그게 곧 원인입니다.

③ CoreDNS 로그

Bash
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 확인

Bash
kubectl exec -it dnsutils -- cat /etc/resolv.conf

정상 예시:

CODE
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

nameserver가 비어 있거나 노드의 외부 DNS(예: 168.126.63.1)만 박혀 있으면 내부 서비스를 못 풉니다. 파일 자체가 없으면 Temporary failure in name resolution이 뜹니다.

⑤ NetworkPolicy 점검

Bash
kubectl get networkpolicy -A

egress를 제한하는 정책이 있는데 kube-system의 53/UDP를 허용하지 않았다면, DNS 패킷이 막혀 connection timed out이 납니다.

3. 왜 외부 도메인이 느릴까 — ndots:5와 search 5단계

Pod의 기본 options ndots:5는 "점(.)이 5개 미만인 이름은 일단 search 도메인을 붙여서 먼저 조회하라"는 뜻입니다. github.com(점 1개)을 조회하면 실제로 다음 순서로 쿼리가 나갑니다.

CODE
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

Bash
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 추가:

YAML
spec:
  dnsConfig:
    options:
      - name: ndots
        value: "1"

ndots를 1로 낮추면 점 있는 외부 도메인은 search 도메인을 거치지 않고 바로 조회합니다.

(c) NetworkPolicy가 53 차단 — DNS egress 허용 정책:

YAML
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 -Sinsert_failed 증가를 확인. UDP는 race condition으로 5초 지연(use-vc/단일 요청 손실)이 잘 생깁니다. TCP 강제(options use-vc)나 NodeLocal DNSCache가 답입니다.

(e) CoreDNS upstream 오설정 — Corefile의 forward 확인:

CODE
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 트래픽 제어가 더 깔끔해지니 같이 검토해 보세요.

한 장 요약 체크리스트

  1. 에러 원문 분류 → 내부 / 외부 / 부분 실패 구분
  2. dnsutils로 nslookup kubernetes.defaultServer: 10.96.0.10 응답 여부
  3. CoreDNS Pod Running 1/1 & replica 확인
  4. CoreDNS 로그에서 SERVFAIL/timeout 확인
  5. resolv.conf의 nameserver·ndots·search 점검
  6. NetworkPolicy 53/UDP 허용 확인
  7. 안정화는 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 -Sinsert_failed를 확인하고, 근본 해결로 NodeLocal DNSCache 도입을 권장합니다.

다음 편(9편) 예고: "Service에 Endpoint가 안 붙는다 — Service/Endpoint 연결 실패와 selector 미스매치 진단"

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Reviewer·검토 · 사람 편집자·발행 · 2026년 6월 13일

댓글

불러오는 중...