# 工作负载DNS配置说明
Kubernetes集群内置DNS插件Kube-DNS/CoreDNS，为集群内的工作负载提供域名解析服务。业务在高并发调用场景下，如果使用到域名解析服务，可能会触及到Kube-DNS/CoreDNS的性能瓶颈，导致DNS请求概率失败，影响用户业务正常运行。在Kubernetes使用的过程中，发现有些场景下工作负载的域名解析存在冗余的DNS查询，使得高并发场景更容易触及DNS的性能瓶颈。根据业务使用场景，对工作负载的DNS配置进行优化，能够在一定程度上减少DNS请求概率失败的问题。
更多DNS相关信息请参见[CoreDNS域名解析](https://support.huaweicloud.com/usermanual-cce/cce_10_0129.html)。
#### DNS配置项说明
在Linux系统的节点或者容器里执行cat /etc/resolv.conf命令，能够查看到DNS配置，以Kubernetes集群的容器DNS配置为例：
```
nameserver 10.247.x.x
search default.svc.cluster.local svc.cluster.local cluster.local
options single-request-reopen timeout:2 ndots:5
```
**配置项说明：**
- nameserver：容器解析域名时查询的DNS服务器的IP地址列表。如果该IP地址为集群CoreDNS的ClusterIP（该IP属于集群的服务网段，如以上示例中的10.247.x.x），说明DNS对接到Kube-DNS/CoreDNS，如果是其他IP地址，则表示采用云上DNS或者用户自建的DNS。
- search：定义域名的搜索域列表，当访问的域名不能被DNS解析时，会把该域名与搜索域列表中的域依次进行组合，并重新向DNS发起请求，直到域名被正确解析或者尝试完搜索域列表为止。对于CCE集群来说，容器的搜索域列表配置3个域，当解析一个不存在的域名时，会产生8次DNS查询，因为对于每个域名需要查询两次，分别是IPv4和IPv6。
- options：定义域名解析配置文件的其他选项，常见的有timeout、ndots等。 Kubernetes集群容器的域名解析文件设置为options ndots:5，该参数的含义是当域名的"."个数小于ndots的值，会先把域名与search搜索域列表进行组合后进行DNS查询，如果均没有被正确解析，再以域名本身去进行DNS查询。当域名的"."个数大于或者等于ndots的值，会先对域名本身进行DNS查询，如果没有被正确解析，再把域名与search搜索域列表依次进行组合后进行DNS查询。
  例如，查询www.\*\*\*.com域名时，由于该域名的"."个数为2，小于ndots的值，所以DNS查询请求的顺序依次为：www.\*\*\*.com.default.svc.cluster.local、www.\*\*\*.com.svc.cluster.local、 www.\*\*\*.com.cluster.local和www.\*\*\*.com，需要发起至少7次DNS查询请求才能解析出该域名的IP。可以看出，这种配置在访问外部域名时，存在大量冗余的DNS查询，存在优化点。
  
 
![](https://support.huaweicloud.com/usermanual-cce/public_sys-resources/note_3.0-zh-cn.png)
完整的Linux域名解析文件配置项说明可以参考文档：<https://man7.org/linux/man-pages/man5/resolv.conf.5.html>。
#### 通过控制台进行工作负载DNS配置
Kubernetes为应用提供了与DNS相关的配置选项，通过对应用进行DNS配置，能够在某些场景下有效地减少冗余的DNS查询，提升业务并发量。以下步骤以nginx应用为例，介绍如何通过控制台为工作负载添加DNS配置。
1. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，单击集群名称进入集群。
2. 在左侧选择"工作负载"，在右上角单击"创建工作负载"。
3. 设置工作负载基本参数，详情请参见[创建工作负载](https://support.huaweicloud.com/usermanual-cce/cce_10_0673.html)。
4. 在"高级配置"中，选择"DNS配置"页签，并按需填写以下参数。 
   - DNS策略：控制台中提供的DNS策略与YAML中的dnsPolicy字段对应，详情请参见[表1]。
     - 追加域名解析配置：即dnsPolicy字段设置为ClusterFirst，此时容器中既能够解析service注册的集群内部域名，也能够解析发布到互联网上的外部域名。
     
     - 替换域名解析配置：即dnsPolicy字段设置为None，此时必须填写"IP地址"和"搜索域"参数。容器将仅使用自定义的IP地址和搜索域配置进行域名解析。
     
     - 继承Pod所在节点域名解析配置：即dnsPolicy字段设置为Default，此时容器将使用Pod所在节点的域名解析配置，无法解析集群内部域名。
      
   
   - 可选对象：即[dnsConfig字段]中的options参数。每个对象可以具有name属性（必需）和value属性（可选），填写完成后需单击"确认添加"。
     - timeout：超时时间 (s)。
     
     - ndots：域名中必须出现的"."的个数。如果域名中的"."的个数不小于ndots，则该域名为一个全限定域名，操作系统会直接查询；如果域名中的"."的个数小于ndots，操作系统会在搜索域中进行查询。
      
   
   - 域名解析服务器地址：即[dnsConfig字段]中的nameservers参数，您可对自定义的域名配置域名服务器，值为一个或一组DNS IP地址。最多仅支持添加2个DNS IP地址。
   
   - 搜索域：即[dnsConfig字段]中的searches参数，表示域名查询时的DNS搜索域列表，此属性是可选的。指定后，提供的搜索域列表将合并到基于dnsPolicy生成的域名解析文件的search字段中，并删除重复的域名。最多仅支持添加3个搜索域。
   
   - 启用hostAliases：配置Pod的本地配置文件"/etc/hosts"，可以将域名和IP地址映射加入到hosts文件中，在本地系统中实现简单的域名解析。更多使用详情请参见[使用HostAliases向Pod /etc/hosts文件添加条目](https://kubernetes.io/zh-cn/docs/tasks/network/customize-hosts-file-for-pods/)。
   
   
   图1工作负载DNS配置   
   ![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000001906173409.png "点击放大")
   
   
5. 单击"创建工作负载"。
 
#### 通过工作负载YAML进行DNS配置
您也可以通过YAML的方式创建工作负载，以nginx应用为例，其YAML文件中的DNS配置示例如下：
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: container-1
          image: nginx:latest
          imagePullPolicy: IfNotPresent
      imagePullSecrets:
        - name: default-secret
      dnsPolicy: None
      dnsConfig:
        options:
          - name: ndots
            value: '5'
          - name: timeout
            value: '3'
        nameservers:
          - 10.2.3.4
        searches:
          - my.dns.search.suffix
```
- **dnsPolicy** **字段说明：**
  dnsPolicy字段是应用设置的DNS策略，默认值为"ClusterFirst"。dnsPolicy当前支持四种参数值：
   表1dnsPolicy字段说明 
  | 参数                    | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                 |
  |:---|:---|
  | ClusterFirst（默认值）      | 即在默认DNS配置中追加自定义的域名解析配置。应用会默认对接CoreDNS（CCE集群的CoreDNS默认级联云上DNS），自定义填写的dnsConfig会追加到默认DNS参数中。这种场景下，容器既能够解析service注册的集群内部域名，也能够解析发布到互联网上的外部域名。由于该配置下，域名解析文件设置了search搜索域列表和ndots: 5，因此当访问外部域名和集群内部长域名（如kubernetes.default.svc.cluster.local）时，大部分域名都会优先遍历search搜索域列表，导致至少有6次无效的DNS查询，只有访问集群内部短域名（如kubernetes）时，才不存在无效的DNS查询。                                                                                                           |
  | ClusterFirstWithHostNet | 对于配置[主机网络（hostNetwork）](https://support.huaweicloud.com/usermanual-cce/cce_10_0402.html)的应用，默认对接Pod所在节点域名解析配置，即kubelet的"--resolv-conf"参数指向的域名解析文件（CCE集群在该配置下对接云上DNS）。如需对接集群的Kube-DNS/CoreDNS，dnsPolicy字段需设置为ClusterFirstWithHostNet，此时容器的域名解析文件配置与"ClusterFirst"一致，也存在无效的DNS查询。 ``` ... spec: containers: - image: nginx:latest imagePullPolicy: IfNotPresent name: container-1 restartPolicy: Always hostNetwork: true dnsPolicy: ClusterFirstWithHostNet ``` |
  | Default             | 即继承Pod所在节点域名解析配置，并在此基础上追加自定义的域名解析配置。容器的域名解析文件使用kubelet的"--resolv-conf"参数指向的域名解析文件（CCE集群在该配置下对接云上DNS），没有配置search搜索域列表和options。该配置只能解析注册到互联网上的外部域名，无法解析集群内部域名，且不存在无效的DNS查询。                                                                                                                                                                                                                                                          |
  | None                | 即替换默认的域名解析配置，完全使用自定义的域名解析配置。设置为None之后，必须设置dnsConfig字段，此时容器的域名解析文件将完全通过dnsConfig的配置来生成。                                                                                                                                                                                                                                                                                                                                            |
     
  ![](https://support.huaweicloud.com/usermanual-cce/public_sys-resources/note_3.0-zh-cn.png)
  此处如果dnsPolicy字段未被指定，其默认值为ClusterFirst，而不是Default。
  
- **dnsConfig字段说明** **：**
  dnsConfig为应用设置DNS参数，设置的参数将合并到基于dnsPolicy策略生成的域名解析文件中。当dnsPolicy为"None"，应用的域名解析文件完全由dnsConfig指定；当dnsPolicy不为"None"时，会在基于dnsPolicy生成的域名解析文件的基础上，追加dnsConfig中配置的dns参数。
   表2dnsConfig字段说明 
  | 参数          | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
  |:---|:---|
  | options       | DNS的配置选项，其中每个对象可以具有name属性（必需）和value属性（可选）。该字段中的内容将合并到基于dnsPolicy生成的域名解析文件的options字段中，dnsConfig的options的某些选项如果与基于dnsPolicy生成的域名解析文件的选项冲突，则会被dnsConfig所覆盖。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
  | nameservers | DNS的IP地址列表。当应用的dnsPolicy设置为"None"时，列表必须至少包含一个IP地址；在其他情况下，此属性是可选的。列出的DNS的IP列表将合并到基于dnsPolicy生成的域名解析文件的nameserver字段中，并删除重复的地址。 说明： 容器DNS配置文件中nameserver最多可设置3个DNS地址： - 当dnsPolicy设置为ClusterFirst时，如果集群使用[CoreDNS](https://support.huaweicloud.com/usermanual-cce/cce_10_0361.html)，除CoreDNS地址外可追加2个自定义DNS地址，超出部分无效。  - 当dnsPolicy设置为ClusterFirst时，如果集群同时使用[CoreDNS](https://support.huaweicloud.com/usermanual-cce/cce_10_0361.html)和[NodeLocal DNSCache](https://support.huaweicloud.com/usermanual-cce/cce_10_0362.html)，除CoreDNS和NodeLocal DNSCache地址外可追加1个自定义DNS地址，超出部分无效。   |
  | searches     | 域名查询时的DNS搜索域列表，此属性是可选的。指定后，提供的搜索域列表将合并到基于dnsPolicy生成的域名解析文件的search字段中，并删除重复的域名。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
     
  
 
#### 工作负载的DNS配置实践
前面介绍了Linux系统域名解析文件以及Kubernetes为应用提供的DNS相关配置项，下面将举例介绍应用如何进行DNS配置。
- **场景1 对接Kubernetes内置的Kube-DNS/CoreDNS**
  **场景说明：**
  这种方式适用于应用中的域名解析只涉及集群内部域名，或者集群内部域名+外部域名两种方式，应用默认采用这种配置。
  **示例：**
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    namespace: default
    name: dns-example
  spec:
    containers:
    - name: test
      image: nginx:alpine
    dnsPolicy: ClusterFirst
    imagePullSecrets:
      - name: default-secret
  ```
  该配置下容器的域名解析文件将如下所示：
  ```
  nameserver 10.247.3.10
  search default.svc.cluster.local svc.cluster.local cluster.local
  options timeout:2 single-request-reopen ndots:5
  ```
  
- **场景2 直接对接云DNS**
  **场景说明：**
  这种方式适用于应用只访问注册到互联网的外部域名，该场景不能解析集群内部域名。
  **示例：**
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    namespace: default
    name: dns-example
  spec:
    containers:
    - name: test
      image: nginx:alpine
    dnsPolicy: Default  #使用kubelet的“--resolv-conf”参数指向的域名解析文件（CCE集群在该配置下对接云DNS）
    imagePullSecrets:
      - name: default-secret
  ```
  该配置下容器的域名解析文件将如下所示，其中100.125.x.x为节点子网DNS地址：
  ```
  nameserver 100.125.x.x
  options timeout:2 single-request-reopen
  ```
  
- **场景3 主机网络模式的应用对接Kube-DNS/CoreDNS**
  **场景说明：**
  对于配置主机网络模式的应用，默认对接云DNS，如果应用需要对接Kube-DNS/CoreDNS，需将dnsPolicy设置为"ClusterFirstWithHostNet"。
  **示例：**
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    name: nginx
  spec:
    hostNetwork: true
    dnsPolicy: ClusterFirstWithHostNet
    containers:
    - name: nginx
      image: nginx:alpine
      ports:
      - containerPort: 80
    imagePullSecrets:
      - name: default-secret
  ```
  该配置下容器的域名解析文件将如下所示：
  ```
  nameserver 10.247.3.10
  search default.svc.cluster.local svc.cluster.local cluster.local
  options ndots:5 single-request-reopen timeout:2
  ```
  
- **场景4 自定义应用的域名配置**
  **场景说明：**
  用户可以完全自定义配置应用的域名解析文件，这种方式非常灵活，dnsPolicy和dnsConfig配合使用，几乎能够满足所有使用场景，如对接用户自建DNS的场景、串联多个DNS的场景以及优化DNS配置选项的场景等等。
  **示例1：对接用户自建DNS**
  该配置下，dnsPolicy为"None"，应用的域名解析文件完全根据dnsConfig配置生成。
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    namespace: default
    name: dns-example
  spec:
    containers:
    - name: test
      image: nginx:alpine
    dnsPolicy: "None"
    dnsConfig:
      nameservers:
      - 10.2.3.4  #用户自建DNS的IP地址
      searches:
      - ns1.svc.cluster.local
      - my.dns.search.suffix
      options:
      - name: ndots
        value: "2"
      - name: timeout
        value: "3"
    imagePullSecrets:
      - name: default-secret
  ```
  该配置下容器的域名解析文件将如下所示：
  ```
  nameserver 10.2.3.4
  search ns1.svc.cluster.local my.dns.search.suffix
  options timeout:3 ndots:2 single-request-reopen
  ```
  **示例2：修改域名解析文件的ndots选项，减少无效的DNS查询**
  该配置下，dnsPolicy不为"None"，会在基于dnsPolicy生成的域名解析文件的基础上，追加dnsConfig中配置的dns参数。
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    namespace: default
    name: dns-example
  spec:
    containers:
    - name: test
      image: nginx:alpine
    dnsPolicy: "ClusterFirst"
    dnsConfig:
      options:
      - name: ndots
        value: "2" #该配置会将基于ClusterFirst策略生成的域名解析文件的ndots:5参数改写为ndots:2
    imagePullSecrets:
      - name: default-secret
  ```
  该配置下容器的域名解析文件将如下所示：
  ```
  nameserver 10.247.3.10
  search default.svc.cluster.local svc.cluster.local cluster.local
  options ndots:2 single-request-reopen timeout:2
  ```
  **示例3：** **串联使用多个DNS**
  ```
  apiVersion: v1
  kind: Pod
  metadata:
    namespace: default
    name: dns-example
  spec:
    containers:
    - name: test
      image: nginx:alpine
    dnsPolicy: ClusterFirst  # 追加域名解析配置，集群中会默认对接CoreDNS
    dnsConfig:
      nameservers:
      - 10.2.3.4 # 用户自建DNS的IP地址
    imagePullSecrets:
      - name: default-secret
  ```
  ![](https://support.huaweicloud.com/usermanual-cce/public_sys-resources/note_3.0-zh-cn.png)
  容器DNS配置文件中nameserver最多可设置3个DNS地址：
  - 当dnsPolicy设置为ClusterFirst时，如果集群使用[CoreDNS](https://support.huaweicloud.com/usermanual-cce/cce_10_0361.html)，除CoreDNS地址外可追加2个自定义DNS地址，超出部分无效。
  
  - 当dnsPolicy设置为ClusterFirst时，如果集群同时使用[CoreDNS](https://support.huaweicloud.com/usermanual-cce/cce_10_0361.html)和[NodeLocal DNSCache](https://support.huaweicloud.com/usermanual-cce/cce_10_0362.html)，除CoreDNS和NodeLocal DNSCache地址外可追加1个自定义DNS地址，超出部分无效。
   
  该配置下容器的域名解析文件将如下所示：
  ```
  nameserver 10.247.3.10 
  nameserver 10.2.3.4
  search default.svc.cluster.local svc.cluster.local cluster.local
  options timeout:2 single-request-reopen ndots:5
  ```
  
 
