CoreDNS 성능 최적화
🚀 Kubernetes DNS 성능 최적화: CoreDNS와 NodeLocalDNS 그리고 ndots 설정 이해하기
쿠버네티스에서 DNS는 중요한 역할을 합니다. 특히 티켓팅 시스템, 게임 서버, 실시간 처리 시스템처럼 요청이 집중되는 서비스에서 CoreDNS 병목이 생길 수 있습니다.
이번 글에서는 CoreDNS와 NodeLocal DNS Cache의 동작 방식을 이해하고, 그 전에 꼭 알아야 할 search 도메인, ndots, FQDN 등에 대해 정리해보겠습니다.
📌 목표
- CoreDNS의 부하 원인을 이해하고
- NodeLocal DNS Cache 도입 전 구조를 파악하며
- DNS 설정(resolv.conf)으로 성능을 향상시킬 수 있는 방법 학습
🔍 A. CoreDNS와 NodeLocalDNS란?
CoreDNS
- 쿠버네티스 클러스터에서 기본적으로 사용되는 DNS 서버
- kube-dns 또는 coredns 서비스로 동작
- 모든 DNS 요청을 처리하는 중앙 허브 역할
NodeLocal DNS Cache
- 노드 로컬에 캐시 DNS 서버를 배포
- CoreDNS 앞단에서 DNS 캐싱 역할 수행
- CoreDNS 부하 감소 + 응답 시간 단축
🔧 B. DNS 기본기 – resolv.conf, search, ndots
1. /etc/resolv.conf 예시
# 파드의 DNS 설정 정보 확인
kubectl exec -it curl-pod -- cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
2. search 도메인이란?
- 상대 도메인을 자동으로 **완전한 도메인(FQDN)**으로 만들어주는 보조 도메인
- nslookup kubernetes 명령을 실행하면, 실제 쿼리는 아래와 같이 변환됨:
kubernetes.default.svc.cluster.local
kubernetes.svc.cluster.local
kubernetes.cluster.local
...
✅ DNS 응답이 NOERROR일 때까지 순차적으로 조회하며, NXDOMAIN이면 다음 search 도메인으로 넘어갑니다.
3. 절대 도메인 vs 상대 도메인
| 절대 도메인 (FQDN) | google.com. | 맨 끝에 .가 붙음 search 도메인 추가 X |
| 상대 도메인 | google.com | ndots 값 기준으로 search 도메인 추가됨 |
✅ 쿼리 시 불필요한 DNS 요청을 줄이려면 FQDN 사용 또는 ndots 값 튜닝이 중요합니다.
4. ndots 옵션이란?
- ndots는 도메인 내 .의 개수에 따라 search 도메인을 붙일지 여부를 결정하는 기준입니다.
예시: ndots:5일 경우?
options ndots:5
- foo.bar.svc.cluster.local → .가 4개 → search 도메인 붙임
- foo.bar.local. → 절대 도메인 (.로 끝나서 붙이지 않음)
⚙️ C. Pod의 DNS 설정 바꾸기
apiVersion: v1
kind: Pod
metadata:
name: dns-example
namespace: default
spec:
containers:
- name: test
image: nginx
dnsPolicy: "None"
dnsConfig:
nameservers:
- 1.2.3.4
searches:
- ns1.svc.cluster-domain.example
- my.dns.search.suffix
options:
- name: ndots
value: "2"
- name: edns0
💡 효과:
- Pod의 /etc/resolv.conf 파일이 위 설정에 맞게 반영됨
- 애플리케이션 코드를 수정하지 않고도 DNS 쿼리 최적화 가능
🚀 D. NodeLocal DNS Cache란?

- Node 단위에 Local DNS 캐시 데몬을 설치
- DNS 쿼리를 CoreDNS까지 보내지 않고, 로컬에서 응답
- 특히 ndots 설정이 높을 때 불필요한 DNS 요청을 캐시로 줄여줌
- 로컬 캐싱 에이전트에서 kube-dns 서비스로의 연결은 TCP로 업그레이드할 수 있습니다. TCP 연결 트랙 항목은 시간 초과를 해야 하는 UDP 항목과 달리 연결 종료 시 제거됩니다(기본값 은 30초)
🔗 설치 참고:
✅ 정리
| search 도메인 | 상대 도메인을 자동 완성해주는 도메인 목록 |
| ndots | 점(.) 개수 기준으로 search 도메인을 붙일지 판단 |
| 절대 도메인 | .로 끝나며, search 도메인 붙지 않음 |
| CoreDNS | 기본 DNS 서버, 중앙 처리 |
| NodeLocalDNS | 노드 캐시 DNS로 부하 감소 및 응답 속도 향상 |
📈 Next 목표
👉 다음은 ndots 값을 변경했을 때 DNS 쿼리 수 변화, NodeLocalDN 설정 방법, 성능 개선 실험 결과를 다룬 글을 추천드립니다. https://themapisto.tistory.com/240
Core DNS 성능개선 [ nodelocaldns / ndots & FQDN ]
먼저 CoreDNS 성능 개선을 위해 여러가지 테스트를 하기전에 CoreDNS와 NodeLocalDNS가 무엇인지, 그리고 그 동작과정에 대해 먼저 알아보겠습니다.이를 이해하기 위해서는 ndots과 search 도메인 , 그리고
themapisto.tistory.com
NodeLocalDNS 실습 + Cilium Local Redirect Policy
🚀 NodeLocalDNS + Cilium Local Redirect Policy
✅ Cilium Local Redirect Policy (LRP)란?
기본 개념
- Cilium의 LocalRedirectPolicy는 특정 IP/포트 조합이나 Kubernetes 서비스로 향하는 트래픽을 해당 노드 내의 백엔드 Pod로만 리디렉션할 수 있도록 해주는 eBPF 기반 정책입니다.
- 즉, 노드를 벗어나지 않고 가능한 경우에 한해 로컬 Pod로 트래픽을 보내는 것입니다.
- 이를 통해 불필요한 cross-node 트래픽을 줄이고, latency를 개선할 수 있습니다.
예시 사용 시나리오
- ClusterIP 서비스가 있고, 이 서비스의 백엔드 Pod가 여러 노드에 퍼져 있는 경우
- 일반적으로 kube-proxy는 트래픽을 어느 노드의 Pod로 보낼지 무작위 선택합니다.
- 그러나 LRP를 설정하면, 동일 노드에 Pod가 있으면 무조건 그 Pod로 먼저 보내게 됩니다.
✅ 함께 사용할 때 ( Cilium LRP와 NodeLocalDNS ) 의 시너지
1. DNS 트래픽까지 완전히 로컬화
- NodeLocal DNS Cache는 기본적으로 169.254.20.10 등의 가상 IP를 사용하며, ClusterIP 서비스입니다.
- 이 서비스를 LRP로 로컬 Pod (nodelocaldns)로 리디렉션하면, DNS 요청이 해당 노드 내 Pod에서 처리됩니다.
- 이는 모든 DNS 요청이 cross-node 없이 처리됨을 의미합니다.
2. 더 빠르고 안정적인 DNS 응답
- DNS 응답이 네트워크 hop을 거치지 않고 로컬에서 반환되므로 latency가 줄고, DNS timeout 문제도 줄어듭니다.
- 특히 DNS 요청이 많거나 서비스 디스커버리 의존성이 높은 시스템에서 매우 유리합니다.
3. 네트워크 효율성 증가
- DNS 요청뿐 아니라, LRP는 애플리케이션 트래픽도 로컬로 묶을 수 있으므로,
- 로컬 DNS 요청 → 로컬 CoreDNS → 로컬 백엔드 서비스
로 end-to-end 트래픽이 전부 해당 노드 안에서 완료될 수 있습니다.
- 로컬 DNS 요청 → 로컬 CoreDNS → 로컬 백엔드 서비스
4. CoreDNS 안정성 강화
- DNS 질의가 CoreDNS까지 전달되지 않게 되므로, CoreDNS가 죽거나 부하가 높을 때도,
- 로컬 캐시에 응답이 남아 있다면 문제없이 처리됨
실습 1. NodeLocalDNS
1. iptables 사용할때의 설치는 간단함
# iptables 확인
iptables-save | tee before.txt
#
wget https://github.com/kubernetes/kubernetes/raw/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
# kubedns 는 coredns 서비스의 ClusterIP를 변수 지정
kubedns=`kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP}`
domain='cluster.local' ## default 값
localdns='169.254.20.10' ## default 값
echo $kubedns $domain $localdns
# iptables 모드 사용 중으로 아래 명령어 수행
sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml
# nodelocaldns 설치
kubectl apply -f nodelocaldns.yaml

# 로그 확인 시 현재 nodelocaldns 미활용!
kubectl -n kube-system logs -l k8s-app=kube-dns -f
kubectl -n kube-system logs -l k8s-app=node-local-dns -f
#
kubectl exec -it curl-pod -- nslookup webpod
kubectl exec -it curl-pod -- nslookup google.com

실습 2. Cilium LRP
#
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set localRedirectPolicy=true
kubectl rollout restart deploy cilium-operator -n kube-system
kubectl rollout restart ds cilium -n kube-system
wget https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes-local-redirect/node-local-dns.yaml
kubedns=$(kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP})
sed -i "s/__PILLAR__DNS__SERVER__/$kubedns/g;" node-local-dns.yaml
vi -d nodelocaldns.yaml node-local-dns.yaml
## before
args: [ "-localip", "169.254.20.10,10.96.0.10", "-conf", "/etc/Corefile", "-upstreamsvc", "kube-dns-upstream" ]
## after
args: [ "-localip", "169.254.20.10,10.96.0.10", "-conf", "/etc/Corefile", "-upstreamsvc", "kube-dns-upstream", "-skipteardown=true", "-setupinterface=false", "-setupiptables=false" ]
# 배포
# Modify Node-local DNS cache’s deployment yaml to pass these additional arguments to node-cache:
## -skipteardown=true, -setupinterface=false, and -setupiptables=false.
# Modify Node-local DNS cache’s deployment yaml to put it in non-host namespace by setting hostNetwork: false for the daemonset.
# In the Corefile, bind to 0.0.0.0 instead of the static IP.
kubectl apply -f node-local-dns.yaml
#
kubectl edit cm -n kube-system node-local-dns # log, debug 추가
kubectl -n kube-system rollout restart ds node-local-dns
kubectl describe cm -n kube-system node-local-dns
cluster.local:53 {
errors
cache {
success 9984 30
denial 9984 5
}
reload
loop
bind 0.0.0.0
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
health
}
...
.:53 {
errors
cache 30
reload
loop
bind 0.0.0.0
forward . __PILLAR__UPSTREAM__SERVERS__
prometheus :9253
}
#
wget https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes-local-redirect/node-local-dns-lrp.yaml
cat node-local-dns-lrp.yaml | yq
apiVersion: "cilium.io/v2"
kind: CiliumLocalRedirectPolicy
metadata:
name: "nodelocaldns"
namespace: kube-system
spec:
redirectFrontend:
serviceMatcher:
serviceName: kube-dns
namespace: kube-system
redirectBackend:
localEndpointSelector:
matchLabels:
k8s-app: node-local-dns
toPorts:
- port: "53"
name: dns
protocol: UDP
- port: "53"
name: dns-tcp
protocol: TCP
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes-local-redirect/node-local-dns-lrp.yaml
#
kubectl get CiliumLocalRedirectPolicy -A
NAMESPACE NAME AGE
kube-system nodelocaldns 5m26s
#
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium-dbg lrp list
LRP namespace LRP name FrontendType Matching Service
kube-system nodelocaldns clusterIP + all svc ports kube-system/kube-dns
| 10.96.0.10:53/UDP -> 172.20.0.52:53(kube-system/node-local-dns-mhv4p),
| 10.96.0.10:53/TCP -> 172.20.0.52:53(kube-system/node-local-dns-mhv4p),
| 10.96.0.10:9153/TCP ->
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium-dbg service list | grep LocalRedirect
2 10.96.0.10:53/UDP LocalRedirect 1 => 172.20.0.52:53/UDP (active)
3 10.96.0.10:53/TCP LocalRedirect 1 => 172.20.0.52:53/TCP (active)
# logs
kubectl -n kube-system logs -l k8s-app=kube-dns -f
kubectl -n kube-system logs -l k8s-app=node-local-dns -f
#
kubectl exec -it curl-pod -- nslookup www.google.com
# nodelocaldns 에 캐시된 정보로 바로 질의 응답 확인!
kubectl -n kube-system logs -l k8s-app=node-local-dns -f
[INFO] 172.20.0.119:59966 - 48193 "A IN www.google.com.default.svc.cluster.local. udp 58 false 512" NXDOMAIN qr,aa,rd 151 0.057756155s
[INFO] 172.20.0.119:57117 - 36265 "A IN www.google.com.svc.cluster.local. udp 50 false 512" NXDOMAIN qr,aa,rd 143 0.000990079s
[INFO] 172.20.0.119:57568 - 25713 "A IN www.google.com.cluster.local. udp 46 false 512" NXDOMAIN qr,aa,rd 139 0.000896198s
[INFO] 172.20.0.119:58204 - 42574 "A IN www.google.com. udp 32 false 512" NOERROR qr,rd,ra 62 0.035130807s
[INFO] 172.20.0.119:46673 - 7830 "AAAA IN www.google.com. udp 32 false 512" NOERROR qr,rd,ra 74 0.007996413s'컨테이너 > 쿠버네티스 네트워크' 카테고리의 다른 글
| [Cilium] (11) 실리움 네트워킹 _ VXLAN Encapsulation (3) | 2025.08.06 |
|---|---|
| [Cilium] (10) 실리움 네트워킹 _ Native Routing (0) | 2025.08.05 |
| [Cilium] (8) 실리움 네트워킹 _ Masquerading (4) | 2025.07.29 |
| [Cilium] (7) 실리움 네트워킹 _ Routing (5) | 2025.07.29 |
| [Cilium] (6) 실리움 네트워킹 _ IPAM (2) | 2025.07.28 |