crashRT のブログ

技術とかそれ以外とか

Knot Resolver と Docker でDNSキャッシュサーバーをたててみた

自宅環境内にDNSキャッシュサーバーをたてました。 Knot Resolver がモダンでステキらしい ので、これを使ってみることにしました。

公式サイト www.knot-resolver.cz

ドキュメント www.knot-resolver.cz

latest と stable の2つのバージョンが選べるのですが、本番環境に使うなら2024.11時点ではlatestなバージョン6(以上)を使う必要があるようです。

Before version 6, our Docker images were not intended for production use due to the lack of systemd in Docker and the inability to manage the multiple independent parts of the resolver. This is no longer the case since the introduction of the Manager that automatically control other parts of the resolver.

https://www.knot-resolver.cz/documentation/latest/deployment-docker.html

ということで、latest のバージョンを使って構築してみます。

構築

とりあえずシンプルなDNSだけやります。 DoHとかDNSSECとかもどこかでやってみたいです。

ファイル構成はこんな感じです

knot-resolver/
├── config
│   └── config.yaml
└── docker-compose.yml

コンテナの設定

コンテナの設定を docker-compose.yml で書きます。

services:
  knot_resolver:
    image: docker.io/cznic/knot-resolver:6
    container_name: knot_resolver
    ports:
      - 192.168.11.4:53:53/udp
      - 192.168.11.4:5000:5000
    volumes:
      - ./config:/config

ports のところで、ホスト側のアドレスを指定していることに注意してください。*1 /udp を忘れると TCP になってしまう点にも注意です。

また、コンフィグのパスについては、ドキュメントには /etc/knot-resolver/config.yaml にある*2 のですが、少なくともこのコンテナイメージで作る場合は /config/config.yaml が使われるので注意してください*3。(環境によってはドキュメント通り /etc/knot-resolver/config.yaml が読まれるらしいです...)

Knot Resolver の設定

config.yaml にKnot Resolver の設定を書きます。

rundir: /run/knot-resolver
workers: 2
cache:
  storage: /var/cache/knot-resolver
logging:
  level: info
network:
  listen:
    - interface: 0.0.0.0
views:
  - subnets: [0.0.0.0/0, "::/0"]
    answer: refused
  - subnets: [192.168.0.0/16, "::1"]
    answer: allow

forward:
  - subtree: .
    servers: [1.1.1.1, 8.8.8.8]

management:
    interface: 0.0.0.0@5000

設定について軽く説明します。

上の方の rundir workers cache logging はデフォルトで入っていた設定をそのまま使っています。

interface については、コンテナNWにおいてこのコンテナに割り当てられるアドレスがわからないのでワイルドカードにしています。 コンテナ側でアドレスをしているので大丈夫なはず...

views のところでアクセス制御をしています。 グローバルIPを持たせるわけではないのであまり気にする必要はないかもしれないですが念の為...

  • 0.0.0.0/0refuse して一旦全部遮断してから、
  • 自宅で使っている 192.168.0.0/16 のアドレス帯のみ許可します。

forward の部分でフォワード先を設定していて、全部Google Public DNSやCloudflare DNSに聞くことにしています。

management で管理用APIの設定をしています。 /metrics/prometheus で Prometheus 向けのメトリクスを取得できます。

起動

docker compose で起動します。

docker compose up -d

Knot DNS の設定を書き換えた場合は以下のコマンドで更新できます。

docker exec -it knot_resolver kresctl reload

また、現在反映されている設定の内容は

docker exec -it knot_resolver kresctl config get

で取得できます。

おまけ:苦労したこと

コンテナのportsでアドレスをしていないときに

dig example.com @localhost
dig example.com @127.0.0.1

でのテストはちゃんとアクセス制御の設定をちゃんとしないとうまくいきませんでした。 具体的には、127.0.0.1 だけではなく、コンテナネットワークで使用される 172.16.0.0/12 も許可に含める必要がありました。

コンテナ側でもアドレスをちゃんと指定して、テストの際も

dig example.com @192.168.11.4

というようにすれば上記のようなアクセス制御を書かなくても問題ないです。

最後に

Knot Resolver を docker を使って構築してみました。 ドキュメント以外に参考にできる情報がなかったのでちょっと苦労しましたが、無事動くようになってよかったです。 DNSSECとか性能チューニングとかできることはまだありそうなので、ぼちぼちやってみようと思います。

DNSSECはデフォルトで対応しているみたいです*4。パブリックDNSフォワードする設定を外すとADフラグが立っていることを確認できました。

*1:

On machines with multiple IP addresses, avoid listening on wildcards like 0.0.0.0 or ::. If a client can be reached through multiple addresses, UDP answers from a wildcard address might pick a wrong source address - most well-behaved clients will then refuse such a response.

Addresses and services — Knot Resolver 6.0.8 documentation

*2:

The easiest way to configure Knot Resolver is via the /etc/knot-resolver/config.yaml file containing a declarative YAML configuration.

Configuration — Knot Resolver 6.0.8 documentation

*3:ログを確認すると

[INFO] knot_resolver_manager.server: Loading configuration from '/config/config.yaml' file.

と書いてある

*4:

Since version 4.0, DNSSEC validation is enabled by default.

DNSSEC, data verification — Knot Resolver 6.0.8 documentation