作者简介: 肖宏辉,毕业于中科院研究生院,8 年的工作经验,其中 6 年云计算开发经验,OpenStack 社区积极活跃,有超过 300 个 commit 和超过 30000 行代码的贡献。目前关注 SDN/NFV 等虚拟网络技术。本文所有观点仅代表作者个人观点,与作者现在或者之前所在的公司无关。

DNS(Domain Name System) 是 Internet 的重要组成部分,它的核心是为 IP 地址提供一个更易记住的名字。Internet 上的大部分服务都会用到 DNS,例如:访问网站,发送邮件,登录软件系统,玩游戏,网络聊天等。浏览器通过域名访问网站的实际过程如下图所示:

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图1

DNS 从 1985 年开始被使用。但是为 IP 地址提供一个更易记住的名字可以追溯到 ARPANET(Internet 前身)时代。最早的 ARPANET 网络通过一个 hosts.txt 文件管理地址和 hostname 的关系,用户需要 DNS 服务,就从一个 ftp 下载 host.txt 文件到本地。最开始的网络中也就几百台计算机,这种方法没什么问题。但是随着网络的增加,文件存储的方式不能满足规模的要求。为了适应日益增长的网络规模,DNS 被提出。不过 host.txt 文件被保留下来了,这就是我们日常熟悉的 hosts 文件,Linux 在 / etc/hosts,Windows 在 C:/Windows/System32/Drivers/etc/hosts。在现代的计算机中,当请求 Domain name(域名)解析时,还是先查找计算机的 hosts 文件,如果 hosts 文件没有相应的记录,才会触发 DNS 请求。
作为 host.txt 的改进方案,DNS 本质上是一个 Internet 上的域名和 IP 地址相互映射的分布式数据库。数据库以树形结构存在,如下图所示:

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图2

树中每个节点都有自己的标签,根节点有个特殊的标签 “.”。树结构中一条路径中所有节点的标签构成了 DNS 域名。这与 Unix 文件系统路径类似,区别在于 Unix 文件系统路径将根节点放在前面,而 DNS 域名反过来了,将根节点放在了最后。例如,图中 host 完整的域名是:“eos.cs.berkeley.edu.”,越靠近根节点 ROOT 的标签在右,越靠近服务器的标签在左。注意,一个完整的域名,是以根节点标签“.” 结束。

1.1 DNS zone 子树

Zone 是 DNS 树中的子树。Zone 本身可以划分成更小的 Zone。前面说过 DNS 的结构与 Unix 文件系统类似,相应的 Zone 与 Unix 文件系统中的磁盘分区类似。我们无法从 DNS 域名看出当前域名在哪个 Zone,就像很难根据 Unix 文件路径,看出当前目录在哪个磁盘分区一样。在 DNS 树形结构中,Zone 可以用下图来描述。

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图3

DNS Zone 通常由一个或者多个 DNS server 管理,一个 DNS server 也可以管理多个 Zone。如下图所示:

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图4

DNS 与传统的 hosts.txt 方式的区别在于,通过 Zone 的划分,将庞大的 DNS 记录划分成了一个个小块,从而解决数据庞大,不易管理的问题。所以 DNS Zone 本质上是 DNS 记录的集合。DNS 记录被称为 Resource Record(RR)。RR 有很多种类型。常见的有以下几种:

  • A:域名与 IPv4 地址的对应
  • AAAA:域名与 IPv6 地址的对应
  • PTR:域名与 IP 地址的对应,区别是 A 或者 AAAA 是通过域名获得 IP 地址,PTR 可以通过 IP 地址获得域名
  • CNAME:记录一个域名与另一个域名的对应关系
  • NS:为当前 Zone 指定一个 DNS server
  • SOA:包含 Zone 的一些信息,例如首要的 DNS server,管理员邮箱地址,更新时间等

1.2 DNS 工作过程

这部分介绍 DNS 工作过程,首先看一下日常中经常接触的 DNS server。DNS server 大体上可以分为两类。

  • 一类是管理 DNS zone 的 DNS server,称为 Authoritative DNS server。这些 DNS Server 只掌握了一个或者多个 DNS zone 的信息,不能为我们提供整个互联网的 DNS 信息。
  • 另一类是 Cache DNS server。这类 DNS server 不管理 DNS zone,但是连接 Authoritative DNS server,并且缓存从 Authoritative DNS Server 获取的信息。最典型的就是谷歌的 8.8.8.8。
    假设我的电脑配置的 DNS server 是 8.8.8.8,我需要访问 www.zhihu.com,首先我的电脑要获取 www.zhihu.com 的 IP 地址,需要经过下面所示的步骤:

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图5

  1. 向 8.8.8.8 请求获取 www.zhihu.com 的 IP 地址。如果 8.8.8.8 包含了 www.zhihu.com 的 IP 地址记录,则直接跳到步骤 8。
  2. 8.8.8.8 所在的 Cache DNS server 并没有 www.zhihu.com 的记录,所以它向 Authoritative DNS server 请求数据。首先发往 Root DNS server,这是全球共有的 13 个逻辑服务器,每一个是由一个集群构成。
  3. Root DNS server 实际上没有 www.zhihu.com 的记录,也不可能有,因为全球的 DNS 记录不可能集中在一起,这在性能上是不能接受的,并且这样就跟之前的 hosts.txt 文件也没有区别了。不过由于需要解析的是 www.zhihu.com,Root DNS server 知道如何到达 “.com” 的 DNS Server,也就是 TLD(Top-Level Domain)DNS server。因此将 TLD DNS server 的信息也就是 “.com” 的 DNS server 地址发送给 8.8.8.8。
  4. 8.8.8.8 收到了 TLD DNS server 的地址之后,继续向 “.com” 的 DNS server 请求数据。
  5. TLD DNS server 仍然没有 www.zhihu.com 的信息,但是 TLD DNS Server 知道 zhihu.com 的 DNS server,于是 TLD DNS Server 将 zhihu.com 的 DNS server 地址发送给 8.8.8.8。
  6. 8.8.8.8 收到了 DNS server 地址之后,继续向 zhihu.com 的 DNS server 请求数据。
  7. 管理 zhihu.com 的 Authoritative DNS server 有 www.zhihu.com 的记录,于是将对应的 IP 地址发送给 8.8.8.8。
  8. 8.8.8.8 拿到了 www.zhihu.com 对应的 IP 地址,首先记录在本地缓存,这样下次不用再走一遍 234567,接着将 IP 地址发送给请求主机。
  9. 主机拿到 IP 地址之后,向 IP 地址所在的 Server 发送实际的 HTTP 请求。

这里的 1-8 实际上就是第一幅图中的步骤 1,2 的详细版。
好了,DNS 的工作过程大概如此,接下来看一下,如何为 OpenStack 中的虚机提供 DNS 服务。OpenStack 中的虚机 DNS 服务,可以分为两个部分:一个是 Internal DNS service,另一个是 External DNS service。Internal DNS service 由 Neutron DHCP Service 完成,External DNS service 由 OpenStack Designate 项目实现。

1.3 OpenStack Neutron DHCP 服务

Neutron DHCP Service 默认是由 dnsmasq 进程实现,dnsmasq 同时提供了 DNS 服务和 DHCP 服务。它的 DHCP 服务在 OpenStack Neutron 中应用广泛,相应的,其提供的 DNS 服务知名度不那么高。OpenStack Neutron DHCP service 是以 tenant network 为单位提供服务的,也就是说每个 tenant network 都有独立的 DHCP service,独立的 dnsmasq 进程。那么相应的,Neutron DHCP service 提供的 DNS service 也只能在 tenant network 范围内。默认情况下,DHCP service 会通过 DHCP 协议,将 dnsmasq 的管理端口地址(也就是 DHCP Server 地址)作为虚机的 DNS Server 写入虚机。在每个 dnsmasq 的配置文件中(存放于 state_path 中),会静态的记录虚机的 hostname 与 IP 地址的对应。这样,当虚机请求 DNS 解析的时候,dnsmasq 可以从静态的配置文件中获取对应的解析记录,并回送给虚机。

相应的配置项有:

| |

/etc/neutron/neutron.conf

[DEFAULT]

Domain to use for building the hostnames (string value)

dns_domain \= test.org.

|

虚机的 FQDN(Full Qualified Domain Name),默认是由虚机名加上这里配置的 dns_domain 构成。部署完虚机之后,在虚机内 ping 同一个 tenant network 下的其他虚机,可以得到如下响应。

| |

ubuntu@vm6:~$ ping vm5.test.org

PING vm5.test.org (192.168.1.9) 56(84) bytes of data.

64 bytes from vm5.test.org (192.168.1.9): icmp_seq\=1 ttl\=64 time\=95.5 ms

64 bytes from vm5.test.org (192.168.1.9): icmp_seq\=2 ttl\=64 time\=0.802 ms

64 bytes from vm5.test.org (192.168.1.9): icmp_seq\=3 ttl\=64 time\=0.737 ms

64 bytes from vm5.test.org (192.168.1.9): icmp_seq\=4 ttl\=64 time\=0.730 ms

|

不过,因为只能同一个租户网络内部主机之间域名解析,Internal DNS service 在 OpenStack 中的应用,并不是很多。

Neutron DHCP service 提供的 DNS 服务,存在两个问题:一是只能在 tenant network 内使用,无法在整个 OpenStack 下使用,另一个是在 OpenStack 之外,无法使用其提供的域名访问虚机。因此,接下来要介绍 OpenStack 中的 External DNS service:Designate。项目的介绍可以在其 wiki 上找到。Designate 号称是一个 DNSaaS 的项目(这年头不把自己叫做 as a Service 就不舒服)。但是 Designate 并没有实现 DNS 协议,而是管理了实现 DNS 协议的软件,例如 BIND9,PowerDNS 等。Designate 将这些软件与 OpenStack 连接了起来,通过一套自己提供的 API,控制底层的 DNS 软件,完成例如创建 DNS Zone,写入 Resource Record 等 DNS 操作。所以,Designate 本身只是一个软件框架,一个适配多种 DNS 软件的软件框架。本文将不会对 Designate 的架构做介绍,也不会贴一段代码来解释它的实现,接下来的介绍将更偏向于应用。
接下来所有的内容都是基于 Pike 版本代码(2017-08-08)完成。

2.1 devstack 安装

用 devstack 安装 Designate 比较简单,只需要在 local.conf 文件中增加下面内容,再执行./stack.sh 即可,这里我用的是 bind9 作为 DNS 后端实现。

| |

Enable designate

enable_plugin designate https://git.openstack.org/openstack/designate

DESIGNATE_BACKEND_DRIVER\=bind9

|

2.2 与 Neutron/Nova 集成

在 OpenStack Mitaka 版本之前,Designate 只是一个独立的 DNS 软件接口,如果用户需要新增 DNS 记录,可以调用 Designate API 完成写入。如果你本身就熟悉 BIND9 的操作,那 Designate 的意义不是那么的明显。在 Mitaka 版本,Designate 与 OpenStack Nova,Neutron 做了集成,真正的将 Designate 与 OpenStack 结合在了一起,具体来说,就是将 DNS 记录的创建,与虚机 / 网络的创建关联起来,用户不再需要特意的去管理 Designate 中的 DNS 记录。
需要注意的是,Devstack 的安装过程,不会完成所有的 Neutron 与 Designate 集成所需要的配置,为了将 Designate 与 Nova/Neutron 集成起来,还需要手动修改一些配置。仔细看的话,下面所有的 DNS 域名都是完整的域名,也就是会以 “.” 结尾。

|

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

|

/etc/neutron/neutron.conf

[DEFAULT]

Domain to use for building the hostnames (string value)

dns_domain \= test.org.

Driver for external DNS integration. (string value)

external_dns_driver \= designate

[designate]

url \= http://:9001/v2

admin_auth_url \= http:///identity

admin_username \=

admin_password \=

admin_tenant_name \=

allow_reverse_dns_lookup \= True

ipv4_ptr_zone_prefix_size \= 24

ipv6_ptr_zone_prefix_size \= 116

/etc/neutron/plugins/ml2/ml2_conf.ini

[ml2]

extension_drivers \= port_security, dns

|

配置完之后,重启 neutron server。接下来看看如何在 Neutron 中使用 Designate。

2.3 Neutron with Designate

为了集成 DNS 功能,Neutron 创建网络时,新增了一个参数,“—dns-domain”。虽然这里指定的是 DNS domain,但是对应到 DNS 数据的话,应该是 DNS Zone。另外需要注意的是,Neutron 创建网络时,如果指定了 dns-domain,Neutron 是认为对应的 DNS Zone 已经存在于 Designate 中,所以为了正常使用,需要先在 Designate 中创建 DNS Zone。一个完整的流程如下所示:

| |

$ openstack zone create —email my@test.com test.org.

$ neutron net-create dns-net —dns-domain test.org.

$ neutron subnet-create —name dns-subnet dns-net 192.168.1.0/24

$ nova boot —image cirros-0.3.5-x86_64-disk —flavor 1 —nic net-name\=dns-net vm5

|

到此为止,DNS 似乎应该工作起来了,但是,查看 Designate 记录,只有默认的记录,感觉不对啊。

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图6

其实这是正常的,因为实际上,现在创建的 vm5 存在于一个 tenant network,默认是 VXLAN 网络,这个网络不能被外部直接访问。所以这个时候就算创建的 DNS 记录,也没有实际意义。因为解析到了的 IP 地址是一个虚拟的私网地址,这个 IP 地址不能被外界访问。OpenStack 的文档是这么定义可以被外部访问的网络的:

| |

The network cannot have attribute router:external set to True.

The network type can be FLAT, VLAN, GRE, VXLAN or GENEVE.

For network types VLAN, GRE, VXLAN or GENEVE, the segmentation ID must be outside the ranges assigned to tenant networks.

|

只有满足这些条件的网络,创建在里面的虚机才会自动设置 DNS 记录。那对于普通 tenant network 中的虚机,希望使用 DNS,该怎么办?通过配置 FloatingIP。配置完 FloatingIP,就可以通过 FloatingIP 访问 tenant network 中的虚机,这样 DNS 记录也有存在的意义,所以我们做如下操作:

| |

$ neutron router-interface-add router1 dns-subnet

$ neutron floatingip-create public —port-id

|

这个时候查看 Designate 记录,可以看到:
OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图7

我们多了一条 A 类型的 DNS 记录,IP 地址是 FloatingIP 地址,hostname 是虚机名 + 虚机所在网络的 dns-domain。
此外,查看 Designate Zone 列表可以发现,多了一个 Zone。

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图8

这个 Zone 是管理 PTR 记录用的,前面说过,PTR 记录用来通过 IP 查找域名。因为我们刚刚在 Neutron 的配置中加入了这条 “allow_reverse_dns_lookup = True”,因此,Neutron 会自动创建这个 Zone,以及 Zone 中的 RR。

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图9

到这里为止,Designate 的介绍完成了。可以看出 Designate 的定位是 OpenStack 内部的 Authoritative DNS server。由于底层连接的是 BIND9,PowerDNS 等,也支持向上连接到 TLD,将定义的 DNS 域名发送出去。

2.4 结果验证

将 Designate 所在的主机 IP 配置到操作系统的 DNS server 列表中。为了省事,我直接修改了 Ubuntu 下的 / etc/resolv.conf 文件。

OpenStack应用Designate实现DNS服务 | SDNLAB | 专注网络创新技术 - 图10

可以看到系统已经能够完成 DNS 解析。
https://www.sdnlab.com/19900.html