CoreDNS入門

# はじめに

この記事は[MicroAd Advent Calendar 2017](https://qiita.com/advent-calendar/2017/microad)の6日目の記事です。

サービスディスカバリ兼内部DNSとしてCoreDNSの導入を検証しており、使い方について簡単に纏めてみました。

## CoreDNSとは

CNCFのプロジェクトのひとつです。
設定を柔軟に管理できるDNSのソフトウェアになります。
SkyDNSと互換があり、etcdをバックエンドとしたDNSサーバとして動作します。
それ以外にもdnsmasqよろしくhostsファイルをベースに名前解決できたりもして、便利な全部のせDNSって感じです。
ちょうど2017/12/1に`v1.0.0`がリリースされました。

## 動かしてみる

では早速動かしてみます。バイナリDLして動かします。

[githubのreleaseページ](https://github.com/coredns/coredns/releases)にバイナリ置いてあるので適当にDLしてパスを通します。

パスが通っているか確認します。

```shell-session
$ coredns -version
CoreDNS-1.0.0
linux/amd64, go1.9.2, a04eeb9c
```

ポート1053で起動します。
また、Corefileという設定ファイルを引数で渡します。


```shell-session
$ coredns -conf Corefile -dns.port 1053
```

```:Corefile
. {
    whoami
    errors
    log
}
```


ちなみに、Corefileのファイル形式はMicroAdのアドベントカレンダーで[昨日紹介していた](https://qiita.com/mmotoi/items/1af28e2e62a4e344eb6c)Caddyと同じ形式になります。
というのも、CoreDNSの元々の出自がCadddyのDNSプラグインだったからだそうです。[※](https://www.infoq.com/jp/news/2017/05/cncf-growing-portfolio)

設定ファイルの中身を解説すると、まず先頭のドットはDNSにおけるrootドメインを表しています。
なのでカッコ内部はrootドメイン配下のドメインについての名前解決における設定となります。

そして`whoami`,`erros`,`logs`といった設定の羅列ですが、これらはrootドメイン配下で有効化するプラグインのリストになります。
CoreDNSはプラグイン形式をとっており、各ドメインの配下の設定として、どのプラグインを有効化していくか記述していく設定方式をとります。

`whoami`プラグインはCoreDNSが動いているローカルIPを返すCoreDNSの動作検証用プラグインです。
`errors`と`log`は名前の通りログを出力するプラグインです。

とりあえずこの状態でdigを使って問い合わせすると、何らか応答がかえってきます。

```shell-session
$ dig -p 1053 @localhost  AAAA .

 ~抜粋~
 ;; ADDITIONAL SECTION:
.			0	IN	AAAA	::1
_udp.			0	IN	SRV	0 0 49745 .

;; Query time: 0 msec
;; SERVER: ::1#1053(::1)
;; WHEN: 火 12月 05 19:19:29 JST 2017
;; MSG SIZE  rcvd: 78
```

動いているっぽい事が分かります。

## リゾルバとして利用する

とりあえず動きました。
とは言っても単にローカルIPだけを返すDNSなんて糞の約にも立たないので、まずはDNSリゾルバとして機能するように設定してみます。
Corefileを以下の内容に編集します。

```:Corefile
. {
    proxy . 8.8.8.8:53 {
        protocol https_google
    }
    errors
    log
}
```

Proxyプラグインを使ってDNSリバースプロキシとしての設定を追加しています。
CoreDNSはリバプロの問い合わせ先としてgoogleの提供する https://dns.google.com を設定することができます。

設定変更後は`SIGUSR1`を送れば設定をリロードしてくれます。

```shell-session
$ pkill -10 coredns
```

リロードが上手く言ってれば以下のようなログが出ます。

```
2017/12/05 19:41:11 [INFO] SIGUSR1: Reloading
2017/12/05 19:41:11 [INFO] Reloading
2017/12/05 19:41:12 [INFO] Bootstrapping A records "dns.google.com." found: [216.58.197.174:443]
2017/12/05 19:41:12 [INFO] Reloading complete
```

では名前解決が可能か確認してみます。

```shell-session
$ dig -p 1053 @localhost A qiita.com +noall +answer
qiita.com.		56	IN	A	54.248.73.175
qiita.com.		56	IN	A	46.51.250.143
```

リゾルバとして仕事してることが確認できました。

## 静的なエントリを追加する

dnsmasqっぽくhostsファイルから名前解決してみます。

適当なディレクトリ（例だと`/tmp/hosts`)に以下のhostsファイルを置きます。

```:hosts
192.168.1.1 hoge.example
192.168.1.2 hoge.sub.example
192.168.1.3 example.com
```

Corefileを書き換えます。

```:Corefile
. {
    proxy . 8.8.8.8:53 {
        protocol https_google
    }
    errors
    log
}


example {
    hosts /tmp/hosts example {
        192.168.1.4 hoge4.example
    }
    errors
    log
}
```

リロード後、digで確認すると.exampleドメインの名前はローカルのIPで解決できます。

```shell-session
$ dig -p 1053 @localhost A hoge.example +noall +answer
hoge.example.		3600	IN	A	192.168.1.1
$ dig -p 1053 @localhost A hoge.sub.example +noall +answer
hoge.sub.example.	3600	IN	A	192.168.1.2
$ dig -p 1053 @localhost A hoge4.example +noall +answer
hoge4.example.		3600	IN	A	192.168.1.4
```

hostsプラグインの対象ドメインでは無いexample.comについてはrootドメインの設定に合致してgoogleに名前解決に行き、グローバルに正しいIPが返却されます。

```shell-session
$ dig -p 1053 @localhost A hoge.example.com +noall +answer +autority
example.com.		3695	IN	A	93.184.216.34
```

## 動的なエントリを追加する

SkyDNSと互換があり、完全に同じ方法でetcdをバックエンドとした動的なエントリの追加ができます。

この辺はSkyDNSとほぼ同じなのでざっくり行きます。

バックエンドのetcdをコンテナで立てます。

```shell-session
$ docker run -p 2379:2379 -p 2380:2380 quay.io/coreos/etcd:latest /usr/local/bin/etcd \
    --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379
```

Corefileを書き換えてtestドメインをetcdで管理させます。

```:Corefile
. {
    proxy . 8.8.8.8:53 {
        protocol https_google
    }
    errors
    log
}

example {
    hosts /tmp/hosts example {
        192.168.1.4 hoge4.example
    }
    errors
    log
}

test {
    etcd test {
        path /skydns
        endpoint http://localhost:2379
    }
    errors
    log
}
```

etcdctlでデータを突っ込んでdigで確認します。

```shell-session
$ etcdctl set /skydns/test/hoge '{"host":"192.168.1.5","port":8080}'
{"host":"192.168.1.5","port":8080}
$ /tmp/etcd-download-test/etcdctl get /skydns/test/hoge
{"host":"192.168.1.5","port":8080}
$ dig -p 1053 @localhost A hoge.test +noall +answer
hoge.test.		300	IN	A	192.168.1.5
```

こんな感じで動的にDNSエントリを追加できます。便利！

## 終わりに

以上、ざっくりとしたCoreDNSの使い方でした。
他のも機能が色々あってもちろん普通のZoneファイルを元にした設定もできますし、Kubernetes連携、というよりkube-dnsの代わりにCoreDNSを使うといった事もできるようです。