阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Kubernetes DNS 简介

242次阅读
没有评论

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

环境

$ 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 的 NDS 搜索列表中会包含 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 有了hostnamesubdomain字段,用于指定 Pod 的 hostname 和 subdomain。它的优先级则高于上面提到的 pod.beta.kubernetes.io/hostnamepod.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/hostnamepod.beta.kubernetes.io/subdomainendpoints.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          m

确认 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'

检查 NDS 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           h
...

如果没有相关的 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        h
...

该服务会默认地被创建,或者如果你手动创建了该服务,但是该服务却并没有在上述命令中出现,请查看 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 可能不能正常的工作,这是已知的问题。可以查看这里获取更多信息。

References

Docs for the DNS cluster addon

Docker 中部署 Kubernetes http://www.linuxidc.com/Linux/2016-07/133020.htm

Kubernetes 集群部署  http://www.linuxidc.com/Linux/2015-12/125770.htm

OpenStack, Kubernetes, Mesos 谁主沉浮  http://www.linuxidc.com/Linux/2015-09/122696.htm

Kubernetes 集群搭建过程中遇到的问题及解决  http://www.linuxidc.com/Linux/2015-12/125735.htm

Kubernetes 集群部署  http://www.linuxidc.com/Linux/2015-12/125770.htm

Ubuntu 16.04 下安装搭建 Kubernetes 集群环境  http://www.linuxidc.com/Linux/2017-02/140555.htm

Ubuntu 上手动安装部署 Kubernetes 详细指南  http://www.linuxidc.com/Linux/2017-04/142514.htm

Kubernetes 的详细介绍:请点这里
Kubernetes 的下载地址:请点这里

本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-04/142647.htm

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计8024字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中