1. DNS的基本知识

1.1 理解 SOA and GLUE Record

首先要明白什么是SOA,NS,请参见[1]和[2]: 如果用户注册了一个域名,把这个域名的name server设置为你的dns server, 你的这个dns server就是这个域名的权威解析服务器. 就要在配置里添加这个域名的SOA记录,

那什么是GLUE记录呢? 假设你注册了一个域名yourname.com 同时你建了一个DNS用来解析你这个域名的,假设这个DNS你设置为ns1.yourname.com.

你在你的域名注册商那儿,要把你的域名的dns设置ns1.yourname.com.

这里就有一个问题: yourname.com下的所有的域名都要通过ns1.yourname.com这个域名所指向的服务器来解析,但时要知道ns1.yourname.com的IP就要先解析这个域名啊,死循环了.

要想破这个死循环,ns1.yourname.com就不能是通过ns1.yourname.com来解析的. 它必须是上级DNS能知道的.

如何让上级的DNS知道呢? 这就需要在上级的DNS里添加一个GLUE记录,把ns1.yourname.com和它的IP填入GLUE记录.

这里假设ns1.yourname.com的IP为 192.168.88.1.

假设我们添加了一个二级域名test.yourname.com,设置A记录为192.168.88.30.

解析过程是这样的:

  1. test.yourname.com上级DNS,也就是解析com域的DNS接收到查询test.yourname.com请求后,查找yourname.com这个域名的DNS,发现设置为ns1.yourname.com

  2. ns1.yourname.comtest.yourname.com它们在同个域里,需要查询它的GLUE记录,发现ns1.yourname.com的IP为192.168.88.1,于是它向192.168.88.1查询test.yourname.com的记录。

  3. 192.168.88.1接到查询请求后,查找本地的记录,把192.168.88.1这个A记录返回给上级DNS,完成域名到IP的解析。

1.2 如何查看GLUE记录呢?

我们用一个实际的例子来看一下.我们看一下百度的域名

$ dig NS baidu.com
...

;; QUESTION SECTION:
;baidu.com.            IN    NS

;; ANSWER SECTION:
baidu.com.        1    IN    NS    ns7.baidu.com.
baidu.com.        1    IN    NS    ns2.baidu.com.
baidu.com.        1    IN    NS    ns4.baidu.com.
baidu.com.        1    IN    NS    ns3.baidu.com.
baidu.com.        1    IN    NS    dns.baidu.com.

...

我们可以看到百度也是自己解析域名的.所以肯定是有GLUE记录添加到com的DNS上的. 接下来我们看看com的DNS

dig NS com

...

;; QUESTION SECTION:
;com.                IN    NS

;; ANSWER SECTION:
com.            164153    IN    NS    e.gtld-servers.net.
com.            164153    IN    NS    a.gtld-servers.net.
com.            164153    IN    NS    l.gtld-servers.net.
com.            164153    IN    NS    g.gtld-servers.net.
com.            164153    IN    NS    k.gtld-servers.net.
com.            164153    IN    NS    c.gtld-servers.net.
com.            164153    IN    NS    f.gtld-servers.net.
com.            164153    IN    NS    j.gtld-servers.net.
com.            164153    IN    NS    m.gtld-servers.net.
com.            164153    IN    NS    b.gtld-servers.net.
com.            164153    IN    NS    h.gtld-servers.net.
com.            164153    IN    NS    d.gtld-servers.net.
com.            164153    IN    NS    i.gtld-servers.net.

...

我们来查询一下baidu.com的NS记录.

$ dig NS baidu.com @b.gtld-servers.net

...

;; QUESTION SECTION:
;baidu.com.            IN    NS

;; AUTHORITY SECTION:
baidu.com.        172800    IN    NS    dns.baidu.com.
baidu.com.        172800    IN    NS    ns2.baidu.com.
baidu.com.        172800    IN    NS    ns3.baidu.com.
baidu.com.        172800    IN    NS    ns4.baidu.com.
baidu.com.        172800    IN    NS    ns7.baidu.com.

;; ADDITIONAL SECTION:
dns.baidu.com.        172800    IN    A    202.108.22.220
ns2.baidu.com.        172800    IN    A    61.135.165.235
ns3.baidu.com.        172800    IN    A    220.181.37.10
ns4.baidu.com.        172800    IN    A    220.181.38.10
ns7.baidu.com.        172800    IN    A    119.75.219.82
...

其中的ADDITIONAL SECTION部分就是GLUE记录.

1.3 理解 txt Record

https://en.wikipedia.org/wiki/TXT_record

在kubernetes里有用到!
這裏是google的解釋:

TXT记录的工作原理
TXT记录可包含任何文本值,具体取决于它的用途。
例如,Google使用TXT记录来验证您拥有希望用于我们企业服务的网域。
具体而言,我们会要求您输入TXT记录,其值为“google-site-verification=rXOxyZounnZasA8Z7oaD3c14JdjS9aKSWvsR1EbUSIQ”。
之后,我们会查询您的网域以确定该TXT记录是否已生效。
如果TXT记录已生效,那么我们会知道您有权访问该网域的DNS设置,那么您一定拥有该网域。

1.4 理解PowerDNS的Authoritative Server 和 Recursor

The Authoritative Server will answer questions about domains it knows about, but will not go out on the net to resolve queries about other domains. However, it can use a recursing backend to provide that functionality

Authoritative Server只回答它知道的域名的信息,它不知道的域名,不会去问网上的其它name server. 不过它可以通过遍历后端(recursing backend)来实现这个功能. 你可以理解为它是这样的一个专家:我知道什么我就答什么,不知道的我也不问别的专家. 不过我有一个后端团队(backend),如果他们知道答案,也可以代我回答.

Recursor 可以理解为一个域名的缓存,本身没有域名信息,你问我,我就问别人(DNS)去.
很多dns是把这两部分的功能融合在一起的,PowerDNS把它们分开提供.

1.5 规划

在VirtualBox里启动两台Ubuntu 16.04的虚机,安装系统自带的PowerDNS,一台设置为master,另一台设置为Slave. 172.16.69.70

First HeaderSecond HeaderSecond HeaderSecond HeaderSecond Header
Content CellContent CellContent CellContent CellContent Cell
Content CellContent CellContent CellContent CellContent Cell

1.6 安装 PowerDNS

安装非常简单:

$ sudo apt install mysql-server 

一定要先安装mysql然后再安装powerdns,而且一定要用安装程序的提示来配置mysql。

$ sudo apt install pdns-server  pdns-backend-mysql

在弹出的对话框Configuring pdns-backend-mysql里填入一个密码,我在这里输入了powerdns.

首先/etc/powerdns/pdns.d目录请只保留pdns.local.gmysql.conf这个文件。

之前我保留了pdns.simplebind.conf这个文件,powerdns就报错。

powerdns Trying to set unexisting parameter 'gmysql-host'
mysql> insert into supermasters values ('111.111.111.111', 'ns2.example-dns.com', 'admin');

1.7 错误处理

因为我是在实验环境搭建的这两个dns.

# /etc/hosts

172.16.69.70 ns1.xiangcloud.com.cn
172.16.69.71 ns2.xiangcloud.com.cn

然后我添加一个测试的域名,它不同步.奇怪. 我把master的日志级别设置为

loglevel=7

然后在/var/log/syslog

Notification for hhhhh.com. to 192.157.208.178:53 failed after retries

这个IP不是slave的IP啊?

明明是已经在/etc/hosts里配置了,PowerDNS怎么不认呢? 我没办法又启动了两个ubuntu 14.04,安装了powerdns 3.3,同样的配置,它可以正常同步. 看来是master的问题, 16.04的PowerDNS是4.0的,可能已经不支持读取/etc/hosts里的配置了. 于是我把这两条NS记录

172.16.69.70 ns1.xiangcloud.com.cn
172.16.69.71 ns2.xiangcloud.com.cn

添加到14.04的PowerDNS里,把70的dns设置为72.

再用命令强制同步就可以了.

$ pdns_control notify hhhhh.com

这个问题在线上系统上应该是不会出现的,因为线上系统的ns记录一定是以GLUE记录的方式添加到上级DNS里的.

问题2: PowerDNS SOA Serial are not updated automatically

虽然可以同步了,但是添加的域名在API更新了记录时, SOA Serial不自动更新,Slave发现 SOA Serial没变化就同步记录了.
所以我们需要在记录变化时自动更新SOA Serial.我在网上找了N久终于找到了相关的设置.

在通过API创建zone的时候添加下面的参数:

"soa_edit_api" : "INCEPTION-INCREMENT",

http://jpmens.net/2015/01/09/a-look-at-the-powerdns-rest-api/

Received NOTIFY for xiangcloud.com.cn. from 122.115.54.57 which is not a master

场景是这样的: 我从原来的dns里导出了域名解析的信息,然后通过powerdns的api插入到了主powerdns里. 不知道什么原因,这些记录没有同步过来,后来我重启了slave的pdns进程. 我发现没有同步后,我就手动把主powerdns的域名和解析记录导出mysqldump出来,导入到slave powerdns里了. 接下来我在master上添加记录,发现还是同步不了.就报上面的这个错误.

看了源代码:

//packethandler.cc
  else if(!db->isMaster(p->qdomain, p->getRemote().toString())) {
    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
    return RCode::Refused;
  }

db是一个DNSBackend,我们用的是sqlbackend,所以其实它是GSQLBackend 是去数据库里查询域名了.然后比对这个域名的master字段.如果字段与给 p->getRemote() 也是上面的122.115.54.57不相等,那就报这个错. 我看了slave上的pdns数据库里的domains表,记录里master字段为空.

于是新插了一个域名,发现同步是好使的,在slave上的pdns数据库里的domains表里,记录是这样的.

mysql> select * from domains where name = 'junaidong1.com.cn';
+-------+-------------------+---------------+------------+-------+-----------------+---------+
| id    | name              | master        | last_check | type  | notified_serial | account |
+-------+-------------------+---------------+------------+-------+-----------------+---------+
| 16266 | test.com.cn | 122.115.54.57 | 1497338783 | SLAVE |            NULL | admin   |
+-------+-------------------+---------------+------------+-------+-----------------+---------+
1 row in set (0.00 sec)

要想实现同步,slave上的数据必须是这样的.

原因找到就好办了,手动把slave上的数据库里的domains表的 master,last_check,type这三个字段加上内容就可以了.

参考:

[1] SOA Records
[2] http://www.zytrax.com/books/dns/ch8/soa.html
[3] How To Install and Configure PowerDNS with a MariaDB Backend on Ubuntu 14.04
[4] dns 里的glue records是什么意思,有什么作用?
[5] Circular_dependencies_and_glue_records [6] 自建PowerDNS免费DNS服务器-PowerDNS和MariaDB安装配置教程
[7] 搭建一套权威 DNS 服务架构