从0到1搞定智能DNS
一、理论基础
1.1 DNS的出现和演化
网络出现的早期是使用 IP 地址通讯的,那时就几台主机通讯。但是随着接入网络主机的增多,这种数字标识的地址非常不便于记忆,UNIX 上就出现了建立一个叫做 hosts 的文件(Linux 和 Windows 也继承保留了这个文件)。这个文件中记录着主机名称和 IP 地址的对应表。这样只要输入主机名称,系统就会去加载 hosts 文件并查找对应关系,找到对应的 IP,就可以访问这个 IP 的主机了。但是后来主机太多了,无法保证所有人都能拿到统一的最新的 hosts 文件,就出现了在文件服务器上集中存放 hosts 文件,以供下载使用。互联网规模进一步扩大,这种方式也不堪重负,而且把所有地址解析记录形成的文件都同步到所有的客户机似乎也不是一个好办法。这时 DNS 系统出现了,随着解析规模的继续扩大,DNS 系统也在不断的演化,直到现今的多层架构体系。
1.2 DNS概念入门
DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的 IP 数串。通过主机名,最终得到该主机名对应的 IP 地址的过程叫做域名解析(或主机名解析)。DNS 协议运行在 UDP协议之上,使用端口号 53。DNS 的分布式数据库是以域名为索引的,每个域名实际上就是一棵很大的逆向树中路径,这棵逆向树称为域名空间(domain name space)。如图所示树的最大深度不得超过 127 层,树中每个节点都有一个可以长达 63 个字符的文本标号。
1.3 DNS域名解析过程
首先,客户端先在本地缓存查找有没有域名缓存,如果没有,客户端发出 DNS 请求翻译 IP 地址或主机名。
DNS 服务器在收到客户机的请求后:
(1)检查 DNS 服务器的缓存,若查到请求的地址或名字,即向客户机发出应答信息;
(2)若没有查到,则在数据库中查找,若查到请求的地址或名字,即向客户机发出应答信息;
(3)若没有查到,则将请求发给根域 DNS 服务器,并依序从根域查找顶级域,由顶级查找二级域,二级域查找三级,直至找到要解析的地址或名字,即向客户机所在网络的 DNS 服务器发出应答信息,DNS 服务 器收到应答后现在缓存中存储,然后,将解析结果发给客户机。
(4)若没有找到,则返回错误信息。
1.4 DNS 的分类
主DNS服务器:就是一台存储着原始资料的 DNS 服务器。
从DNS服务器:使用自动更新方式从主 DNS 服务器同步数据的 DNS 服务器。也成辅助 DNS 服务器。
缓存服务器:不负责本地解析,采用递归方式转发客户机查询请求,并返回结果给客户机的 DNS 服务器。 同时缓存查询回来的结果,也叫递归服务器。
转发器:这台 DNS 发现非本机负责的查询请求时,不再向根域发起请求,而是直接转发给指定的一台或者多台服务器。自身并不缓存查询结果。
1.5 DNS 中记录类型
SOA 可以理解为一段为自己dns做备注说明的文本,一般与ns一致
比如:dns.chuck-blog.com sa.chuck-blog.com
示例:
a.shifen.com. 579 IN SOA dns.baidu.com. sa.baidu.com. (
1408010001 ; serial number
5 ; refresh 5s
5 ; retry 5s
86400 ; expire 1d
3600 ;min TTL 1h
)
NS 域的授权名称服务器
NSDName:DNS 的 FQDN
baidu.com. 64899 IN NS ns2.baidu.com.
baidu.com. 64899 IN NS ns4.baidu.com.
baidu.com. 64899 IN NS dns.baidu.com.
baidu.com. 64899 IN NS ns7.baidu.com.
baidu.com. 64899 IN NS ns3.baidu.com.
MX 域的邮件交换器,要跟着一个优先级值,越小越高
baidu.com. 7200 IN MX 20 jpmx.baidu.com.
baidu.com. 7200 IN MX 20 mx50.baidu.com.
baidu.com. 7200 IN MX 10 mx.n.shifen.com.
baidu.com. 7200 IN MX 20 mx1.baidu.com.
A记录 IPV4主机地址 域名==》IP
AAAA IPV6主机地址
PTR 解析IP的指针,反向记录(服务器多的时候,通过ip映射出域名或主机名,也可以定位服务器位置,私有云搭建时最好也使用PRT记录)
CNAME 权威(正式)名称,定义别名记录,流量大或者出现故障时可以用来切域名
www.baidu.com. 1154 IN CNAME www.a.scahifen.com.
1.6、DNS命名规范
1). 26个英文字母
2). “0,1,2,3,4,5,6,7,8,9”十个数字
3). “-”(英文中的连词号)
4). 最多63字节长度
要不按照这个,bind支不支持,支持,合适么,不合适。
非要不按照这个,怎么办?master-view文件上配置check-names ignore;
二、使用bind搭建DNS服务器
2.1环境准备
机器:两台centos虚拟机
主DNS:系统环境和安装bind
[root@linux-node1 ~]# uname -r
2.6.32-573.el6.x86_64
[root@linux-node1 ~]# uname -n
linux-node1
[root@linux-node1 ~]# uname -m
x86_64
[root@linux-node1 ~]#
yum install -y bind-utils bind bind-devel bind-chroot
[root@linux-node1 ~]# rpm -qa|grep bind
bind-libs-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-utils-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-chroot-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-devel-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-9.8.2-0.37.rc1.el6_7.6.x86_64
从DNS:系统环境和安装bind
[root@linux-node2 ~]# uname -r
2.6.32-573.el6.x86_64
[root@linux-node2 ~]# uname -n
linux-node1
[root@linux-node2 ~]# uname -m
x86_64
[root@linux-node2 ~]#
yum install -y bind-utils bind bind-devel bind-chroot
[root@linux-node1 ~]# rpm -qa|grep bind
bind-libs-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-utils-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-chroot-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-devel-9.8.2-0.37.rc1.el6_7.6.x86_64
bind-9.8.2-0.37.rc1.el6_7.6.x86_64
2.2部署master-ns
编辑nameserver配置文件
[root@linux-node1 ~]# cat /etc/named.conf
options {
version "1.1.1";
listen-on port 53 {any;}; #监听53端口,any集群时需要添加vip,此处始终any即可
directory "/var/named/chroot/etc/"; #bind软件的安全机制,即使是root用户进来,最多只会进入到chroot目录,chroot目录也称假根。
pid-file "/var/named/chroot/var/run/named/named.pid";
allow-query { any; }; #允许哪些地址可以请求
Dump-file "/var/named/chroot/var/log/binddump.db";#将内存数据存到这里
Statistics-file "/var/named/chroot/var/log/named_stats";
#状态文件,监控用得到
zone-statistics yes; #智能DNS针对不同zone进行数据分析
memstatistics-file "log/mem_stats";#内存状态的文件
empty-zones-enable no; #避免误操作导致线上问题
forwarders {202.106.196.115;8.8.8.8; };#自己解析不了,直接转发给别的ns,让他给解析
};
key "rndc-key" { #rndc组件通过key和ip的方式允许谁可以执行reload操作
algorithm hmac-md5;
secret "Eqw4hClGExUWeDkKBX/pBg=="; #key,用来联系rndc
};
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc-key"; }; #允许127.0.0.1的953端口链接,使用rndc-key
};
logging { #日志相关记录
channel warning {
file "/var/named/chroot/var/log/dns_warning" versions 10 size 10m;
severity warning;
print-category yes;
print-severity yes;
print-time yes;
};
channel general_dns {
file "/var/named/chroot/var/log/dns_log" versions 10 size 100m;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
category default {
warning;
};
category queries {
general_dns;
};
};
include "/var/named/chroot/etc/view.conf";
编辑rndc.key文件,用来管理ns
[root@linux-node1 ~]# cat /etc/rndc.key
key "rndc-key" {
algorithm hmac-md5;
secret "Eqw4hClGExUWeDkKBX/pBg=="; #key和named.conf保持一致
};
编辑rndc的配置文件
[root@linux-node1 ~]# cat /etc/rndc.conf
key "rndc-key" {
algorithm hmac-md5;
secret "Eqw4hClGExUWeDkKBX/pBg==";
};
options {
default-key "rndc-key";
default-server 127.0.0.1;
default-port 953;
};
编辑view.conf,文件名自己定义的
[root@linux-node1 ~]# cat /var/named/chroot/etc/view.conf
view "View" {
zone "chuck-blog.com" { #为哪个域名提供解析
type master; #此ns为master
file "chuck-blog.com.zone"; #这个file的相对路径在 /var/named/chroot/etc/下
allow-transfer {
10.0.0.8; #允许谁来同步
};
notify yes;
also-notify {
10.0.0.8; #通知谁来同步
};
};
};
配置chuck-blog的zone文件,下面是对配置文件中几个名词的解释
1)Serial:只是一个序号,但这个序号可被用来作为 slave 与 master 更新的依据。 举例来说, master 序号为 100 但 slave 序号为 90 时,那么这个 zone file 的资料就会被传送到 slave 来更新了。由于这个序号代表新旧资料,通常我们建议你可以利用日期来设定!举例来说,上面的资料是在 2006/10/20 所写的第一次,所以用 2006102001 作为序号代表!(yyyymmddnn,nn代表这一天是第几次修改)
2)Refresh:除了根据 Serial 来判断新旧之外,我们可以利用这个 refresh(更新) 命令 slave 多久进行一次主动更新;
3) Retry:如果到了 Refresh 的时间,但是 slave 却无法连接到 master 时, 那么在多久之后,slave 会再次的主动尝试与主机连线;
4) Expire:如果 slave 一直无法与 master 连接上,那么经过多久的时间之后, 则命令 slave 不要再连接 master 了! 也就是说,此时我们假设 master DNS 可能遇到重大问题而无法上线,则等待系统管理员处理完毕后, 再重新来到 slave DNS 重新启动 bind 吧!
5) Minimun:这个就有点象是 TTL !
[root@linux-node1 ~]# cat /var/named/chroot/etc/chuck-blog.com.zone
$ORIGIN . #在整个.下生效的,下面可能还有其他zone,如果不配置.,则只在view.conf中的chuck-blog.com下生效
$TTL 3600 ; 1 hour #server端缓存一小时
chuck-blog.com IN SOA op.chuck-blog.com. dns.chuck-blog.com. ( #对DNS服务器在公网做声明,一般配置两个
2000 ; serial#每次改完master文件,都要加大,slave才会同步到;生产环境可以改为时间戳,自自然增大
900 ; refresh (15 minutes)#不配置also notify的时候,slave多久同步一次
600 ; retry (10 minutes)
#slave同步失败相隔多久重试一次
86400 ; expire (1 day) #salve超过多久同步失败,表示salve挂了,不再同步
3600 ; minimum (1 hour) #
)
NS op.chuck-blog.com. #告诉别人自己的DNS服务器的名称,对应的是公网的ip地址
$ORIGIN chuck-blog.com.
shanks A 1.2.3.4
op A 1.2.3.4
更改named目录下的文件属主为named,并启动DNS服务
[root@linux-node1 etc]# cd /var && chown -R named.named named/
[root@linux-node1 etc]# /etc/init.d/named start
启动 named: [确定]
[root@linux-node1 etc]# chkconfig named on
使用dig查看解析结果
[root@linux-node1 etc]# dig @127.0.0.1 shanks.chuck-blog.com
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.6 <<>> @127.0.0.1 shanks.chuck-blog.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60720
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;shanks.chuck-blog.com. IN A
;; ANSWER SECTION:
shanks.chuck-blog.com. 3600 IN A 1.2.3.4
;; AUTHORITY SECTION:
chuck-blog.com. 3600 IN NS op.chuck-blog.com.
;; ADDITIONAL SECTION:
op.chuck-blog.com. 3600 IN A 1.2.3.4
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Mar 1 11:38:50 2016
;; MSG SIZE rcvd: 88
2.3部署salve-ns
编辑slave端的name.conf,rndc.key,rndc.conf
[root@linux-node1 etc]# scp /etc/named.conf 10.0.0.8:/etc/
[root@linux-node1 etc]# scp /etc/rndc.* 10.0.0.8:/etc/
编辑slave端的view.conf文件
[root@linux-node2 ~]# cat /var/named/chroot/etc/view.conf
view "SlaveView" {
zone "chuck-blog.com" {
type slave;
masters {10.0.0.7; }; #master,可以写多个,分号隔开
file "slave.chuck-blog.com.zone";
};
};
更改slave的文件属主
[root@linux-node2 ~]# cd /var && chown -R named.named named/
/etc/init.d/named start
chkconfig named on[root@linux-node2 var]# /etc/init.d/named start
启动 named: [确定]
[root@linux-node2 var]# chkconfig named on
修改master端的chuck-blog的zone文件,添加一个A记录;增大serial数字,并重载
[root@linux-node1 etc]# cat chuck-blog.com.zone
$ORIGIN .
$TTL 3600 ; 1 hour
chuck-blog.com IN SOA op.chuck-blog.com. dns.chuck-blog.com. (
2001 ; serial
900 ; refresh (15 minutes)
600 ; retry (10 minutes)
86400 ; expire (1 day)
3600 ; minimum (1 hour)
)
NS op.chuck-blog.com.
$ORIGIN chuck-blog.com.
shanks A 1.2.3.4
op A 1.2.3.4
a A 10.0.0.100
[root@linux-node1 etc]# rndc reload
WARNING: key file (/etc/rndc.key) exists, but using default configuration file (/etc/rndc.conf)
server reload successful
salve会自动同步出一个chuck-blog的zone文件
[root@linux-node2 etc]# pwd
/var/named/chroot/etc
[root@linux-node2 etc]# ll|grep chuck
-rw-r--r-- 1 named named 380 3月 1 12:15 slave.chuck-blog.com.zone
分别在主从两端测试
[root@linux-node2 etc]# dig @10.0.0.7 a.chuck-blog.com
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.6 <<>> @10.0.0.7 a.chuck-blog.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52114
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;a.chuck-blog.com. IN A
;; ANSWER SECTION:
a.chuck-blog.com. 3600 IN A 10.0.0.100
;; AUTHORITY SECTION:
chuck-blog.com. 3600 IN NS op.chuck-blog.com.
;; ADDITIONAL SECTION:
op.chuck-blog.com. 3600 IN A 1.2.3.4
;; Query time: 4 msec
;; SERVER: 10.0.0.7#53(10.0.0.7)
;; WHEN: Tue Mar 1 12:18:18 2016
;; MSG SIZE rcvd: 83
[root@linux-node2 etc]# dig @10.0.0.8 a.chuck-blog.com
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.6 <<>> @10.0.0.8 a.chuck-blog.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33586
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;a.chuck-blog.com. IN A
;; ANSWER SECTION:
a.chuck-blog.com. 3600 IN A 10.0.0.100
;; AUTHORITY SECTION:
chuck-blog.com. 3600 IN NS op.chuck-blog.com.
;; ADDITIONAL SECTION:
op.chuck-blog.com. 3600 IN A 1.2.3.4
;; Query time: 1 msec
;; SERVER: 10.0.0.8#53(10.0.0.8)
;; WHEN: Tue Mar 1 12:18:24 2016
;; MSG SIZE rcvd: 83
三、 添加A,CNAME,MX和PTR记录
3.1 添加A记录
编辑master节点/var/named/chroot/etc/chuck-blog.com.zone,在文件末尾添加一条记录,将serial值+1,执行rndc reload命令
[root@linux-node1 ~]# tail -5 /var/named/chroot/etc/chuck-blog.com.zone
NS op.chuck-blog.com.
$ORIGIN chuck-blog.com.
shanks A 1.2.3.4
op A 1.2.3.4
a A 192.168.122.100
a A 192.168.122.100
分别对master、slave解析下:host a.chuck-blog.com 127.0.0.1 结果应该是192.168.122.100
[root@linux-node1 ~]# host a.chuck-blog.com 127.0.0.1 Using domain server:
Name: 10.0.0.7
Address: 10.0.0.7#53
Aliases:
a.chuck-blog.com has address 192.168.122.100
[root@linux-node2 ~]# host a.chuck-blog.com 127.0.0.1
Using domain server:
Name: 10.0.0.7
Address: 10.0.0.7#53
Aliases:
a.chuck-blog.com has address 192.168.122.100
3.2 添加CNAME记录
编辑master节点/var/named/chroot/etc/chuck-blog.com.zone,在文件末尾添加一条记录,将serial值+1,执行rndc reload命令
[root@linux-node1 ~]# tail -5 /var/named/chroot/etc/chuck-blog.com.zone
shanks A 1.2.3.4
op A 1.2.3.4
a A 192.168.122.100
cname CNAME a.chuck-blog.com.(cname和PTR记录最后一定要写一个.或者直接主机头)
分别对master、slave解析下:host cname.chuck-blog.com 127.0.0.1结果应该是192.168.122.101
[root@linux-node1 ~]# host cname.chuck-blog.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
cname.chuck-blog.com is an alias for a.chuck-blog.com.
a.chuck-blog.com has address 192.168.122.100
[root@linux-node2 named]# host cname.chuck-blog.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
cname.chuck-blog.com is an alias for a.chuck-blog.com.
a.chuck-blog.com has address 192.168.122.100
3.3 添加Mx记录
编辑master节点/var/named/chroot/etc/chuck-blog.com.zone,在文件末尾添加一条记录,将serial值+1,执行rndc reload命令
[root@linux-node1 ~]# tail -5 /var/named/chroot/etc/chuck-blog.com.zone
a A 192.168.122.100
cname CNAME a.chuck-blog.com.
mx MX 5 (此数字越小,优先级越高) 192.168.122.101
mx MX 10 192.168.123.101
分别对master、slave解析下:host mx.chuck-blog.com 127.0.0.1 结果应该是192.168.122.101
[root@linux-node1 ~]# host mx.chuck-blog.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
mx.chuck-blog.com mail is handled by 10 192.168.123.101.chuck-blog.com.
mx.chuck-blog.com mail is handled by 5 192.168.122.101.chuck-blog.com.
[root@linux-node2 named]# host mx.chuck-blog.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
mx.chuck-blog.com mail is handled by 10 192.168.123.101.chuck-blog.com.
mx.chuck-blog.com mail is handled by 5 192.168.122.101.chuck-blog.com.
3.4 添加PTR记录
编辑master节点/var/named/chroot/etc/view.conf,加入ptr的zone配置,配置后如下
[root@linux-node1 etc]# cat view.conf
view "View" {
zone "chuck-blog.com" {
type master;
file "chuck-blog.com.zone";
allow-transfer {
10.0.0.8;
};
notify yes;
also-notify {
10.0.0.8;
};
};
zone "168.192.in-addr.arpa" {
type master;
file "168.192.zone";
allow-transfer {
10.0.0.8;
};
notify yes;
also-notify {
10.0.0.8;
};
};
};
编辑PTR168.1922网段的zone文件
[root@linux-node1 etc]# cat 168.192.zone
$TTL 3600 ; 1 hour
@ IN SOA op.chuck-blog.com. dns.chuck-blog.com. (
2004 ; serial
900 ; refresh (15 minutes)
600 ; retry (10 minutes)
86400 ; expire (1 day)
3600 ; minimum (1 hour)
)
NS op.chuck-blog.com.
102.122 IN PTR a.chuck-blog.com.
更改为named属主并重载配置
[root@linux-node1 etc]# chown named.named 168.192.zone
[root@linux-node1 etc]# rndc reload
编辑从节点的view.conf
[root@linux-node2 etc]# cat view.conf
view "SlaveView" {
zone "chuck-blog.com" {
type slave;
masters {10.0.0.7; };
file "slave.chuck-blog.com.zone";
};
zone "168.192.in-addr.arpa" {
type slave;
masters {10.0.0.7; };
file "slave.168.192.zone";
};
};
从DNS服务器同步
[root@linux-node2 etc]# rndc reload
从节点自动生成一个zone文件
[root@linux-node2 etc]# ll|grep 192
-rw-r--r-- 1 named named 528 3月 3 10:22 168.192.zone
在主从DNS上解析ip:192.168.122.101
[root@linux-node1 etc]# host 192.168.122.102 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
102.122.168.192.in-addr.arpa domain name pointer a.chuck-blog.com.
[root@linux-node2 etc]# host 192.168.122.102 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
102.122.168.192.in-addr.arpa domain name pointer a.chuck-blog.com.
四、DNS负载均衡和DNS视图
4.1 通过DNS实现服务的负载均衡
编辑master节点/var/named/chroot/etc/chuck-blog.com.zone,在文件末尾添加一条记录,将serial值+1,执行rndc reload命令
[root@linux-node1 etc]# tail -5 chuck-blog.com.zone
a A 192.168.122.100
cname CNAME a.chuck-blog.com.
mx MX 5 192.168.122.101
mx MX 10 192.168.123.101
a A 192.168.122.102
a A 192.168.122.102
分别对master、slave解析下:host a.chuck-blog.com 127.0.0.1,结果应该是192.168.122.100和192.168.122.102
[root@linux-node1 etc]# host a.chuck-blog.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
a.chuck-blog.com has address 192.168.122.100
a.chuck-blog.com has address 192.168.122.102
[root@linux-node2 etc]# host a.chuck-blog.com 127.0.0.1
Using domain server:
Name: 127.0.0.1
Address: 127.0.0.1#53
Aliases:
a.chuck-blog.com has address 192.168.122.100
a.chuck-blog.com has address 192.168.122.102
4.2 配置DNS试图(智能DNS)
编辑master节点vim /var/named/chroot/etc/named.conf,修改结果如下
[root@linux-node1 etc]# cat named.conf
options {
version "1.1.1";
listen-on port 53 {any;};
directory "/var/named/chroot/etc/";
pid-file "/var/named/chroot/var/run/named/named.pid";
allow-query { any; };
Dump-file "/var/named/chroot/var/log/binddump.db";
Statistics-file "/var/named/chroot/var/log/named_stats";
zone-statistics yes;
memstatistics-file "log/mem_stats";
empty-zones-enable no;
forwarders {202.106.196.115;8.8.8.8; };
};
key "rndc-key" {
algorithm hmac-md5;
secret "Eqw4hClGExUWeDkKBX/pBg==";
};
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc-key"; };
};
logging {
channel warning {
file "/var/named/chroot/var/log/dns_warning" versions 10 size 10m;
severity warning;
print-category yes;
print-severity yes;
print-time yes;
};
channel general_dns {
file "/var/named/chroot/var/log/dns_log" versions 10 size 100m;
severity info;
print-category yes;
print-severity yes;
print-time yes;
};
category default {
warning;
};
category queries {
general_dns;
};
};
acl group1 {
10.0.0.7;(此处可使用网段)
};
acl group2 {
10.0.0.8;(此处可使用网段)
};
include "/var/named/chroot/etc/view.conf";
编辑view.conf
[root@linux-node1 etc]# cat view.conf
view "GROUP1" {
match-clients { group1; };
zone "viewchuck-blog.com" {#zone的作用:当一个用户请求解析的时候,如果没有这个zone并且没有缓存,就forward(前面有指定)出去;有这个zone,但是zone里面没有记录,直接返回不存在
type master;
file "group1.viewchuck-blog.com.zone";
allow-transfer {
10.0.0.8;
};
notify yes;
also-notify {
10.0.0.8;
};
};
};
view "GROUP2" {
match-clients { group2; };
zone "viewchuck-blog.com" { #zone的作用:当一个用户请求解析的时候,如果没有这个zone并且没有缓存,就forward(前面有指定)出去;有这个zone,但是zone里面没有记录,直接返回不存在
type master;
file "group2.viewchuck-blog.com.zone";
allow-transfer {
10.0.0.8;
};
notify yes;
also-notify {
10.0.0.8;
};
};
};
编辑master节点 /var/named/chroot/etc/group1(2).viewchuck-blog.com.zone
[root@linux-node1 etc]# cat group1.viewchuck-0blog.com.zone
$ORIGIN .
$TTL 3600 ; 1 hour
viewchuck-blog.com IN SOA op.viewchuck-blog.com. dns.viewchuck-blog.com. (
2005 ; serial
900 ; refresh (15 minutes)
600 ; retry (10 minutes)
86400 ; expire (1 day)
3600 ; minimum (1 hour)
)
NS op.viewchuck-blog.com.
$ORIGIN viewchuck-blog.com.
op A 192.168.122.1
view A 192.168.122.1
[root@linux-node1 etc]# cat group2.viewchuck-blog.com.zone
$ORIGIN .
$TTL 3600 ; 1 hour
viewchuck-blog.com IN SOA op.viewchuck-blog.com. dns.viewchuck-blog.com. (
2005 ; serial
900 ; refresh (15 minutes)
600 ; retry (10 minutes)
86400 ; expire (1 day)
3600 ; minimum (1 hour)
)
NS op.viewchuck-blog.com.
$ORIGIN viewchuck-blog.com.
op A 192.168.122.2
view A 192.168.122.2
修改文件所属,加载配置
[root@linux-node1 etc]#chown named.named /var/named/chroot/etc/group*.zone
[root@linux-node1 etc]#rndc reload
在从节点配置named.conf,直接拷贝主节点的即可
[root@linux-node1 etc]#scp -rdp named.conf 10.0.0.8:/var/named/chroot/etc/
在从节点配置view.conf并reload
[root@linux-node2 etc]# cat view.conf
view "GROUP1" {
match-clients { group1; };
zone "viewchuck-blog.com" {
type slave;
masters {10.0.0.7; };
file "slave.group1.viewchuck-blog.com.zone";
};
};
view "GROUP2" {
match-clients { group2; };
zone "viewchuck-blog.com" {
type slave;
masters {10.0.0.7; };
file "slave.group2.viewchuck-blog.com.zone";
};
};
[root@linux-node2 etc]# rndc reload
分别在主机A与B上做view.viewchuck-blog.com的域名解析测试
结果应为主机A上是192.168.122.1主机B上是192.168.122.2
[root@linux-node1 etc]# host view.viewchuck-blog.com 10.0.0.7
Using domain server:
Name: 10.0.0.7
Address: 10.0.0.7#53
Aliases:
view.viewchuck-blog.com has address 192.168.122.1
[root@linux-node2 etc]# host view.viewchuck-blog.com 10.0.0.7
Using domain server:
Name: 10.0.0.7
Address: 10.0.0.7#53
Aliases:
view.viewchuck-blog.com has address 192.168.122.2
五、构建企业级DNS
5.1 硬件选型
cpu:12c以上配置
内存:16G
网络:千兆
注:此配置的QPS可以达到27000上下,可以根据此单台的配置,和线上流量的情况,选择多少台DNS服务器来承接线上的请求,同时保证了DNS的高性能,更要保证DNS高可用。
5.2 初始化系统
1)关闭selinux
2)关闭iptables + chkconfig
3)调整ulimit限制,改为65535
echo -e '* soft nproc 65536\n* hard nproc 65536\n* soft nofile 65536\n* hard nofile 65536\n' >>/etc/security/limits.conf
5.3 构建高性能,高可用的DNS
采用lvs-dr模式负载均衡,多idc,多套dns集群,通过master-slave技术保证dns配置的一致性。
5.3.1 高可用
物理层
首先确保两台lvs不在同一机柜、同一物理交换机接入;
其次确保将所有dns服务器也做到不在同一机柜、同一物理交换机接入。
同时,在不同的idc构建多套dns集群,为客户端提供可切换的配置。
服务层
坚决摒弃lvs上端口检测这种方式,采用自定义脚本检测,为dns的健康检测单独设置一个域名,就为了lvs检测dns是否存活而设计。检测脚本示例如下:
客户端层:
多idc之间的流量切换是通过客户端的健康检测cron实现的,脚本每分钟运行一次,分别检测每个dns集群虚地址的可用性,如果某个虚地址不可用,使用脚本前面添加#注释即可。
5.3.2 高性能
通过lvs可以对每个集群做横向扩容,是否需要扩容的依据是对现有系统的压测结果,以及实时的监控数据。亦或者可以在最靠近应用层处,加上一层cache-only集群,但前提是你的线上环境中,没有任何系统依赖于dns负载均衡。
5.4 压测
安装queryperf
下载并安装
wget http://ftp.isc.org/isc/bind9/9.7.3/bind-9.7.3.tar.gz
tar zxf bind-9.7.3.tar.gz
cd bind-9.7.3/contrib/queryperf/
./configure
make
会在当前目录下出现queryperf,可以将它拷贝至/usr/bin/下
编辑域名记录文件(test.txt),格式如下:
www.baidu.com A
www.baidu.com A
www.baidu.com A
www.baidu.com A
www.baidu.com A
压测命令:queryperf -d test.txt -s 8.8.8.8
按照5.1中的硬件选型,也做了5.2的初始化,这样在相同idc的压测下,单台dns-server的qps可以达到35~40k
5.5 监控
5.5.1 系统基础性能
使用zabbix自带模板即可。Cpu、内存、主机存活、磁盘空间、主机运行时间、系统load
5.5.2 Loopback地址绑定状态监控
该架构中,dnsserver在集群中充当realserver的角色,在dr中,需要绑定loopback地址方能通信,因此当loopback地址没有绑定上时,lvs健康检测通过,但是当请求到达dnsserver时,请求被拒绝,dns集群会出现异常。
5.5.3 Dns数据与master一致性监控
此处方案是分为两部分
一是通过写zabbix自定义discovery,扫出dns配置中所有zone,然后分别对比slave和master每个zone的serial值,当slave与master的值持续5分钟不一致时报警
二是写脚本,每15分钟扫一遍master上所有域名解析结果,与每个slave的结果做对比,当出现结果不一致情况时,报警
5.5.4 Dns响应时间监控
远端一组主机跑在fullnat下(提供高可用),通过dig命令检测dnsserver的响应时间。
5.5.5 Dns每秒请求数监控
在每台dns主机上,编写zabbix脚本,分析named_stats文件,获取每秒请求数
#!/bin/bash
#rndc stats
STATS='/var/named/chroot/var/log/named_stats'
if [[ $# -ne 1 ]]
then
echo "$0 [querys]"
exit 2
else
which=$1
fi
if [[ -f "${STATS}" ]]
then
echo > ${STATS}
rndc stats >/dev/null 2>&1
else
echo "${STATS} not found."
exit 2
fi
case ${which} in
querys)
RESULT=`awk '{if ($2=="QUERY") {print $1}}' ${STATS}`
;;
*)
echo "$0 [querys]"
exit 2
;;
esac
echo ${RESULT}
5.5.6 Dns可用性监控
远端一组主机跑在fullnat下(提供高可用),通过host命令检测dnsserver的可用性,脚本与lvs健康检测脚本类似。
5.6 自动化
5.6.1 saltstack安装、部署
通过定制saltstack配置,实现自动、批量安装、部署dns
5.6.2 配置管理自动化
业界最多的是bind-dlz,dlz是指将所有的配置都存在mysql表中,对bind做特殊配置,使得每次bind接受的请求都去mysql中查询数据之后返回给用户。
5.6.3 bind-dlz的优缺点
优势:将数据全部存在数据库,符合运维开发的理念。
劣势:每次解析都要select数据库,性能低下;
增加了系统的藕合性,还需要保证mysql的高可用。
dlz劣势的解决方案:
1)采用dlz的数据库部分表结构;
2)用thinkphp实现对mysql的增删改查,和一些权限控制的页面,在该页面,用户可以完成对域名的增删改查操作,数据源在MySQL中;
3)通过saltstack+py实现从mysql中调数据,生成bind的配置文件,并检测文件格式,之后reload;
为什么做这些,我要将dns做成可交付、已维护的系统,交付给应用运维同学使用,我只负责dns架构的server端;
此工具开源地址:github
5.7 安全
时刻关注dns相关的漏洞、补丁;
选用稍大些的厂商作为域名服务商,我们是万网;
对服务器的登录日志做监控分析;
5.8 日常运维规范
Dns作为基础服务,在做好高可用、高性能、好扩容的基础上,任何时刻都不能掉以轻心!!!
1)确保所有监控均处于生效状态,每天发监控信息邮件
2)所有新机器,均在saltstack上完成初始化和安装、部署操作,不能单独操作;
3)所有针对dns架构调整的操作,均需在流量低谷时操作;
4)对集群扩容操作时,务必对新加入节点做压测,同时重启服务器并检测5)重启后各项指标是否正常;
6)关注dns相关新闻,时刻跟进;
7)故障演练;
六、DNS的发展趋势
6.1 DNSmasq
DNSmasq是一个小巧且方便地用于配置DNS和DHCP的工具,适用于小型网络,它提供了DNS功能和可选择的DHCP功能。它服务那些只在本地适用的域名,这些域名是不会在全球的DNS服务器中出现的。DHCP服务器和DNS服务器结合,并且允许DHCP分配的地址能在DNS中正常解析,而这些DHCP分配的地址和相关命令可以配置到每台主机中,也可以配置到一台核心设备中(比如路由器),DNSmasq支持静态和动态两种DHCP配置方式。
有一些公司在每台服务器上都起着dnsmasq,充当本地dns缓存服务,来提高dns解析性能同时减轻dnsserver的压力。
6.2 HTTP DNS
但凡使用域名来给用户提供服务的互联网企业,都或多或少地无法避免在有中国特色的互联网环境中遭遇到各种域名被缓存、用户跨网访问缓慢等问题。首先是域名缓存,不同运营商,不同节点的缓存时间设置的差别较大。这样在流量切换时,就会产生新、旧应用数据不一致的现象。其次就是域名解析过了太多层的nat,这就导致dns获取客户端地址时很难准确定位,从而智能dns的准确度大打折扣。
最近两年,httpdns出现了,用户明确的知道我在访问某厂的服务时,应该去找哪个ip要对应的域名,实现这个的前提是你可以左右用户的访问习惯,目前应用最适合的场景是app
在可预见的未来,不论在公司内网还是公网环境,dns在整个架构中,都将会以一个基础服务的位置存在,而目前最为稳定、高效的,依然是bind。
七、生产常见DNS问题以及排障方法
7.1 运维同学突然告诉我,你的DNS不能用了
记得那时我刚来公司还没转正的时候。有个哥们问我,dns现在没什么事吧?卧槽,dns?什么dns记得那会线上跑着多少dns,每台dns配置一不一样,没人说得清楚。于是我说兄弟,你什么dns,怎么了?他告诉我一个ip,说用的这个dns,现在解析不了了。我说我看下,你先改个别的dns,这种时候一定要先恢复业务,然后再排查、解决问题。
我尝试用那台dns解析域名,确实不行了,登上去看,dns进程还在,想来是有什么瓶颈了,看日志吧,在日志中发现有报netfilter满了的日志,怎么tm会报这个呢,难道机器起着iptables?卧槽,还真是起着呢,这不蛋逼呢么。赶紧把iptables停掉,问题恢复了。
在iptable运行时,即便是没有任何规则,所有的报文也要过netfilter表,而dns这种高并发的业务很容易把netfilter表填满,从而影响服务。
后续的工作就是整理线上dns,同一配置,做好监控,做好高可用和负载均衡
7.2 突然收到报警,提示DNS虚地址不能正常解析了
那天请了一天假,还在医院的时候,收到的报警,赶紧电话到公司,询问怎么回事,原来是有同事将zabbix的一个域名删除了,而这个域名恰恰是我lvs健康检测dns服务是否可以提供解析的域名,域名都没了,那肯定解析失败,于是lvs把所有dns都剔除了。
虽然恢复起来很快,但是这也提醒我,系统之间,一定要尽量减小藕合性,避免雪崩。
7.3 调用微信支付接口有超时的现象,错误日志中报解析微信域名失败
接到这个case,首先是确认问题是否出现在域名解析的环节,我登录到服务器上,用nslookup解析对应的域名,连续解析1000次均没问题,但开发小妹依然喋喋不休,我按耐住tmd心情。突然想起也许她php中调用的解析函数与nslookup不同,于是我用host解析,这时发现问题了。每次解析微信支付这个域名的时候,都要等10s左右才出结果。这时,我又找其他机器做测试,发现只有这个微信支付的域名有这种现象,这不由得让我对大qq产生了膜拜的情绪。出现这种情况让人很头大,而旁边开发小妹还在殷切的看着你,你背后还有领导不时的喘着粗气,而恰恰此时你对这问题一点头绪也没有,怎么办?
越是这种时候,越要淡定,不然怎么办?!这玩意不是谁教的,是你多遇到几次这种情况,每次都要提醒自己,冷静、冷静、tmd冷静
既然只有解析微信这个接口有问题,那我想可能是微信对dns这块有什么限制,那我可不可以换个forward的公网dns试下呢?分两头,一头是我去测试,另外一头让同事联系微信,给提供一个qq那边的权威dnsip,最终我将qq权威dns的ip加到我dns的forward列表中解决了这个case。