Kubernetes の名前解決を速くする: ndots:5 の総当たりを避ける接続先の書き方と CoreDNS の設定
Pod の DNS クエリは、接続先の書き方ひとつで 1 回にも 4 回にもなる。末尾ドット・<svc>.<ns> 形式・dnsPolicy: Default で無駄なクエリを減らす。
どんなときに使うか
- 性能要件が厳しいアプリで、接続のたびの名前解決の遅れや CoreDNS の負荷が気になるとき
- CoreDNS のログに
xxx.default.svc.cluster.localのような NXDOMAIN が大量に並んでいるとき - ノードの conntrack テーブルが逼迫している(DNS は UDP なので 1 クエリごとにエントリができる)とき
仕組み
kubelet は dnsPolicy: ClusterFirst(既定)の Pod に次の /etc/resolv.conf を入れる。nameserver はクラスタ DNS(kube-dns Service の ClusterIP)だけに置き換えられる。
search <ns>.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5ドットが 5 個未満の名前は search の各ドメインを順に付けて試し、最後にそのままの名前を試す。そのため nginx.default.svc.cluster.local(ドット 4 個)と完全な名前を書いても、末尾ドットがなければ NXDOMAIN を 3 回もらってから 4 回目で解決する。外部ドメインの kubernetes.io も同じく 4 回になる。
接続先の書き方とクエリ回数(kind + CoreDNS の log で実測された値)
log で| 書き方 | クエリ回数 |
|---|---|
nginx(同じ Namespace) | 1 回 |
nginx.default(別 Namespace) | 2 回 |
nginx.default.svc.cluster.local(末尾ドットなし) | 4 回 |
nginx.default.svc.cluster.local.(末尾ドットあり) | 1 回 |
kubernetes.io | 4 回 |
kubernetes.io. | 1 回 |
やり方
- 同じ Namespace の Service は名前だけ(
nginx)で書く。 - 別 Namespace の Service は
<svc>.<ns>か、末尾ドット付きの完全な名前で書く。末尾ドットなしの FQDN は一番損。 - 外部ドメインは設定で書けるなら
api.example.com.のように末尾ドットを付ける。 - 外部ドメインしか引かない Pod は
dnsPolicy: Defaultにしてノードの resolv.conf を直接使う。ただしクラスタ内の Service 名は引けなくなり、CoreDNS の共有キャッシュも通らなくなるので、アプリ側で DNS 結果をキャッシュしていないと上流 DNS への問い合わせはむしろ増える。
yaml
spec:
dnsPolicy: Default- 確認は
nicolaka/netshootなどの Pod からdig +search +noall +answer +comments A <名前>を打ち、Corefile に一時的にlogを足して CoreDNS 側のクエリ行を数える(常時有効は性能に響く)。
CoreDNS 側の設定メモ
- Corefile に書く順番と実行順は別物。実行順はビルド時の
plugin.cfgで決まり、cacheとautopathはkubernetesより先に動く。 cacheにdisable success cluster.local/disable denial cluster.localを入れると、クラスタ内の応答をキャッシュせず、Service や EndpointSlice の変更がすぐ反映される。- 上流 DNS の障害対策に
prefetch 5 60s 10%とserve_stale 1h verify。verifyの方が古い IP を返し続けるリスクが低い。古い CoreDNS には SERVFAIL が肯定キャッシュを上書きする不具合(coredns#8003)があったので版を確認する。 autopath @kubernetesは search の総当たりをサーバー側で肩代わりできるが、pods verified(全 Pod の watch でメモリ・CPU が増える)が必須で、IP 再利用時に Namespace を取り違えることがある。まずは上のクライアント側の書き方で減らし、それでも残るときに検討する。health { lameduck 10s }で終了時の猶予を延ばし、EndpointSlice の反映待ちの間も応答を続けさせる。- 公式の
forward . /etc/resolv.conf { max_concurrent 1000 }は上限超過で即REFUSEDを返す。外すかどうかは conntrack 逼迫とのトレードオフ。
注意
- マネージド k8s では Corefile を触れないことが多い。クライアント側の書き方と
dnsPolicyは使える。 - 数字は記事の kind 検証(Kubernetes v1.37 / CoreDNS v1.14.6)の結果。
出典
- @yosshi_ · 2026-11-09 (Qiita「CoreDNS の Kubernetes プラグインで、Service のドメイン名がクラスタ内で名前解決できるまで」の第 4 章が要点)