CoreDNS作为现阶段k8s的默认DNS服务以及服务发现的重要一环,其内置的kubernetes插件可谓是举足轻重。本文主要讲解介绍CoreDNS内置的核心插件kubernetes的使用方式和适用场景。

CoreDNS的kubernetes插件的具体实现遵循k8s官方提供的标准指南Kubernetes DNS-Based Service Discovery Specification,这也是它能够替代kube-dns成为kubebernetes中默认的DNS的重要原因。

虽然 Kubernetes 中的服务发现可以通过其他协议和机制提供(如consul等服务注册发现中心),但DNS是非常常用的一种协议,同时考虑到K8S中的东西流量互访主要也是通过域名实现,因此K8S官方非常推荐使用DNS插件来实现K8S中的服务发现。

This document is a specification for DNS-based Kubernetes service discovery. While service discovery in Kubernetes may be provided via other protocols and mechanisms, DNS is very commonly used and is a highly recommended add-on. The actual DNS service itself need not be provided by the default Kube-DNS implementation. This document is intended to provide a baseline for commonality between implementations.

在开始介绍kubernetes插件之前,我们需要先了解一些K8S中的基础DNS知识。

1、K8S中的DNS服务

众所周知,在K8S中,IP是随时会发生变化的,变化最频繁的就是Pod IPCluster IP也并不是一定不会发生变化,EXTERNAL-IP虽然可以手动指定静态IP保持不变,但是主要面向的是集群外部的服务;因此在K8S集群中,最好的服务之间相互访问的方式就是通过域名。

1.1 DNS创建规则

在K8S集群中,Kubernetes 为 Service 和 Pod 创建 DNS 记录。

前面我们介绍了K8S中的每个SVC都会有一个对应的域名,域名的组成格式为$service_name.$namespace_name.svc.$cluster_name,同时也会给这个SVC下的所有Pod都创建一个$pod_name.$service_name.$namespace_name.svc.$cluster_name的这种域名,这个域名的解析结果就是Pod IP。

Pod域名有两个比较明显的特征:

  • 一是域名的组成比较特殊,因为域名中使用了Pod的名称,而pod名称在K8S中是会发生变化的(例如在服务更新或者滚动重启时),同时由于默认情况下Pod的命名是没有太明显的规律(大部分名字中会包含一串随机UUID)
  • 二是域名的解析结果特殊,相较于集群内的其他类型域名,Pod域名的解析是可以精确到特定的某个Pod,因此一些特殊的需要点对点通信的服务可以使用这类Pod域名

1.2 DNS策略配置

DNS 策略可以逐个 Pod 来设定。目前 Kubernetes 支持以下特定 Pod 的 DNS 策略。 这些策略可以在 Pod 规约中的 dnsPolicy 字段设置:

  • Default: Pod 从运行所在的K8S宿主机节点继承域名解析配置;
  • ClusterFirst: 不指定任何dnsPolicy配置情况下的默认选项,所有查询的域名都会根据生成的集群的K8S域名等信息生成的 /etc/resolv.conf 配置进行解析和转发到集群内部的DNS服务进行解析;
  • ClusterFirstWithHostNet:主要用于以 hostNetwork 方式运行的 Pod,如果这些pod想要使用K8S集群内的DNS服务,则可以配置为这个字段;
  • None: 此设置允许 Pod 忽略 Kubernetes 环境中的 DNS 设置,Pod 会使用其 dnsConfig 字段 所配置的 DNS 设置;

说明: 下面主要介绍ClusterFirst模式

1.3 DNS解析规则

DNS 查询参照 Pod 中的 /etc/resolv.conf 配置,kubelet 会为每个 Pod 生成此文件。因此在每个pod里面都有一个类似下面这样的 /etc/resolv.conf文件,通过修改其中的配置可以更改DNS的查询规则:

nameserver 10.32.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

这里的配置有几个需要注意的点:

  • nameserver:集群中的DNS服务器IP,一般来说就是CoreDNSClusterIP
  • search:需要搜索的域,默认情况下会从该pod所属的namespace开始逐级补充
  • options ndots:触发上面的search的域名点数,默认为1,上限15,在K8S中一般为5;例如在Linux中tinychen.com这个域名的ndots是1,tinychen.com.这个域名的ndots才是2(需要注意所有域名其实都有一个根域.,因此tinychen.com的全称应该是tinychen.com.

这是一个比较通用的案例,我们再来看一个比较特殊的配置

# 首先进入一个pod查看里面的DNS解析配置
[root@tiny-calico-master-88-1 tiny-calico]# kubectl exec -it -n ngx-system ngx-ex-deploy-6bf6c99d95-5qh2w /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
[root@ngx-ex-deploy-6bf6c99d95-5qh2w /]# cat /etc/resolv.conf
nameserver 10.88.0.10
search ngx-system.svc.cali-cluster.tclocal svc.cali-cluster.tclocal cali-cluster.tclocal k8s.tcinternal
options ndots:5
[root@ngx-ex-deploy-6bf6c99d95-5qh2w /]# exit

这个pod里面的/etc/resolv.conf配置文件有两个和前面不同的地方:

  • cluster.local变成了cali-cluster.tclocal

    这里我们可以看到coredns的配置中就是配置的cali-cluster.tclocal,也就是说/etc/resolv.conf中的配置其实是和coredns中的配置一样,更准确的说是和该K8S集群初始化时配置的集群名一样

    # 再查看K8S集群中的coredns的configmap
    [root@tiny-calico-master-88-1 tiny-calico]# kubectl get configmaps -n kube-system coredns -oyaml
    apiVersion: v1
    data:Corefile: |.:53 {errorshealth {lameduck 5s}readykubernetes cali-cluster.tclocal in-addr.arpa ip6.arpa {pods insecurefallthrough in-addr.arpa ip6.arpattl 30}prometheus :9153forward . 10.31.100.100 {max_concurrent 1000}cache 30loopreloadloadbalance}
    kind: ConfigMap
    metadata:creationTimestamp: "2022-05-06T05:19:08Z"name: corednsnamespace: kube-systemresourceVersion: "3986029"uid: 54f5f803-a5ab-4c77-b149-f02229bcad0a
    
  • search新增了一个k8s.tcinternal

    实际上我们再查看K8S的宿主机节点的DNS配置规则时会发现这个k8s.tcinternal是从宿主机上面继承而来的

    # 最后查看宿主机节点上面的DNS解析配置
    [root@tiny-calico-master-88-1 tiny-calico]# cat /etc/resolv.conf
    # Generated by NetworkManager
    search k8s.tcinternal
    nameserver 10.31.254.253
    

1.4 DNS解析流程

温馨提示:阅读这部分内容的时候要特别注意域名结尾是否有一个点号.

当ndots小于options ndots

前面我们说过options ndots的值默认情况下是1,在K8S中为5,为了效果明显,我们这里使用K8S中的5作为示例:

这里同样是在一个命名空间demo-ns中有两个SVC,分别为demo-svc1demo-svc2,那么他们的/etc/resolv.conf应该是下面这样的:

nameserver 10.32.0.10
search demo-ns.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

我们在demo-svc1中直接请求域名demo-svc2,此时ndots为1,小于配置中的5,因此会触发上面的search规则,这时第一个解析的域名就是demo-svc2.demo-ns.svc.cluster.local,当解析不出来的时候继续下面的demo-svc2.svc.cluster.localdemo-svc2.cluster.local,最后才是直接去解析demo-svc2.

注意上面的规则适用于任何一个域名,也就是当我们试图在pod中去访问一个外部域名如tinychen.com的时候也会依次进行上述查询。

当ndots大于等于options ndots

我们在demo-svc1中直接请求域名demo-svc2.demo-ns.svc.cluster.local,此时的ndots为4,还是会触发上面的search规则。

而请求域名demo-svc2.demo-ns.svc.cluster.local.,ndots为5,等于配置中的5,因此不会触发上面的search规则,直接去解析demo-svc2.demo-ns.svc.cluster.local.这个域名并返回结果

如果我们请求更长的域名如POD域名pod-1.demo-svc2.demo-ns.svc.cluster.local.,此时的ndots为6,大于配置中的5,因此也不会触发上面的search规则,会直接查询域名并返回解析

小结

通过上面的分析我们不难得出下面几点结论:

  • 同命名空间(namespace)内的服务直接通过$service_name进行互相访问而不需要使用全域名(FQDN),此时DNS解析速度最快;
  • 跨命名空间(namespace)的服务,可以通过$service_name.$namespace_name进行互相访问,此时DNS解析第一次查询失败,第二次才会匹配到正确的域名
  • 所有的服务之间通过全域名(FQDN)$service_name.$namespace_name.svc.$cluster_name.访问的时候DNS解析的速度最快
  • 在K8S集群内访问大部分的常见外网域名(ndots小于5)都会触发search规则,因此在访问外部域名的时候可以使用FQDN,即在域名的结尾配置一个点号.

2、kubernetes插件

kubernetes插件的主要作用就是用来连接k8s集群的apiserver并对外提供符合规范的域名解析服务,该插件在每个配置块中仅能使用一次,但在一个coredns实例中可以存在多个配置块,也就意味着一个coredns实例实际上是可以连接多个k8s集群并对外提供域名解析的。

接下来我们详细看一下kubernetes插件的各种具体配置,下面的这个是官方给出的一个配置文件示例:

kubernetes [ZONES...] {endpoint URLtls CERT KEY CACERTkubeconfig KUBECONFIG [CONTEXT]namespaces NAMESPACE...namespace_labels EXPRESSIONlabels EXPRESSIONpods POD-MODEendpoint_pod_namesttl TTLnoendpointsfallthrough [ZONES...]ignore empty_service
}
  • endpoint

    用来指定k8s集群的apiserver地址,如https://10.31.88.1:6443,当然也可以是域名等其他形式,如果不配置,那么默认情况下会使用对应的service account去连接当前k8s集群内的apiserver,如果不是在k8s集群中部署,那么就会连接失败。

  • tls

    CERT KEY CACERT是远程 k8s 连接的 TLS 证书、密钥和 CA 证书文件名。如果前面的endpoint没有配置,那么这个配置项会被忽略。

  • kubeconfig

    KUBECONFIG [CONTEXT]使用 kubeconfig 文件验证与远程 k8s 集群的连接。 [CONTEXT]是可选配置的,如果未设置,则将使用 kubeconfig中默认的[CONTEXT]。它支持 TLS、用户名和密码或基于令牌的身份验证。

    如果前面的endpoint没有配置,那么这个配置项会被忽略。

  • namespaces

    NAMESPACE [NAMESPACE…] 用来限制对外暴露的命名空间,多个命名空间之间使用空格间隔。如果不配置的话,则会暴露所有的命名空间。

  • namespace_labels

    namespace_labels EXPRESSION可以限定DNS的查询范围,仅有匹配labels命名空间才能被查询到。

  • labels

    labels EXPRESSION可以限定DNS的查询范围,仅有匹配lalelsservice才能被查询到。

注意这里的labels匹配的是service中的labels,而前面的labels匹配的是namespace中的labels。这两个labels的配置写法可以和使用kubectl命令中的-l参数完全一致。

如果要使用多个labels匹配规则,注意不要使用空格,而是对应的表达式进行匹配:

-l, --selector=‘’: Selector (label query) to filter on, supports ‘=’, ‘==’, and ‘!=’.(e.g. -l key1=value1,key2=value2)

  • pods

    pods POD-MODE设置处理基于 IP 的 pod A 记录的模式,例如客户端向coredns查询域名1-2-3-4.ns.pod.cluster.local.,该参数用于控制响应的结果,提供此选项是为了方便在直接连接到 pod 时使用 SSL 证书。

    **POD-MODE **有效值:

    • disabled: 默认。不处理 pod 请求,总是返回NXDOMAIN
    • insecure:总是从请求中返回带有 IP 的 A 记录(不检查 k8s),即查询域名1-2-3-4.ns.pod.cluster.local.的时候,不论是否存在一个IP地址为1.2.3.4的pod,都返回这个结果给客户端。如果与通配符 SSL 证书一起被恶意使用,此选项很容易被滥用。提供此选项是为了向后兼容 kube-dns。
    • verified: 如果在同一个命名空间中存在匹配 IP 的 Pod,则返回 A 记录,即查询域名1-2-3-4.ns.pod.cluster.local.的时候,只有当该ns中确实存在一个IP地址为1.2.3.4的pod,才返回这个结果给客户端,否则返回NXDOMAIN。与insecure模式相比,此选项需要更多的内存,因为它需要监控所有的pods。
  • endpoint_pod_names

    使用endpoints所对应的pod名称作为A记录中的端点名称,例如, endpoint-name.my-service.namespace.svc.cluster.local. in A 1.2.3.4

    在没有配置该参数的情况下,endpoints名称选择如下:优先使用endpoints的hostname,如果endpoints没有配置hostname,则使用 IP 地址的虚线形式(例如,1-2-3-4.my-service.namespace.svc.cluster.local.

    如果配置了该参数,则endpoints名称选择如下:优先使用endpoints的hostname,如果endpoints没有配置hostname,则使用endpoints对应的pod名称,如果pod名称不存在或者长度超过63,则使用 IP 地址的虚线形式。

  • ttl

    设置标准的DNS域名TTL,默认值为 5 秒。允许的最小 TTL 为 0 秒,最大值为 3600 秒。将 TTL 设置为 0 将防止记录被缓存(如果查询的客户端遵循DNS规范)。

  • noendpoints

    配置该参数将禁用对K8S集群中的endpoints记录功能,因此所有endpoints查询和headless服务查询都将返回 NXDOMAIN。

  • fallthrough [ZONES…]

    正常情况下一个客户端对CoreDNS发起了一个DNS查询,如果该记录不存在,那么就会直接返回一个NXDOMAIN的响应。

    但是我们可以通过配置fallthrough参数来将这些NXDOMAIN的域名转发到配置块中的下一个插件。

    例如在fallthrough插件后面还使用了诸如file插件之类的配置了DNS解析,那么这个请求就会转发到file插件进行查询并响应

    zones参数可以用来控制哪些域的域名会被fallthrough插件转发,留空的情况下是所有的域名都会被转发,当然也可以指定部分域名如(for example in-addr.arpa and ip6.arpa),此时就只有in-addr.arpaip6.arpa的查询出现NXDOMAIN才会被转发到下一个插件进行查询

  • ignore empty_service

    如果一个service当中没有任何可用的endpoints(即关联的所有pods都不是ready状态),那么会返回一个NXDOMAIN。

    这个配置项的主要作用就是让这类不正常的服务域名查询的时候能够返回NXDOMAIN响应码,从而触发配置的其他插件(如上面提到的fallthrough)进行组合操作。

3、一些其他问题

3.1 延迟启动

当CoreDNS启用了kubernetes插件之后,CoreDNS实例在启动的时候会延迟5s的时间再对外提供服务,这5s内CoreDNS会尝试和K8S的apiserver建立连接并同步信息。

如果5s内CoreDNS还是无法和k8s的apiserver完成信息同步工作,那么会开始对外提供服务,并且继续尝试同步信息,但是在成功和apiserver建立连接并同步信息之前,所有k8s相关的域名查询都会返回SERVFAIL

3.2 连接中断

如果在CoreDNS实例正常运行的时候,突然和k8s的apiserver断开连接,并且一直没有恢复,那么此时的CoreDNS实例是依旧正常运行的,对应的K8S集群域名也是能够正常解析的,但是解析出来的endpoint信息就有可能不是最新的。

如果此时再对CoreDNS实例进行重启操作,那么具体的过程就和上面讲述的延迟启动一样,最后会导致所有k8s相关的域名查询都会返回SERVFAIL

3.3 配置检查

kubernetes的健康状态会暴露在ready插件中,如果出现配置错误可以通过请求ready插件暴露的接口发现,但是如果出现连接异常这种情况,ready接口是无法探测出来的。

CoreDNS篇9-kubernetes插件相关推荐

  1. 第二篇:kubernetes部署calico网络插件

    说明: 总的目标是在k8s集群部署gitlab.jenkins,并且在本地提交代码到gitlab后jenkin流水线可以自动编译打包成为docker镜像然后部署到k8s中并实现客户端外部域名访问,在文 ...

  2. [k8s]jenkins配合kubernetes插件实现k8s集群构建的持续集成

    另一个结合harbor自动构建镜像的思路: 即code+baseimage一体的方案 - 程序员将代码提交到代码仓库gitlab - 钩子触发jenkins master启动一次构建 - jenkin ...

  3. CoreDNS篇1-简介和安装

    本文主要对coredns的原理和特性进行介绍,同时会对其二进制的安装方法进行尝试. 1.coredns简介 coredns是一个用go语言编写的开源的DNS服务,它的官网可以点击这里,github页面 ...

  4. CoreDNS篇8-健康检查

    本文主要讲解介绍CoreDNS内置的两个健康检查插件health和ready的使用方式和适用场景. 1.health插件 health插件默认情况下会在8080端口的/health路径下提供健康状态查 ...

  5. onenote 模板_onenote实用?炫酷功能系列篇②:用插件让效率翻倍

    对我而言,onenote作为office系列的一员,最大的遗憾就是--竟然不支持VBA!office如此强大的一个通用神器,在onenote这里竟然直接被砍了.好在还有个替代品--Onetastic, ...

  6. 【风宇冲】Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载

    [风宇冲]Unity3D教程宝典之插件篇:Unity3D插件详细评测及教学下载 (2012-12-09 07:27:51) 转载▼ 标签: unity3d unity unity3d教程 unity3 ...

  7. 第五篇:kubernetes部署dashboard(图形化界面)

    说明: 总的目标是在k8s集群部署gitlab.jenkins,并且在本地提交代码到gitlab后jenkin流水线可以自动编译打包成为docker镜像然后部署到k8s中并实现客户端外部域名访问,在文 ...

  8. CoreDNS篇5-日志处理

    本文主要用于介绍CoreDNS用来记录日志的几种方式以及在生产环境中遇到的一些问题和解决方案. 1.log插件 coredns的日志输出并不如nginx那么完善(并不能在配置文件中指定输出的文件目录, ...

  9. 【外行也能看懂的RabbitMQ系列(四)】—— RabbitMQ进阶篇之通过插件实现延迟队列(内含实现代码及rabbitmq_delayed_message_exchange安装)

    系列文章目录 准备篇 RabbitMQ安装文档 第一章 RabbitMQ快速入门篇 第二章 RabbitMQ的Web管理界面详解 第三章 RabbitMQ进阶篇之死信队列 第四章 RabbitMQ进阶 ...

最新文章

  1. Java学习总结:2
  2. 学习进度条(第一周)
  3. win10 电脑 .Net framework3.5 组件无法安装0x800f801f
  4. 关于C#内存释放的BUG?
  5. c语言switch scanf语句,C语言中scanf函数与switch语句
  6. JVM-内存溢出场景模拟
  7. python canvas画移动物体_Python:Tkinter的GUI设计——物体实时移动
  8. js中this的问题
  9. 随机数-random模块
  10. android 头像存储,安卓裁剪上传保存头像
  11. 申请美国大学计算机专业,申请美国大学计算机CS专业的4个要点
  12. EWM 创建包装物料
  13. 怎么用python下载网易云_如何使用python批量下载网易云音乐的免费音乐
  14. Android沉浸式的两种方法
  15. 亮度对比度色调饱和度最佳_数码教程丨如何仿电影胶片色调与质感?
  16. 【卡尔曼滤波】我所理解的卡尔曼滤波
  17. 社区的网络舆情信息监测具体实施方案
  18. 美发店为什么需要做线上预约系统
  19. Leetcode 590: N-ary树的后序遍历
  20. PCL_ROS的使用

热门文章

  1. 冥想的重大功能——人类21在21世纪的伟大发现
  2. 大数据分析案例-基于决策树算法构建银行客户流失预测模型
  3. 职业学校计算机知识,中等职业学校计算机教学大纲.doc
  4. python获取某年某月的第一天和最后一天获取某年某月的天数
  5. 不同鸟的叫声Java编程_飞扬小鸟java版(3种版本一次下载)
  6. 次要和主要等位基因的定义
  7. npm 安装 node-sass 失败问题分析及解决方案
  8. 计算机OSI七层参考模型
  9. 看,2021年,一个普通应届生的成长之旅
  10. [转]把自己从一个疯狂下载者变成一个学习者