2026年6月11日

2026年6月11日

CoreDNS のパフォーマンスチューニング|権威DNSとして使うときのゾーン配信・DNSSEC・OS設定

CoreDNS を権威DNS(自分のゾーンに答えるサーバー)として使う場合、速度を左右するのは上流への転送ではなく、ゾーンの読み込み方、DNSSEC 署名の負荷、そして OS 側で UDP パケットを取りこぼしていないかの3点です。この記事では、file・auto・secondary プラグインでゾーンを配る構成を前提に、計測、ゾーン配信の設定、DNSSEC、OS とプロセスの設定、悪用される問い合わせへの備えを順に説明します。

キャッシュサーバー(forward と cache で外部の名前を引く用途)や Kubernetes のクラスター DNS としての調整は、問題の性質が異なるためここでは扱いません。プラグインの有無や既定値は CoreDNS のバージョンで変わるため、coredns -version と coredns -plugins で手元の版と組み込まれたプラグインを確認してから読み進めてください(2026年10月現在)。

まず計測する

権威サーバーとしての性能は、問い合わせの種類によって大きく変わります。計測は次の2つを組み合わせます。

一つ目は prometheus プラグインのメトリクスです。応答時間の分布(coredns_dns_request_duration_seconds)、応答コードの内訳(coredns_dns_responses_total)、ゾーンごとの問い合わせ数を見ます。平均ではなく99パーセンタイルのような遅い側と、SERVFAIL の増減に注目します。

二つ目は検証環境での負荷試験です。DNS-OARC の dnsperf に、自分のゾーンに実在する名前と、存在しない名前(NXDOMAIN になるもの)を混ぜた一覧を与えます。

cat > queries.txt <<'EOF'
www.example.com A
example.com MX
example.com TXT
nosuch-1234.example.com A
EOF

dnsperf -s 192.0.2.53 -d queries.txt -l 30 -c 20 -Q 5000

存在しない名前を入れるのは、DNSSEC を使っているときに否定応答の生成が重くなりやすいためです。本番サーバーや他人の DNS サーバーに負荷をかけないでください。

プラグインの並び順は Corefile ではなくビルド時に決まる

最初に押さえておきたいのは、Corefile にプラグインを書いた順番は処理の順番にならないことです。処理順は CoreDNS をビルドしたときの plugin.cfg で決まっています。「cache を file より前に書いたから先にキャッシュが効くはず」といった読み方は誤りなので、順番を変えて速くしようとする調整は効果がありません。

また、権威サーバーの前に cache を置いても、file プラグインはもともとメモリ上のゾーンから答えるため、効果は小さいことが多いです。キャッシュを足すと、ゾーンを更新したときに古い応答が残る時間が増えるという副作用のほうが目立つこともあります。入れる場合は計測で差が出ることを確かめてからにします。

ゾーンの読み込み設定

file プラグイン

file はゾーンファイルをメモリに読み込んで応答します。読み込みの再確認間隔は reload で指定できます。

example.com {
    file /etc/coredns/zones/example.com.zone {
        reload 1m
    }
    errors
    prometheus 127.0.0.1:9153
}

file は SOA のシリアル番号が変わったときにゾーンを読み直します。ファイルを書き換えたのにシリアルを上げないと、変更が反映されません。再確認の間隔を極端に短くしても応答速度は上がらず、大きなゾーンでは読み直しの負荷が増えるだけなので、更新頻度に合わせた値にします。

ゾーンが多いときは auto プラグイン

数百のゾーンをそれぞれ file で書くと、Corefile が膨らみ、ゾーンの追加のたびに設定変更が要ります。auto プラグインは、ディレクトリ内のファイル名の規則からゾーンを自動で読み込みます。

. {
    auto {
        directory /etc/coredns/zones db\.(.*) {1}
        reload 1m
    }
    errors
}

この例では db.example.com というファイルを example.com のゾーンとして扱います。ゾーン数が増えるとメモリ使用量も比例して増えるため、メトリクスとプロセスのメモリを見ながら台数やメモリ割り当てを決めます。

secondary プラグインで受け取る場合

別のプライマリからゾーン転送で受け取る場合は secondary を使います。受け取ったゾーンはメモリ上で保持されるため、再起動直後は転送が終わるまで応答できない点に注意します。ゾーンが大きい場合、再起動の手順に「転送の完了を待ってから次の台へ進む」を入れておくと、全台が同時に答えられない時間を作らずに済みます。

DNSSEC の負荷を抑える

DNSSEC は権威サーバーで最も CPU を使う処理です。CoreDNS には大きく2つの方法があります。

  • **dnssec プラグイン(応答時に署名する)**:問い合わせが来たときに署名を作ります。手軽ですが、署名の生成は重い処理なので、問い合わせが多いと CPU が先に詰まります。プラグインは作った署名をキャッシュしており、その容量は cache_capacity で調整できます。存在しない名前への問い合わせが多いと、キャッシュが効きにくくなります。
  • **sign プラグイン(事前に署名する)**:ゾーンファイルを定期的に署名し直して署名済みのファイルを書き出し、file プラグインで配ります。応答時に署名の計算が発生しないため、問い合わせが多い環境ではこちらが有利です。

署名アルゴリズムの選択も負荷に関わります。楕円曲線系の ECDSA P-256(アルゴリズム13)は、同等の強度の RSA に比べて署名が小さく、応答のサイズを抑えられます。アルゴリズムを変える場合は鍵の切り替え(ロールオーバー)と親ゾーンの DS レコードの更新が伴うため、手順を確認してから行ってください。

応答サイズと悪用への備え

権威サーバーは、送信元を偽った問い合わせで第三者を攻撃する「反射・増幅」に悪用されることがあります。性能の調整とあわせて、大きな応答を作らない設定にしておきます。

example.com {
    bufsize 1232
    any
    file /etc/coredns/zones/example.com.zone
    errors
}
  • bufsize:EDNS で受け付ける UDP 応答の上限サイズを指定します。1232 バイトは、IP の断片化を避けるために DNS 業界で広く推奨されている値です。上限を超える応答は TCP での再問い合わせに回ります。
  • any:ANY 型の問い合わせに対して、全レコードを返す代わりに短い応答を返します(RFC 8482 の考え方)。

BIND の RRL(応答レート制限)に当たる機能が標準プラグインにあるかは、版によって状況が異なる可能性があるため、プラグイン一覧で確認してください。標準で足りない場合は、手前のファイアウォールや DDoS 対策サービスで送信元ごとの流量を制限します。

OS とプロセスの設定

CoreDNS 自体の設定を詰めても、OS 側でパケットを捨てていれば遅延や取りこぼしになります。

UDP 受信バッファのあふれ

瞬間的に問い合わせが集中すると、カーネルの UDP 受信バッファがあふれてパケットが捨てられます。この場合、CoreDNS のメトリクスには表れません。

nstat -az UdpRcvbufErrors

値が増え続けていれば、受信バッファが足りていません。net.core.rmem_default と net.core.rmem_max を sysctl で大きくするのが基本の対処です。値は環境に合わせて検証環境で決め、変更前の値を控えておきます。

新しい版の CoreDNS には、同じポートを複数のソケットで受けて CPU コアに処理を分ける multisocket プラグインが加わっています。コア数が多いのに CPU 使用率が一部のコアに偏る場合の選択肢になりますが、対応する版かどうかを確認してから使ってください。

接続追跡(conntrack)

Linux で iptables や nftables の接続追跡が有効だと、UDP の問い合わせ1件ごとに追跡表へ記録が作られます。問い合わせが多いと追跡表があふれ、新しいパケットが捨てられます。dmesg に conntrack の表が一杯だという趣旨のメッセージが出ていれば、この問題です。DNS の 53 番ポートを接続追跡の対象から外す方法がありますが、その場合はステートフルなルールで許可していた通信を明示的に許可し直す必要があるため、ファイアウォール全体の設計とあわせて検討します。

ファイル記述子と CPU 割り当て

TCP の問い合わせやゾーン転送が多い場合は、同時に開けるファイル記述子の上限(systemd なら LimitNOFILE)を確認します。コンテナで動かしている場合、CPU の上限(limits)が小さいと、負荷の集中時に処理が絞られて応答時間が跳ね上がります。Go で書かれた CoreDNS は、使う CPU 数を GOMAXPROCS で決めます。コンテナの CPU 上限を自動で反映するかは Go のバージョンによって異なるため、上限と実際の値がずれていないかを確認します。

ログとデバッグを本番で外す

log プラグインは全問い合わせを記録するため、権威サーバーでも CPU とディスクを大きく使います。調査が終わったら外すか、class denial error のように記録する種類を絞ります。debug と pprof も、調査時以外は無効にしておきます。

変更の進め方

  1. Corefile、ゾーンファイル、DNSSEC の鍵をバックアップする
  2. 検証環境で dnsperf を使い、変更前後の数字を比べる
  3. 本番では1台ずつ、1項目ずつ反映し、メトリクスと UdpRcvbufErrors を確認する
  4. 悪化したらバックアップに戻す

複数台で運用している場合は、外部からの応答を dig で確認し、全台が同じ SOA シリアルを返しているかも確かめます。

まとめ

  • 権威DNSとしての CoreDNS は、ゾーンの読み込み、DNSSEC 署名、OS のパケット取りこぼしの3点を中心に調整します。
  • プラグインの処理順はビルド時に決まり、Corefile の記述順では変わりません。
  • ゾーンが多いときは auto、DNSSEC の負荷が高いときは事前署名の sign を検討します。
  • bufsize と any で大きな応答を抑え、増幅攻撃への悪用を防ぎます。
  • UDP 受信バッファ、接続追跡、CPU 割り当ては CoreDNS の外で確認します。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲