🖥

CoreDNS でローカルアプリケーションの名前解決をする。

2024/11/29に公開

記事を書いたきっかけ

Arch Linux で Kubernetes 環境を構築していたある日のこと...

「ちゃんとDNSサーバ勉強したいよなぁ」
/etc/hosts 管理脱却できないかなぁ」
「別にお金払って何かやる気はないんだよなぁ」

と漠然と考え、「じゃあまずローカルで OSS の DNS サーバ立ち上げて動作見てみようぜ」ということで CoreDNS の動作確認を兼ねて設定をしていたので、共有と備忘録がてら記事に残します。

やりたかったこと

  • 53 ポートを使う名前解決サーバをローカルに立てる。
  • 名前解決に関する設定を一か所に集約する。

つまりはスタブリゾルバを触りたかった (重要)。
当時 DNSSEC の勉強も兼ねて KnotDNS をローカルでいじっていたんですが「いや CoreDNS で十分じゃね」となり方向転換を決めました。

CoreDNS とは

CoreDNS is a DNS server/forwarder, written in Go, that chains plugins. Each plugin performs a (DNS) function.

CoreDNS is a Cloud Native Computing Foundation graduated project.

CoreDNS is a fast and flexible DNS server. The key word here is flexible: with CoreDNS you are able to do what you want with your DNS data by utilizing plugins. If some functionality is not provided out of the box you can add it by writing a plugin.[1]

CoreDNS はプラガブルなアーキテクチャを持つ OSS DNS サーバ/フォワーダです。
起動が簡単、動作が軽量はさることながら、機能拡張方法が明瞭である点が最大の魅力です。
また、設定ファイルは /etc/hosts の書きなれた形式で記載することができます。
様々ないいとこどりをした DNS という印象です。

Cloud Native Computing Foundation (CNCF) の Graduated Project であることもあって知名度はそれなりに高いです。
Kubernetes 環境で kubectl した時に「中で名前解決してるっぽいやつ見たな」という感じの方が多いのではないでしょうか。

動作環境

以下の本でまとめた Arch Linux 環境を使用しました。

https://zenn.dev/caunus/books/archlinux-introduction/viewer/environments

設定手順

make からバイナリを作成することもできますが、今回は GitHub の Releases からダウンロードしてきます。

# もし CPU アーキテクチャが不安であれば確認しておく
uname -m

# 取得
wget https://github.com/coredns/coredns/releases/download/v1.11.4/coredns_1.11.4_linux_amd64.tgz

# 展開
tar -xzvf coredns_1.11.4_linux_amd64.tgz

# パスが通っている場所に移動
sudo mv coredns /usr/local/bin

次に設定ファイル Corefile を作成します。

vim Corefile
.:53 {
  forward . 8.8.8.8:53
  hosts {
    127.0.0.1 desktop-arch0001
    fallthrough
  }
  log
  errors
}

forward, hosts などが CoreDNS で設定するプラグインです。

https://coredns.io/plugins/

上記は「8.8.8.8 にフォワードする」「desktop-arch0001 は 127.0.0.1 に解決する」といった感じです。
なお、CoreDNS ではプラグインの実行順は Corefile の記載順ではなくビルド時の指定順で決まるようです。[2]

hosts プラグインは forward より優先されます。
fallthroughhosts での解決不可によって forward に進めなくなってしまうことを防いでいます。

これで /etc/hosts の設定は Corefile に移せたので、晴れて /etc/hosts の記載は削除できます。

既にローカルで動いている (53番ポートを使っている) スタブリゾルバである systemd-resolved.service を止めて、CoreDNS を起動します。

# systemd-resolved.service が 53 ポートを使っている
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

# CoreDNS 起動。Well-known port を使うので sudo
sudo coredns -conf Corefile -dns.port 53

次に DNS 設定を変えます。

## DNS サーバを設定する。
sudo nmcli conn show
sudo nmcli conn modify SSID ipv4.dns "127.0.0.1"
sudo systemctl restart NetworkManager
sudo cat /etc/resolv.conf
> Generated by NetworkManager
> nameserver 127.0.0.1

これで名前解決を行う設定が整いました!
nslookup zenn.devnslookup desktop-arch0001 で確認ができます。

最後に CoreDNS を自動起動できるように systemd 管理にしておきます。
coredns.service を公式が準備してくれているので参考にします。

https://github.com/coredns/deployment/blob/master/systemd/coredns.service

# nologin のユーザ作成
sudo mkdir /etc/coredns
sudo mv Corefile /etc/coredns
sudo useradd -r -s /usr/sbin/nologin -m -d /var/lib/coredns -c 'CoreDNS DNS Server' coredns

# .service ファイル作成
sudo vim /etc/systemd/system/coredns.service
> [Unit]
> Description=CoreDNS DNS server
> Documentation=https://coredns.io
> After=network.target
>
> [Service]
> PermissionsStartOnly=true
> LimitNOFILE=1048576
> LimitNPROC=512
> CapabilityBoundingSet=CAP_NET_BIND_SERVICE
> AmbientCapabilities=CAP_NET_BIND_SERVICE
> NoNewPrivileges=true
> User=coredns
> WorkingDirectory=/var/lib/coredns
> ExecStart=/usr/local/bin/coredns -conf=/etc/coredns/Corefile
> ExecReload=/bin/kill -SIGUSR1 $MAINPID
> Restart=on-failure
> StandardOutput=append:/var/log/coredns.log
> StandardError=append:/var/log/coredns.err.log
>
> [Install]
> WantedBy=multi-user.target

# 自動起動に設定&起動
systemctl enable coredns
systemctl start coredns

これでローカルのスタブリゾルバを CoreDNS 化し、名前解決の設定を一つの Corefile に集約することができました。

思ったこと

実は仕組み的には systemd-resolved/etc/hosts で使っていた方がローカルの名前解決は速かったんじゃないかなって思ってます。

systemd-resolved の Protocols and Routing[3] にこんなことがかかれています。

The lookup requests that systemd-resolved.service receives are routed to the available DNS servers, LLMNR, and MulticastDNS interfaces according to the following rules:

・Names for which synthetic records are generated (the local hostname, "localhost" and "localdomain", local gateway, as listed in the previous section) and addresses configured in /etc/hosts are never routed to the network and a reply is sent immediately.
...

...つまりローカルで解決するものはわざわざ問い合わせないってことですね。
今回 Corefile にすべてを記載する方針でいたので仕方ないことではあるんですが、このあたりの最適化は systemd-resolved の方が既にやっていて分がありそうです (計測もしていないので正確には比較できませんが)。

次にもう少し詳しく調査する時間が取れたら、ソースコードをいじってビルドするところからやってみようと思います。

脚注
  1. https://github.com/coredns/coredns ↩︎

  2. https://coredns.io/2017/06/08/how-queries-are-processed-in-coredns/ ↩︎

  3. https://www.freedesktop.org/software/systemd/man/latest/systemd-resolved.service.html#Protocols and Routing ↩︎

Discussion