园区网为主的 DNS 架构设计

image.png

前言

DNS 这个东西,可大可小,可简单可复杂。对于以园区网为主的传统企业/单位而言,要考虑多出口的链路优化,智能解析,私有域名的解析 ,监控,管理等一系列问题,还是需要有一个好的设计优化的。

我们前阵子刚完成了 DNS 架构的升级,在这里整理一下做个分享

需求分析

在讨论 DNS 的架构之前我们先分析一下我们的需求

多链路优化

通常一个园区网都会有多个出口。我们需要通过路由策略来决定用户的请求最终落入那个出口上。在网络层上,BGP 自然不必多说了,静态路由的话,我们也可以设法去弄到各个运营商的地址表(万能的淘宝)然后写入路由,从而让用户的请求落入最合理的出口链路上。

“让用户的请求落入最合理的出口链路上”,靠路由表就够了吗?非也,因为还有 CDN。很自然的,由于有 CDN ,大部分网站的所提供的解析,都会根据用户的 DNS 请求来源,而智能解析到对应运营商区域内的 CDN 上。也就是说,实际上我们 DNS 递归时的网络路由策略,基本决定了用户访问网站的实际路由。例如我们的 DNS 通过电信的链路去递归解析,那么用户解析到的网站地址多半也会落在该网站的电信 CDN 上,因此最终的请求也将被路由至电信链路上。

现在的问题在于,不同网站,在不同链路的 CDN 上的访问体验是不一致的!举个例子,QQ 邮箱(mail.qq.com),如果他落在教科网的 CDN 上,附件经常就传不上去。12306 在电信的 CDN 上访问很快,而在教科网的 CDN 上就经常卡的飞起。。。说到底这其实就是不同链路之间的质量差异,毕竟价格也要差好多呢。

把默认路由全都给质量最好的链路就行了呗?
理想很丰满,但是小钱钱很骨干呐!实际上我们拥有的链路带宽大小通常也与链路质量成反比。因此我们需要在用户的访问体验和链路的带宽利用率上寻找一个平衡。

智能解析

如同 CDN 一般。我们自己也有多条出口,因此我们自己的服务在提供 DNS 解析的时候,也得根据用户解析的请求地址,来进行智能的解析,来提高我们网站的外部访问速率。

私有域名

在我们的数据中心里,我们会需要一些私有的域名分配给服务器。这样会方便管理,也可以利用 DNS 做一些服务注册的工作。所以我们要有私有的域名,但是需要限制在数据中心之内,避免园区内的普通用户能够直接解析到。

API

刚才我们提到了服务注册。实际上无论是从运维自动化来考虑还是流程自动化来考虑,我们都需要 DNS 对应的 API 接口,能够让我们自动化的注册,修改,删除域名。

服务状态监控

如同我们所有的服务一样,DNS 我们也需要有对应的服务监控。这需要我们的 DNS 本身能够暴露出相应的状态接口,提供服务状态的查询方法。我们通过脚本等去采集状态信息推送给监控系统(Open-Falcon)

管理

我们需要一个方便易用的前端来做 DNS 的域名管理。需要能够进行权限的控制,给不同的域分配不同的管理员。能够记录每次变更的操作记录。彻底结束 SSH 到服务器上改 ZONE 文件的历史。
同时后端数据最好落到数据库里,这样做一些查询的时候会方便很多。比如我要查所有解析的 IP 落在外部而非校内 IP 的域名,数据库里只要一条 SQL 就搞定了,而 ZONE 文件的话就得写脚本了。

传统架构

大家可能看过前阵子 GitHub 的 dns-infrastructure-at-github 这篇文章。这里面 GitHub 说他们以前的 DNS 架构就是两台服务器,包含了缓存,递归和权威服务。文章里没说用的是啥软件,不过 8 成是 Bind 吧。
我们学校之前的 DNS 架构也是如此,两台 Bind 做完所有的事情。我所了解的许多学校 DNS 架构亦是如此。很多地方的 DNS 架构都是这样子,简单,稳定。

然而对应我们刚才的需求

  1. 多链路优化——搞不了
  2. 智能解析——这个可以用 bind views 来做
  3. 私有域名——不好控制园区普通用户的访问
  4. API——木有
  5. 服务状态监控——只能通过分析日志,有限
  6. 管理——Bind 都有对应的第三方解决办法,但是都相对比较麻烦

新架构

技术选型

GitHub 在 dns-infrastructure-at-github 里面提到,他们使用了 Unbound 作为缓存,NSD 作为边缘节点,PowerDNS 作为权威服务。

我们则选择了使用 PowerDNS 全家。即PowerDNS-Authoritative 作为权威服务,PowerDNS-Recursor 作为递归服务,dnsdist 作为边缘节点来提供智能解析。
并且使用 PowerDNS-Admin 进行权威服务的管理。

架构

先看总体架构

image.png
递归服务

我们将两台主递归服务器默认通过链路质量稍差一点,但带宽比较充裕的 ISP 进行递归。同时,在链路质量较好的 ISP 上再放两台递归服务器,将部分域名 Forward 给他去递归,从而在基本不降低用户访问体验的情况下,充分利用两条链路的带宽。

当然我们会把自身的域名直接 Forward 给我们的权威服务,避免了无谓的外部递归。

权威服务

我们根据两条不同的链路做了两套权威服务,一套解析 ISP-1 的地址,另一台则解析为 ISP-2 的地址。然后在这两套权威服务之前,放了两台 dnsdist 作为边缘节点。

dnsdist 根据请求的 IP 地址,将请求转发给对应的后端权威服务,实现智能解析。

私有域名

在数据中心内,我们需要一些私有的内部域名来做点服务注册之类的活。这些域名我们希望只能被我们数据中心内的服务器们请求到,普通的园区用户无法请求。
类似的,我们在私有的权威服务之前,使用 dnsdist 进行 ACL 过滤。这两台 dnsdist 就作为数据中心的
DNS 服务提供给服务器使用。仅匹配数据中心网段的服务器允许解析,并转发私有的域名请求给权威服务器,其他请求则转发给园区的主递归服务。普通用户的请求则无法匹配 ACL 将被拒绝。

image.png

API

Powerdns 提供了简单易用的 API 调用。像这样

# curl -v -X PATCH -H 'X-API-Key: d37757d0adfa0d3dc26a11119134f92' --data '{"rrsets":[{"name":"testtesttest.ecnu.edu.cn.","type":"A","ttl":3600,"changetype":"REPLACE","records":[{"content":"192.168.0.1","disabled":false,"set-ptr":false}]}]}' "http://127.0.0.1:8081/api/v1/servers/localhost/zones/ecnu.edu.cn"
* About to connect() to 127.0.0.1 port 8081 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8081 (#0)
> PATCH /api/v1/servers/localhost/zones/ecnu.edu.cn HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8081
> Accept: */*
> X-API-Key: d37757d0adfa0d3dc26a11119134f92
> Content-Length: 165
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 165 out of 165 bytes
< HTTP/1.1 204 No Content
< Access-Control-Allow-Origin: *
< Connection: close
< Content-Length: 0
< Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
< Server: PowerDNS/4.1.0-rc1
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Permitted-Cross-Domain-Policies: none
< X-Xss-Protection: 1; mode=block
< 
* Closing connection 0

所以我们可以很容易的将他和流程系统,运维系统进行对接。实现域名注册的自动化

监控

与 Bind 最大的区别就在监控上了。Powerdns 内置了大量的性能指标项,我们可以非常容易的去采集这些指标,然后推送给我们的监控系统。详细的指标可以参看官网说明:
recursor
authoritative

我们使用 open-falcon 作为监控系统,效果如下:

image.png
image.png

实际上我们可以看出来,对于规模不是很大的 DNS 而言,是不需要 DNS 的负载均衡的。因为在达到单机的性能瓶颈之前,cache 的命中率才是决定请求平均延迟的主要因素。我们做双机的唯一目的只是冗余而已。

Powerdns 的单机性能,根据 官网介绍,至少能够 Hold 住 400K 每秒的请求,所以性能还是蛮好的。

管理

powerdns 由于提供了丰富的 API 接口,因此社区内有很多适配的 WEB 前端可以选择。WebFrontends

我们选择了 PowerDNS-Admin 作为管理前端。

image.png

他可以实现 DNS 的分级权限管理,同时记录每次变更的记录。

image.png

完整的变更记录在 mysql 内

MariaDB [powerdnsadmin]> select * from history order by created_on desc limit 1 \G;

这样如果发生手抖事件误操作了,也抵赖不了啦,该背锅背锅。

数据存储

Powerdns 支持多种数据后端,也包含 BIND 的 Zone 文件模式。

Name Native Master Slave Super slave Auto serial DNSSEC Launch
BIND Yes Yes Yes Experimental No Yes bind
Generic Mysql Yes Yes Yes Yes Yes Yes gmysql
Generic ODBC Yes Yes Yes Yes Yes Yes godbc
Generic Oracle Yes Yes Yes Yes Yes Yes goracle
Generic Postgresql Yes Yes Yes Yes Yes Yes gpgsql
GeoIP Yes No No No No Yes geoip
LDAP Yes No No No No No ldap
MyDNS Yes No No No No No mydns
OpenDBX Yes Yes Yes Yes No No opendbx
Oracle Yes Yes Yes Yes Yes Yes oracle
Pipe Yes No No No No Partial pipe
Random Yes No No No No Partial random
Remote Yes Yes* Yes* Yes* Yes* Yes* remote
TinyDNS Yes Yes No No No Parti pipe

我们为了将来的管理方便,选择将数据迁移到 MySQL 中作为 Backend。Powerdns 自带迁移工具 zone2sql,可以很方便的把 zone 文件转换成 sql 语句然后导入 mysql

# zone2sql --help
syntax:

  --filter-duplicate-soa | --filter-duplicate-soa=yes | --filter-duplicate-soa=no
        Filter second SOA in zone
  --gmysql | --gmysql=yes | --gmysql=no
        Output in format suitable for default gmysqlbackend
  --goracle | --goracle=yes | --goracle=no
        Output in format suitable for the goraclebackend
  --gpgsql | --gpgsql=yes | --gpgsql=no
        Output in format suitable for default gpgsqlbackend
  --gsqlite | --gsqlite=yes | --gsqlite=no
        Output in format suitable for default gsqlitebackend
  --help
        Provide a helpful message
  --json-comments | --json-comments=yes | --json-comments=no
        Parse json={} field for disabled & comments
  --mydns | --mydns=yes | --mydns=no
        Output in format suitable for default mydnsbackend
  --named-conf=...
        Bind 8/9 named.conf to parse
  --on-error-resume-next | --on-error-resume-next=yes | --on-error-resume-next=no
        Continue after errors
  --oracle | --oracle=yes | --oracle=no
        Output in format suitable for the oraclebackend
  --slave | --slave=yes | --slave=no
        Keep BIND slaves as slaves. Only works with named-conf.
  --soa-expire-default=...
        Do not change
  --soa-minimum-ttl=...
        Do not change
  --soa-refresh-default=...
        Do not change
  --soa-retry-default=...
        Do not change
  --transactions | --transactions=yes | --transactions=no
        If target SQL supports it, use transactions
  --verbose | --verbose=yes | --verbose=no
        Verbose comments on operation
  --version
        Print the version
  --zone=...
        Zonefile to parse
  --zone-name=...
        Specify an $ORIGIN in case it is not present
主从同步

传统的 DNS 主从同步是通过 AXFR 来同步。在 Powerdns 中,我们将主/从的 权威 DNS 分别设置为 MasterSlave 就可以实现。

然而既然我们的后端已经是 MySQL 了~~所以完全可以用 MySQL 同步来做嘛。因此我们把 Powerdns 的类型设置为 Native,并且配置了两台权威服务器的 MySQL 进行主从同步。MySQL 的主从同步很可靠,同时 binlog 也能够方便的进行回退。

复杂查询

由于我们把数据放到了 MySQL 里,因此现在做一些复杂的记录查询变的非常容易了。例如我们需要查一下某个网段内的所有 A 记录解析。换以前可能得对着 Zone 文本写脚本了。现在只要一条 SQL 语句就搞定了

MariaDB [powerdns]> select * from records where type="A" and content>="192.168.80.1" and content<="192.168.80.255"; 
数据备份

同样,由于现在数据在 MySQL 内,数据备份也变得非常容易了。我们可以使用 MySQL 的 binlog 机制,很容易的实现数据的增量备份。再辅以每天一次全量的备份,数据的备份机制也比过去来的更完善了

总结

新的架构上线之后,通过管理权限的下放和自动化的 API 调用,管理负担降低了,管理透明度提升了。整个结构清晰,易于维护。通过多链路的优化,我们在基本不降低用户的网络访问质量的同时,尽可能的利用了每一条 ISP 链路。

解放我们的双手,去做更多有意义的事情。

参考文档

PowerDNS-Authoritative
PowerDNS-Recursor
dnsdist
PowerDNS-Admin
dns-infrastructure-at-github

以上

转载授权

CC BY-SA

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容