# 在 Kubernetes（1.6）中配置私有 DNS 区域以及上级域名服务

原文：[Configuring Private DNS Zones and Upstream Nameservers in Kubernetes](https://kubernetes.io/blog/2017/04/configuring-private-dns-zones-upstream-nameservers-kubernetes)

很多用户都有自己的域名区域，并且希望能够集成到 Kubernetes DNS 的命名空间去。例如混合云用户可能希望能在集群内解析他们内部的 “.corp” 。其他用户用户可能有一个受**非 Kubernetes**管理的服务发现系统（例如 Consul）。我们在 Kubernetes 1.6 中推出了新功能，kube-dns 添加了可配置的私有 DNS 区域（通常称为存根域）以及外部的上级域名服务，本文将会讲解如何使用这一功能。

Kubernetes 目前在 Pod 定义中支持两个 DNS 策略：`Default`和`ClusterFirst`，`dnsPolicy`缺省为`ClusterFirst`：

- 如果`dnsPolicy`设置为`Default`，那么域名解析配置会从 Pod 所在节点继承而来。注意，本文所述功能在`dnsPolicy`设置为`Default`时无效。
- 如果`dnsPolicy`设置为`ClusterFirst`，DNS 查询会被发送到 kube-dns 服务。kube-dns 服务负责相应以集群域名为后缀（例如`.cluster.local`）的查询。其他的域名查询（例如 www.kubernetes.io ）会被转发给来自节点定义的上级域名服务器。

在这一功能推出之前，通常需要利用替换上级 DNS 为自定义解析的方式来完成存根域查询。然而这就使得这个自定义域名解析器成为 DNS 解析过程中的一个高风险因素。本功能让用户能够无需对整个 DNS 路径进行改造就完成自定义解析过程。

## 自定义 DNS 流程

从 Kubernetes 1.6 开始，集群管理员能够利用 ConfigMap 指定自定义的存根域以及上级 NameServer。下文的配置包含一个存根域和两个上级域名服务器。对域名后缀为`.aceme.local`的查询会被发送到地址为 1.2.3.4 的 DNS 服务。另外会把 Google 公共 DNS 作为上级服务器。注意本节末尾对 ConfigMap 中的数据格式进行的解释。

~~~yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {"acme.local": ["1.2.3.4"]}
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]

~~~

下图显示了配置中所指示的 DNS 查询过程。当`dnsPolicy`设置为`ClusterFirst`时，DNS 查询首先被发送到 kube-dns 的 DNS 缓存层。从这里开始检查域名后缀，然后发送到指定的 DNS。在本例中，集群后缀的域名（`.cluster.local`），被发送到 kube-dns，最后不符合上面后缀的其他查询被转发到上级 DNS 去进行解析。

下文表格用来说明域名解析的过程：

|域名|解析服务|
|---|---|
|kubernetes.default.svc.cluster.local|kube-dns|
|foo.acme.local|自定义 DNS（1.2.3.4）|
|widget.com|上级 DNS（8.8.8.8 和 8.8.4.4）中的一个|

### ConfigMap 配置说明

- `stubDomains` (可选)
  - 格式：一个 JSON 编码的 Map 格式，其 Key 为 DNS 后缀（也就是`acme.local`），值是一个 JSON 数组，代表一组 DNS IP。
  - 注意：目标域名服务器也可以是 Kuernetes 服务。例如可以用 dnsmasq 把自定义 DNS 导出到 ClusterDNS 的命名空间中。
- `upstreamNameservers`
  - 格式：一个 DNS IP 组成的 JSON 数组。
  - 注意：如果指定了这个值，那么从节点的 `/etc/resolv.conf` 继承过来的值就会被覆盖。
  - 限制：最多可以指定三个。

## 例 1：添加一个 Consul DNS 存根域

这个例子中，用户希望把 Consul DNS 服务集成到 kube-dns。Consul 服务位于`10.150.0.1`，所有的 consul 命名后缀都是`.consul.local`。Kubernetes 管理员简单的创建一个`ConfigMap`对象就可以完成。注意：本例中管理员不想覆盖节点的上级 DNS 定义，所以不需要指定`upstreamNameservers`：

~~~yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {"consul.local": "10.150.0.1"}
~~~

## 例 2：替换上级 Nameserver

这个例子中，集群管理员希望所有的集群外 DNS 查询由`172.16.0.1`的服务来完成，同样的用一个 ConfigMap 完成：

~~~yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  upstreamNameservers: |
    ["172.16.0.1"]
~~~
