0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EKS で NodeLocal DNSCache を導入して DNS レイテンシを改善してみた

0
Last updated at Posted at 2026-04-13

はじめに

Amazon EKS クラスターで NodeLocal DNSCache を導入し、DNS クエリのレイテンシがどの程度改善されるかを検証しました。

NodeLocal DNSCache は、各ノード上で DNS キャッシュエージェントを DaemonSet として動作させる Kubernetes の機能です。Pod からの DNS クエリをノードローカルで処理することで、CoreDNS への負荷軽減とレイテンシ低減を実現します。Kubernetes v1.18 で stable になっています。

architecture.png

この記事で学べること

  • NodeLocal DNSCache の仕組みと導入方法
  • EKS クラスターへの具体的なデプロイ手順
  • 導入前後の DNS レイテンシの比較結果
  • メトリクスによるキャッシュ効果の確認方法

想定読者

  • EKS を使い始めた方
  • Kubernetes の DNS の仕組みに興味がある方
  • クラスター内の DNS パフォーマンスを改善したい方

背景・課題

Kubernetes クラスターでは、Pod 間の通信やサービスディスカバリに DNS が多用されます。デフォルトでは、すべての DNS クエリが CoreDNS Pod に送られます。

この構成には以下の課題があります。

  • Pod と CoreDNS が別ノードにある場合、ネットワークホップが発生しレイテンシが増加する
  • クラスター規模が大きくなると CoreDNS への負荷が集中する
  • iptables の DNAT とコネクション追跡(conntrack)による conntrack テーブルの枯渇リスク

NodeLocal DNSCache はこれらの課題を解決するために、各ノードに DNS キャッシュを配置します。

検証環境

項目 内容
EKS バージョン 1.34
ノード t3.medium × 2(Managed Node Group)
リージョン ap-northeast-1
kube-proxy モード iptables
NodeLocal DNSCache CoreDNS 1.13.1 ベース
DNS テスト用イメージ gcr.io/kubernetes-e2e-test-images/dnsutils:1.3

検証内容

1. EKS クラスターの作成

eksctl でクラスターを作成しました。

cat <<'EOF' > cluster-config.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: nodelocaldns-test
  region: ap-northeast-1
  version: "1.31"

managedNodeGroups:
  - name: ng-default
    instanceType: t3.medium
    desiredCapacity: 2
    minSize: 2
    maxSize: 3
EOF

eksctl create cluster -f cluster-config.yaml
$ kubectl get nodes
NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-xx-xx.ap-northeast-1.compute.internal   Ready    <none>   57s   v1.34.4-eks-f69f56f
ip-192-168-xx-xx.ap-northeast-1.compute.internal   Ready    <none>   56s   v1.34.4-eks-f69f56f

2. 導入前の DNS レイテンシ計測

dig コマンドが使える dnsutils イメージでテスト Pod を作成し、ベースラインを計測しました。

kubectl run dnstest --image=gcr.io/kubernetes-e2e-test-images/dnsutils:1.3 --restart=Never --command -- sleep 3600

クラスター内部 DNS(kubernetes.default.svc.cluster.local):

;; Query time: 2 msec
;; Query time: 2 msec
;; Query time: 1 msec
;; Query time: 2 msec
;; Query time: 1 msec
;; Query time: 7 msec
;; Query time: 17 msec
;; Query time: 1 msec
;; Query time: 3 msec
;; Query time: 2 msec

外部 DNS(amazon.com):

;; Query time: 3 msec
;; Query time: 2 msec
;; Query time: 1 msec
;; Query time: 1 msec
;; Query time: 2 msec
;; Query time: 1 msec
;; Query time: 2 msec
;; Query time: 2 msec
;; Query time: 2 msec
;; Query time: 2 msec

導入前の時点で、クラスター内部 DNS は 1〜17 msec、外部 DNS は 1〜3 msec でした。

また、resolv.conf を確認すると CoreDNS の ClusterIP が設定されています。

nameserver 10.100.0.10
search default.svc.cluster.local svc.cluster.local cluster.local ap-northeast-1.compute.internal
options ndots:5

3. NodeLocal DNSCache のデプロイ

Kubernetes 公式ドキュメントの手順に従い、マニフェストをダウンロードして変数を置換します。

curl -o nodelocaldns.yaml https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml

localdns=169.254.20.10
domain=cluster.local
kubedns=$(kubectl get svc kube-dns -n kube-system -o jsonpath='{.spec.clusterIP}')

# Linux の場合
sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml

# macOS の場合
sed -i '' "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml

kubectl apply -f nodelocaldns.yaml

実行結果:

serviceaccount/node-local-dns created
service/kube-dns-upstream created
configmap/node-local-dns created
daemonset.apps/node-local-dns created
service/node-local-dns created

4. 動作確認

node-local-dns のログを確認すると、169.254.20.1010.100.0.10(kube-dns の ClusterIP)の両方でリッスンしていることがわかります。

.:53 on 169.254.20.10
cluster.local.:53 on 169.254.20.10
.:53 on 10.100.0.10
cluster.local.:53 on 10.100.0.10
CoreDNS-1.13.1

iptables モードでは、NodeLocal DNSCache が kube-dns の ClusterIP でもリッスンするため、Pod の resolv.conf を変更する必要がありません。既存の Pod もそのまま恩恵を受けられます。

5. 導入後の DNS レイテンシ計測

テスト Pod を再作成して計測しました。

クラスター内部 DNS(kubernetes.default.svc.cluster.local):

;; Query time: 4 msec  ← 初回(キャッシュミス)
;; Query time: 0 msec  ← 2回目以降(キャッシュヒット)
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec

外部 DNS(amazon.com):

;; Query time: 2 msec  ← 初回(キャッシュミス)
;; Query time: 0 msec  ← 2回目以降(キャッシュヒット)
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec
;; Query time: 0 msec

初回クエリのみ数ミリ秒かかりますが、2回目以降はキャッシュヒットにより 0 msec になりました。

6. メトリクスによるキャッシュ効果の確認

node-local-dns コンテナには curl/wget が入っていないため、kubectl port-forward でメトリクスを取得しました。

NODE_LOCAL_POD=$(kubectl get pods -n kube-system -l k8s-app=node-local-dns -o jsonpath='{.items[0].metadata.name}')
kubectl port-forward -n kube-system ${NODE_LOCAL_POD} 9253:9253 &
sleep 2
curl -s http://localhost:9253/metrics | grep -E "^coredns_(cache_hits|cache_misses|dns_requests_total)"
kill %1

主要なメトリクス:

coredns_cache_hits_total{...,zones="."} 15
coredns_cache_hits_total{...,zones="cluster.local."} 9
coredns_cache_misses_total{...,zones="."} 1
coredns_cache_misses_total{...,zones="cluster.local."} 1

キャッシュヒットが 24 回に対してキャッシュミスは 2 回のみ。キャッシュヒット率は約 92% でした。

検証結果のまとめ

検証項目 導入前 導入後(初回) 導入後(キャッシュヒット)
クラスター内部 DNS 1〜17 msec 4 msec 0 msec
外部 DNS 1〜3 msec 2 msec 0 msec
キャッシュヒット率 - - 約 92%

わかったこと・学び

  • 導入は簡単: マニフェストをダウンロードして変数を置換し kubectl apply するだけで導入できます
  • iptables モードなら設定変更不要: kube-dns の ClusterIP でもリッスンするため、Pod の resolv.conf を変更する必要がありません。既存の Pod もそのまま恩恵を受けられます
  • キャッシュ効果は明確: 2回目以降のクエリは 0 msec になり、キャッシュの効果がはっきり確認できました
  • メトリクスで可視化できる: Prometheus 形式のメトリクスが公開されており、キャッシュヒット率やリクエスト数を監視できます
  • EKS Auto Mode なら自動: EKS Auto Mode を使用している場合、NodeLocal DNSCache は自動的に含まれます

ハマりポイント・トラブルシューティング

busybox の time + nslookup では精度が足りない

当初 busybox イメージの time nslookup で計測しましたが、すべて 0m00.00s と表示され差分が見えませんでした。dig コマンド(dnsutils イメージ)を使うことで、ミリ秒単位の Query time が取得できます。

macOS の sed -i はオプションが異なる

Kubernetes 公式ドキュメントの sed -i コマンドは Linux 前提です。macOS の BSD sed では -i '' のように空文字列の拡張子指定が必要です。

# Linux
sed -i "s/..." nodelocaldns.yaml

# macOS
sed -i '' "s/..." nodelocaldns.yaml

node-local-dns コンテナに curl/wget がない

メトリクス取得時、コンテナ内に HTTP クライアントがないため kubectl exec では取得できません。kubectl port-forward を使ってローカルからアクセスする方法で解決しました。

dnsutils イメージの起動に時間がかかる

gcr.io/kubernetes-e2e-test-images/dnsutils:1.3 はイメージの pull に時間がかかる場合があります。kubectl wait のタイムアウトを 120 秒程度に設定しておくと安心です。

まとめ

NodeLocal DNSCache を EKS クラスターに導入し、DNS クエリのレイテンシが大幅に改善されることを確認しました。特にキャッシュヒット時は 0 msec となり、CoreDNS への不要なネットワークホップを完全に排除できます。

導入手順もシンプルで、既存の Pod に影響を与えずに適用できるため、EKS クラスターの DNS パフォーマンス改善の第一歩としておすすめです。

クリーンアップ

検証後は忘れずにリソースを削除してください。

kubectl delete pod dnstest --force
kubectl delete -f nodelocaldns.yaml
eksctl delete cluster --name nodelocaldns-test --region ap-northeast-1

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?