参考:
- 官方网站,CoreDNS: DNS and Service Discovery
- CoreDNS安装,https://my.oschina.net/u/2306127/blog/1618543
- CoreDNS使用手册,CoreDNS: DNS and Service Discovery
- CoreDNS源码,CoreDNS · GitHub
- CoreDNS配置,https://my.oschina.net/u/2306127/blog/1788566
从Kubernetes 1.11开始,可使用CoreDNS作为Kubernetes的DNS插件进入GA状态,Kubernetes推荐使用CoreDNS作为集群内的DNS服务。 我们先看一下Kubernetes DNS服务的发展历程。
Kubernetes 1.3之前的版本使用skyDNS作为DNS服务,这个有点久远了。Kubernetes的DNS服务由kube2sky、skyDNS、etcd组成。 kube2sky通过kube-apiserver监听集群中Service的变化,将生成的DNS记录信息更新到etcd中,而skyDNS将从etcd中获取数据对外提供DNS的查询服务。
Kubernetes 1.3开始使用kubeDNS和dnsmasq替换了原来的kube2sky和skyDNS,不再使用etcd,而是将DNS记录直接存放在内存中,通过dnsmasq的缓存功能提高DNS的查询效率。下图是描述了Kubernetes使用kubeDNS实现服务发现的整体架构:
从Kubernetes 1.11开始,可使用CoreDNS作为Kubernetes的DNS插件进入GA状态,Kubernetes推荐使用CoreDNS作为集群内的DNS服务。 CoreDNS从2017年初就成为了CNCF的的孵化项目,CoreDNS的特点就是十分灵活和可扩展的插件机制,
各种插件实现:
不同的功能,如重定向、定制DNS记录、记录日志等等。下图描述了CoreDNS的整体架构:
Kubernetes包括用于服务发现的DNS服务器Kube-DNS。 该DNS服务器利用SkyDNS的库来为Kubernetes pod和服务提供DNS请求。SkyDNS2的作者,Miek Gieben,创建了一个新的DNS服务器,CoreDNS,它采用更模块化,可扩展的框架构建。 Infoblox已经与Miek合作,将此DNS服务器作为Kube-DNS的替代品。
CoreDNS利用作为Web服务器Caddy的一部分而开发的服务器框架。该框架具有非常灵活,可扩展的模型,用于通过各种中间件组件传递请求。这些中间件组件根据请求提供不同的操作,例如记录,重定向,修改或维护。虽然它一开始作为Web服务器,但是Caddy并不是专门针对HTTP协议的,而是构建了一个基于CoreDNS的理想框架。
在这种灵活的模型中添加对Kubernetes的支持,相当于创建了一个Kubernetes中间件。该中间件使用Kubernetes API来满足针对特定Kubernetes pod或服务的DNS请求。而且由于Kube-DNS作为Kubernetes的另一项服务,kubelet和Kube-DNS之间没有紧密的绑定。您只需要将DNS服务的IP地址和域名传递给kubelet,而Kubernetes并不关心谁在实际处理该IP请求。
1.0.0版本主要遵循Kube-DNS的当前行为。 CoreDNS的005及更高版本实现了完整的规范和更多功能。
- A记录(正常的Service分配了一个名为my-svc.my-namespace.svc.cluster.local的DNS A记录。 这解决了服务的集群IP)
- “headless”(没有集群IP)的Service也分配了一个名为my-svc.my-namespace.svc.cluster.local的DNS A记录。 与普通服务不同,这解决了Service选择了pods的一组IP。 客户预计将从这ip集合中消耗集合或使用标准循环选择。
- 针对名为正常或无头服务的端口创建的SRV记录,对于每个命名的端口,SRV记录的格式为_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local。对于常规服务,这将解析为端口号和CNAME:my-svc.my-namespace.svc.cluster.local;对于无头服务,这解决了多个答案,一个用于支持服务的每个pod,并包含端口号还有格式为auto-generated-name.my-svc.my-namespace.svc.cluster.local 的pod的CNAME 。SRV记录包含它们中的“svc”段,对于省略“svc”段的旧式CNAME不支持。
- 作为Service一部分的endpoints的A记录(比如“pets”的记录)
- pod的Spec中描述的A记录
- 还有就是用来发现正在使用的DNS模式版本的TXT记录
所有群集中不需要pod A记录支持,默认情况下禁用。 此外,CoreDNS对此用例的支持超出了在Kube-DNS中找到的标准行为。
在Kube-DNS中,这些记录不反映集群的状态,例如,对w-x-y-z.namespace.pod.cluster.local的任何查询将返回带有w.x.y.z(ip)的A记录,即使该IP不属于指定的命名空间,甚至不属于集群地址空间。最初的想法是启用对* .namespace.pod.cluster.local这样的域使用通配符SSL证书。
CoreDNS集成了提供pod验证的选项,验证返回的IP地址w.x.y.z实际上是指定命名空间中的pod的IP。他防止在命名空间中欺骗DNS名称。 然而,它确实会大大增加CoreDNS实例的内存占用,因为现在它需要观察所有的pod,而不仅仅是服务端点。
2、架构
整个 CoreDNS 服务都建立在一个使用 Go 编写的 HTTP/2 Web 服务器 Caddy · GitHub 上,CoreDNS 整个项目可以作为一个 Caddy 的教科书用法。
CoreDNS 的大多数功能都是由插件来实现的,插件和服务本身都使用了 Caddy 提供的一些功能,所以项目本身也不是特别的复杂。
作为基于 Caddy 的 Web 服务器,CoreDNS 实现了一个插件链的架构,将很多 DNS 相关的逻辑都抽象成了一层一层的插件,包括 Kubernetes 等功能,每一个插件都是一个遵循如下协议的结构体:
所以只需要为插件实现 以及 这两个接口并且写一些用于配置的代码就可以将插件集成到 CoreDNS 中。
另一个 CoreDNS 的特点就是它能够通过简单易懂的 DSL 定义 DNS 服务,在 Corefile 中就可以组合多个插件对外提供服务:
对于以上的配置文件,CoreDNS 会根据每一个代码块前面的区和端点对外暴露两个端点提供服务:
该配置文件对外暴露了两个 DNS 服务,其中一个监听在 5300 端口,另一个在 53 端口,请求这两个服务时会根据不同的域名选择不同区中的插件进行处理。
CoreDNS 可以通过四种方式对外直接提供 DNS 服务,分别是 UDP、gRPC、HTTPS 和 TLS:
但是无论哪种类型的 DNS 服务,最终队会调用以下的 方法,为服务的调用者提供 DNS 服务:
在上述这个已经被简化的复杂函数中,最重要的就是调用了『插件链』的 方法,将来源的请求交给一系列插件进行处理,如果我们使用以下的文件作为 Corefile:
那么在 CoreDNS 服务启动时,对于当前的 这个组,它会依次加载 、、 和 几个插件,这里的顺序是由 zdirectives.go 文件定义的,启动的顺序是从下到上:
因为启动的时候会按照从下到上的顺序依次『包装』每一个插件,所以在真正调用时就是从上到下执行的,这就是因为 方法中对插件进行了组合:
对于 Corefile 里面的每一个配置组, 都会讲配置组中提及的插件按照一定的顺序组合起来,原理跟 Rack Middleware 的机制非常相似,插件 其实就是一个出入参数都是 的函数:
所以我们可以将它们叠成堆栈的方式对它们进行操作,这样在最后就会形成一个插件的调用链,在每个插件执行方法时都可以通过 函数调用下一个插件的 方法:
除了通过 调用下一个插件之外,我们也可以调用 方法并结束整个调用链。
从插件的堆叠到顺序调用以及错误处理,我们对 CoreDNS 的工作原理已经非常清楚了,接下来我们可以简单介绍几个插件的作用。
https://github.com/coredns/deployment/tree/master/kubernetes
注意和k8s的版本对应关系:https://github.com/coredns/deployment/blob/master/kubernetes/CoreDNS-k8s_version.md
主要有几个文件:
deploy.sh是一个便捷的脚本,用于生成用于在当前运行标准kube-dns的集群上运行CoreDNS的清单。使用coredns.yaml.sed文件作为模板,它创建一个ConfigMap和一个CoreDNS deployment,然后更新 Kube-DNS service selector以使用CoreDNS deployment。 通过重新使用现有服务,服务请求不会中断。
脚本不会删除kube-dns的deployment或replication controller - 您必须手动执行:
kubectl delete --namespace=kube-system deployment kube-dns
要使用它,只需将它们放在同一目录中,然后运行deploy.sh脚本,将其传递给您的服务CIDR(10.3.0.0/24)。 这将生成具有必要Corefile的ConfigMap。 它还将查找现有的kube-dns服务的集群IP。
[root@k8s-master conf.d]# etcdctl ls /k8s/network/subnets
/k8s/network/subnets/10.0.24.0-24
/k8s/network/subnets/10.0.86.0-24
/k8s/network/subnets/10.0.35.0-24
(注意:以上原始脚本只适用于当前kubernetes集群含有kube-dns的情况,如果没有需要修改下脚本
10.0.24.200
默认情况下CLUSTER_DNS_IP是自动获取kube-dns的集群ip的,但是由于没有部署kube-dns所以只能手动指定一个集群ip了。
执行: https://blog.csdn.net/hguisu/article/details/deploy.sh 10.0.0.0/24 cluster.local
以上脚本执行后可以看到预览的效果。
仔细观察上面的Corefile部分,这是一个在端口53上运行CoreDNS并为Kubernetes提供cluster.local域的示例
1)errors官方没有明确解释,后面研究
2)log stdout:日志中间件配置为将日志写入STDOUT
3)health:健康检查,提供了指定端口(默认为8080)上的HTTP端点,如果实例是健康的,则返回“OK”。
4)cluster.local:CoreDNS为kubernetes提供的域,10.3.0.0/24这告诉Kubernetes中间件它负责为反向区域提供PTR请求0.0.3.10.in-addr.arpa ..换句话说,这是允许反向DNS解析服务(我们经常使用到得DNS服务器里面有两个区域,即“正向查找区域”和“反向查找区域”,正向查找区域就是我们通常所说的域名解析,反向查找区域即是这里所说的IP反向解析,它的作用就是通过查询IP地址的PTR记录来得到该IP地址指向的域名,当然,要成功得到域名就必需要有该IP地址的PTR记录。PTR记录是邮件交换记录的一种,邮件交换记录中有A记录和PTR记录,A记录解析名字到地址,而PTR记录解析地址到名字。地址是指一个客户端的IP地址,名字是指一个客户的完全合格域名。通过对PTR记录的查询,达到反查的目的。)
5)proxy:这可以配置多个upstream 域名服务器,也可以用于延迟查找 /etc/resolv.conf 中定义的域名服务器
6)cache:这允许缓存两个响应结果,一个是肯定结果(即,查询返回一个结果)和否定结果(查询返回“没有这样的域”),具有单独的高速缓存大小和TTLs。
# https://blog.csdn.net/hguisu/article/details/deploy.sh -r 10.0.0.0/16 -i 192.168.10.90 -d cluster.local -t coredns.yaml.sed -s > coredns.yaml
# .kubectl apply -f coredns.yaml
或者直接执行:
# https://blog.csdn.net/hguisu/article/details/deploy.sh -r 10.0.0.0/16 -i 192.168.10.90 -d cluster.local -t coredns.yaml.sed -s | kubectl apply -f -
查看service
[root@k8s-master coredns]# kubectl get service -l k8s-app=kube-dns --namespace=kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 192.168.10.90 <none> 53/UDP,53/TCP,9153/TCP 15d
查看coredns的Pod,确认所有Pod都处于Running状态:
方式一kubelet统一修改:
kubelet的启动参数添加--cluster-dns配置:修改master节点和所有node节点--cluster-dns配置,修改内容如红色所注,与上面的Corefile中的值对应。
方式二:在pod启动添加
通过上述配置创建 之后,执行 命令即可看到额外的配置项目
即在 中多了 172.16.1.21、 中多了 和 两项值,及多了 配置。
因此,直接通过 进行配置后,默认是追加到当前默认配置中。
现在我们来创建一个wepapp的pod和service,测试一下coredns是否起作用
[root@k8s-master conf.d]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
webapp-nrz4t 1/1 Running 0 1d 10.0.35.3 192.168.10.39
webapp-zp69q 1/1 Running 0 1d 10.0.24.4 192.168.10.50
[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 28d
webapp ClusterIP 192.168.14.242 <none> 9081/TCP 17d
webapp2 ClusterIP 192.168.22.2 <none> 9082/TCP 17d
[root@k8s-master ~]# curl 192.168.22.2:9082
Hello world
1、检查集群的pod /etc/resolv.conf是否生效:
首先进入这个集群内的另一个pod
kubectl exec -it webapp-nrz4t /bin/sh 或者 docker exec -it 0d0874df9e15 /bin/sh
$ cat /etc/resolv.conf
sh-4.2# cat /etc/resolv.conf
nameserver 192.168.10.90
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
2、curl测试服务:
3、在master的主机上修改 /etc/resolv.conf,增加一行:nameserver 192.168.10.90后执行
通过域名访问成功!
我们在kubelet的启动参数添加--cluster-dns配置--cluster-dns=172.16.10.254。在Kubelet配置中通过使用–cluster-dns=10.10.10.2参数指定的coredns地址会被写入容器的/etc/resolv.conf配置中。
在 kubernetes 中还提供了 决定 内预设4种DNS策略:
None,无任何策略:表示空的DNS设置,这种方式一般用于想要自定义 DNS 配置的场景,往往需要和 dnsConfig 配合一起使用达到自定义 DNS 的目的。
Default,默认: 此种方式是让kubelet来决定使用何种DNS策略。而kubelet默认的方式,就是使用宿主机的/etc/resolv.conf文件。同时,kubelet也可以配置指定的DNS策略文件,使用kubelet参数即可,如:–resolv-conf=/etc/resolv.conf
ClusterFirst, 集群 DNS 优先:此种方式是使用kubernets集群内部中的kubedns或coredns服务进行域名解析。若解析不成功,才会使用宿主机的DNS配置来进行解析。
ClusterFistWithHostNet,集群 DNS 优先,并伴随着使用宿主机网络:在某些场景下,我们的 POD 是用 HOST 模式启动的(HOST模式,是共享宿主机网络的),一旦用 HOST 模式,表示这个 POD 中的所有容器,都要使用宿主机的 /etc/resolv.conf 配置进行DNS查询,但如果你想使用了 HOST 模式,还继续使用 Kubernetes 的DNS服务,那就将 dnsPolicy 设置为 ClusterFirstWithHostNet。
清除 Pod 预设 DNS 配置,当 dnsPolicy 设置成为这个值之后, kubernetes 不会为 Pod 预先加载任何逻辑用于判定得到 DNS 的配置。因此若将 dnsPolicy 设置为 None , 为了避免 Pod 里面没有 DNS 配置,最好通过 dnsConfig 来描述自定义的 DNS 参数。如下所示:
Pod 里面的 DNS 配置继承了宿主机上的 DNS 配置。即,该 Pod 的 DNS 配置与宿主机完全一致。
查看到宿主机上的配置如下:
通过上述配置创建 之后即可看到额外的配置项目,如下:
注意:这个会覆盖--cluster-dns配置
与 Default 相反,会预先使用 (或 ) 的信息当预设置参数写入到该 Pod 内的DNS配置。
通过上述配置创建 之后,执行 springbootweb 命令即可看到额外的配置项目,如下:
如设置了 时, 会被强制转化为 。如下:
nameserver 172.16.1.21
nameserver 119.29.29.29
设置 之后,会让 Pod 与该节点公用相同的网络空间(网卡/路由等)
同时使用 与 作为 Pod 预设 DNS 配置。
1、CoreDNS ConfigMap选项
CoreDNS是一个模块化和可插拔的DNS服务器,每个插件都为CoreDNS添加了新功能。这可以通过维护Corefile来配置,Corefile是CoreDNS配置文件。集群管理员可以修改CoreDNS Corefile的ConfigMap以更改服务发现的工作方式。
在Kubernetes中,CoreDNS安装了以下默认的Corefile配置。先来看看默认的CoreDns的配置文件:
kubectl edit configmap coredns -n kube-system, 红框部分是新加的:
- error: 错误记录到stdout
- health:CoreDNS的运行状况报告为http:// localhost:8080 / health
- kubernetes:CoreDNS将根据Kubernetes服务和pod的IP回复DNS查询
- prometheus:CoreDNS的度量标准可以在http://localhost:9153/Prometheus格式的指标中找到
- forward:任何不在Kubernetes集群域内的查询都将转发到预定义的解析器(/etc/resolv.conf)
- cache:启用前端缓存
- loop:检测简单的转发循环,如果找到循环则停止CoreDNS进程
- reload:允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,请等待两分钟以使更改生效
- loadbalance:这是一个循环DNS负载均衡器,可以在答案中随机化A,AAAA和MX记录的顺序
注意:CoreDNS 1.5.0以后不在使用proxy关键字,而是使用forward。
我们强制所有非集群 DNS 查找通过特定的域名服务器(位于172.16.1.21)来解析,将forward 指向域名服务器,而不是 /etc/resolv.conf。
如果域名后缀都为.xxxapi.com,并通过172.16.1.21域名服务器来解析,
配置如下:
xxxapi.com:53 {
errors
cache 30
forward . 172.16.1.21
}
即上面截图。
然后可以访问进入容器:docker exec -it 7d9ba3b6acdf /bin/sh 可以ping通了:
如果执行 nslookup 命令失败,检查如下内容:
1、先检查本地 DNS 配置
查看配置文件 resolv.conf。
按照如下方法(注意搜索路径可能会因为云提供商不同而变化)验证搜索路径和 Name Server 的建立:
nameserver 192.168.10.90
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
2、快速诊断
出现类似如下指示的错误,说明 kube-dns 插件或相关 Service 存在问题:
检查service是否正常运行:
kubectl get svc --namespace=kube-system
或者检查是否 DNS Pod 正在运行
使用 命令验证 DNS Pod 正在运行:
kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
应该能够看到类似如下信息:
如果看到没有 Pod 运行,或 Pod 失败/结束,DNS 插件不能默认部署到当前的环境,必须手动部署。
或者查看service的Endpoint是否正常:
kubectl get ep kube-dns --namespace=kube-system
如果没有看到 Endpoint,查看 调试 Service 文档 中的 Endpoint 段内容。
3、检查 DNS Pod 中的错误信息
使用 命令查看 DNS 后台进程的日志:
看到错误信息:
eflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Namespace: Get https://192.168.0.1:443/api/v1/namespace
2.168.0.1:443/api/v1/endpoints?limit=500&resourceVersion=0: x509: certificate is valid for 192.168.10.50, 10.0.0.1, not 192.168.0.1
E0710 16:00:58.986103 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Namespace: Get https://192.168.0.1:443/api/v1/namespaces?limit=500&resourceVersion=0: x509: certificate is valid for 192.168.10.50, 10.0.0.1, not 192.168.0.1
E0710 16:00:58.989633 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Service: Get https://192.168.0.1:443/api/v1/services?limit=500&resourceVersion=0: x509: certificate is valid for 192.168.10.50, 10.0.0.1, not 192.168.0.1
E0710 16:00:58.991655 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Endpoints: Get https://192.168.0.1:443/api/v1/endpoints?limit=500&resourceVersion=0: x509: certificate is valid for 192.168.10.50, 10.0.0.1, not 192.168.0.1
E0710 16:00:59.990732 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+inco
原因:192.168.0.1不在证书里面
解决:需要重新设置:apiserver证书
masterssl.cnf文件的示例如下:IP.3 = 192.168.0.1
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster.local
IP.1 = ${K8S_SERVICE_IP}
IP.2 = ${MASTER_IPV4}
IP.3 = 192.168.0.1
错误信息:
E0712 02:25:45.326123 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Service: Unauthorized
E0712 02:25:45.327038 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Endpoints: Unauthorized
E0712 02:25:45.328029 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Namespace: Unauthorized
E0712 02:25:46.327153 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Service: Unauthorized
E0712 02:25:46.328210 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Endpoints: Unauthorized
E0712 02:25:46.329160 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Namespace: Unauthorized
E0712 02:25:47.328243 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Service: Unauthorized
E0712 02:25:47.329143 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Endpoints: Unauthorized
E0712 02:25:47.330086 1 reflector.go:134] pkg/mod/k8s.io/client-go@v10.0.0+incompatible/tools/cache/reflector.go:95: Failed to list *v1.Namespace: Unauthorized
原因:service account 的token认知不通过,是因为重新生成证书后,需要删除旧的token。
解决:
以上就是本篇文章【k8s实践(11) --服务发现CoreDNS和Kubernetes内部域名解析】的全部内容了,欢迎阅览 ! 文章地址:http://dfvalve.xrbh.cn/news/923.html 资讯 企业新闻 行情 企业黄页 同类资讯 首页 网站地图 返回首页 迅博思语资讯移动站 http://keant.xrbh.cn/ , 查看更多