ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

《kubernetes权威指南第五版》读书笔记

2021-09-05 13:37:03  阅读:546  来源: 互联网

标签:Endpoint Service Kubernetes 读书笔记 调度 设置 kubernetes Pod 第五版


修改kubeadm的默认配置

  kubeadm的初始化控制平面(init)命令和加入节点(join)命令均可以通过指定的配置文件修改默认参数的值。kubeadm将配置文件以ConfigMap形式保存到集群中,便于后续的查询和升级工作。kubeadm config子命令提供了对这组功能的支持。

  • kubeadm config print init-defaults:输出kubeadm init命令默认参数的内容。
  • kubeadm config print join-defaults:输出kubeadm join命令默认参数的内容。
  • kubeadm config migrate:在新旧版本之间进行配置转换。
  • kubeadm config images list:列出所需的镜像列表。
  • kubeadm config images pull:拉取镜像到本地。
kubeadm config print init-defaults >init-default.yaml

  对生成的文件进行编辑,可以按需生成合适的配置。例如,若需要自定义镜像的仓库地址、需要安装的Kubernetes版本号及Pod的IP地址范围

kubeadm config images list:列出所需的镜像列表

  如果无法访问k8s.gcr.io,则可以使用国内镜像托管站点进行下载,例如https://1nj0zren.mirror.aliyuncs.com,这可以通过修改Docker服务的配置文件(默认为/etc/docker/daemon.json)进行设置,例如:
  然后,使用kubeadm config images pull命令或者docker pull命令下载上述镜像,

kubeadm config images pull --config=init-config.yaml

  在镜像下载完成之后,就可以进行安装了。

  在开始之前需要注意:kubeadm的安装过程不涉及网络插件(CNI)的初始化,因此kubeadm初步安装完成的集群不具备网络功能,任何Pod(包括自带的CoreDNS)都无法正常工作。而网络插件的安装往往对kubeadm init命令的参数有一定要求

创建和使用命令行插件


  为了扩展kubectl的功能,Kubernetes从1.8版本开始引入插件机制,在1.14版本时达到稳定版。
  用户自定义插件的可执行文件名需要以“kubectl-”开头,复制到$PATH中的某个目录(如/usr/local/bin)下,然后就可以通过kubectl <plugin-name>运行自定义插件了。
  例如,通过Shell脚本实现一个名为hello的插件,其功能为在屏幕上输出字符串“hello world”。创建名为“kubectl-hello”的Shell脚本文件
  通过插件机制,可以将某些复杂的kubectl命令简化为运行插件的方式。例如想创建一个命令来查看当前上下文环境(context)中的用户名,则可以通过kubectl config view命令进行查看

使用kubectl plugin list命令可以查看当前系统中已安装的插件列表

Pod深入了解

pod生命周期和重启策略

Pod在整个生命周期中被系统定义为各种状态

  

 

 

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器

 Pod的重启策略包括Always、OnFailure和Never,默认值为Always。

  • Always:当容器失效时,由kubelet自动重启该容器。
  • OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
  • Never:不论容器运行状态如何,kubelet都不会重启该容器。

  kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算,例如1、2、4、8倍等,最长延时5min,并且在成功重启后的10min后重置该时间

  Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet,还可以通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下

  • RC和DaemonSet:必须设置为Always,需要保证该容器持续运行
  • Job:OnFailure或Never,确保容器执行完成后不再重启
  • kubelet:在Pod失效时自动重启它,不论将RestartPolicy设置为什么值,也不会对Pod进行健康检查

Pod常见的状态转换场景

  

  RC的继任者其实并不是Deployment,而是ReplicaSet,因为ReplicaSet进一步增强了RC标签选择器的灵活性。之前RC的标签选择器只能选择一个标签,而ReplicaSet拥有集合式的标签选择器,可以选择多个Pod标签
  其实,Kubernetes的滚动升级就是巧妙运用ReplicaSet的这个特性来实现的,同时,Deployment也是通过ReplicaSet来实现Pod副本自动控制功能的。我们不应该直接使用底层的ReplicaSet来控制Pod副本,而应该通过管理ReplicaSet的Deployment对象来控制副本

Pod健康检查和服务可用性检查

探针的种类

  Kubernetes对Pod的健康状态可以通过三类探针来检查:LivenessProbe、ReadinessProbe及StartupProbe,其中最主要的探针为LivenessProbe与ReadinessProbe,kubelet会定期执行这两类探针来诊断容器的健康状况。

(1)LivenessProbe探针:用于判断容器是否存活(Running状态),如果LivenessProbe探针探测到容器不健康,则kubelet将“杀掉”该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,那么kubelet认为该容器的LivenessProbe探针返回的值永远是Success。
(2)ReadinessProbe探针:用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod,Service与Pod Endpoint的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。这样就能保证客户端在访问Service时不会被转发到服务不可用的Pod实例上。需要注意的是,ReadinessProbe也是定期触发执行的,存在于Pod的整个生命周期中。
(3)StartupProbe探针:某些应用会遇到启动比较慢的情况,例如应用程序启动时需要与远程服务器建立网络连接,或者遇到网络访问较慢等情况时,会造成容器启动缓慢,此时ReadinessProbe就不适用了,因为这属于“有且仅有一次”的超长延时,可以通过StartupProbe探针解决该问题

探针均可配置以下三种实现方式

(1)ExecAction:在容器内部运行一个命令,如果该命令的返回码为0,则表明容器健康

  通过运行cat/tmp/health命令来判断一个容器运行是否正常。在该Pod运行后,将在创建/tmp/health文件10s后删除该文件,而LivenessProbe健康检查的初始探测时间(initialDelaySeconds)为15s,探测结果是Fail,将导致kubelet“杀掉”该容器并重启它

(2)TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。

(3)HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康

对于每种探测方式,都需要设置initialDelaySeconds和timeoutSeconds两个参数,它们的含义分别如下。

  • initialDelaySeconds:启动容器后进行首次健康检查的等待时间,单位为s。
  • timeoutSeconds:健康检查发送请求后等待响应的超时时间,单位为s。当超时发生时,kubelet会认为容器已经无法提供服务,将会重启该容器。

  如下代码片段是StartupProbe探针的一个参考配置,可以看到,这个Pod可以有长达30×10=300s的超长启动时间:

  

pod调度策略

Deployment或RC:全自动调度

  Deployment或RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量
  Pod由系统全自动完成调度。它们各自最终运行在哪个节点上,完全由Master的Scheduler经过一系列算法计算得出,用户无法干预调度过程和结果
  除了使用系统自动调度算法完成一组Pod的部署,Kubernetes也提供了多种丰富的调度策略,用户只需在Pod的定义中使用NodeSelector、NodeAffinity、PodAffinity、Pod驱逐等更加细粒度的调度策略设置,就能完成对Pod的精准调度

NodeSelector:定向调度

  除了用户可以自行给Node添加标签,Kubernetes也会给Node预定义一些标签,包括:

  • kubernetes.io/hostname;
  • beta.kubernetes.io/os(从1.14版本开始更新为稳定版,到1.18版本删除);
  • beta.kubernetes.io/arch(从1.14版本开始更新为稳定版,到1.18版本删除);
  • kubernetes.io/os(从1.14版本开始启用);
  • kubernetes.io/arch(从1.14版本开始启用)。

  NodeSelector通过标签的方式,简单实现了限制Pod所在节点的方法。亲和性调度机制则极大扩展了Pod的调度能力,主要的增强功能如下。

  • 更具表达力(不仅仅是“符合全部”的简单情况)。
  • 可以使用软限制、优先采用等限制方式,代替之前的硬限制,这样调度器在无法满足优先需求的情况下,会退而求其次,继续运行该Pod。
  • 可以依据节点上正在运行的其他Pod的标签来进行限制,而非节点本身的标签。这样就可以定义一种规则来描述Pod之间的亲和或互斥关系。

  亲和性调度功能包括节点亲和性(NodeAffinity)和Pod亲和性(PodAffinity)两个维度的设置。节点亲和性与NodeSelector类似,增强了上述前两点优势;Pod的亲和与互斥限制则通过Pod标签而不是节点标签来实现,也就是上面第4点内容所陈述的方式,同时具有前两点提到的优点

NodeAffinity:Node亲和性调度

  NodeAffinity意为Node亲和性的调度策略,是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。

  • RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上(功能与nodeSelector很像,但是使用的是不同的语法),相当于硬限制。
  • PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。

  IgnoredDuringExecution的意思是:如果一个Pod所在的节点在Pod运行期间标签发生了变更,不再符合该Pod的节点亲和性需求,则系统将忽略Node上Label的变化,该Pod能继续在该节点上运行。
  下面的例子设置了NodeAffinity调度的如下规则。

  • required DuringS chedulingIgnoredDuringExecution:要求只运行在amd64的节点上(beta.kubernetes.io/arch In amd64)。
  • preferredDuringSchedulingIgnoredDuringExecution:要求尽量运行在磁盘类型为ssd(disk-type In ssd)的节点上。

  NodeAffinity规则设置的注意事项如下。

  • 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行在指定的Node上。
  • 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能匹配成功即可。
  • 如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该Pod。

PodAffinity:Pod亲和与互斥调度策略

  与节点亲和性类似,Pod亲和性的操作符也包括In、NotIn、Exists、DoesNotExist、Gt、Lt。
  原则上,topologyKey可以使用任意合法的标签Key赋值,但是出于性能和安全方面的考虑,对topologyKey有如下限制。

  • 在Pod亲和性和RequiredDuringScheduling的Pod互斥性的定义中,不允许使用空的topologyKey。
  • 如果Admission controller包含了LimitPodHardAntiAffinityTopology,那么针对Required DuringScheduling的Pod互斥性定义就被限制为kubernetes.io/hostname,要使用自定义的topologyKey,就要改写或禁用该控制器。
  • 在PreferredDuringScheduling类型的Pod互斥性定义中,空的topologyKey会被解释为kubernetes.io/hostname、failure-domain.beta.kubernetes.io/zone及failure-domain.beta.kubernetes.io/region的组合。

  如果不是上述情况,就可以采用任意合法的topologyKey了。

  PodAffinity规则设置的注意事项如下

  • 除了设置Label Selector和topologyKey,用户还可以指定Namespace列表进行限制,同样,使用Label Selector对Namespace进行选择。Namespace的定义和Label Selector及topologyKey同级。省略Namespace的设置,表示使用定义了affinity/anti-affinity的Pod所在的命名空间。如果Namespace被设置为空值(""),则表示所有命名空间。
  • 在所有关联requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全都满足之后,系统才能将Pod调度到某个Node上

Pod Priority Preemption:Pod优先级调度

  在Kubernetes 1.8版本之前,当集群的可用资源不足时,在用户提交新的Pod创建请求后,该Pod会一直处于Pending状态,即使这个Pod是一个很重要(很有身份)的Pod,也只能被动等待其他Pod被删除并释放资源,才能有机会被调度成功。

  Kubernetes 1.8版本引入了基于Pod优先级抢占(Pod Priority Preemption)的调度策略,此时Kubernetes会尝试释放目标节点上低优先级的Pod,以腾出空间(资源)安置高优先级的Pod,这种调度方式被称为“抢占式调度”。在Kubernetes 1.11版本中,该特性升级为Beta版本,默认开启,在后续的Kubernetes 1.14版本中正式Release。如何声明一个负载相对其他负载更重要?我们可以通过以下几个维度来定义:Priority:优先级;QoS:服务质量等级;系统定义的其他度量指标。

  优先级抢占调度策略的核心行为分别是驱逐(Eviction)与抢占(Preemption),这两种行为的使用场景不同,效果相同。Eviction是kubelet进程的行为,即当一个Node资源不足(under resource pressure)时,该节点上的kubelet进程会执行驱逐动作,此时kubelet会综合考虑Pod的优先级、资源申请量与实际使用量等信息来计算哪些Pod需要被驱逐;当同样优先级的Pod需要被驱逐时,实际使用的资源量超过申请量最大倍数的高耗能Pod会被首先驱逐。对于QoS等级为“Best Effort”的Pod来说,由于没有定义资源申请(CPU/Memory Request),所以它们实际使用的资源可能非常大。Preemption则是Scheduler执行的行为,当一个新的Pod因为资源无法满足而不能被调度时,Scheduler可能(有权决定)选择驱逐部分低优先级的Pod实例来满足此Pod的调度目标,这就是Preemption机制

  优先级为100000,数字越大,优先级越高,超过一亿的数字被系统保留,用于指派给系统组件

DaemonSet:在每个Node上都调度一个Pod

  这种用法适合有这种需求的应用。

  • 在每个Node上都运行一个GlusterFS存储或者Ceph存储的Daemon进程。
  • 在每个Node上都运行一个日志采集程序,例如Fluentd或者Logstach。
  • 在每个Node上都运行一个性能监控程序,采集该Node的运行性能数据,例如Prometheus Node Exporter、collectd、New Relic agent或者Ganglia gmond等。

  DaemonSet调度不同于普通的Pod调度,所以没有用默认的Kubernetes Scheduler进行调度,而是通过专有的**DaemonSet Controller**进行调度。但是随着Kubernetes版本的改进和调度特性不断丰富,产生了一些难以解决的矛盾,最主要的两个矛盾如下。

  • 普通的Pod是在Pending状态触发调度并被实例化的,DaemonSet Controller并不是在这个状态调度Pod的,这种不一致容易误导和迷惑用户。
  • Pod优先级调度是被Kubernetes Scheduler执行的,而DaemonSet Controller并没有考虑到Pod优先级调度的问题,也产生了不一致的结果。
  • 从Kubernetes 1.18开始,DaemonSet的调度默认切换到Kubernetes Scheduler进行,**从而一劳永逸地解决了以上问题及未来可能的新问题。因为默认切换到了Kubernetes Scheduler统一调度Pod,因此DaemonSet也能正确处理Taints和Tolerations的问题。

Taints和Tolerations(污点和容忍)

  Pod的Toleration声明中的key和effect需要与Taint的设置保持一致,并且满足以下条件之一。

  • operator的值是Exists(无须指定value)。
  • operator的值是Equal并且value相等。
  • 如果不指定operator,则默认值为Equal。

  另外,有如下两个特例

  • 空的key配合Exists操作符能够匹配所有键和值。
  • 空的effect匹配所有effect

  几种特殊情况

  • 如果在剩余的Taint中存在effect=NoSchedule,则调度器不会把该Pod调度到这一节点上。
  • 如果在剩余的Taint中没有NoSchedule效果,但是有PreferNoSchedule效果,则调度器会尝试不把这个Pod指派给这个节点。

Job:批处理调度

  

  考虑到批处理的并行问题,Kubernetes将Job分以下三种类型

(1)Non-parallel Jobs:通常一个Job只启动一个Pod,除非Pod异常,才会重启该Pod,一旦此Pod正常结束,Job将结束。
(2)Parallel Jobs with a fixed completion count:并行Job会启动多个Pod,此时需要设定Job的.spec.completions参数为一个正数,当正常结束的Pod数量达至此参数设定的值后,Job结束。此外,Job的.spec.parallelism参数用来控制并行度,即同时启动几个Job来处理Work item。
(3)Parallel Jobs with a work queue:任务队列方式的并行Job需要一个独立的Queue,Work item都在一个Queue中存放,不能设置Job的.spec.completions参数,此时Job有以下特性。

  • 每个Pod都能独立判断和决定是否还有任务项需要处理。
  • 如果某个Pod正常结束,则Job不会再启动新的Pod。
  • 如果一个Pod成功结束,则此时应该不存在其他Pod还在工作的情况,它们应该都处于即将结束、退出的状态。
  • 如果所有Pod都结束了,且至少有一个Pod成功结束,则整个Job成功结束

Cronjob:定时任务

  首先,确保Kubernetes的版本为1.8及以上
  其次,需要掌握Cron Job的定时表达式,它基本上照搬了Linux Cron的表达式

pod的容灾调度

  为了满足这种容灾场景下的特殊调度需求,在Kubernetes 1.16版本中首次引入Even Pod Spreading特性,用于通过topologyKey属性识别Zone,并通过设置新的参数topologySpreadConstraints来将Pod均匀调度到不同的Zone
  关键的参数是maxSkew。maxSkew用于指定Pod在各个Zone上调度时能容忍的最大不均衡数:值越大,表示能接受的不均衡调度越大;值越小,表示各个Zone的Pod数量分布越均匀。
  为了理解maxSkew,我们需要先理解skew参数的计算公式:skew[topo]=count[topo]-min(count[topo]),即每个拓扑区域的skew值都为该区域包括的目标Pod数量与整个拓扑区域最少Pod数量的差,而maxSkew就是最大的skew值

假如在上面的例子中有3个拓扑区域,分别为Zone A、Zone B及Zone C,有3个目标Pod需要调度到这些拓扑区域,那么前两个毫无疑问会被调度到Zone A和Zone B
可以手动计算每个Zone的skew,首先计算出min(count[topo])是0,对应Zone C,于是Zone A的skew=1-0=1,Zone B的skew=1-0=0,Zone C的skew=0-0=0,于是第3个Pod应该被放在Zone C,此时min(count[topo])的值就变成了1,而实际的maxSkew的值为0,符合预期设置。如果我们把maxSkew设置为2,则在这种情况下,第3个Pod被放在Zone A或Zone B都是符合要求的

StatefulSet

  在创建StatefulSet之前,需要确保在Kubernetes集群中管理员已经创建好共享存储,并能够与StorageClass对接,以实现动态存储供应的模式
  为了完成MongoDB集群的搭建,需要部署以下三个资源对象。

  • 一个StorageClass:用于StatefulSet自动为各个应用Pod申请PVC。
  • 一个Headless Service(clusterIP: None):用于设置MongoDB实例的域名。
  • 一个StatefulSet

  mongo-sidecar作为MongoDB集群的管理者,将使用此Headless Service来维护各个MongoDB实例之间的集群关系,以及集群规模变化时的自动更新

StatefulSet的常见应用场景

  • 集群进行扩容,仅需要通过对StatefulSet进行scale操作(或修改yaml文件)
  • 自动故障修复
    • 实例或其所在主机发生故障,则StatefulSet将会自动重建该实例,并保证其身份(ID)和使用的数据(PVC)不变

Service

Service概念和原理

  Service是Kubernetes实现微服务架构的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上

  Service用于为一组提供服务的Pod抽象一个稳定的网络访问地址,是Kubernetes实现微服务的核心概念。通过Service的定义设置的访问地址是DNS域名格式的服务名称,对于客户端应用来说,网络访问方式并没有改变(DNS域名的作用等价于主机名、互联网域名或IP地址)。Service还提供了负载均衡器功能,将客户端请求负载分发到后端提供具体服务的各个Pod上

  Service主要用于提供网络服务,通过Service的定义,能够为客户端应用提供稳定的访问地址(域名或IP地址)和负载均衡功能,以及屏蔽后端Endpoint的变化,是Kubernetes实现微服务的核心资源

  Service不仅具有标准网络协议的IP地址,还以DNS域名的形式存在。Service的域名表示方法为<servicename>.<namespace>.svc.<clusterdomain>,servicename为服务的名称,namespace为其所在namespace的名称,clusterdomain为Kubernetes集群设置的域名后缀。服务名称的命名规则遵循RFC 1123规范

Service负载均衡机制

  kube-proxy的代理模式、会话保持机制和基于拓扑感知的服务路由机制(EndpointSlices)

kube-proxy的代理模式

  kube-proxy提供了以下代理模式(通过启动参数--proxy-mode设置)

  • userspace模式:用户空间模式,由kube-proxy完成代理的实现,效率最低,不再推荐使用。
  • iptables模式:kube-proxy通过设置Linux Kernel的iptables规则,实现从Service到后端Endpoint列表的负载分发规则,效率很高。但是,如果某个后端Endpoint在转发时不可用,此次客户端请求就会得到失败的响应,相对于userspace模式来说更不可靠。此时应该通过为Pod设置readinessprobe(服务可用性健康检查)来保证只有达到ready状态的Endpoint才会被设置为Service的后端Endpoint。
  • ipvs模式:在Kubernetes 1.11版本中达到Stable阶段,kube-proxy通过设置Linux Kernel的netlink接口设置IPVS规则,转发效率和支持的吞吐率都是最高的。ipvs模式要求Linux Kernel启用IPVS模块,如果操作系统未启用IPVS内核模块,kube-proxy则会自动切换至iptables模式。同时,ipvs模式支持更多的负载均衡策略,如下所述。
    • rr:round-robin,轮询。
    • lc:least connection,最小连接数。
    • dh:destination hashing,目的地址哈希。
    • sh:source hashing,源地址哈希。
    • sed:shortest expected delay,最短期望延时。
    • nq:never queue,永不排队。
  • kernelspace模式:Windows Server上的代理模式
会话保持机制

  Service支持通过设置sessionAffinity实现基于客户端IP的会话保持机制,即首次将某个客户端来源IP发起的请求转发到后端的某个Pod上,之后从相同的客户端IP发起的请求都将被转发到相同的后端Pod上,配置参数为service.spec.sessionAffinity

  同时,用户可以设置会话保持的最长时间,在此时间之后重置客户端来源IP的保持规则,配置参数为service.spec.sessionAffinityConfig.clientIP.timeoutSeconds

基于拓扑感知的服务路由机制制(EndpointSlices)

将外部服务定义为Service

  普通的Service通过Label Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint不是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,供集群内的其他应用访问,常见的应用场景包括:

  • 已部署的一个集群外服务,例如数据库服务、缓存服务等;
  • 其他Kubernetes集群的某个服务;
  • 迁移过程中对某个服务进行Kubernetes内的服务名访问机制的验证。

  对于这种应用场景,用户在创建Service资源对象时不设置Label Selector(后端Pod也不存在),同时再定义一个与Service关联的Endpoint资源对象,在Endpoint中设置外部服务的IP地址和端口号

  

将Service暴露到集群外部

目前Service的类型如下。

  • ClusterIP:Kubernetes默认会自动设置Service的虚拟IP地址,仅可被集群内部的客户端应用访问。当然,用户也可手工指定一个ClusterIP地址,不过需要确保该IP在Kubernetes集群设置的ClusterIP地址范围内(通过kube-apiserver服务的启动参数--service-cluster-ip-range设置),并且没有被其他Service使用。
  • NodePort:将Service的端口号映射到每个Node的一个端口号上,这样集群中的任意Node都可以作为Service的访问入口地址,即NodeIP:NodePort。
  • LoadBalancer:将Service映射到一个已存在的负载均衡器的IP地址上,通常在公有云环境中使用。
  • ExternalName:将Service映射为一个外部域名地址,通过externalName字段进行设置

Service支持的网络协议

  • TCP:Service的默认网络协议,可用于所有类型的Service。
  • UDP:可用于大多数类型的Service,LoadBalancer类型取决于云服务商对UDP的支持。
  • HTTP:取决于云服务商是否支持HTTP和实现机制。
  • PROXY:取决于云服务商是否支持HTTP和实现机制。
  • SCTP:从Kubernetes 1.12版本引入,到1.19版本时达到Beta阶段,默认启用,如需关闭该特性,则需要设置kube-apiserver的启动参数--feature-gates=SCTPSupport=false进行关闭  

  Kubernetes从1.17版本开始,可以为Service和Endpoint资源对象设置一个新的字段“AppProtocol”,用于标识后端服务在某个端口号上提供的应用层协议类型,例如HTTP、HTTPS、SSL、DNS等,该特性在Kubernetes 1.19版本时达到Beta阶段,计划于Kubernetes 1.20 版本时达到GA阶段。要使用AppProtocol,需要设置kube-apiserver的启动参数--feature-gates=ServiceAppProtocol=true进行开启,然后在Service或Endpoint的定义中设置AppProtocol字段指定应用层协议的类型

Kubernetes的服务发现机制

环境变量方式

  在一个Pod运行起来的时候,系统会自动为其容器运行环境注入所有集群中有效Service的信息。Service的相关信息包括服务IP、服务端口号、各端口号相关的协议等,通过{SVCNAME}_SERVICE_HOST和{SVCNAME}_SERVICE_PORT格式进行设置。其中,SVCNAME的命名规则为:将Service的name字符串转换为全大写字母,将中横线“-”替换为下画线“_”

DNS方式

  Service在Kubernetes系统中遵循DNS命名规范,Service的DNS域名表示方法为<servicename>.<namespace>.svc.<clusterdomain>,其中servicename为服务的名称,namespace为其所在namespace的名称,clusterdomain为Kubernetes集群设置的域名后缀(例如cluster.local),服务名称的命名规则遵循RFC 1123规范的要求

  对于客户端应用来说,DNS域名格式的Service名称提供的是稳定、不变的访问地址,可以大大简化客户端应用的配置,是Kubernetes集群中推荐的使用方式。
  目前由CoreDNS作为Kubernetes集群的默认DNS服务器提供域名解析服务

  Service定义中的端口号如果设置了名称(name),则该端口号也会拥有一个DNS域名,在DNS服务器中以SRV记录的格式保存:_<portname>._<protocol>.<servicename>.<namespace>.svc.<clusterdomain>,其值为端口号的数值

Headless Service

  Headless Service的概念是这种服务没有入口访问地址(无ClusterIP地址),kube-proxy不会为其创建负载转发规则,而服务名(DNS域名)的解析机制取决于该Headless Service是否设置了Label Selector

Headless Service没有设置Label Selector

如果Headless Service没有设置Label Selector,则Kubernetes将不会自动创建对应的Endpoint列表。DNS系统会根据下列条件尝试对该服务名设置DNS记录:

  • 如果Service的类型为ExternalName,则对服务名的访问将直接被DNS系统转换为Service设置的外部名称(externalName);
  • 如果系统中存在与Service同名的Endpoint定义,则服务名将被解析为Endpoint定义中的列表,适用于非ExternalName类型的Service。

端点分片与服务拓扑

  Service的后端是一组Endpoint列表,为客户端应用提供了极大的便利。但是随着集群规模的扩大及Service数量的增加,特别是Service后端Endpoint数量的增加,kube-proxy需要维护的负载分发规则(例如iptables规则或ipvs规则)的数量也会急剧增加,导致后续对Service后端Endpoint的添加、删除等更新操作的成本急剧上升。

  举例来说,假设在Kubernetes集群中有10000个Endpoint运行在大约5000个Node上,则对单个Pod的更新将需要总计约5GB的数据传输,这不仅对集群内的网络带宽浪费巨大,而且对Master的冲击非常大,会影响Kubernetes集群的整体性能,在Deployment不断进行滚动升级操作的情况下尤为突出。

  Kubernetes从1.16版本开始引入端点分片(Endpoint Slices)机制,包括一个新的EndpointSlice资源对象和一个新的EndpointSlice控制器。从Kubernetes 1.17版本开始,EndpointSlice机制默认是启用的(在1.16版本中需要通过设置kube-apiserver和kube-proxy服务的启动参数--feature-gates="EndpointSlice=true"进行启用)

  另外,kube-proxy默认仍然使用Endpoint对象,为了提高性能,可以设置kube-proxy启动参数--feature-gates="EndpointSliceProxying=true"让kube-proxy使用EndpointSlice,这样可以减少kube-proxy与master之间的网络通信并提高性能。Kubernetes从1.19版本开始默认开启该特性

  EndpointSlice通过对Endpoint进行分片管理来实现降低Master和各Node之间的网络传输数据量及提高整体性能的目标。对于Deployment的滚动升级,可以实现仅更新部分Node上的Endpoint信息,Master与Node之间的数据传输量可以减少100倍左右,能够大大提高管理效率

  

 

  默认情况下,在由EndpointSlice控制器创建的EndpointSlice中最多包含100个Endpoint,如需修改,则可以通过kube-controller-manager服务的启动参数--max-endpoints-per-slice设置,但上限不能超过1000

  EndpointSlice的关键信息如下。
(1)关联的服务名称:将EndpointSlice与Service的关联信息设置为一个标签kubernetes.io/service-name=webapp,该标签标明了服务名称。
(2)地址类型AddressType:包括以下3种取值类型

  • IPv4:IPv4格式的IP地址
  • IPv6:IPv6格式的IP地址。
  • FQDN:全限定域名。

(3)在Endpoints列表中列出的每个Endpoint的信息。

  • Addresses:Endpoint的IP地址。
  • Conditions:Endpoint状态信息,作为EndpointSlice的查询条件。
  • Hostname:在Endpoint中设置的主机名hostname。
  • TargetRef:Endpoint对应的Pod名称。
  • Topology:拓扑信息,为基于拓扑感知的服务路由提供数据。

  目前EndpointSlice控制器自动设置的拓扑信息如下。

  • kubernetes.io/hostname:Endpoint所在Node的名称。
  • topology.kubernetes.io/zone:Endpoint所在的Zone信息,使用Node标签topology.kubernetes.io/zone的值,例如上例中的Node拥有“topology.kubernetes.io/zone:north”标签。
  • topology.kubernetes.io/region:Endpoint所在的Region信息,使用Node标签topology.kubernetes.io/region的值。

(4)EndpointSlice的管理控制器:通过endpointslice.kubernetes.io/managed-by标签进行设置,用于存在多个管理控制器的应用场景中

DNS服务搭建和配置指南

kubernetes中的dns发展史

  在Kubernetes 1.2版本时,DNS服务是由SkyDNS提供的,它由4个容器组成:kube2sky、skydns、etcd和healthz

  从Kubernetes 1.4版本开始,SkyDNS组件便被KubeDNS替换,主要考虑的是SkyDNS组件之间通信较多,整体性能不高。KubeDNS由3个容器组成:kubedns、dnsmasq和sidecar,去掉了SkyDNS中的etcd存储,将DNS记录直接保存在内存中,以提高查询性能

  从Kubernetes 1.11版本开始,Kubernetes集群的DNS服务便由CoreDNS提供。CoreDNS是CNCF基金会孵化的一个项目,是用Go语言实现的高性能、插件式、易扩展的DNS服务端,目前已毕业。

  CoreDNS解决了KubeDNS的一些问题,例如dnsmasq的安全漏洞、externalName不能使用stubDomains进行设置,等等。CoreDNS支持自定义DNS记录及配置upstream DNS Server,可以统一管理Kubernetes基于服务的内部DNS和数据中心的物理DNS。它没有使用多个容器的架构,只用一个容器便实现了KubeDNS内3个容器的全部功能

  coreDNS的架构

    

 

 

修改每个Node上kubelet的启动参数,在其中加上以下两个参数。

◎ --cluster-dns=169.169.0.100:为DNS服务的ClusterIP地址。
◎ --cluster-domain=cluster.local:为在DNS服务中设置的域名。
然后重启kubelet服务。

部署CoreDNS服务

  部署CoreDNS服务时需要创建3个资源对象:1个ConfigMap、1个Deployment和1个Service。在启用了RBAC的集群中,还可以设置ServiceAccount、ClusterRole、ClusterRoleBinding对CoreDNS容器进行权限设置

  Deployment“coredns”主要设置CoreDNS容器应用的内容,其中,replicas副本的数量通常应该根据集群的规模和服务数量确定,如果单个CoreDNS进程不足以支撑整个集群的DNS查询,则可以通过水平扩展提高查询能力。由于DNS服务是Kubernetes集群的关键核心服务,所以建议为其Deployment设置自动扩缩容控制器,自动管理其副本数量。

  另外,对资源限制部分(CPU限制和内存限制)的设置也应根据实际环境进行调整

  Service“kube-dns”是DNS服务的配置,这个服务需要设置固定的ClusterIP地址,也需要将所有Node上的kubelet启动参数--cluster-dns都设置为这个ClusterIP地址

CoreDNS的配置说明

  CoreDNS的主要功能是通过插件系统实现的。CoreDNS实现了一种链式插件结构,将DNS的逻辑抽象成了一个个插件,能够灵活组合使用

常用的插件如下。

  • loadbalance:提供基于DNS的负载均衡功能。
  • loop:检测在DNS解析过程中出现的简单循环问题。
  • cache:提供前端缓存功能。
  • health:对Endpoint进行健康检查。
  • kubernetes:从Kubernetes中读取zone数据。
  • etcd:从etcd中读取zone数据,可用于自定义域名记录。
  • file:从RFC1035格式文件中读取zone数据。
  • hosts:使用/etc/hosts文件或者其他文件读取zone数据,可用于自定义域名记录。
  • auto:从磁盘中自动加载区域文件。
  • reload:定时自动重新加载Corefile配置文件的内容。
  • forward:转发域名查询到上游DNS服务器上。
  • prometheus:为Prometheus系统提供采集性能指标数据的URL。
  • pprof:在URL路径/debug/pprof下提供运行时的性能数据。
  • log:对DNS查询进行日志记录。
  • errors:对错误信息进行日志记录。

  域名“cluster.local”设置了一系列插件,包括errors、health、ready、kubernetes、prometheus、forward、cache、loop、reload和loadbalance,在进行域名解析时,这些插件将以从上到下的顺序依次执行

  

 

 

       

 

标签:Endpoint,Service,Kubernetes,读书笔记,调度,设置,kubernetes,Pod,第五版
来源: https://www.cnblogs.com/happy-king/p/15228894.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有