其他分享
首页 > 其他分享> > 《kubernetes权威指南第五版》读书笔记

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

作者:互联网

修改kubeadm的默认配置

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

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。

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

  Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet,还可以通过kubelet管理(静态Pod)。每种控制器对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两个参数,它们的含义分别如下。

  如下代码片段是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预定义一些标签,包括:

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

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

NodeAffinity:Node亲和性调度

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

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

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

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

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

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

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

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

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

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

Taints和Tolerations(污点和容忍)

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

  另外,有如下两个特例

  几种特殊情况

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有以下特性。

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集群的搭建,需要部署以下三个资源对象。

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

StatefulSet的常见应用场景

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设置)

会话保持机制

  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,供集群内的其他应用访问,常见的应用场景包括:

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

  

将Service暴露到集群外部

目前Service的类型如下。

Service支持的网络协议

  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的后端是一组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种取值类型

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

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

(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的逻辑抽象成了一个个插件,能够灵活组合使用

常用的插件如下。

  域名“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