转自: https://help.aliyun.com/document_detail/188179.html?utm_content=g_1000230851&spm=5176.20966629.toubu.3.f2991ddcpxxvD1#title-b7y-d6a-bcy

DNS原理和配置说明

本文介绍Kubernetes集群中集群DNS服务原理,并针对不同场景介绍如何进行DNS策略配置。

背景信息

K8S集群默认部署了一套DNS服务,通过kube-dns的服务名暴露DNS服务。你可执行以下命令查看kube-dns的服务详情。

1
kubectl get svc kube-dns -n kube-system

预期输出:

1
2
NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
kube-dns ClusterIP 172.24.0.10 <none> 53/UDP,53/TCP,9153/TCP 27d

K8S部署的DNS服务后端是两个名为CoreDNS的Pod。你可执行以下命令查看CoreDNS的Pod详情。

1
kubectl get deployment coredns -n kube-system

预期输出:

1
2
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
coredns 2/2 2 2 27d

集群DNS域名解析原理

K8S集群中kubelet的启动参数有--cluster-dns=<dns-service-ip>--cluster-domain=<default-local-domain>,这两个参数分别被用来设置集群DNS服务器的IP地址和主域名后缀。

Pod内的DNS域名解析配置文件为/etc/resolv.conf,文件内容如下。

1
2
3
nameserver xx.xx.0.10
search kube-system.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
参数描述
nameserver定义DNS服务器的IP地址。
search设置域名的查找后缀规则,查找配置越多,说明域名解析查找匹配次数越多。K8S集群匹配有kube-system.svc.cluster.localsvc.cluster.localcluster.local3个后缀,最多进行8次查询才能得到正确解析结果,因为集群里面进行IPV4和IPV6查询各四次。
options定义域名解析配置文件选项,支持多个KV值。例如该参数设置成ndots:5,说明如果访问的域名字符串内的点字符数量超过ndots值,则认为是完整域名,并被直接解析;如果不足ndots值,则追加search段后缀再进行查询。

根据上述Pod内的配置,集群会将域名请求(集群内部定义的服务或是集群外部域名)查询发往集群DNS服务器获取结果。

集群dnsPolicy配置和场景说明

K8S支持通过dnsPolicy字段为每个Pod配置不同的DNS策略。目前K8S集群支持四种策略:

  • ClusterFirst:通过CoreDNS来做域名解析,Pod内/etc/resolv.conf配置的DNS服务地址是集群DNS服务的kube-dns地址。该策略是集群工作负载的默认策略。
  • None:忽略集群DNS策略,需要自己提供dnsConfig字段来指定DNS配置信息。
  • Default:Pod直接继承集群节点的域名解析配置。即在K8S集群直接使用ECS的/etc/resolv.conf文件(文件内配置的是阿里云DNS服务)。
  • ClusterFirstWithHostNet:强制在hostNetWork网络模式下使用ClusterFirst策略(默认使用Default策略)。

针对上述四种策略,本文列举四种场景分别介绍如何配置dnsPolicy。

  • 场景一:使用K8S集群提供的CoreDNS来做域名解析

    针对这种场景,可使用dnsPolicy: ClusterFirst策略。示例配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    apiVersion: v1
    kind: Pod
    metadata:
    name: alpine
    namespace: default
    spec:
    containers:
    - image: alpine
    command:
    - sleep
    - "10000"
    imagePullPolicy: Always
    name: alpine
    dnsPolicy: ClusterFirst
  • 场景二:Pod层面自定义DNS配置

    当你需要给Deployment类型的工作负载指定DNS配置时,可使用dnsPolicy: None策略。示例配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    apiVersion: v1
    kind: Pod
    metadata:
    name: alpine
    namespace: default
    spec:
    containers:
    - image: alpine
    command:
    - sleep
    - "10000"
    imagePullPolicy: Always
    name: alpine
    dnsPolicy: None
    dnsConfig:
    nameservers: ["169.254.xx.xx"]
    searches:
    - default.svc.cluster.local
    - svc.cluster.local
    - cluster.local
    options:
    - name: ndots
    value: "2"

    其中,dnsConfig中的参数说明如下:

    | 参数 | 描述 |
    | :——————— | :—————————————————————————————- |
    | nameservers | 将用作Pod的DNS服务器的IP地址列表。最多可以指定3个IP地址。当Pod的dnsPolicy设置为None时,列表必须至少包含一个IP地址,否则此属性是可选的。列出的DNS的IP列表将合并到基于dnsPolicy生成的域名解析文件的nameserver字段中,并删除重复的地址。 |
    | searches | Pod中主机名查找的DNS搜索域列表。此属性是可选的。指定后,提供的列表将合并到从所选DNS策略生成的基本搜索域名中,并删除重复的域名。Kubernetes最多允许6个搜索域。 |
    | options | 可选的对象列表,其中每个对象可以具有name属性(必需)和value属性(可选)。此属性中的内容将合并到从指定的DNS策略生成的选项中,并删除重复的条目。 |

    更多信息,请参见Kubernetes官网的DNS配置说明

  • 场景三:采用阿里云ECS的DNS配置

    当你的应用Pod不需要访问集群内的其它服务,只需要通过阿里云DNS来做解析,也不希望DNS解析经过CoreDNS,可以采用dnsPolicy: Default策略。示例配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    apiVersion: v1
    kind: Pod
    metadata:
    name: alpine
    namespace: default
    spec:
    containers:
    - image: alpine
    command:
    - sleep
    - "10000"
    imagePullPolicy: Always
    name: alpine
    dnsPolicy: Default
  • 场景四:在HostNetwork网络模式下访问集群服务

    如果你的应用Pod使用hostNetwork:true来配置网络,Pod中运行的应用程序可以直接看到宿主机的网络接口,其DNS策略默认为Default,不能访问集群内的服务。如果你希望在此网络模式下访问集群内服务,可使用dnsPolicy: ClusterFirstWithHostNet策略。示例配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    apiVersion: v1
    kind: Pod
    metadata:
    name: alpine
    namespace: default
    spec:
    hostNetwork: true
    dnsPolicy: ClusterFirstWithHostNet
    containers:
    - image: alpine
    command:
    - sleep
    - "10000"
    imagePullPolicy: Always
    name: alpine

转自华为云

在Kubernetes 中,有4种 DNS 策略,从 Kubernetes 源码中看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const (
// DNSClusterFirstWithHostNet indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default
// (as determined by kubelet) DNS settings.
DNSClusterFirstWithHostNet DNSPolicy = "ClusterFirstWithHostNet"

// DNSClusterFirst indicates that the pod should use cluster DNS
// first unless hostNetwork is true, if it is available, then
// fall back on the default (as determined by kubelet) DNS settings.
DNSClusterFirst DNSPolicy = "ClusterFirst"

// DNSDefault indicates that the pod should use the default (as
// determined by kubelet) DNS settings.
DNSDefault DNSPolicy = "Default"

// DNSNone indicates that the pod should use empty DNS settings. DNS
// parameters such as nameservers and search paths should be defined via
// DNSConfig.
DNSNone DNSPolicy = "None"
)

这几种DNS策略,需要在Pod,或者Deployment、RC等资源中,设置 dnsPolicy 即可,以 Pod 为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: v1
kind: Pod
metadata:
labels:
name: cadvisor-nodexxxx
hostip: 192.168.x.x
name: cadvisor-nodexxxx
namespace: monitoring
spec:
containers:
- args:
- --profiling
- --housekeeping_interval=10s
- --storage_duration=1m0s
image: google/cadvisor:latest
name: cadvisor-nodexxxx
ports:
- containerPort: 8080
name: http
protocol: TCP
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
nodeName: nodexxxx

具体来说:

None

表示空的DNS设置
这种方式一般用于想要自定义 DNS 配置的场景,而且,往往需要和 dnsConfig 配合一起使用达到自定义 DNS 的目的。

Default

有人说 Default 的方式,是使用宿主机的方式,这种说法并不准确。
这种方式,其实是,让 kubelet 来决定使用何种 DNS 策略。而 kubelet 默认的方式,就是使用宿主机的 /etc/resolv.conf(可能这就是有人说使用宿主机的DNS策略的方式吧),但是,kubelet 是可以灵活来配置使用什么文件来进行DNS策略的,我们完全可以使用 kubelet 的参数:–resolv-conf=/etc/resolv.conf 来决定你的DNS解析文件地址。

ClusterFirst

这种方式,表示 POD 内的 DNS 使用集群中配置的 DNS 服务,简单来说,就是使用 Kubernetes 中 kubedns 或 coredns 服务进行域名解析。如果解析不成功,才会使用宿主机的 DNS 配置进行解析。

ClusterFirstWithHostNet

在某些场景下,我们的 POD 是用 HOST 模式启动的(HOST模式,是共享宿主机网络的),一旦用 HOST 模式,表示这个 POD 中的所有容器,都要使用宿主机的 /etc/resolv.conf 配置进行DNS查询,但如果你想使用了 HOST 模式,还继续使用 Kubernetes 的DNS服务,那就将 dnsPolicy 设置为 ClusterFirstWithHostNet。

如果未明确指定dnsPolicy,则默认使用“ClusterFirst”:

  • 如果将dnsPolicy设置为“Default”,则名称解析配置将从运行pod的工作节点继承。

  • 如果将dnsPolicy设置为“ClusterFirst”,则DNS查询将发送到kube-dns服务。

    对于以配置的集群域后缀为根的域的查询将由kube-dns服务应答。所有其他查询(例如,www.kubernetes.io)将被转发到从节点继承的上游名称服务器。在此功能之前,通常通过使用自定义解析程序替换上游DNS来引入存根域。但是,这导致自定义解析程序本身成为DNS解析的关键路径,其中可伸缩性和可用性问题可能导致集群丢失DNS功能。此特性允许用户在不接管整个解析路径的情况下引入自定义解析。

如果某个工作负载不需要使用集群内的coredns,可以使用kubectl命令或API将此策略设置为dnsPolicy: Default。

关于”hostNetwork: true”

kubernetes “hostNetwork: true”,这是一种直接定义Pod网络的方式。如果在POD中

使用”hostNetwork: true”配置网络,pod中运行的应用程序可以直接看到宿主主机的网

络接口,宿主机所在的局域网上所有网络接口都可以访问到该应用程序及端口。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
hostNetwork: true
# 使用主机网络
dnsPolicy: ClusterFirstWithHostNet
# 该设置是使POD使用k8s的dns,dns配置在/etc/resolv.conf文件中
# 如果不加,pod默认使用所在宿主主机使用的DNS,这样会导致容器
# 内不能通过service name访问k8s集群中其他POD
containers:
- name: nginx
image: nginx:1.7.9
#ports:
# - name: metrics
# hostPort: 80
# containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
nodePort: 30080

80端口是使用pod的”hostNetwork: true”方式暴露的,30080端口是使用service的”type: NodePort”方式暴露的。