运维工程师-kubernetes

基础概念

  • 什么是 Kubernetes:Kubernetes 是一个开源的容器编排工具,用于自动执行管理、监控、扩展和部署容器化应用程序,可实现容器的自动化部署、伸缩、负载均衡等功能.
  • Kubernetes 的主要组件有哪些及作用 :
    • kube-apiserver:是 Kubernetes 集群的前端接口,提供了资源操作的唯一入口,负责接收和处理来自客户端的请求,如 kubectl 命令行工具、UI 界面等发来的请求,并将请求转发给相应的控制器或存储后端。
    • kube-controller-manager:运行着多个控制器,如副本控制器、端点控制器等,负责维护集群的状态,确保资源的期望状态与实际状态一致,例如自动创建或删除 Pod 副本以保证副本数量符合预期等。
    • kube-scheduler:负责根据调度算法和策略,将未调度的 Pod 分配到合适的 Node 节点上运行,考虑因素包括节点的资源使用情况、Pod 的资源请求、亲和性与反亲和性等。
    • kubelet:运行在每个 Node 节点上,作为代理与 Master 节点通信,负责管理本节点上的容器,包括容器的创建、启动、停止、监控等操作,同时向 Master 节点汇报本节点的资源使用情况和容器状态。
    • kube-proxy:主要负责实现 Kubernetes Service 的通信与负载均衡功能,通过在节点上设置 iptables 规则或 IPVS 规则,将对 Service 的访问请求转发到后端的 Pod 实例上。
  • Pod 是什么:Pod 是 Kubernetes 中最小的可部署和可调度单元,一个 Pod 可以包含一个或多个紧密相关的容器,这些容器共享网络命名空间、存储卷等资源,并且在同一 Pod 中的容器会在同一台主机上被共同调度和管理,它们的生命周期也是相同的.

资源对象

  • Deployment 和 ReplicaSet 的区别:Deployment 是用于控制副本数量和配置的资源对象,它基于模板创建新的容器副本,并提供了方便的滚动更新、回滚等功能,适合用于部署无状态应用。而 ReplicaSet 是 Deployment 的底层实现,提供更细粒度的副本控制和容错机制,主要用于确保指定数量的 Pod 副本始终处于运行状态.
  • StatefulSet 的作用及使用场景:StatefulSet 用于管理有状态应用,确保每个 Pod 都有一个唯一的标识符,并且 Pod 之间的启动和终止顺序是有序的,常用于需要持久化存储和稳定网络标识符的场景,如数据库应用等.
  • Service 的类型及作用 :
    • ClusterIP:这是默认的 Service 类型,为 Kubernetes 集群内部的 Pod 提供一个虚拟的服务 IP 地址,用于集群内部的 Pod 之间通信,在 Node 上 kube-proxy 通过设置 iptables 规则进行转发。
    • NodePort:使用宿主机的端口,使得能够访问各 Node 的外部客户端通过 Node 的 IP 地址和端口号就能访问服务,主要用于在集群外部访问集群内的服务。
    • LoadBalancer:使用外接负载均衡器完成到服务的负载分发,通常用于公有云环境,需要在 spec.status.loadBalancer 字段指定外部负载均衡器的 IP 地址。

网络与通信

  • Kubernetes 的网络模型是怎样的:Kubernetes 采用了 CNI(Container Network Interface)插件机制来实现网络功能,默认情况下使用的是基于 IP-per-Pod 的网络模型,即每个 Pod 都有一个独立的 IP 地址,Pod 内的容器共享该 IP 地址,并且可以通过该 IP 地址与其他 Pod 或外部网络进行通信.
  • 不同 Node 上的 Pod 之间是如何通信的:不同 Node 上的 Pod 之间通信主要通过 Kubernetes 的网络插件来实现,常见的网络插件如 Calico、Flannel 等会为 Pod 分配可路由的 IP 地址,并建立起跨节点的网络连接,使得 Pod 之间能够直接通过 IP 地址进行通信。同时,Service 也为 Pod 之间的通信提供了一种稳定的方式,Pod 可以通过 Service 的 DNS 名称或 ClusterIP 来访问其他 Pod.
  • kube-proxy 的作用及原理:kube-proxy 主要负责实现 Kubernetes Service 的通信与负载均衡功能,其原理是通过在节点上设置 iptables 规则或 IPVS 规则,将对 Service 的访问请求转发到后端的 Pod 实例上。当客户端访问 Service 时,kube-proxy 会根据设置的规则将请求转发到对应的 Pod,从而实现负载均衡和服务发现的功能.

存储管理

  • 什么是 PVC 和 PV:PVC(Persistent Volume Claim)是用户对存储资源的申请,用于声明对持久卷的需求;而 PV(Persistent Volume)是对底层网络共享存储的抽象,将共享存储定义为一种 “资源”,PVC 会向 PV 申请存储资源,Pod 通过挂载 PVC 来使用持久化存储.
  • Kubernetes 支持哪些存储类型:Kubernetes 支持多种存储类型,如 EmptyDir、HostPath、NFS、Ceph 等,不同的存储类型适用于不同的场景,例如 EmptyDir 适用于临时存储,HostPath 适用于在节点上共享本地文件系统,NFS 适用于网络共享存储等.
  • 持久化存储 (Persistent Storage)
    1. PersistentVolume (PV) 和 PersistentVolumeClaim (PVC):
      • PV 是集群中的一块存储资源,由管理员配置。
      • PVC 是用户对存储资源的请求。
      • 一旦 PVC 绑定到 PV,数据就可以持久化保存,即使 Pod 被重新调度或删除。
      • 支持多种后端存储系统,如 NFS、iSCSI、云提供商的存储服务等。
    1. StorageClass:
      • 提供了一种动态供应 PV 的方法。
      • 管理员可以定义不同级别的存储,并通过标签选择器来指定存储类型。
      • 用户只需创建一个 PVC,系统会根据 StorageClass 自动创建相应的 PV。
    1. CSI (Container Storage Interface):
      • CSI 是一种标准接口,允许任意存储供应商为 Kubernetes 提供存储插件。
      • 它使得第三方存储系统能够无缝集成到 Kubernetes 集群中。
      • 支持动态卷供应、快照、克隆等功能。
    1. Local Persistent Volumes:
      • 用于将本地磁盘直接作为 PV 使用。
      • 通常与 StatefulSets 结合使用,以确保数据持久性和高可用性。
      • 需要特别注意的是,如果底层硬件故障,数据可能会丢失,因此通常需要额外的数据复制机制。

调度与资源管理

  • Pod 的调度策略有哪些:常见的 Pod 调度策略包括基于资源请求的调度、亲和性与反亲和性调度、污点与容忍度调度等。基于资源请求的调度会根据 Pod 对 CPU、内存等资源的请求量,将 Pod 调度到资源充足的节点上;亲和性与反亲和性调度可以让 Pod 根据标签选择调度到特定的节点或避免调度到某些节点;污点与容忍度调度则用于限制 Pod 在具有特定污点的节点上的调度35.
  • 如何实现 Pod 的自动扩展:Kubernetes 支持水平 Pod 自动缩放(Horizontal Pod Autoscaler,HPA)功能,可以根据 Pod 的 CPU 或内存使用率来自动调整 Pod 的数量。当 Pod 的使用率超过预设的阈值时,HPA 会自动增加 Pod 的数量以满足负载需求;反之,当使用率降低时,HPA 会减少 Pod 的数量以节省资源.

运维与监控

  • 如何进行 Kubernetes 集群的监控:可以使用多种工具来监控 Kubernetes 集群,如 Prometheus、Grafana 等。Prometheus 可以收集集群中各种资源的指标数据,如 Pod 的 CPU、内存使用情况,Service 的请求量等,然后通过 Grafana 进行数据可视化展示,以便于运维人员及时了解集群的运行状态和性能瓶颈。
  • Kubernetes 中的日志收集方案有哪些:常见的日志收集方案包括使用 Fluentd、Elasticsearch、Kibana 组成的 EFK 日志收集系统,或者使用 Loki 等工具。这些工具可以将 Pod 中的日志收集到统一的存储后端,并提供查询和分析功能,方便运维人员排查问题。

kube - proxy 是 Kubernetes 集群中负责实现服务发现和负载均衡的重要组件,它主要有以下几种网络模式:

  1. Userspace 模式
    • 工作原理:在 Userspace 模式下,kube - proxy 会在用户空间监听服务的请求。当有请求到达时,它会从内核空间获取网络数据包,然后根据负载均衡策略选择一个后端的 Pod。之后,它会在用户空间建立与所选 Pod 的连接,并将请求转发到该 Pod。最后,将 Pod 返回的响应再转发回客户端。
    • 性能特点:这种模式的性能相对较低,因为数据包需要在用户空间和内核空间之间进行多次切换。每一个请求都涉及到用户态和内核态的上下文切换,这会产生一定的开销,尤其是在高流量、高并发的场景下,这种开销会更加明显。
    • 适用场景:由于其性能的限制,Userspace 模式通常适用于开发和测试环境。在这些环境中,流量负载相对较小,对性能的要求不是特别高,更注重功能的验证和开发的便利性。
  2. Iptables 模式
    • 工作原理:Iptables 模式利用 Linux 操作系统的 iptables 规则来实现服务的负载均衡。kube - proxy 会在节点启动时为每个服务设置一系列的 iptables 规则。当有请求到达节点时,iptables 规则会根据目标服务的 IP 和端口,将请求直接转发到后端的 Pod。具体来说,它通过对网络数据包进行目标地址转换(DNAT)来实现请求的转发。
    • 性能特点:相比 Userspace 模式,Iptables 模式的性能有了一定的提升。因为数据包的转发主要是通过内核中的 iptables 规则来完成,减少了用户空间和内核空间之间的切换次数。然而,随着服务数量和 Pod 数量的增加,iptables 规则会变得越来越复杂,可能会导致性能下降,特别是在规则更新时会有一定的延迟。
    • 适用场景:在中小型规模的 Kubernetes 集群中应用较为广泛。对于一些对性能有一定要求,但集群规模不是特别大的场景,如企业内部的一些中小规模的微服务架构,Iptables 模式可以提供较好的负载均衡效果。
  3. IPVS 模式(推荐)
    • 工作原理:IPVS 模式基于 Linux 内核的 IPVS(IP Virtual Server)技术。kube - proxy 会使用 IPVS 来配置虚拟服务器和真实服务器(即后端 Pod)之间的映射关系。IPVS 在内核态直接处理请求的负载均衡,它通过维护一个虚拟服务器的 IP 地址和端口到后端 Pod 的映射表,根据配置的负载均衡算法(如轮询、最少连接等)将请求快速地转发到合适的 Pod。
    • 性能特点:这种模式具有较高的性能,因为它是在内核态完成负载均衡操作,避免了用户空间和内核空间频繁的数据拷贝和上下文切换。同时,IPVS 支持多种高效的负载均衡算法,可以根据不同的业务场景灵活选择,并且能够更好地处理大规模的流量和高并发请求。
    • 适用场景:适用于大规模、高流量的生产环境。例如,在大型互联网公司的云原生架构中,面对海量的用户请求和众多的微服务,IPVS 模式的 kube - proxy 可以有效地实现服务的负载均衡和流量分发,提高集群的整体性能和可靠性。

 

k8s的网络为什么要用ipvs

  1. 高性能
    • 连接处理能力:IPVS(IP Virtual Server)在内核态实现了负载均衡功能。与传统的基于用户态的代理(如 iptables)相比,IPVS 在处理大量网络连接时具有更高的性能。因为它直接在操作系统内核中工作,避免了用户态和内核态之间频繁的数据拷贝和上下文切换。例如,当有大量的 Pod 之间进行通信或者有高并发的外部请求进入集群时,IPVS 能够快速地对数据包进行转发,减少延迟。
    • 减少资源消耗:在处理大规模流量时,IPVS 消耗的 CPU 资源相对较少。这是因为它的算法优化和内核级别的实现使得其能够高效地处理数据包。以一个有数千个 Pod 的大型 Kubernetes 集群为例,如果使用 iptables 进行网络转发,随着 Pod 数量的增加和网络流量的增长,iptables 可能会因为大量的规则匹配而导致性能下降,而 IPVS 可以更高效地应对这种情况。
  2. 灵活的负载均衡算法
    • 多种算法支持:IPVS 支持多种负载均衡算法,如轮询(Round - Robin)、加权轮询(Weighted Round - Robin)、最少连接(Least - Connections)、加权最少连接(Weighted Least - Connections)等。这使得它能够根据不同的应用场景和服务需求来灵活地分配流量。例如,对于计算资源密集型的服务,可以使用最少连接算法,将请求发送到当前连接数最少的后端 Pod,以平衡各个 Pod 的负载;对于性能基本相同的一组 Pod,可以使用简单的轮询算法来平均分配流量。
    • 动态调整:这些算法可以根据后端服务的实时状态进行动态调整。例如,当某个后端 Pod 的性能下降或者出现故障时,IPVS 可以根据负载均衡算法自动将流量转移到其他健康的 Pod 上,提高了服务的可用性和可靠性。
  3. 支持多种协议
    • TCP 和 UDP 支持:IPVS 能够很好地支持 TCP 和 UDP 协议。在 Kubernetes 集群中,许多服务可能会同时使用这两种协议。例如,Web 服务通常使用 TCP 协议传输 HTTP/HTTPS 流量,而一些实时通信应用或者域名系统(DNS)服务可能会使用 UDP 协议。IPVS 可以为这些不同协议的服务提供高效的负载均衡,确保数据包的正确转发和负载分配。
  4. 与 Kubernetes 集成良好
    • 服务发现集成:IPVS 与 Kubernetes 的服务发现机制紧密集成。当 Kubernetes 中的服务(Service)创建或更新时,IPVS 能够自动更新其转发规则,以确保流量能够正确地导向到新的后端 Pod 或者服务端点。这使得在 Kubernetes 集群中管理和部署服务更加方便和高效。例如,当一个新的 Pod 被创建并加入到一个服务中时,IPVS 可以自动将该 Pod 纳入负载均衡的范围,无需手动配置。
    • 易于配置和管理:通过 Kubernetes 的相关工具和配置文件,管理员可以方便地配置 IPVS 的参数,如负载均衡算法、服务的 IP 地址和端口等。这降低了网络管理的复杂性,使得在 Kubernetes 环境中实现复杂的网络负载均衡策略变得更加容易。

 

在 Kubernetes 中,服务发现有几种方式:

①:基于环境变量的方式
②:基于内部域名的方式
基本上,使用环境变量的方式很少,主要还是使用内部域名这种服务发现的方式。
其中,基于内部域名的方式,涉及到 Kubernetes 内部域名的解析,而 kubedns,是 Kubernetes 官方的 DNS 解析组件。从 1.11 版本开始,kubeadm 已经使用第三方的 CoreDNS 替换官方的 kubedns 作为 Kubernetes 集群的内部域名解析组件,我们的重点,是 CoreDNS,但是在开始 CoreDNS 之前,需要先了解下 kubedns,后续,会对这2个 DNS 组件做对比,分析它们的优劣势。

Kubernetes 中的域名是如何解析的

在 Kubernetes 中,比如服务 a 访问服务 b,对于同一个 Namespace下,可以直接在 pod 中,通过 curl b 来访问。对于跨 Namespace 的情况,服务名后边对应 Namespace即可。比如 curl b.default。那么,使用者这里边会有几个问题:
①:服务名是什么?②:为什么同一个 Namespace 下,直接访问服务名即可?不同 Namespace 下,需要带上 Namespace 才行?③:为什么内部的域名可以做解析,原理是什么?
DNS 如何解析,依赖容器内 resolv 文件的配置
cat /etc/resolv.conf 
nameserver 10.233.0.3 
search default.svc.cluster.local svc.cluster.local cluster.local
这个文件中,配置的 DNS Server,一般就是 K8S 中,kubedns 的 Service 的 ClusterIP,这个IP是虚拟IP,无法ping,但可以访问。
[root@node4 user1]# kubectl get svc -n kube-system
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
kube-dns               ClusterIP   10.233.0.3      <none>        53/UDP,53/TCP   270d
kubernetes-dashboard   ClusterIP   10.233.22.223   <none>        443/TCP         124d
所以,所有域名的解析,其实都要经过 kubedns 的虚拟IP 10.233.0.3 进行解析,不论是 Kubernetes 内部域名还是外部的域名。
Kubernetes 中,域名的全称,必须是 service-name.namespace.svc.cluster.local 这种模式,服务名,就是Kubernetes中 Service 的名称,所以,当我们执行下面的命令时:
curl b
必须得有一个 Service 名称为 b,这是前提。
在容器内,会根据 /etc/resolve.conf 进行解析流程。选择 nameserver 10.233.0.3 进行解析,然后,用字符串 “b”,依次带入 /etc/resolve.conf 中的 search 域,进行DNS查找,分别是:
// search 内容类似如下(不同的pod,第一个域会有所不同)
search default.svc.cluster.local svc.cluster.local cluster.local
b.default.svc.cluster.local -> b.svc.cluster.local -> b.cluster.local ,直到找到为止。
所以,我们执行 curl b,或者执行 curl b.default,都可以完成DNS请求,这2个不同的操作,会分别进行不同的DNS查找步骤:
// curl b,可以一次性找到(b +default.svc.cluster.local)
b.default.svc.cluster.local
// curl b.default,第一次找不到( b.default + default.svc.cluster.local)
b.default.default.svc.cluster.local
// 第二次查找( b.default + svc.cluster.local),可以找到
b.default.svc.cluster.local

So Questions

curl b,要比 curl b.default 效率高?

答案是肯定的,因为 curl b.default,多经过了一次 DNS 查询。
当执行 curl b.default,也就使用了带有命名空间的内部域名时,容器的第一个 DNS 请求是
// b.default + default.svc.cluster.local
b.default.default.svc.cluster.local
当请求不到 DNS 结果时,使用
// b.default + svc.cluster.local
b.default.svc.cluster.local
进行请求,此时才可以得到正确的DNS解析。

访问外部域名走 search 域吗

这个答案,不能说肯定也不能说否定,看情况,可以说,大部分情况要走 search 域。
我们以请求 youku.com 为例,通过抓包的方式,看一看在某个容器中访问 youku.com,进行的DNS查找的过程,都产生了什么样的数据包。注意:我们要抓DNS容器的包,就得先进入到DNS容器的网络中(而不是发起DNS请求的那个容器)。
由于DNS容器往往不具备bash,所以无法通过 docker exec 的方式进入容器内抓包,我们采用其他的方式:
// 1、找到容器ID,并打印它的NS ID
docker inspect --format "{{.State.Pid}}"  16938de418ac
// 2、进入此容器的网络Namespace
nsenter -n -t  54438
// 3、抓DNS包
tcpdump -i eth0 udp dst port 53|grep youku.com
在其他的容器中,进行 youku.com 域名查找
nslookup  youku.com 172.22.121.65
注意:nslookup命令的最后指定DNS服务容器的IP,是因为,如果不指定,且DNS服务的容器存在多个的话,那么DNS请求,可能会均分到所有DNS服务的容器上,我们如果只抓某单个DNS服务容器抓到的包,可能就不全了,指定IP后,DNS的请求,就必然只会打到单个的DNS容器。抓包的数据才完整。
可以看到类似如下结果:
17:01:28.732260 IP 172.20.92.100.36326 > nodexxxx.domain: 4394+ A? youku.com.default.svc.cluster.local. (50)
17:01:28.733158 IP 172.20.92.100.49846 > nodexxxx.domain: 60286+ A? youku.com.svc.cluster.local. (45)
17:01:28.733888 IP 172.20.92.100.51933 > nodexxxx.domain: 63077+ A? youku.com.cluster.local. (41)
17:01:28.734588 IP 172.20.92.100.33401 > nodexxxx.domain: 27896+ A? youku.com.local. (27)
17:01:28.734758 IP nodexxxx.34138 > 192.168.x.x.domain: 27896+ A? youku.com. (27)
我们可以看到,在真正解析 youku.com 之前,经历了 youku.com.default.svc.cluster.local. -> youku.com.svc.cluster.local. -> youku.com.cluster.local. -> youku.com.local. ->youku.com.
这也就意味着有3次DNS请求,是浪费的无意义的请求。

为何会出现DNS请求浪费的情况

这是因为,在 Kubernetes 中,其实 /etc/resolv.conf 这个文件,并不止包含 nameserver 和 search 域,还包含了非常重要的一项:ndots。我们之前没有提及这个项,也是希望再次能引起读者重视。
[root@xxxx-67f54c6dff-h4zxq /]# cat /etc/resolv.conf 
nameserver 10.233.0.3
search cicd.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
ndots:5,表示:如果查询的域名包含的点“.”,不到5个,那么进行DNS查找,将使用非完全限定名称(或者叫绝对域名),如果你查询的域名包含点数大于等于5,那么DNS查询,默认会使用绝对域名进行查询。举例来说:
如果我们请求的域名是,a.b.c.d.e,这个域名中有4个点,那么容器中进行DNS请求时,会使用非绝对域名进行查找,使用非绝对域名,会按照 /etc/resolv.conf 中的 search 域,走一遍追加匹配:
a.b.c.d.e.cicd.svc.cluster.local. ->a.b.c.d.e.svc.cluster.local. ->a.b.c.d.e.cluster.local.
直到找到为止。如果走完了search域还找不到,则使用 a.b.c.d.e. ,作为绝对域名进行DNS查找。
我们通过抓包分析一个具体案例:
域名中点数少于5个的情况:
// 对域名 a.b.c.d.ccccc 进行DNS解析请求 
[root@xxxxx-67f54c6dff-h4zxq /]# nslookup  a.b.c.d.ccccc 172.22.121.65 
Server:         172.22.121.65
Address:        172.22.121.65#53

** server can't find a.b.c.d.ccccc: NXDOMAIN

// 抓包数据如下:
18:08:11.013497 IP 172.20.92.100.33387 > node011094.domain: 28844+ A? a.b.c.d.ccccc.cicd.svc.cluster.local. (54)
18:08:11.014337 IP 172.20.92.100.33952 > node011094.domain: 57782+ A? a.b.c.d.ccccc.svc.cluster.local. (49)
18:08:11.015079 IP 172.20.92.100.45984 > node011094.domain: 55144+ A? a.b.c.d.ccccc.cluster.local. (45)
18:08:11.015747 IP 172.20.92.100.54589 > node011094.domain: 22860+ A? a.b.c.d.ccccc. (31)
18:08:11.015970 IP node011094.36383 > 192.168.x.x.domain: 22860+ A? a.b.c.d.ccccc. (31)

// 结论:
// 点数少于5个,先走search域,最后将其视为绝对域名进行查询
域名中点数>=5个的情况:
// 对域名 a.b.c.d.e.ccccc 进行DNS解析请求
[root@xxxxx-67f54c6dff-h4zxq /]# nslookup  a.b.c.d.e.ccccc 172.22.121.65 
Server:         172.22.121.65
Address:        172.22.121.65#53

** server can't find a.b.c.d.e.ccccc: NXDOMAIN

// 抓包数据如下:
18:10:14.514595 IP 172.20.92.100.34423 > node011094.domain: 61170+ A? a.b.c.d.e.ccccc. (33)
18:10:14.514856 IP node011094.58522 > 192.168.x.x.domain: 61170+ A? a.b.c.d.e.ccccc. (33)
18:10:14.515880 IP 172.20.92.100.49328 > node011094.domain: 267+ A? a.b.c.d.e.ccccc.cicd.svc.cluster.local. (56)
18:10:14.516678 IP 172.20.92.100.35651 > node011094.domain: 54181+ A? a.b.c.d.e.ccccc.svc.cluster.local. (51)
18:10:14.517356 IP 172.20.92.100.33259 > node011094.domain: 53022+ A? a.b.c.d.e.ccccc.cluster.local. (47)

// 结论:
// 点数>=5个,直接视为绝对域名进行查找,只有当查询不到的时候,才继续走 search 域。

如何优化 DNS 请求浪费的情况

优化方式1:使用全限定域名

其实最直接,最有效的优化方式,就是使用 “fully qualified name”,简单来说,使用“完全限定域名”(也叫绝对域名),你访问的域名,必须要以 “.” 为后缀,这样就会避免走 search 域进行匹配,我们抓包再试一次:
// 注意:youku.com 后边有一个点 .
nslookup  youku.com. 172.22.121.65
在DNS服务容器上抓到的包如下:
16:57:07.628112 IP 172.20.92.100.36772 > nodexxxx.domain: 46851+ [1au] A? youku.com. (38)
16:57:07.628339 IP nodexxxx.47350 > 192.168.x.x.domain: 46851+ [1au] A? youku.com. (38)
并没有多余的DNS请求。

优化方式2:具体应用配置特定的 ndots

其实,往往我们还真不太好用这种绝对域名的方式,有谁请求youku.com的时候,还写成 youku.com. 呢?
在 Kubernetes 中,默认设置了 ndots 值为5,是因为,Kubernetes 认为,内部域名,最长为5,要保证内部域名的请求,优先走集群内部的DNS,而不是将内部域名的DNS解析请求,有打到外网的机会,Kubernetes 设置 ndots 为5是一个比较合理的行为。
如果你需要定制这个长度,最好是为自己的业务,单独配置 ndots 即可(Pod为例,其实配置deployment最好)。
apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsConfig:
    options:
      - name: ndots
        value: "1"

Kubernetes DNS 策略

在Kubernetes 中,有4种 DNS 策略,从 Kubernetes 源码中看:
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 为例:
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。