2026年6月13日

2026年6月13日

CoreDNS から Unbound へ移行する手順|Corefile の forward・hosts・file・acl を unbound.conf に置き換え、並行稼働で比べて切り替える

CoreDNS から Unbound への移行は、Corefile のプラグインを1つずつ unbound.conf の項目に対応させ、Unbound を別のポートで並行稼働させて応答を比べてから、同じアドレスのまま入れ替える流れで進めると、利用者への影響を小さくできます。注意したいのは、Unbound が既定で DNSSEC の検証を行うことと、社内向けのゾーンや逆引きの扱いが CoreDNS と異なることです。この記事では、移行の対象を見極める方法、設定の対応、DNSSEC と社内ゾーンの注意点、並行稼働での比較、切り替えと切り戻しを説明します。

移行の対象を見極める

最初に、その CoreDNS が何の役割を担っているかを確認します。

  • 単体のキャッシュ・転送サーバー:社内の端末が使う名前解決サーバーとして、上流への転送とキャッシュを担っている CoreDNS です。Unbound への移行に向いています。
  • Kubernetes のクラスター DNS:kubernetes プラグインで Service や Pod の名前を答えている CoreDNS です。Unbound には同じ機能がないため、置き換えの対象にはしません。クラスターの外の名前解決だけを Unbound に任せたい場合は、CoreDNS の forward の転送先を Unbound に向ける構成にします。

Unbound に移す理由も整理しておきます。DNSSEC の検証を名前解決サーバーで行いたい、上流に頼らずルートから自分で名前をたどりたい、キャッシュの統計を細かく見たい、といった理由がよく挙げられます。理由がはっきりしていると、移行後の確認項目も決めやすくなります。

現在の Corefile を棚卸しする

移行前の Corefile の例です。この内容を Unbound に移していきます。

# 移行前の /etc/coredns/Corefile
.:53 {
    bind 10.0.0.53
    acl {
        allow net 10.0.0.0/8 127.0.0.1/32
        block
    }
    hosts /etc/coredns/hosts {
        fallthrough
    }
    forward . 192.0.2.1 192.0.2.2
    cache 300
    errors
}

corp.example.com:53 {
    bind 10.0.0.53
    forward . 172.16.0.53 172.16.0.54
    errors
}

lab.example.com:53 {
    bind 10.0.0.53
    file /etc/coredns/db.lab.example.com
    errors
}

使っているプラグインを書き出し、Unbound での対応先を決めます。主な対応は次のとおりです。

CoreDNS のプラグイン Unbound での対応
bind interface
acl access-control(送信元ごとの許可・拒否)
forward(. 全体) forward-zone の name: "."、または転送せず自分でルートからたどる
forward(特定ゾーン) forward-zone(転送先が再帰サーバー)または stub-zone(転送先が権威サーバー)
hosts local-data と local-data-ptr
file auth-zone(ゾーンファイルをそのまま使える)、小さなゾーンなら local-zone と local-data
cache cache-max-ttl・cache-min-ttl とキャッシュの容量の設定
log log-queries・log-replies
prometheus・health・ready 直接の対応なし(unbound-control stats や外部の監視で代替)

rewrite や template のように、Unbound に同じ働きをする項目がないプラグインを使っている場合は、移行の前にその機能が今も必要かを確かめてください。必要なら、その部分だけ CoreDNS を残す構成も選択肢になります。

unbound.conf を書く

上の Corefile を置き換えた例です。並行稼働のため、最初は 5353番ポートで待ち受けます。

# /etc/unbound/unbound.conf.d/migrate.conf
server:
    # 並行稼働中は 5353番で待ち受ける。切り替え時に @5353 を外す
    interface: 10.0.0.53@5353
    interface: 127.0.0.1@5353

    # acl の置き換え。書いていない送信元は拒否される
    access-control: 10.0.0.0/8 allow
    access-control: 127.0.0.0/8 allow

    # cache 300 の置き換え(キャッシュの最大 TTL を 300秒にする)
    cache-max-ttl: 300

    # hosts の置き換え
    local-data: "nas.corp.example.com. IN A 10.0.0.30"
    local-data-ptr: "10.0.0.30 nas.corp.example.com."

    # 社内ゾーンは公開側の DNSSEC の検証から外す(理由は後述)
    domain-insecure: "corp.example.com."
    domain-insecure: "lab.example.com."

    # 社内のアドレスの逆引きを上流に流すため、既定の空応答を止める
    local-zone: "10.in-addr.arpa." nodefault

# forward . の置き換え
forward-zone:
    name: "."
    forward-addr: 192.0.2.1
    forward-addr: 192.0.2.2

# corp.example.com の転送(転送先は社内の再帰サーバー)
forward-zone:
    name: "corp.example.com."
    forward-addr: 172.16.0.53
    forward-addr: 172.16.0.54

# 10.0.0.0/8 の逆引きも社内の DNS に転送する
forward-zone:
    name: "10.in-addr.arpa."
    forward-addr: 172.16.0.53

# file プラグインのゾーンを auth-zone で配信する
auth-zone:
    name: "lab.example.com."
    zonefile: "/etc/unbound/zones/db.lab.example.com"
    for-downstream: yes
    for-upstream: yes

CoreDNS の file プラグインで使っていたゾーンファイルは、標準的なゾーンファイルの書式であれば auth-zone でそのまま読み込めます。コピーした後、ファイルの所有者と権限を Unbound の実行ユーザーが読める状態にしてください。

設定を書いたら、sudo unbound-checkconf で文法を検査してから Unbound を起動します。

DNSSEC と社内ゾーンの注意点

CoreDNS の forward プラグインは DNSSEC の検証を行いませんが、Unbound はトラストアンカーが設定されていれば、既定で検証を行います。この違いが、移行で最もつまずきやすい点です。

corp.example.com のような社内ゾーンは、インターネット上では親の example.com から委任されていません。親ゾーンが DNSSEC で署名されていると、Unbound は「そのような子ゾーンは存在しない」という署名付きの証明を受け取り、社内 DNS から届いた答えを不正なものとして扱って SERVFAIL を返します。domain-insecure は、指定したゾーンをこの検証から外す設定です。社内ゾーンごとに指定してください。

逆引きにも違いがあります。Unbound は、10.in-addr.arpa などのプライベートアドレスの逆引きゾーンについて、既定で外に問い合わせず空の答えを返します。CoreDNS で社内の逆引きを社内 DNS に転送していた場合は、上の例のように local-zone を nodefault にしたうえで、転送先を書く必要があります。対象のゾーンと既定の動作はバージョンによって変わることがあるため、手元のバージョンの unbound.conf の説明で確かめてください(2026年10月現在)。

社内の名前がプライベートアドレスを返す環境で private-address を設定している場合は、private-domain で社内ゾーンを除外しないと、答えが取り除かれます。CoreDNS にはこの仕組みがないため、新たに設定するときは影響を確認してから有効にします。

並行稼働で応答を比べる

CoreDNS を 53番、Unbound を 5353番で動かしたまま、同じ名前を両方に問い合わせて答えを比べます。

# 比べたい名前を names.txt に1行ずつ書いておく(社内・社外・逆引き・存在しない名前を含める)
while read -r name type; do
  a=$(dig @10.0.0.53 -p 53   "$name" "$type" +short | sort)
  b=$(dig @10.0.0.53 -p 5353 "$name" "$type" +short | sort)
  [ "$a" = "$b" ] && echo "OK   $name $type" || echo "DIFF $name $type"
done < names.txt

names.txt には、www.example.org A、nas.corp.example.com A、30.0.0.10.in-addr.arpa PTR、no-such-host.corp.example.com A のように、種類の違う問い合わせを並べます。複数のアドレスを順番を変えて返す名前は、sort で並べ替えてから比べています。

DIFF が出た名前は、+short を外して status と答えの中身を確認します。CoreDNS では NOERROR なのに Unbound で SERVFAIL になる場合は、前の節の DNSSEC の検証が原因であることが多いです。Unbound のログの詳しさを一時的に上げると、検証の失敗の理由が記録されます。

あわせて、実際の利用者に近い使い方でも試します。検証用の端末の DNS サーバーを Unbound に向けられない場合は、dig -p 5353 での確認を、普段よく使う社内システムの名前にも広げておきます。

切り替える

比較で問題がなければ、同じアドレスのまま CoreDNS から Unbound に入れ替えます。端末側の DNS サーバーの設定を変えずに済むため、影響は入れ替えの数秒に限られます。利用の少ない時間帯を選び、関係者に作業時間を伝えておきます。

# 1. Unbound の待ち受けを 53番に変える(interface から @5353 を外す)
sudo unbound-checkconf

# 2. CoreDNS を止めて、Unbound を再起動する
sudo systemctl stop coredns
sudo systemctl restart unbound

# 3. 53番で Unbound が答えるかを確認する
dig @10.0.0.53 www.example.org
dig @10.0.0.53 nas.corp.example.com

CoreDNS をコンテナで動かしている場合は、コンテナの停止に置き換えてください。確認が済んだら、CoreDNS がサーバーの再起動時に自動で起動しないよう systemctl disable coredns しておきます。設定とバイナリは、しばらく残しておきます。

問題が出たときの切り戻し

社内のシステムで名前が引けないなどの問題が出たら、原因の調査より先に元に戻します。

sudo systemctl stop unbound
sudo systemctl start coredns

戻した後、Unbound を再び 5353番で動かし、問題の名前で並行稼働の比較を行って原因を調べます。切り戻しの手順は作業前に一度試しておくと、いざというときに慌てずに済みます。

まとめ

  • Kubernetes のクラスター DNS は移行の対象にせず、単体のキャッシュ・転送サーバーとして動く CoreDNS を移します。
  • Corefile のプラグインを棚卸しし、forward・hosts・file・acl などを unbound.conf の項目に対応させます。対応する機能がないものは、要否を確かめます。
  • Unbound は既定で DNSSEC を検証するため、社内ゾーンには domain-insecure、社内の逆引きには nodefault と転送先の設定が必要です。
  • 5353番で並行稼働させて応答を比べ、同じアドレスのまま入れ替えます。切り戻しの手順も事前に用意しておきます。

お気軽にご相談ください

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