Published on

EKS CoreDNS 장애? DNS 타임아웃 8단계

Authors

서버가 멀쩡한데 애플리케이션만 간헐적으로 i/o timeout, Temporary failure in name resolution, SERVFAIL을 뿜는 순간이 있습니다. 특히 EKS에서는 이 증상이 CoreDNS 자체 장애처럼 보이지만, 실제로는 네트워크 경로, 업스트림 리졸버, 노드/파드 리소스 압박, conntrack 포화, 보안그룹/네트워크 정책, 심지어는 애플리케이션의 DNS 사용 방식까지 다양한 지점에서 터집니다.

이 글은 “CoreDNS 장애인가?”를 8단계로 쪼개 빠르게 결론을 내리는 절차입니다. 각 단계는 관측(증거)조치(복구/개선) 로 구성했고, 바로 실행 가능한 커맨드와 설정 예시를 포함합니다.

관련해서 AWS 인증/호출 레벨 이슈가 동반되는 경우도 많습니다. 예를 들어 IRSA는 정상인데 STS 호출이 과도하게 발생해 장애로 확대되는 케이스는 아래 글도 같이 보면 좋습니다.

0) 먼저 증상을 분류한다: “어디서” 타임아웃인가

DNS 문제는 크게 3가지로 나뉩니다.

  1. 파드에서 CoreDNS까지 질의가 못 감 (클러스터 내부 경로 문제)
  2. CoreDNS에서 업스트림(예: VPC Resolver) 으로 포워딩이 못 감 (VPC/DNS/네트워크 문제)
  3. 업스트림은 되는데 응답이 느리거나 캐시/부하로 드랍 (리소스/튜닝 문제)

가장 먼저 “파드에서 어떤 DNS 서버로 질의하는지”부터 확인합니다.

kubectl exec -it -n <namespace> <pod> -- cat /etc/resolv.conf

여기서 nameserver가 보통 CoreDNS 서비스 IP(예: 172.20.0.10)를 가리킵니다. 이 값이 비정상(다른 IP, 외부 DNS 등)이라면 CoreDNS 문제가 아니라 Pod DNS 설정/런타임/네트워크 문제일 가능성이 큽니다.


1단계) CoreDNS 파드/엔드포인트가 “살아있는지”부터 확인

CoreDNS가 죽었거나 엔드포인트가 비어 있으면, 애플리케이션은 대체로 즉시 타임아웃을 겪습니다.

kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
kubectl get svc -n kube-system kube-dns -o wide
kubectl get endpoints -n kube-system kube-dns -o wide

관측 포인트:

  • CrashLoopBackOff, ImagePullBackOff, Pending 여부
  • endpoints가 비어 있는지
  • CoreDNS 파드가 특정 노드에만 몰려 있는지

조치:

  • 파드가 죽는다면 로그부터 봅니다.
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=200
  • 엔드포인트가 비어 있으면 디플로이/레이블/셀렉터가 꼬였을 수 있습니다. kube-dns 서비스의 selector가 CoreDNS 파드 레이블과 매칭되는지 확인합니다.

2단계) “파드에서 CoreDNS까지” 네트워크가 열려 있는지 검사

CoreDNS 서비스 IP로 UDP/TCP 53이 막히면 전형적인 타임아웃이 납니다. 네트워크 정책, 보안그룹, CNI 이슈가 원인일 수 있습니다.

테스트는 디버그 파드로 합니다.

kubectl run -it --rm dns-debug --image=busybox:1.36 --restart=Never -- sh

디버그 파드 안에서:

nslookup kubernetes.default.svc.cluster.local
nslookup google.com

추가로 CoreDNS 서비스 IP로 직접 질의해 경로를 분리합니다.

nslookup kubernetes.default.svc.cluster.local 172.20.0.10

관측 포인트:

  • 특정 네임스페이스/파드에서만 실패하면 NetworkPolicy 가능성이 큽니다.
  • UDP만 실패하고 TCP는 되는 경우도 있습니다(중간 장비/정책).

조치:

  • 네임스페이스에 NetworkPolicy가 있다면 DNS 예외(UDP/TCP 53)를 명시합니다.
  • 보안그룹을 파드 단위로 쓰는 환경(보안그룹 for 파드)을 사용한다면, CoreDNS로의 egress가 막히지 않았는지 확인합니다.

3단계) CoreDNS 로그에서 “업스트림 타임아웃” 패턴을 찾는다

CoreDNS가 살아 있는데도 타임아웃이면, CoreDNS가 업스트림으로 포워딩하다 막히는 경우가 많습니다.

CoreDNS 설정을 확인합니다.

kubectl get configmap -n kube-system coredns -o yaml

대표적으로 이런 블록이 있습니다.

forward . /etc/resolv.conf

CoreDNS 로그에서 자주 보이는 신호:

  • plugin/errors와 함께 i/o timeout
  • upstream 관련 메시지
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=500 | grep -E "timeout|SERVFAIL|upstream|error"

조치:

  • 업스트림이 /etc/resolv.conf를 통해 VPC Resolver로 가는지 확인합니다.
  • VPC Resolver(일반적으로 VPC CIDR의 +2 주소)로의 네트워크가 막혔거나, 노드의 DNS 설정이 꼬였을 수 있습니다.

4단계) VPC Resolver 및 라우팅/보안그룹을 점검

EKS에서 CoreDNS의 업스트림은 보통 VPC DNS(예: 10.0.0.2)입니다. 이 경로가 막히면 CoreDNS가 외부 도메인 질의에서 타임아웃을 냅니다.

검증 방법(노드에서 직접 확인하는 게 가장 빠름):

  • 노드에 SSM이나 SSH로 접속 가능하다면
cat /etc/resolv.conf
nslookup amazonaws.com 10.0.0.2

관측 포인트:

  • 특정 AZ/서브넷의 노드에서만 실패하면 라우팅/네트워크 ACL/보안그룹이 의심됩니다.
  • NAT 게이트웨이 장애는 주로 “외부로 나가는 트래픽” 문제지만, VPC Resolver 자체는 VPC 내부이므로 NAT와는 분리해서 봐야 합니다.

조치:

  • 서브넷 라우팅 테이블, NACL, 보안그룹 egress에서 VPC DNS로 UDP/TCP 53이 허용되는지 확인합니다.
  • VPC에서 enableDnsHostnames, enableDnsSupport가 꺼져 있지 않은지 점검합니다.

5단계) CoreDNS 리소스 압박과 HPA/스케일링 확인

CoreDNS는 트래픽이 몰리면 CPU가 치솟고 응답이 지연되며, 결국 타임아웃처럼 보입니다. 특히 트래픽 급증 시 “정확히 CoreDNS만 느려짐”이 발생합니다.

kubectl top pods -n kube-system -l k8s-app=kube-dns
kubectl describe pod -n kube-system -l k8s-app=kube-dns

관측 포인트:

  • CPU throttling(리밋이 낮아 스로틀링) 여부
  • 메모리 부족으로 OOMKilled 여부
  • 파드 수가 트래픽에 비해 너무 적은지

조치:

  • CoreDNS 리소스 요청/제한을 현실적으로 조정합니다.
  • HPA를 고려합니다(다만 CoreDNS는 안정성이 중요하므로 급격한 스케일 변동도 리스크입니다).
  • CoreDNS 파드가 한 노드에 몰리지 않도록 anti-affinity를 설정합니다.

예시(개념 코드):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
spec:
  template:
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    k8s-app: kube-dns
                topologyKey: kubernetes.io/hostname

6단계) conntrack 포화로 UDP 드랍이 나는지 확인

DNS는 UDP 기반이 많고, 노드의 conntrack 테이블이 포화되면 UDP 패킷이 드랍되어 “간헐적 DNS 타임아웃”이 발생합니다. 이건 CoreDNS를 아무리 늘려도 해결이 안 됩니다.

관측 포인트:

  • 노드 커널 로그에 드랍 메시지가 있는지
  • conntrack 사용량이 상한에 근접하는지

노드에서 확인(예시):

sudo sysctl net.netfilter.nf_conntrack_max
sudo cat /proc/sys/net/netfilter/nf_conntrack_count
sudo dmesg | grep -i conntrack

조치:

  • 워크로드 트래픽 특성에 맞게 nf_conntrack_max를 상향
  • 커넥션을 과도하게 만드는 앱(짧은 주기의 outbound)을 튜닝
  • 노드 스케일 아웃(노드당 conntrack 부담 분산)

7단계) NodeLocal DNSCache로 “노드 단 캐시”를 붙여 변동성을 줄인다

CoreDNS가 정상이어도 네트워크 지터나 순간 부하로 타임아웃이 나면, 노드 로컬 캐시가 체감 장애를 크게 줄입니다. AWS/EKS에서도 흔히 권장되는 패턴입니다.

핵심 아이디어:

  • 파드는 노드 로컬 IP로 DNS 질의
  • 노드 로컬 캐시가 CoreDNS로 포워딩
  • 캐시 히트 시 CoreDNS/업스트림 부담 감소

조치:

  • NodeLocal DNSCache 데몬셋을 적용하고, kubelet --cluster-dns 또는 파드 DNS 설정이 노드 로컬을 보도록 구성합니다.

적용 후에는 파드의 /etc/resolv.confnameserver가 노드 로컬 주소로 바뀌는지 확인합니다.

kubectl exec -it -n <namespace> <pod> -- cat /etc/resolv.conf

8단계) 애플리케이션 레벨 DNS 사용 습관을 점검한다

마지막 단계지만, 실제 현장에서는 이 비중이 큽니다. CoreDNS가 “원인”이 아니라 “증폭기”인 경우가 많습니다.

대표적인 문제 패턴:

  • 짧은 주기로 매 요청마다 DNS lookup을 강제(커넥션 풀/keep-alive 미사용)
  • JVM/언어 런타임의 DNS 캐시 TTL이 0 또는 지나치게 짧음
  • 서비스 디스커버리 이름을 잘못 사용(불필요한 FQDN 반복)

관측 포인트:

  • 애플리케이션 지표에서 outbound 커넥션 생성률이 비정상적으로 높은지
  • DNS 질의량이 트래픽 대비 과도한지(CoreDNS metrics 사용)

CoreDNS에 Prometheus 메트릭이 켜져 있다면, CoreDNS Corefileprometheus 플러그인이 있는지 확인하고, 질의량/에러율을 봅니다.

prometheus :9153

조치:

  • HTTP keep-alive, 커넥션 풀 적용
  • SDK 재시도 정책이 DNS 실패를 폭증시키지 않도록 제한
  • 필요 시 애플리케이션 내부 캐시/리졸브 전략 개선

이 과정에서 AWS API 호출이 과도해져 장애가 커지는 경우(예: STS 호출 폭증)는 아래 글의 패턴과도 연결됩니다.


실전 복구 체크리스트(요약)

장애 대응 중에는 “정밀 분석”보다 “빠른 복구”가 우선일 때가 많습니다. 아래 순서대로 보면 대부분의 DNS 타임아웃은 10~30분 내로 방향이 잡힙니다.

  1. endpoints가 비었는지 확인하고 CoreDNS 파드 상태 확인
  2. 디버그 파드에서 nslookup으로 클러스터 도메인과 외부 도메인을 각각 테스트
  3. CoreDNS 로그에서 업스트림 타임아웃 패턴 확인
  4. 노드에서 VPC Resolver로 직접 질의해 네트워크 경로 분리
  5. CoreDNS CPU throttling/OOM 여부 확인 후 스케일/리소스 조정
  6. 노드 conntrack 포화 여부 확인
  7. NodeLocal DNSCache 도입으로 변동성 완화
  8. 애플리케이션의 커넥션 풀/DNS 캐시/재시도 정책 점검

마무리: “CoreDNS 장애”라는 결론을 서두르지 말자

EKS에서 DNS 타임아웃은 CoreDNS가 가장 눈에 띄는 컴포넌트라서 쉽게 희생양이 됩니다. 하지만 실제로는 경로(파드 -> CoreDNS -> 업스트림) 중 어디가 끊겼는지 분해해서 봐야 재발을 막을 수 있습니다. 위 8단계를 그대로 실행하면, 장애의 위치가 최소한 “클러스터 내부”, “업스트림/VPC”, “리소스/튜닝”, “애플리케이션” 중 하나로 빠르게 수렴합니다.

다음 액션으로는 CoreDNS 메트릭 대시보드(질의량, 에러율, 레이턴시), 노드 conntrack/네트워크 드랍 모니터링, 그리고 NodeLocal DNSCache 표준화까지 묶어두면 같은 유형의 장애가 훨씬 덜 아프게 지나갑니다.