Kubernetes DNS的示例分析

64次阅读
没有评论

共计 7645 个字符,预计需要花费 20 分钟才能阅读完成。

这篇文章给大家分享的是有关 Kubernetes DNS 的示例分析的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。

环境

$ sudo lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.2 LTS
Release: 16.04
Codename: xenial
$ kubectl version
Client Version: version.Info{Major: 1 , Minor: 5 , GitVersion: v1.5.4 , GitCommit: 7243c69eb523aa4377bce883e7c0dd76b84709a1 , GitTreeState: clean , BuildDate: 2017-03-07T23:53:09Z , GoVersion: go1.7.4 , Compiler: gc , Platform: linux/amd64}
Server Version: version.Info{Major: 1 , Minor: 5 , GitVersion: v1.5.4 , GitCommit: 7243c69eb523aa4377bce883e7c0dd76b84709a1 , GitTreeState: clean , BuildDate: 2017-03-07T23:34:32Z , GoVersion: go1.7.4 , Compiler: gc , Platform: linux/amd64}

介绍

从 Kubernetes 1.3 开始,DNS 通过使用插件管理系统 cluster add-on,成为了一个内建的自启动服务。
Kubernetes DNS 在 Kubernetes 集群上调度了一个 DNS Pod 和 Service,并配置 kubelet,使其告诉每个容器使用 DNS Service 的 Ip 来解析 DNS 名称。

什么是 DNS 名称

集群中定义的每个 Service(包括 DNS Service 它自己)都被分配了一个 DNS 名称。默认的,Pod 的 DNS 搜索列表中会包含 Pod 自己的命名空间和集群的默认域,下面我们用示例来解释以下。
假设有一个名为 foo 的 Service,位于命名空间 bar 中。运行在 bar 命名空间中的 Pod 可以通过 DNS 查找 foo 关键字来查找到这个服务,而运行在命名空间 quux 中的 Pod 可以通过关键字 foo.bar 来查找到这个服务。

支持的 DNS 模式

下面的章节详细的描述了支持的记录(record)类型和 layout。

Services

普通(非 headless)的 Service 都被分配了一个 DNS 记录,该记录的名称格式为 my-svc.my-namespace.svc.cluster.local,通过该记录可以解析出服务的集群 IP。
Headless(没有集群 IP)的 Service 也被分配了一个 DNS 记录,名称格式为 my-svc.my-namespace.svc.cluster.local。与普通 Service 不同的是,它会解析出 Service 选择的 Pod 的 IP 列表。

SRV records

SRV records 用于为命名端口服务,这些端口是 headless 或者普通 Service 的一部分。对于每个命名端口,SRV record 的格式为:_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local。对于普通服务来说,这会解析出端口号和 CNAMEmy-svc.my-namespace.svc.cluster.local。对于 headless 服务来说,这会解析出多个结果,一个是 service 后端的每个 pod,一个是包含端口号,和格式为 auto-generated-name.my-svc.my-namespace.svc.cluster.local 的 pod 的 CNAME。

向后兼容性

kube-dns 的之前版本,使用了格式为 my-svc.my-namespace.cluster.local(svc 这一层是后面加上的)的名称。但这种格式不再被支持了。

Pods

pod 会被分配一个 DNS 记录,名称格式为 pod-ip-address.my-namespace.pod.cluster.local。
比如,一个 pod,它的 IP 地址为 1.2.3.4,命名空间为 default,DNS 名称为 cluster.local,那么它的记录就是:1-2-3-4.default.pod.cluster.local。
当 pod 被创建时,它的 hostname 设置在 Pod 的 metadata.name 中(写 yaml 的时候应该很清楚这点)。
在 v1.2 版本中,用户可以指定一个 Pod 注解,pod.beta.kubernetes.io/hostname,用于指定 Pod 的 hostname。这个 Pod 注解,一旦被指定,就将优先于 Pod 的名称,成为 pod 的 hostname。比如,一个 Pod,其注解为 pod.beta.kubernetes.io/hostname: my-pod-name,那么该 Pod 的 hostname 会被设置为 my-pod-name。
v1.2 中还引入了一个 beta 特性,用户指定 Pod 注解,pod.beta.kubernetes.io/subdomain,来指定 Pod 的 subdomain。比如,一个 Pod,其 hostname 注解设置为“foo”,subdomain 注解为“bar”,命名空间为“my-namespace”,那么它最终的 FQDN 就是“foo.bar.my-namespace.svc.cluster.local”。
在 v1.3 版本中,PodSpec 有了 hostname 和 subdomain 字段,用于指定 Pod 的 hostname 和 subdomain。它的优先级则高于上面提到的 pod.beta.kubernetes.io/hostname 和 pod.beta.kubernetes.io/subdomain。
示例:

apiVersion: v1
kind: Service
metadata:
 name: default-subdomain
spec:
 selector:
 name: busybox
 clusterIP: None
 ports:
 - name: foo # Actually, no port is needed.
 port: 1234 
 targetPort: 1234
apiVersion: v1
kind: Pod
metadata:
 name: busybox1
 labels:
 name: busybox
spec:
 hostname: busybox-1
 subdomain: default-subdomain
 containers:
 - image: busybox
 command:
 - sleep
 -  3600 
 name: busybox
apiVersion: v1
kind: Pod
metadata:
 name: busybox2
 labels:
 name: busybox
spec:
 hostname: busybox-2
 subdomain: default-subdomain
 containers:
 - image: busybox
 command:
 - sleep
 -  3600 
 name: busybox

如果一个 headless service 中,多个 pod 都在同一个命名空间里,并且 subdomain 名称也相同,集群的 KubeDNS 还是会为每个 Pod 返回完整而合格的 hostname。给定一个 Pod,其 hostname 设置为 busybox-1,subdomain 设置为 default-subdomain,同一个命名空间中的 headless Service 名为 default-subdomain,那么 pod 自己的 FQDN 就是“busybox-1.default-subdomain.my-namespace.svc.cluster.local”。
在 Kubernetes v1.2 里,Endpoint 对象还使用了注解 endpoints.beta.kubernetes.io/hostnames-map。它的值就是 json 格式中的 map[string(IP)][endpoints.HostRecord],比如‘{“10.245.1.6”:{HostName:“my-webserver”}}’。如果 Endpoint 是用于 headless service 的,就会为其创建一个格式为 …svc 的记录。以 json 格式为例,如果 Endpoint 用于名为“bar”的 headless service,其中一个 Endpoint 的 ip 为“10.245.1.6”,就会创建一个名为“my-webserver.bar.my-namespace.svc.cluster.local”的记录,查询该记录就会得到“10.245.1.6”。这个 Endpoint 注解一般不需要终端用户来指定,但可以被内部服务控制器使用,来实现上面的特性。
在 v1.3 中,Endpoint 对象可以为任何一个 Endpoint 指定 hostname 和 IP。hostname 字段会覆盖 endpoints.beta.kubernetes.io/hostnames-map 注解的值。
在 v1.3 中,以下注解被弃用了:pod.beta.kubernetes.io/hostname,pod.beta.kubernetes.io/subdomain,endpoints.beta.kubernetes.io/hostnames-map。

如何测试 DNS 是否工作创建一个简单地 Pod,使用测试环境

创建一个名为 busybox.yaml 文件,使用下面的内容:

apiVersion: v1
kind: Pod
metadata:
 name: busybox
 namespace: default
spec:
 containers:
 - image: busybox
 command:
 - sleep
 -  3600 
 imagePullPolicy: IfNotPresent
 name: busybox
 restartPolicy: Always

使用该文件创建 pod:

kubectl create -f busybox.yaml

等待 pod 进入 running 状态

获取 pod 状态:

$ kubectl get pods busybox

你会看到:

NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 7m

确认 DNS 是否工作

一旦 pod 处于 running 状态时,可以使用 exec nslookup 来查询状态:

$ kubectl exec -ti busybox -- nslookup kubernetes.default

你应该看到类似的结果:

Server: 10.0.0.10
Address 1: 10.0.0.10
Name: kubernetes.default
Address 1: 10.0.0.1

如果出现上述结果,则说明 DNS 正常工作。

故障排查

如果 nslookup 失败,检查以下选项:

检查本地 DNS 配置

检查 pod 的 resolv.conf 文件。

$ kubectl exec busybox cat /etc/resolv.conf

确认搜索路径和 name sever 被设置成类似下面的样子(注意搜索路径可能因云提供商不同而有所差异):

search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
nameserver 10.0.0.10
options ndots:5

快速诊断

如下的错误表明 kube-dns add-on 或者相关服务有问题:

$ kubectl exec -ti busybox -- nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10
nslookup: can t resolve  kubernetes.default 

或者

$ kubectl exec -ti busybox -- nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
nslookup: can t resolve  kubernetes.default 

检查 DNS pod 是否运行

使用 kubectl get pods 命令来确认 DNS pod 是否正在运行。

$ kubectl get pods --namespace=kube-system -l k8s-app=kube-dns

应该会有如下的结果:

NAME READY STATUS RESTARTS AGE
kube-dns-v19-ezo1y 3/3 Running 0 1h
...

如果没有相关的 pod 运行,或者 pod 状态为 failed/completed,那么就说明你的环境下,没有默认部署 DNS add-on,你需要手动部署它。

检查 DNS pod 中的错误

使用 kubectl log 命令来查看 DNS 守护程序的日志。

$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns
$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq
$ kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c healthz

如果有任何可疑的日志,每一行开头的 W,E,F 字母分别表示警告、错误和故障。请搜索这些错误日志的条目,或者通过 kubernetes issues 页面来报错非预期的错误。

DNS 服务是否启动

使用 kubectl get service 命令来查看 DNS 服务是否已经启动。

$ kubectl get svc --namespace=kube-system

你会看到:

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns 10.0.0.10  none  53/UDP,53/TCP 1h
...

该服务会默认地被创建,或者如果你手动创建了该服务,但是该服务却并没有在上述命令中出现,请查看 debugging services page 页面获取更多信息。

是否暴露了 DNS Endpoint?

可通过 kubectl get endpoints 命令来确认是否暴露了 DNS Endpoint。

$ kubectl get ep kube-dns --namespace=kube-system

你应该会看到下面的结果:

NAME ENDPOINTS AGE
kube-dns 10.180.3.17:53,10.180.3.17:53 1h

如果没有看到 Endpoint,那么请查看 debugging services page 页面。
若要查看更多的 Kubernetes DNS 示例,请在 Kubernetes Github 仓库中查看 cluster-dns examples。

如何工作

运行的 Kubernetes DNS pod 包含 3 个容器——kubedns、dnsmasq 和一个叫做 healthz 的健康检查容器。kubedns 进程监视 Kubernetes master 上 Service 和 Endpoint 的改变,并在内存中维护 lookup 结构用于服务 DNS 请求。dnsmasq 容器增加 DNS 缓存,从而提升性能。healthz 容器提供一个单点的健康检查 Endpoint,检查 dnsmasq 和 kubedns 的健康程度。
DNS pod 以服务的形式暴露出来,它拥有一个静态 IP。一旦被创建,kubelet 就使用 –cluster-dns=10.0.0.10 标识,将 DNS 配置信息传递给每个容器。
DNS 名称也需要域。本地域是可以配置的,在 kubelet 中,使用 –cluster-domain= default local domain 参数。
Kubernetes 集群的 DNS 服务(基于 SkyDNS 库)支持 forward lookup(A recoreds),service lookup(SRV records)和反向 IP 地址查找(PTR recoreds)。

从 node 继承 DNS

当运行 pod 时,kubelet 会预先考虑集群的 DNS 服务,并在 node 本地的 DNS 设置中搜索路径。如果 node 能够解析 DNS 名称,那么 pod 也可以做到。
如果你希望在 pod 中使用不同的 DNS,那么你可以使用 kubelet 的 –resolv-conf 参数。该设置意味着 pod 不会从 node 继承 DNS。设置该值为其他的文件路径,意味着会使用该文件来配置 DNS,而不是 /etc/resolv.conf。

已知的问题

Kubernetes 安装默认并不会使用集群的 DNS 配置来设置 Kubernetes node 的 resolv.conf 文件,因为该进程依赖于发行版的配置。
Linux 的 libc 有着 3 个 DNS nameserver 和 6 个 DNS 搜索记录的限制,Kubernetes 需要消耗一个 nameserver 和 3 个搜索记录。这意味着如果一个本地配置已经使用了 3 个 nameserver 或者使用了 3 个以上的搜索记录,那么这些配置可能会丢失。有一个临时方案,node 可以运行 dnsmasq,它可以提供更多的 nameserver 选项,但不能提供更多的搜索选项。你也可以使用 kubelet 的 –resolv-conf 选项。
如果你使用的是 Alpine 3.3 或更早的版本,DNS 可能不能正常的工作,这是已知的问题。

感谢各位的阅读!关于“Kubernetes DNS 的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计7645字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)