본문 바로가기

컨테이너/쿠버네티스 네트워크

[Cilium] (9) 실리움 네트워킹_ NodeLocalDNS, Cilium LRP

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 트래픽이 전부 해당 노드 안에서 완료될 수 있습니다.

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

iptables를 사용하지 않기 때문에 (Cilium) 현재 작용안하고 있음

실습 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