- Published on
EKS에서 Pod DNS만 느릴 때 ndots·search 튜닝
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버나 노드(EC2)에서 dig는 즉시 응답하는데, EKS Pod 안에서만 외부 도메인 조회가 느려지는 경우가 있습니다. 특히 curl https://api.example.com 같은 호출이 첫 요청에서만 1~3초씩 지연되거나, 애플리케이션 로그에 getaddrinfo 지연이 반복된다면 대부분 DNS 질의가 불필요하게 여러 번 발생하고 있을 확률이 큽니다.
이 글은 그중에서도 가장 흔한 원인인 ndots·search(search domain) 설정으로 인한 조회 폭증을 빠르게 확인하고, EKS에서 안전하게 튜닝하는 실전 절차를 다룹니다. (간헐 실패/타임아웃이 동반된다면 NodeLocal DNSCache도 함께 고려하세요: EKS NodeLocal DNSCache로 DNS 간헐 실패 잡기)
증상: “Pod만 느리다”의 전형적인 패턴
다음 패턴이면 ndots/search 문제를 의심할 가치가 큽니다.
- 노드에서
dig api.example.com은 1030ms인데, Pod에서 동일 질의가 500ms수 초 - 애플리케이션이 FQDN을 쓰는데도 DNS lookup이 여러 번 발생
- CoreDNS 로그에 NXDOMAIN이 많이 찍힘(특히
svc.cluster.local같은 suffix가 붙은 형태) - VPC DNS, Route53 Resolver, 외부 DNS 장애가 아닌데도 지연
원리는 간단합니다.
ndots값이 크면(예: 5)api.example.com같은 이름도 **“상대 도메인일 수 있다”**고 판단- 그래서
search리스트(예:default.svc.cluster.local,svc.cluster.local,cluster.local,ap-northeast-2.compute.internal등)를 붙여가며 여러 번 질의 - 앞의 질의들이 NXDOMAIN/timeout이면 그만큼 지연이 누적
1분 진단: Pod의 resolv.conf 확인
먼저 문제 Pod에서 /etc/resolv.conf를 확인합니다.
kubectl exec -it deploy/myapp -- cat /etc/resolv.conf
EKS 기본에 가까운 예시는 대략 아래처럼 보입니다(클러스터/네임스페이스에 따라 다름).
nameserver 10.100.0.10
search default.svc.cluster.local svc.cluster.local cluster.local ap-northeast-2.compute.internal
options ndots:5
여기서 핵심은 두 가지입니다.
options ndots:5search ...에 여러 suffix가 존재
ndots:5는 “점(.)이 5개 미만이면 search를 붙여 먼저 시도”라는 의미에 가깝습니다. 즉 api.example.com(점 2개)은 search 후보로 간주되어 다음처럼 질의가 늘어납니다.
api.example.com.default.svc.cluster.localapi.example.com.svc.cluster.localapi.example.com.cluster.localapi.example.com.ap-northeast-2.compute.internal- 마지막에야
api.example.com(절대 이름) 질의
각 단계가 50~200ms만 먹어도 체감은 “DNS가 느리다”가 됩니다.
왜 EKS에서 ndots가 크게 잡히는가?
Kubernetes는 서비스 디스커버리 편의성을 위해 search 도메인을 적극적으로 사용합니다.
redis만 써도redis.default.svc.cluster.local을 찾게 해줌- 네임스페이스 내 서비스는
redis처럼 짧은 이름으로 접근 가능
이 편의가 외부 FQDN 조회에는 비용이 됩니다. 특히 다음 환경에서 악화됩니다.
- 애플리케이션이 외부 호출을 많이 함(SSO, 결제, STS, OpenSearch 등)
- 첫 질의가 캐시되기 전까지 호출이 몰림(스파이크)
- NXDOMAIN 응답이 느리거나(상위 DNS/경로 문제), 일부 suffix가 timeout
STS/외부 엔드포인트와 섞여 “네트워크 타임아웃”처럼 보일 때도 있습니다. 예를 들어 IRSA/STS 호출이 느릴 때 DNS가 원인인 케이스가 있어 함께 점검하면 좋습니다: EKS Pod STS AssumeRole 타임아웃 - NAT·PrivateLink·DNS
빠른 재현: ndots/search가 만드는 질의 폭증 보기
방법 A: dig로 추적
+trace는 내부 DNS에서 의미가 제한적일 수 있으니, 우선 단순 질의 시간과 응답을 봅니다.
kubectl exec -it deploy/myapp -- sh -c 'time dig +tries=1 +timeout=1 api.example.com A'
그리고 search를 붙인 이름이 실제로 질의되는지 CoreDNS 로그에서 확인합니다.
방법 B: CoreDNS 로그로 NXDOMAIN 확인
CoreDNS에 로그를 잠시 켜고(운영에서는 짧게), svc.cluster.local로 붙은 NXDOMAIN이 폭증하는지 봅니다.
kubectl -n kube-system edit configmap coredns
Corefile에서 log 플러그인을 잠깐 활성화:
.:53 {
log
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
}
이후 Pod에서 외부 FQDN을 몇 번 호출해보고, CoreDNS 로그에 다음 같은 형태가 반복되면 거의 확정입니다.
api.example.com.default.svc.cluster.local NXDOMAINapi.example.com.svc.cluster.local NXDOMAIN
해결 전략: “클러스터 서비스 편의”와 “외부 FQDN 성능”의 균형
정답은 하나가 아닙니다. 워크로드 특성에 따라 Pod 단위로 조정하는 것이 안전합니다.
옵션 1) ndots를 낮춘다(가장 효과적)
외부 FQDN 호출이 많고, 서비스 이름을 짧게 쓰는 패턴이 적다면 ndots:1~2로 낮추는 것만으로도 체감이 크게 좋아집니다.
ndots:5→ndots:1:api.example.com같은 이름을 빠르게 “절대 이름”으로 취급- 내부 서비스 호출은
redis처럼 점이 없는 이름이므로 여전히 search를 타게 됨
Pod spec에 dnsConfig로 적용
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
dnsPolicy: ClusterFirst
dnsConfig:
options:
- name: ndots
value: "1"
- name: timeout
value: "1"
- name: attempts
value: "2"
containers:
- name: app
image: public.ecr.aws/docker/library/nginx:stable
ndots=1은 보수적으로도 많이 쓰는 값입니다.timeout/attempts는 “느린 NXDOMAIN/timeout” 상황에서 대기 시간을 줄이지만, 너무 공격적으로 낮추면 일시적 네트워크 지터에 취약해질 수 있습니다. 운영에서는timeout=1~2,attempts=2정도부터 시작하는 편이 무난합니다.
적용 후 Pod에서 다시 확인:
kubectl rollout restart deploy/myapp
kubectl exec -it deploy/myapp -- cat /etc/resolv.conf
옵션 2) search 리스트를 줄인다(신중히)
search를 줄이면 불필요한 suffix 시도 자체가 줄어 효과가 있지만, 클러스터 내부 서비스 해석에 영향이 있을 수 있습니다.
- 예:
redis를redis.default또는 FQDN으로 쓰도록 강제할 수 있음
그래도 특정 워크로드가 외부 호출 전용(예: outbound-only gateway/agent)이라면 search를 최소화하는 것이 합리적입니다.
spec:
dnsPolicy: ClusterFirst
dnsConfig:
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "1"
ap-northeast-2.compute.internal 같은 노드/서브넷 환경의 search suffix는 케이스에 따라 큰 의미가 없고, 외부 FQDN에 불필요한 시도를 늘릴 수 있습니다.
옵션 3) 애플리케이션에서 FQDN을 “명시적으로” 쓴다
애플리케이션이 내부 서비스를 redis처럼 짧게 쓰고 있다면, 외부 호출과 섞일 때 디버깅이 어려워집니다. 다음처럼 정책을 정하면 튜닝과 운영이 쉬워집니다.
- 내부:
redis.default.svc.cluster.local또는 최소redis.default - 외부: 항상 FQDN
다만 이 방식은 코드/설정 변경이 필요합니다.
튜닝 후 검증 체크리스트
1) 외부 FQDN lookup 시간 비교
kubectl exec -it deploy/myapp -- sh -c 'for i in 1 2 3; do time getent hosts api.example.com >/dev/null; done'
- 첫 번째가 특히 빨라졌는지 확인
- 여전히 첫 요청이 느리면 DNS 캐시 계층(CoreDNS cache, NodeLocal DNSCache, 애플리케이션 캐시)을 점검
2) 내부 서비스 해석 영향 확인
kubectl exec -it deploy/myapp -- sh -c 'getent hosts kubernetes.default.svc.cluster.local && getent hosts kubernetes'
kubernetes(짧은 이름)도 의도대로 해석되는지 확인
3) CoreDNS 지표/로그에서 NXDOMAIN 감소 확인
NXDOMAIN비율이 줄어드는지- 특정 suffix로 timeout이 나던 패턴이 사라지는지
운영 팁: 어디까지를 “표준”으로 둘 것인가
- 클러스터 전체 기본값을 바꾸기보다, 우선은 문제 워크로드에만 Pod 단위 dnsConfig 적용이 안전합니다.
- 외부 호출이 많은 워크로드(예: API 서버, 배치, STS/외부 SaaS 연동)는
ndots=1이 체감 개선이 큽니다. - DNS가 “느린” 수준을 넘어 간헐 실패/타임아웃이 섞이면, ndots 튜닝만으로는 부족할 수 있고 NodeLocal DNSCache, CoreDNS 리소스/스케일, upstream resolver 경로(NAT/PrivateLink)까지 같이 봐야 합니다.
자주 하는 실수
ndots를 0으로 둔다?
일반적으로 ndots는 0을 권장하지 않습니다(구현/동작이 런타임/라이브러리에 따라 미묘할 수 있고, 디버깅 난이도가 올라갑니다). 1이 현실적인 하한선인 경우가 많습니다.
search를 과감히 다 지운다?
search를 없애면 redis 같은 짧은 서비스 이름 해석이 깨질 수 있습니다. “외부 전용 Pod”처럼 영향 범위가 명확할 때만 제한적으로 적용하세요.
timeout/attempts를 너무 낮춰 장애를 만든다
timeout=1 attempts=1은 평시엔 빨라 보이지만, 네트워크 지터가 있는 순간부터 앱이 DNS 실패를 더 자주 경험할 수 있습니다. 성능과 안정성의 균형이 필요합니다.
결론
EKS에서 “Pod DNS만 느린” 문제는 복잡한 네트워크 이슈처럼 보이지만, 실제로는 ndots:5 + 긴 search 리스트가 외부 FQDN 조회를 여러 번 시도하게 만들어 발생하는 경우가 매우 흔합니다.
가장 안전하고 효과적인 첫 처방은 문제 Pod에 한해 ndots=1로 낮추는 것입니다. 이후에도 간헐 실패가 남거나 CoreDNS 부하가 크다면 NodeLocal DNSCache 같은 캐시 계층을 추가로 검토하세요(EKS NodeLocal DNSCache로 DNS 간헐 실패 잡기).