Kubernetes应用服务质量管理的方法是什么
本篇内容主要讲解“Kubernetes应用服务质量管理的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Kubernetes应用服务质量管理的方法是什么”吧!
服务质量管理
在Kubernetes中,Pod是最小的调度单元,所以跟资源和调度相关的属性都是Pod对象的字段,而其中最重要的就是CPU和内存。
如下所示:
---apiVersion:v1kind:Podmetadata:name:pod-demospec:containers:-name:mywebimage:wordpressimagePullPolicy:IfNotPresentresources:requests:memory:"128Mi"cpu:"250m"limits:memory:"256Mi"cpu:"500m"
其中resources就是资源限制部分。
注:由于一个Pod里可以定义多个Containers,而每个资源限制都是配置在各自的Container,所以Pod的整体配置资源是所有Containers的总和。
在Kubernetes中,CPU这样的资源被称为"可压缩资源",所谓可压缩资源就是当可用资源不足的时候,Pod只会"饥饿",不会退出。而向Memory这样的资源被称为"不可压缩资源",所谓的不可压缩资源就是当资源不足的时候Pod只会OOM。
其中CPU的设置单位是CPU的个数,比如CPU=1就表示这个Pod的CPU限额是1个CPU,而到底是1个CPU核心、是1个vCPU还是1个CPU超线程,这要取决于宿主机上CPU实现方式,而Kunernetes只需要保证该Pod能够使用到1个CPU的使用能力。
Kubernetes允许将CPU的限额设置位分数,比如上面我们设置的CPU.limits的值为500m,而所谓的500m就是500milliCPU,也就是0.5个CPU,这样,这个Pod就会被分到一个CPU一半的计算能力。所以我们可以直接把配置写成cpu=0.5,不过官方推荐500m的写法,这是Kubernetes内部的CPU计算方式。
在Kubernetes中,内存资源的单位是bytes,支持使用Ei,Pi,Ti,Gi,Mi,Ki的方式作为bytes的值,其中需要注意Mi和M的区别(1Mi=1024_1024,1M=1000_1000)。
Kubernetes中Pod的CPU和内存的资源限制,实际上分为requests和limits两种情况。
spec.containers[].resources.limits.cpuspec.containers[].resources.limits.memoryspec.containers[].resources.requests.cpuspec.containers[].resources.requests.memory
这两者的区别如下:
在调度的时候,kube-scheduler会安requests的值进行计算;
在设置CGroups的时候,kubelet会安limits的值来进行设置;
QoS模型
Kubernetes中支持三种QoS模型。其分类是基于requests和limits的不同配置。
Guaranteed
当Pod里的每一个Containers都设置了requests和limits,并且其值都相等的时候,这种Pod就属于Guaranteed类别,如下:
apiVersion:v1kind:Podmetadata:name:qos-demonamespace:qos-examplespec:containers:-name:qos-demo-ctrimage:nginxresources:limits:memory:"200Mi"cpu:"700m"requests:memory:"200Mi"cpu:"700m"
注意,当这Pod仅设置limits,没有设置requests的时候,系统默认为它分配于limits相等的requests值,也就会被划分为Guaranteed类别。
Burstable
而当这个Pod不满足Guaranteed条件,但至少有一个Contaienrs设置了requests,那么这个Pod就会被划分为Burstable类别。如下:
apiVersion:v1kind:Podmetadata:name:qos-demo-2namespace:qos-examplespec:containers:-name:qos-demo-2-ctrimage:nginxresources:limitsmemory:"200Mi"requests:memory:"100Mi"
BestEffort
如果这个Pod既没有设置requests值,也没有设置limits的值的时候,那么它的QoS类别就是BestEffort类别。
apiVersion:v1kind:Podmetadata:name:qos-demo-3namespace:qos-examplespec:containers:-name:qos-demo-3-ctrimage:nginx
而QoS划分的主要场景就是当宿主机资源紧张的时候,kubelet对资源进行Eviction时需要用到。目前Kubernetes设置的默认Eviction的阈值如下:
memory.available<100Minodefs.available<10%nodefs.inodesFree<5%imagefs.available<15%
上述条件可以在kubelet中设置:
kubelet--eviction-hard=imagefs.available<10%,memory.available<500Mi,nodefs.available<5%,nodefs.inodesFree<5%--eviction-soft=imagefs.available<30%,nodefs.available<10%--eviction-soft-grace-period=imagefs.available=2m,nodefs.available=2m--eviction-max-pod-grace-period=600
Kubernetes中的Eviction分为Soft Eviction和Hard Eviction两种模式。
Soft Eviction允许设置优雅等待时间,如上设置imagefs.available=2m,允许在Imagefs不足阈值达到2分钟之后才进行Eviction;
Hard Eviction在达到阈值就进行Eviction;
当宿主机的Eviction阈值达到后,就会进入MemoryPressure或者DiskPressure状态,从而避免新的Pod调度到上面去。而当Eviction发生时,kubelet删除Pod的先后顺序如下:
BestEffort 类型的Pod;
Burstable类别并且发生"饥饿"的资源使用量已经超出了requests的Pod;
Guaranteed类别并且只有当Guaranteed类别的Pod的资源使用量超过了其limits限制,或者宿主机本身处于Memory Pressure状态时,Guaranteed才会被选中被Eviction;
cpuset
cpuset,就是把容器绑定到某个CPU核上,减少CPU的上下文切换。
Pod必须是Guaranteed类型;
只需要将Pod的CPU资源的requests和limits设置为同一个相等的数值;
spec:containers:-name:nginximage:nginxresources:limits:memory:"200Mi"cpu:"2"requests:memory:"200Mi"cpu:"2"
LimitRange
在正常配置应用Pod的时候,都会把服务质量加上,也就是配置好requests和limits,但是,如果Pod非常多,而且很多Pod只需要相同的限制,我们还是像上面那样一个一个的加就非常繁琐了,这时候我们就可以通过LimitRange
做一个全局限制。如果在部署Pod的时候指定了requests和Limits,则指定的生效。反之则由全局的给Pod加上默认的限制。
总结,LimitRange
可以实现的功能:
限制namespace中每个pod或container的最小和最大资源用量。
限制namespace中每个PVC的资源请求范围。
限制namespace中资源请求和限制数量的比例。
配置资源的默认限制。
常用的场景如下(来自《Kubernetes权威指南》)
集群中的每个节点都有2GB内存,集群管理员不希望任何Pod申请超过2GB的内存:因为在整个集群中都没有任何节点能满足超过2GB内存的请求。如果某个Pod的内存配置超过2GB,那么该Pod将永远都无法被调度到任何节点上执行。为了防止这种情况的发生,集群管理员希望能在系统管理功能中设置禁止Pod申请超过2GB内存。
集群由同一个组织中的两个团队共享,分别运行生产环境和开发环境。生产环境最多可以使用8GB内存,而开发环境最多可以使用512MB内存。集群管理员希望通过为这两个环境创建不同的命名空间,并为每个命名空间设置不同的限制来满足这个需求。
用户创建Pod时使用的资源可能会刚好比整个机器资源的上限稍小,而恰好剩下的资源大小非常尴尬:不足以运行其他任务但整个集群加起来又非常浪费。因此,集群管理员希望设置每个Pod都必须至少使用集群平均资源值(CPU和内存)的20%,这样集群能够提供更好的资源一致性的调度,从而减少了资源浪费。
(1)、首先创建一个namespace
apiVersion:v1kind:Namespacemetadata:name:coolops
(2)、为namespace配置LimitRange
apiVersion:v1kind:LimitRangemetadata:name:mylimitnamespace:coolopsspec:limits:-max:cpu:"1"memory:1Gimin:cpu:100mmemory:10MimaxLimitRequestRatio:cpu:3memory:4type:Pod-default:cpu:300mmemory:200MidefaultRequest:cpu:200mmemory:100Mimax:cpu:"2"memory:1Gimin:cpu:100mmemory:10MimaxLimitRequestRatio:cpu:5memory:4type:Container
参数说明:
max:如果type是Pod,则表示pod中所有容器资源的Limit值和的上限,也就是整个pod资源的最大Limit,如果pod定义中的Limit值大于LimitRange中的值,则pod无法成功创建。如果type是Container,意义类似。
min:如果type是Pod,则表示pod中所有容器资源请求总和的下限,也就是所有容器request的资源总和不能小于min中的值,否则pod无法成功创建。如果type是Container,意义类似。
maxLimitRequestRatio:如果type是Pod,表示pod中所有容器资源请求的Limit值和request值比值的上限,例如该pod中cpu的Limit值为3,而request为0.5,此时比值为6,创建pod将会失败。
defaultrequest和defaultlimit则是默认值,只有type为Container才有这两项配置
注意:
(1)、如果container
设置了max
, pod
中的容器必须设置limit
,如果未设置,则使用defaultlimt
的值,如果defaultlimit
也没有设置,则无法成功创建
(2)、如果设置了container
的min
,创建容器的时候必须设置request
的值,如果没有设置,则使用defaultrequest
,如果没有defaultrequest
,则默认等于容器的limit
值,如果limit
也没有,启动就会报错
创建上面配置的LimitRange:
$kubectlapply-flimitrange.yamllimitrange/mylimitcreated$kubectlgetlimitrange-ncoolopsNAMECREATEDATmylimit2023-08-02T06:08:43Z$kubectldescribelimitranges-ncoolopsmylimitName:mylimitNamespace:coolopsTypeResourceMinMaxDefaultRequestDefaultLimitMaxLimit/RequestRatio---------------------------------------------------------------------Podcpu100m1--3Podmemory10Mi1Gi--4Containercpu100m2200m300m5Containermemory10Mi1Gi100Mi200Mi4
(3)、创建一个允许范围之内的requests和limits的pod
apiVersion:v1kind:Podmetadata:name:pod01namespace:coolopsspec:containers:-name:pod-01image:nginximagePullPolicy:IfNotPresentresources:requests:cpu:200mmemory:30Milimits:cpu:300mmemory:50Mi
我们通过kubectl apply -f pod-01.yaml
可以正常创建Pod。
(4)、创建一个cpu超出允许访问的Pod
apiVersion:v1kind:Podmetadata:name:pod02namespace:coolopsspec:containers:-name:pod-02image:nginximagePullPolicy:IfNotPresentresources:requests:cpu:200mmemory:30Milimits:cpu:2memory:50Mi
然后我们创建会报如下错误:
#kubectlapply-fpod-02.yamlErrorfromserver(Forbidden):errorwhencreating"pod-02.yaml":pods"pod02"isforbidden:[maximumcpuusageperPodis1,butlimitis2,cpumaxlimittorequestratioperPodis3,butprovidedratiois10.000000,cpumaxlimittorequestratioperContaineris5,butprovidedratiois10.000000]
(5)创建低于允许范围的Pod
apiVersion:v1kind:Podmetadata:name:pod03namespace:coolopsspec:containers:-name:pod-03image:nginximagePullPolicy:IfNotPresentresources:requests:cpu:200mmemory:30Milimits:cpu:100mmemory:10Mi
然后会报如下错误:
#kubectlapply-fpod-03.yamlThePod"pod03"isinvalid:*spec.containers[0].resources.requests:Invalidvalue:"200m":mustbelessthanorequaltocpulimit*spec.containers[0].resources.requests:Invalidvalue:"30Mi":mustbelessthanorequaltomemorylimit
(6)、创建一个未定义request或Limits的Pod
apiVersion:v1kind:Podmetadata:name:pod04namespace:coolopsspec:containers:-name:pod-04image:nginximagePullPolicy:IfNotPresentresources:requests:cpu:200mmemory:200Mi
然后我们创建完Pod后会发现自动给我们加上了limits。如下:
#kubectldescribepod-ncoolopspod04...Limits:cpu:300mmemory:200MiRequests:cpu:200mmemory:200Mi...
上面我指定了requests,LimitRange自动给我们加上了defaultLimits,你也可以试一下全都不加或者加一个,道理是一样的。值得注意的是这里要注意一下我们设置的maxLimitRequestRatio
,配置的比列必须小于等于我们设置的值。
上文有介绍LimitRange还可以限制还可以限制PVC,如下:
apiVersion:v1kind:LimitRangemetadata:name:storagelimitsnamespace:coolopsspec:limits:-type:PersistentVolumeClaimmax:storage:2Gimin:storage:1Gi
创建完后即可查看:
kubectldescribelimitranges-ncoolopsstoragelimitsName:storagelimitsNamespace:coolopsTypeResourceMinMaxDefaultRequestDefaultLimitMaxLimit/RequestRatio---------------------------------------------------------------------PersistentVolumeClaimstorage1Gi2Gi---
你可以创建PVC进行测试,道理是一样的。
服务可用性管理
高可用
生产级别应用,为了保证应用的可用性,除了特殊应用(例如批次应用)都会保持高可用,所以在设计应用Pod的时候,就要考虑应用的高可用。
最简单的就是多副本,也就是在创建应用的时候,至少需要2个副本,如下指定replicas为3就表示该应用有3个副本:
apiVersion:apps/v1kind:Deploymentmetadata:labels:app:nginxname:nginx-deploymentspec:progressDeadlineSeconds:600replicas:3revisionHistoryLimit:10selector:matchLabels:app:nginxstrategy:rollingUpdate:maxSurge:25%maxUnavailable:25%type:RollingUpdatetemplate:metadata:creationTimestamp:nulllabels:app:nginxspec:containers:-image:nginx:1.8imagePullPolicy:IfNotPresentname:nginxresources:requests:cpu:0.5memory:500Mlimits:cpu:0.5memory:500Mports:-containerPort:80name:httpprotocol:TCP
但是光配置多副本就够了么?
如果这三个副本都调度到一台服务器上,该服务器因某些原因宕机了,那上面的应用是不是就不可用?
为了解决这个问题,我们需要为同一个应用配置反亲和性,也就是不让同一应用的Pod调度到同一主机上,将上面的应用YAML改造成如下:
apiVersion:apps/v1kind:Deploymentmetadata:labels:app:nginxname:nginx-deploymentspec:progressDeadlineSeconds:600replicas:3revisionHistoryLimit:10selector:matchLabels:app:nginxstrategy:rollingUpdate:maxSurge:25%maxUnavailable:25%type:RollingUpdatetemplate:metadata:creationTimestamp:nulllabels:app:nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchExpressions:-key:appoperator:Invalues:-nginxtopologyKey:kubernetes.io/hostnamecontainers:-image:nginx:1.8imagePullPolicy:IfNotPresentname:nginxresources:requests:cpu:0.5memory:500Mlimits:cpu:0.5memory:500Mports:-containerPort:80name:httpprotocol:TCP
这样能保证同应用不会被调度到同节点,基本的高可用已经做到了。
可用性
但是光保证应用的高可用,应用本身不可用,也会导致异常。
我们知道Kubernetes的Deployment的默认更新策略是滚动更新,如何保证新应用更新后是可用的,这就要使用readinessProbe,用来确保应用可用才会停止老的版本,上面的YAML修改成如下:
apiVersion:apps/v1kind:Deploymentmetadata:labels:app:nginxname:nginx-deploymentspec:progressDeadlineSeconds:600replicas:3revisionHistoryLimit:10selector:matchLabels:app:nginxstrategy:rollingUpdate:maxSurge:25%maxUnavailable:25%type:RollingUpdatetemplate:metadata:creationTimestamp:nulllabels:app:nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchExpressions:-key:appoperator:Invalues:-nginxtopologyKey:kubernetes.io/hostnamecontainers:-image:nginx:1.8imagePullPolicy:IfNotPresentname:nginxresources:requests:cpu:0.5memory:500Mlimits:cpu:0.5memory:500MreadinessProbe:failureThreshold:3httpGet:path:/port:httpscheme:HTTPinitialDelaySeconds:10periodSeconds:10successThreshold:1timeoutSeconds:3ports:-containerPort:80name:httpprotocol:TCP
这样至少能保证只有新版本可访问才接收外部流量。
但是应用运行过程中异常了呢?这就需要使用livenessProbe来保证应用持续可用,上面的YAML修改成如下:
apiVersion:apps/v1kind:Deploymentmetadata:labels:app:nginxname:nginx-deploymentspec:progressDeadlineSeconds:600replicas:3revisionHistoryLimit:10selector:matchLabels:app:nginxstrategy:rollingUpdate:maxSurge:25%maxUnavailable:25%type:RollingUpdatetemplate:metadata:creationTimestamp:nulllabels:app:nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchExpressions:-key:appoperator:Invalues:-nginxtopologyKey:kubernetes.io/hostnamecontainers:-image:nginx:1.8imagePullPolicy:IfNotPresentname:nginxresources:requests:cpu:0.5memory:500Mlimits:cpu:0.5memory:500MreadinessProbe:failureThreshold:3httpGet:path:/port:httpscheme:HTTPinitialDelaySeconds:10periodSeconds:10successThreshold:1timeoutSeconds:3livenessProbe:failureThreshold:3httpGet:path:/port:httpscheme:HTTPinitialDelaySeconds:20periodSeconds:10successThreshold:1timeoutSeconds:3ports:-containerPort:80name:httpprotocol:TCP
上面的readinessProbe和livenessProbe都是应用在运行过程中如何保证其可用,那应用在退出的时候如何保证其安全退出?
所谓安全退出,也就是能正常处理退出逻辑,能够正常处理退出信号,也就是所谓的优雅退出。
优雅退出有两种常见的解决方法:
应用本身可以处理SIGTERM信号。
设置一个preStop hook,在hook中指定怎么优雅停止容器
这里抛开应用本身可以处理SIGTERM信号不谈,默认其能够处理,我们要做的就是协助其能优雅退出。在Kubernetes中,使用preStop hook来协助处理,我们可以将上面的YAML修改成如下:
apiVersion:apps/v1kind:Deploymentmetadata:labels:app:nginxname:nginx-deploymentspec:progressDeadlineSeconds:600replicas:3revisionHistoryLimit:10selector:matchLabels:app:nginxstrategy:rollingUpdate:maxSurge:25%maxUnavailable:25%type:RollingUpdatetemplate:metadata:creationTimestamp:nulllabels:app:nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchExpressions:-key:appoperator:Invalues:-nginxtopologyKey:kubernetes.io/hostnamecontainers:-image:nginx:1.8imagePullPolicy:IfNotPresentname:nginxlifecycle:preStop:exec: mand:-/bin/sh--c-sleep15resources:requests:cpu:0.5memory:500Mlimits:cpu:0.5memory:500MreadinessProbe:failureThreshold:3httpGet:path:/port:httpscheme:HTTPinitialDelaySeconds:10periodSeconds:10successThreshold:1timeoutSeconds:3livenessProbe:failureThreshold:3httpGet:path:/port:httpscheme:HTTPinitialDelaySeconds:20periodSeconds:10successThreshold:1timeoutSeconds:3ports:-containerPort:80name:httpprotocol:TCP
当然,这里只是一个样例,实际的配置还需要根据企业情况做跳转,比如企业使用了注册中心如zk或者nacos,我们就需要把服务从注册中心下掉。
PDB
上面的那些配置基本可以让应用顺利的在Kubernetes里跑了,但是不可避免有维护节点的需求,比如升级内核,重启服务器等。
而且也不是所有的应用都可以多副本,当我们使用kubectl drain
的时候,为了避免某个或者某些应用直接销毁而不可用,Kubernetes引入了PodDisruptionBudget(PDB)控制器,用来控制集群中Pod的运行个数。
在PDB中,主要通过两个参数来控制Pod的数量:
minAvailable:表示最小可用Pod数,表示在Pod集群中处于运行状态的最小Pod数或者是运行状态的Pod数和总数的百分比;
maxUnavailable:表示最大不可用Pod数,表示Pod集群中处于不可用状态的最大Pod数或者不可用状态Pod数和总数的百分比;
注意:minAvailable和maxUnavailable是互斥了,也就是说两者同一时刻只能出现一种。
kubectl drain命令已经支持了PodDisruptionBudget控制器,在进行kubectl drain操作时会根据PodDisruptionBudget控制器判断应用POD集群数量,进而保证在业务不中断或业务SLA不降级的情况下进行应用POD销毁。在进行kubectl drain或者Pod主动逃离的时候,Kubernetes会通过以下几种情况来进行判断:
minAvailable设置成了数值5:应用POD集群中最少要有5个健康可用的POD,那么就可以进行操作。
minAvailable设置成了百分数30%:应用POD集群中最少要有30%的健康可用POD,那么就可以进行操作。
maxUnavailable设置成了数值5:应用POD集群中最多只能有5个不可用POD,才能进行操作。
maxUnavailable设置成了百分数30%:应用POD集群中最多只能有30%个不可用POD,才能进行操作。
在极端的情况下,比如将maxUnavailable设置成0,或者设置成100%,那么就表示不能进行kubectl drain操作。同理将minAvailable设置成100%,或者设置成应用POD集群最大副本数,也表示不能进行kubectl drain操作。
注意:使用PodDisruptionBudget控制器并不能保证任何情况下都对业务POD集群进行约束,PodDisruptionBudget控制器只能保证POD主动逃离的情况下业务不中断或者业务SLA不降级,例如在执行kubectldrain命令时。
(1)、定义minAvailable
apiVersion:policy/v1kind:PodDisruptionBudgetmetadata:name:pdb-demospec:minAvailable:2selector:matchLabels:app:nginx
(2)、定义maxUnavailable
apiVersion:policy/v1kind:PodDisruptionBudgetmetadata:name:pdb-demospec:maxUnavailable:1selector:matchLabels:app:nginx
可以看到PDB是通过label selectors和应用Pod建立关联,而后在主动驱逐Pod的时候,会保证app: nginx的Pod最大不可用数为1,假如本身是3副本,至少会保证2副本正常运行。
到此,相信大家对“Kubernetes应用服务质量管理的方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是主机评测网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
上一篇:CSS渐变锯齿问题怎么解决
下一篇:Kubernetes存储系统数据持久化管理方法是什么