Kubernetes——资源调度与Pod探针

目录

前言

一、资源调度策略

1.默认调度器(Default Scheduler)

2.自定义调度器(Custom Scheduler)

3.亲和性与反亲和性(Affinity and Anti-Affinity)

4.污点与容忍(Taints and Tolerations)

5.资源配额和限制(Resource Quotas and Limits)

6.优先级和抢占(Priority and Preemption)

7.多调度器(Multiple Schedulers)

二、资源调度机制实现原理

1.调度器组件(Scheduler Component)

2.调度队列(Scheduling Queue)

3.调度循环(Scheduling Cycle)

4.过滤阶段(Filtering Phase)

5.打分阶段(Scoring Phase)

6.节点绑定(Node Binding)

7.Pod条件(Pod Conditions)

8.抢占(Preemption)

9.扩展性(Extensibility)

10.事件和日志(Events and Logging)

11.回退机制(Fallback Mechanism)

三、资源限制

1.CPU资源单位

2.内存资源单位

3.资源限制示例

四、Pod探针——健康检查

1.Pod探针的三种规则

2.Probe支持的三种检查方法

3.探针原理

3.1Exec方式

3.2http-Get方式

3.3TcpSocket方式

3.4就绪检测1

3.5就绪检测2

3.6启动和退出动作探测

4.探针参数

5.探针结果

五、探针总结

1.ReadinessProbe

2.LivenessProbe

3.StartupProbe

六、实践

七、总结

1.Pod容器的资源限制

2.Pod探针

2.1探针机制

2.2探针方法

3.Pod状态

4.Container生命周期


前言

Kubernetes(K8s)的资源调度策略是高度可配置和可扩展的,以适应不同类型的工作负载和集群配置。

一、资源调度策略

1.默认调度器(Default Scheduler)

预选阶段(Predicates):这一阶段会过滤掉无法满足Pod需求的节点。例如,如果节点的CPU或内存资源不足,或者不满足Pod的节点选择器(Node Selector)要求,那么该节点会被排除。

优选阶段(Priorities):在预选阶段后,调度器会对剩余的节点进行评分,评分标准可能包括节点的资源空闲程度、Pod与节点的亲和性、节点上的Pod密度等。

绑定阶段(Binding):选择得分最高的节点,并将Pod绑定到该节点上。

2.自定义调度器(Custom Scheduler)

用户可以编写自己的调度器,以实现特定的调度策略。自定义调度器可以与默认调度器并行运行,或者通过配置替换默认调度器。

3.亲和性与反亲和性(Affinity and Anti-Affinity)

节点亲和性(Node Affinity):允许Pod指定对节点的偏好,例如,可以指定Pod只调度到具有特定标签的节点上。

Pod亲和性与反亲和性(Pod Affinity and Anti-Affinity):这些规则允许Pod根据其他Pod的运行位置来选择调度位置,或者避免与某些Pod运行在同一个节点上。

4.污点与容忍(Taints and Tolerations)

污点(Taints):节点可以设置污点,以防止Pod调度到该节点上。例如,如果一个节点需要维护,可以给它添加一个污点。

容忍(Tolerations):Pod可以定义容忍,以允许它们被调度到有相应污点的节点上。

5.资源配额和限制(Resource Quotas and Limits)

资源配额(Resource Quotas):用于管理计算资源在命名空间级别的使用,可以限制Pod可以使用的资源总量。

资源限制(Resource Limits):Pod可以设置资源请求(requests)和限制(limits),以确保它们在运行时得到足够的资源,并且不会超过某个最大值。

6.优先级和抢占(Priority and Preemption)

优先级(Priority):Pod可以设置优先级,用于在资源不足时决定哪个Pod可以被抢占。

抢占(Preemption):当高优先级的Pod无法调度时,调度器可能会终止低优先级的Pod以释放资源。

7.多调度器(Multiple Schedulers)

在大型集群中,可能需要多个调度器来处理不同类型的工作负载。例如,一个调度器可能专门用于在线服务,而另一个可能用于批处理作业。

总之,Kubernetes的资源调度是集群管理中的关键组成部分,它们确保了Pod可以有效地利用集群资源,同时满足特定的业务需求和约束。通过提供丰富的调度选项,Kubernetes能够适应各种复杂的应用场景。

二、资源调度机制实现原理

Kubernetes的资源调度内部实现机制涉及到多个组件和步骤。

1.调度器组件(Scheduler Component)

Kubernetes调度器是一个独立的组件,它负责将Pods分配到集群中的节点上。调度器不断 watch API server,一旦有新的Pod被创建并且尚未被调度,调度器就会尝试为它找到一个合适的节点。

2.调度队列(Scheduling Queue)

调度器维护了一个待调度Pod的队列。这个队列中的Pod按照一定的优先级排序,确保高优先级的Pod先被调度。

3.调度循环(Scheduling Cycle)

调度器为每个待调度的Pod执行一个调度循环,这个循环包括两个主要步骤:过滤(Filtering)和打分(Scoring)。

4.过滤阶段(Filtering Phase)

在这个阶段,调度器会运行一系列预选规则(Predicates)来过滤出不能运行该Pod的节点。这些规则包括但不限于:节点是否有足够的资源、节点是否满足Pod的亲和性要求、节点是否有Pod所容忍的污点等。

5.打分阶段(Scoring Phase)

过滤阶段完成后,调度器会对剩余的节点进行打分。打分基于一系列优先级函数(Priorities),这些函数考虑了各种因素,如节点的资源空闲程度、Pod与节点的亲和性、节点上的Pod密度等。

6.节点绑定(Node Binding)

一旦调度器选出了最佳节点,它就会将该Pod绑定到该节点上。这个过程是通过更新Pod的API对象来完成的,将Pod的`spec.nodeName`字段设置为选中的节点名。

7.Pod条件(Pod Conditions)

调度器会检查Pod的状态和条件,以确保Pod可以正常运行。例如,如果Pod依赖于一个ConfigMap或Secret,调度器会确保这些资源已经准备好。

8.抢占(Preemption)

如果一个高优先级的Pod无法调度,调度器可能会启动抢占逻辑,尝试删除一些低优先级的Pod来为高优先级的Pod腾出空间。

9.扩展性(Extensibility)

Kubernetes调度器允许通过插件(Plugins)来扩展其功能。这些插件可以在过滤阶段和打分阶段被调用,以实现自定义的调度逻辑。

10.事件和日志(Events and Logging)

调度器会生成事件和日志,这些信息对于调试和理解调度决策非常有用。

11.回退机制(Fallback Mechanism)

如果调度器在给定的时间内无法找到一个合适的节点,Pod可能会被放入一个待定状态,等待重新调度。

总之,上述Kubernetes调度器的内部实现机制是高度优化的,以确保能够快速、有效地将Pods调度到集群中的节点上。通过不断地迭代和改进,Kubernetes调度器能够适应不断变化的集群状态和复杂的用户需求。

三、资源限制

当定义 Pod 时可以选择性地为每个容器设定所需要的资源数量。 最常见的可设定资源是 CPU 和内存大小,以及其他类型的资源。

当为 Pod 中的容器指定了 request 资源时,调度器就使用该信息来决定将 Pod 调度到哪个节点上。当还为容器指定了 limit 资源时,kubelet 就会确保运行的容器不会使用超出所设的 limit 资源量。kubelet 还会为容器预留所设的 request 资源量, 供该容器使用。

如果 Pod 运行所在的节点具有足够的可用资源,容器可以使用超出所设置的 request 资源量。不过,容器不可以使用超出所设置的 limit 资源量。

如果给容器设置了内存的 limit 值,但未设置内存的 request 值,Kubernetes 会自动为其设置与内存 limit 相匹配的 request 值。 类似的,如果给容器设置了 CPU 的 limit 值但未设置 CPU 的 request 值,则 Kubernetes 自动为其设置 CPU 的 request 值 并使之与 CPU 的 limit 值匹配。

官网示例:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

Pod 和 容器 的资源请求和限制:
spec.containers[].resources.requests.cpu		//定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory		//定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu			//定义 cpu 的资源上限 
spec.containers[].resources.limits.memory		//定义内存的资源上限

1.CPU资源单位

CPU 资源的 request 和 limit 以 cpu 为单位。Kubernetes 中的一个 cpu 相当于1个 vCPU(1个超线程)。
Kubernetes 也支持带小数 CPU 的请求。spec.containers[].resources.requests.cpu 为 0.5 的容器能够获得一个 cpu 的  、一半 CPU 资源(类似于Cgroup对CPU资源的时间分片)。表达式 0.1 等价于表达式 100m(毫核),表示每 1000 毫秒内容器可以使用的 CPU 时间总量为 0.1*1000 毫秒。
Kubernetes 不允许设置精度小于 1m 的 CPU 资源。 

2.内存资源单位

内存的 request 和 limit 以字节为单位。可以以整数表示,或者以10为底数的指数的单位(E、P、T、G、M、K)来表示, 或者以2为底数的指数的单位(Ei、Pi、Ti、Gi、Mi、Ki)来表示。
如:1KB=10^3=1000,1MB=10^6=1000000=1000KB,1GB=10^9=1000000000=1000MB
1KiB=2^10=1024,1MiB=2^20=1048576=1024KiB

在买硬盘的时候,操作系统报的数量要比产品标出或商家号称的小一些,主要原因是标出的是以 MB、GB为单位的,1GB 就是1,000,000,000Byte,而操作系统是以2进制为处理单位的,因此检查硬盘容量时是以MiB、GiB为单位,1GiB=2^30=1,073,741,824,相比较而言,1GiB要比1GB多出1,073,741,824-1,000,000,000=73,741,824Byte,所以检测实际结果要比标出的少一些。

3.资源限制示例

官方网站:https://kubernetes.io/zh-cn/docs/concepts/configuration/manage-resources-containers/

vim demo1.yamlapiVersion: v1
kind: Pod
metadata:name: frontend
spec:containers:- name: webimage: nginxenv:- name: WEB_ROOT_PASSWORDvalue: "password"resources:requests:memory: "64Mi"cpu: "250m"limits:memory: "128Mi"cpu: "500m"- name: dbimage: mysqlenv:- name: MYSQL_ROOT_PASSWORDvalue: "abc123"resources:requests:memory: "64Mi"cpu: "0.25"limits:memory: "128Mi"cpu: "500m"kubectl apply -f demo1.yamlkubectl get pod

OOMKilled:内存资源不足

kubectl logs frontend -c db

查找到该Pod容器资源是Mysql无法正常Running,显示的是内存资源不足,无法正常启用,所以我们要对该问题进行解决。

kubectl delete -f demo1.yamlvim demo1.yaml kubectl apply -f demo1.yaml kubectl get pod

kubectl describe pod frontend

kubectl describe nodes node

四、Pod探针——健康检查

探针是由kubelet对容器执行的定期诊断检查。

Kubernetes 可以对业务进行故障自愈,即针对运行异常的 Pod 进行重启。那么 K8S 是如何认定 Pod 是否异常呢?

Kubelet 组件根据 Pod 中容器退出状态码判定 Pod 是否异常,然后重启 Pod,进而达到故障自愈的效果。但是有些复杂场景,这种判定 Pod 异常的机制就无法满足了。

例如,Pod 中容器进程依然存在,但是容器死锁了,那么服务肯定是异常了,但是这时候利用上述异常检测机制就无法认定 Pod 异常了,从而无法重启 Pod。

这时候就需要利用 K8S 中的探针检测机制

1.Pod探针的三种规则

  • LivenessProbe :判断容器是否正在运行。如果探测失败,则kubelet会杀死容器,并且容器将根据 restartPolicy 来设置 Pod 状态。 如果容器不提供存活探针,则默认状态为Success。
  • ReadinessProbe :判断容器是否准备好接受请求。如果探测失败,端点控制器将从与 Pod 匹配的所有 service 址endpoints 中剔除删除该Pod的IP地。 初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。
  • StartupProbe(这个1.17版本增加的):判断容器内的应用程序是否已启动,主要针对于不能确定具体启动时间的应用。如果配置了 startupProbe 探测,在则在 startupProbe 状态为 Success 之前,其他所有探针都处于无效状态,直到它成功后其他探针才起作用。 如果 startupProbe 失败,kubelet 将杀死容器,容器将根据 restartPolicy 来重启。如果容器没有配置 startupProbe, 则默认状态为 Success。

注:以上规则可以同时定义。在readinessProbe检测成功之前,Pod的running状态是不会变成ready状态的。

StartupProbe只在容器启动时进行探测,只探测一次,之后不进行探测。

2.Probe支持的三种检查方法

  • Exec :在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
  • TcpSocket :对指定端口上的容器的IP地址进行TCP检查(三次握手)。如果端口打开,则诊断被认为是成功的。
  • HttpGet :对指定的端口和路径上的容器的IP地址执行HTTPGet请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的

3.探针原理

K8S 中探针的原理,实际上就是利用业务服务自身提供的健康检查接口,Kubelet 根据策略去探测该接口。

探针定义在Pod、Spec、Containers字段中,如下我们举一个官网的例子

3.1Exec方式

#官方示例exec方式apiVersion: v1
kind: Pod
metadata:labels:test: livenessname: liveness-exec
spec:containers:- name: livenessimage: k8s.gcr.io/busyboxargs:  - /bin/sh- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60livenessProbe:exec:command:- cat- /tmp/healthyfailureThreshold: 1 initialDelaySeconds: 5periodSeconds: 5#可以看到 Pod 中只有一个容器。kubelet 在执行第一次探测前需要等待 5 秒,kubelet 会每 5 秒执行一次存活探测。kubelet 在容器内执行命令 cat /tmp/healthy 来进行探测。如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 当到达第 31 秒时,这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。
vim demo2.yamlapiVersion: v1
kind: Pod
metadata:labels:test: livenessname: liveness-exec
spec:containers:- name: livenessimage: k8s.gcr.io/busyboxargs:  - /bin/sh- -c- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60livenessProbe:exec:command:- cat- /tmp/healthyfailureThreshold: 2initialDelaySeconds: 5periodSeconds: 5kubectl apply -f demo2.yamlkubectl get podkubectl get pod -w#initialDelaySeconds:指定 kubelet 在执行第一次探测前应该等待5秒,即第一次探测是在容器启动后的第6秒才开始执行。默认是 0 秒,最小值是 0。
#periodSeconds:指定了 kubelet 应该每 5 秒执行一次存活探测。默认是 10 秒。最小值是 1。
#failureThreshold: 当探测失败时,Kubernetes 将在放弃之前重试的次数。 存活探测情况下的放弃就意味着重新启动容器。就绪探测情况下的放弃 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。
#timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。(在 Kubernetes 1.20 版本之前,exec 探针会忽略 timeoutSeconds 探针会无限期地 持续运行,甚至可能超过所配置的限期,直到返回结果为止。)#在这个配置文件中,可以看到 Pod 中只有一个 Container。 periodSeconds 字段指定了 Kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds 字段告诉 Kubelet 在执行第一次探测前应该等待 5 秒。Kubelet 在容器内执行命令 cat /tmp/healthy 来进行探测。如果命令执行成功并且返回值为 0,Kubelet 就会认为这个容器是健康存活的。如果这个命令返回非 0 值,Kubelet 会根据 pod restartPolicy 决定是否杀死这个容器并重新启动它。

kubectl describe pod liveness-exec 

这里查看当前的状态是正常的

这里会探测Pod容器资源是否存活

上面例子使用 EXEC 执行命令的方式来探测服务,同样还支持 HTTP、TCP、GRPC 协议这三种探测的方式,使用方式和上面例子类似,具体可参考 kubernetes 官网

使用探针来检查容器有四种不同的方法。每个探针都必须准确定义为这四种机制中的一种

  • Exec 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
  • Grpc 使用 gRPC 执行一个远程过程调用。目标应该实现  gRPC 健康检查。如果响应的状态是 "SERVING",则认为诊断成功。
  • HttpGet 对容器的 IP 地址上指定端口和路径执行 HTTP GET 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
  • TcpSocket 对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。如果远程系统(容器)在打开连接后立即将其关闭,这算作是健康的。

 注意: 和其他机制不同,exec 探针的实现涉及每次执行时创建/复制多个进程。因此,在集群中具有较高 pod 密度、较低的 initialDelaySeconds 和 periodSeconds 时长的时候, 配置任何使用 exec 机制的探针可能会增加节点的 CPU 负载。这种场景下,请考虑使用其他探针机制以避免额外的开销。

3.2http-Get方式

#官方示例httpGet方式apiVersion: v1
kind: Pod
metadata:labels:test: livenessname: liveness-http
spec:containers:- name: livenessimage: k8s.gcr.io/livenessargs:- /serverlivenessProbe:httpGet:path: /healthzport: 8080httpHeaders:- name: Custom-Headervalue: AwesomeinitialDelaySeconds: 3periodSeconds: 3#在这个配置文件中,可以看到 Pod 也只有一个容器。initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。kubelet 会向容器内运行的服务(服务会监听 8080 端口)发送一个 HTTP GET 请求来执行探测。如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。如果处理程序返回失败代码,则 kubelet 会杀死这个容器并且重新启动它。
vim demo3.yamlapiVersion: v1
kind: Pod
metadata:name: liveness-httpgetnamespace: default
spec:containers:- name: liveness-httpget-containerimage: soscscs/myapp:v1imagePullPolicy: IfNotPresentports:- name: httpcontainerPort: 80livenessProbe:httpGet:port: httppath: /index.htmlinitialDelaySeconds: 1periodSeconds: 3timeoutSeconds: 10#在这个配置文件中,可以看到 Pod 也只有一个容器。initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。kubelet 会向容器内运行的服务(服务会监听 80 端口)发送一个 HTTP GET 请求来执行探测。如果服务器上 /index.html 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。如果处理程序返回失败代码,则 kubelet 会杀死这个容器并且重新启动它。
#任何大于或等于 200 并且小于 400 的返回代码标示成功,其它返回代码都标示失败。kubectl apply -f demo3.yaml kubectl get pod

kubectl describe pod liveness-httpget

我们看到http-get目前是没有问题的,Pod探测服务是正常启用的。下面我们模拟破坏当前Pod

kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.htmlkubectl get pod

我们可以看到删除一次,就会重启一次Pod资源

3.3TcpSocket方式

#官方示例tcpSocket方式apiVersion: v1
kind: Pod
metadata:name: goproxylabels:app: goproxy
spec:containers:- name: goproxyimage: k8s.gcr.io/goproxy:0.1ports:- containerPort: 8080readinessProbe:tcpSocket:port: 8080initialDelaySeconds: 5periodSeconds: 10livenessProbe:tcpSocket:port: 8080initialDelaySeconds: 15periodSeconds: 20#这个例子同时使用 readinessProbe 和 livenessProbe 探测。kubelet 会在容器启动 5 秒后发送第一个 readinessProbe 探测。这会尝试连接 goproxy 容器的 8080 端口。如果探测成功,kubelet 将继续每隔 10 秒运行一次检测。除了 readinessProbe 探测,这个配置包括了一个 livenessProbe 探测。kubelet 会在容器启动 15 秒后进行第一次 livenessProbe 探测。就像 readinessProbe 探测一样,会尝试连接 goproxy 容器的 8080 端口。如果 livenessProbe 探测失败,这个容器会被重新启动。
vim demo4.yamlapiVersion: v1
kind: Pod
metadata:name: cxk-tcp-live
spec:containers:- name: nginximage: soscscs/myapp:v1livenessProbe:initialDelaySeconds: 5timeoutSeconds: 1tcpSocket:port: 8080periodSeconds: 10failureThreshold: 2kubectl create -f demo4.yamlkubectl exec -it probe-tcp  -- netstat -natp

我们可以看到Pod服务资源没问题,但是Pod探针探测的8080端口有问题,所以会重启 

3.4就绪检测1

vim demo5.yamlapiVersion: v1
kind: Pod
metadata:name: readiness-httpgetnamespace: default
spec:containers:- name: readiness-httpget-containerimage: soscscs/myapp:v1imagePullPolicy: IfNotPresentports:- name: httpcontainerPort: 80readinessProbe:httpGet:port: 80path: /index1.htmlinitialDelaySeconds: 1periodSeconds: 3livenessProbe:httpGet:port: httppath: /index.htmlinitialDelaySeconds: 1periodSeconds: 3timeoutSeconds: 10kubectl apply -f demo5.yamlkubectl get pod

kubectl describe pod readiness-httpget 

探测404报错,这里提示是缺少一个页面,我们需要进入容器资源内创建一个页面

kubectl exec -it readiness-httpget shcd /usr/share/nginx/html/echo "this is test" > index1.html 

 此时Pod资源探测结果/index1.html已经有了,所以该资源正常运行Running

我们再删除刚才新建的页面

readiness探测失败,无法进入READY状态

3.5就绪检测2

vim demo6.yamlapiVersion: v1
kind: Pod
metadata:name: myapp1labels:app: myapp
spec:containers:- name: myappimage: soscscs/myapp:v1ports:- name: httpcontainerPort: 80readinessProbe:httpGet:port: 80path: /index.htmlinitialDelaySeconds: 5periodSeconds: 5timeoutSeconds: 10 
---
apiVersion: v1
kind: Pod
metadata:name: myapp2labels:app: myapp
spec:containers:- name: myappimage: soscscs/myapp:v1ports:- name: httpcontainerPort: 80readinessProbe:httpGet:port: 80path: /index.htmlinitialDelaySeconds: 5periodSeconds: 5timeoutSeconds: 10 
---
apiVersion: v1
kind: Pod
metadata:name: myapp3labels:app: myapp
spec:containers:- name: myappimage: soscscs/myapp:v1ports:- name: httpcontainerPort: 80readinessProbe:httpGet:port: 80path: /index.htmlinitialDelaySeconds: 5periodSeconds: 5timeoutSeconds: 10 
---
apiVersion: v1
kind: Service
metadata:name: myapp
spec:selector:app: myapptype: ClusterIPports:- name: httpport: 80targetPort: 80kubectl create -f demo6.yamlkubectl get pods,svc,endpoints -o wide

下面我们模拟删除页面文件,测试就绪探针探测 

kubectl exec -it pod/myapp1 -- rm -rf /usr/share/nginx/html/index.htmlkubectl get pods,svc,endpoints -o wide

这里我们看到由于删掉了一个Pod资源内的index.html,所以myapp的Pod就将没有index.html的资源剔除地址池中(Pod有问题就剔除该地址池)

3.6启动和退出动作探测

vim demo7.yamlapiVersion: v1
kind: Pod
metadata:name: lifecycle-demo
spec:containers:- name: lifecycle-demo-containerimage: soscscs/myapp:v1lifecycle:postStart:exec:command: ["/bin/sh", "-c", "echo Hello from the postStart handler >> /var/log/nginx/message"]      preStop:exec:command: ["/bin/sh", "-c", "echo Hello from the poststop handler >> /var/log/nginx/message"]volumeMounts:- name: message-logmountPath: /var/log/nginx/readOnly: falseinitContainers:- name: init-myserviceimage: soscscs/myapp:v1command: ["/bin/sh", "-c", "echo 'Hello initContainers'   >> /var/log/nginx/message"]volumeMounts:- name: message-logmountPath: /var/log/nginx/readOnly: falsevolumes:- name: message-loghostPath:path: /data/volumes/nginx/log/type: DirectoryOrCreatekubectl apply -f demo7.yamlkubectl get pods -o wide

#在 node02 节点上查看
cd /data/volumes/nginx/log/cat message 
Hello initContainers
Hello from the postStart handler
#由上可知,init Container先执行,然后当一个主容器启动后,Kubernetes 将立即发送 postStart 事件。

#在原Master删除 pod 后,再在 node02 节点上查看
kubectl delete -f demo7.yaml

cat message 
Hello initContainers
Hello from the postStart handler
Hello from the poststop handler
#由上可知,当在容器被终结之前, Kubernetes 将发送一个 preStop 事件。

综上所述,探针的时候先启动Init初始化,然后开启探针,探测存活和就绪准备工作,删除资源的话,最后才是停止探针(生命周期结束)

4.探针参数

上面例子发现探针配置中有几个配置参数,可以使用这些字段精确地控制启动、存活和就绪检测的行为

  • initialDelaySeconds:容器启动后要等待多少秒后才启动启动、存活和就绪探针。如果定义了启动探针,则存活探针和就绪探针的延迟将在启动探针已成功之后才开始计算。如果 periodSeconds 的值大于 initialDelaySeconds,则 initialDelaySeconds 将被忽略。默认是 0 秒,最小值是 0。

  • periodSeconds:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。

  • timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。

  • successThreshold:探针在失败后,被视为成功的最小连续成功数。默认值是 1。存活和启动探测的这个值必须是 1。最小值是 1。

  • failureThreshold:探针连续失败了 failureThreshold 次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。对于启动探针或存活探针而言,如果至少有 failureThreshold 个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。Kubelet 遵循该容器的 terminationGracePeriodSeconds 设置。对于失败的就绪探针,Kubelet 继续运行检查失败的容器,并继续运行更多探针;因为检查失败,Kubelet 将 Pod 的 Ready 状况设置为 false

  • terminationGracePeriodSeconds:为 Kubelet 配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长。默认值是继承 Pod 级别的 terminationGracePeriodSeconds 值(如果不设置则为 30 秒),最小值为 1。更多细节请参见探针级别 terminationGracePeriodSeconds

5.探针结果

三种类型的探针每次探测都将获得以下三种结果之一:

  • Success(成功)容器通过了诊断。
  • Failure(失败)容器未通过诊断。
  • Unknown(未知)诊断失败,因此不会采取任何行动。

五、探针总结

1.ReadinessProbe

就绪探针,探测容器启动后,是否就绪,是否能够提供服务,只有 pod 所有容器都探测成功后,pod 状态变成 Ready。只要有一个容器的 readinessProbe 失败,那么整个 pod 都会处于 NotReady 状态。

控制器将此 Pod 的 Endpoint 从对应的 service 的 Endpoint 列表中移除,从此不再将任何请求调度此 Pod 上,直到下次探测成功。

通过使用 ReadinessProbe,Kubernetes 能够等待应用程序完全启动,然后才允许服务将流量发送到新副本。

2.LivenessProbe

存活探针,检查容器是否运行正常,如死锁、无法响应等,探测失败后 Kubelet 根据 restartPolicy 来重启容器。

当一个 pod 内有多个容器,且 restartpolicy 为默认值( Always )。其中某个容器探针失败后,Kubelet 重启该容器,并不会重启其他容器,且 pod 的状态值会变为 NotReady

如果一个容器不包含 livenessProbe 探针,则 Kubelet 认为容器的 livenessProbe 探针的返回值永远成功。

3.StartupProbe

启动探针,判断容器是否已启动。如果提供了启动探测探针,则禁用所有其他探测探针( readinessProbe,livenessProbe ),直到它成功为止。如果启动探测失败,Kubelet 将杀死容器,容器将服从其重启策略。如果容器没有提供启动探测,则默认状态为成功。

那什么时候需要使用到启动探针呢?

例如如下有个含有 livenessProbe 的 pod

livenessProbe:httpGet:path: /healthzprot: 80failureThreshold: 1initialDelay:10periodSeconds: 10#该探针的意思是容器启动 10s 后开始探测,每 10s 检查一次,允许失败的次数是 1 次。如果失败次数超过 1 则表示探针失败。

如果这个服务启动时间在 10s 内则没有任何问题,因为探针 10s 后才开始探测。但是该服务在启动的时候需要一些预启动的操作,比如导数据之类,需要 60s 才能完全启动好。这时候上面的探针就会进入死循环,因为上面的探针10s 后就开始探测,这时候我们服务并没有起来,发现探测失败就会触发容器重启策略。当然可以把 initialDelay 调成 60s ,但是我们并不能保证这个服务每次起来都是 60s ,假如新的版本起来要70s,甚至更多的时间,我们就不好控制了。有的朋友可能还会想到把失败次数增加,比如下面配置

livenessProbe:httpGet:path: /healthzprot: 80failureThreshold: 5initialDelay:60periodSeconds: 10

这在启动的时候是可以解决我们目前的问题,但是如果这个服务挂了呢?如果 failureThreshold=1 则 10s 后就会报警通知服务挂了,如果设置了failureThreshold=5,那么就需要 5*10s=50s 的时间,在现在大家追求快速发现、快速定位、快速响应的时代是不被允许的。

在这时候我们把 startupProbe 和 livenessProbe 结合起来使用就可以很大程度上解决我们的问题。

livenessProbe:httpGet:path: /healthzprot: 80failureThreshold: 1initialDelay:10periodSeconds: 10startupProbe:httpGet:path: /healthzprot: 80failureThreshold: 10initialDelay:10periodSeconds: 10

上面的配置是只有 startupProbe 探测成功后再交给 livenessProbe 。应用在 10s + 10s * 10s = 110s 内启动都是可以的,而且应用启动后运行过程中挂掉了 10s 就会发现问题。

所以说启动探针一般都是搭配着存活探针一起工作的,不会单独配置启动配置。

六、实践

熟练使用好上面三种探针,可以增强业务的可用性和稳定性。

如果服务自身启动时间略长,0s-20s 之间那么需要配置 readinessProbe

readinessProbe:httpGet:path: /healthzprot: 80failureThreshold: 1initialDelay:10periodSeconds: 10
  • 该配置作用是当容器启动 10s 后,开始第一次探针,且每隔 10s 探针一次。
  • 一次探针失败即表示失败,将该 pod 表示为 NotReady
  • 如果启动后探针成功后,pod 状态置为 Ready,该服务即可被请求。
  • 后续每隔 10s 请求一次,如果失败了,将 pod 状态置为 NotReady,Endpoint Controller 就会将该 endpoint 从 service 上剔除。

关于 ReadinessProbe 有一点很重要,它会在容器的整个生命周期中运行。这意味着 ReadinessProbe 不仅会在启动时运行,而且还会在 Pod 运行期间反复运行。这是为了处理应用程序暂时不可用的情况(比如加载大量数据、等待外部连接时)。在这种情况下,我们不一定要杀死应用程序,可以等待它恢复。ReadinessProbe 可用于检测这种情况,并在 Pod 再次通过 ReadinessProbe 检查后,将流量发送到这些 Pod。 

如果服务会出现假死现象,即服务进程在,但已经无法提供服务了。那么这时候就需要 livenessProbe

readinessProbe:httpGet:path: /healthzprot: 80failureThreshold: 3initialDelay:10periodSeconds: 10livenessProbe:httpGet:path: /healthzprot: 80failureThreshold: 10initialDelay:15periodSeconds: 10

当同时使用 readinessProbe、livenessProbe,两者配置不能保持一样。

  • 如果两者 initialDelay 都为 10 ,即服务启动 10s 后,readinessProbe、livenessProbe 都开始探测,这样两者都探测失败后,该 pod 即重启也会 NotReady 是一个多此一举的过程。
  • 可以将 readinessProbe 的 initialDelay 设置的短一点,即先开始就绪探针,再开始存活探针。
  • 或者将 livenessProbe 的 failureThreshold 设置大一点。(例如,在 3 次尝试后标记为未就绪,在 10 次尝试后将 LivenessProbe 标记为失败)

如果服务启动时间很长,20s - 100s,就需要使用 startupProbe

readinessProbe:httpGet:path: /healthzprot: 80failureThreshold: 3initialDelay:10periodSeconds: 10livenessProbe:httpGet:path: /healthzprot: 80failureThreshold: 10initialDelay:15periodSeconds: 10startupProbe:httpGet:path: /healthzprot: 80failureThreshold: 10initialDelay:10periodSeconds: 10
  • 当该服务启动 10s 后开始启动探针,探测成功后,该探针结束,后面不会再探测了,然后到 readinessProbe、livenessProbe 工作;
  • startupProbe 探测失败后,重启该 pod,重新探测,直到服务启动成功。 

七、总结

1.Pod容器的资源限制

spec.containers.resources.requests.cpu/memory
#创建Pod容器时需要预留的资源量0.5/500m 内存 MI(以2为底的) M G(以10为底的)spec.containers.resources.limit.cpu/memory
#Pod容器能够使用资源量的一个上限,举例 4Gi 内存的上限(不允许超过上限值) 1 cpu的上限kubectl describe 名称
#查看Pod或查看Node资源使用情况

2.Pod探针

2.1探针机制

  • LivenessProbe:存活探针,即探测容器是否运行、存活
  • ReadinessProbe:就绪探针,探测容器是否就绪,是否能够正常提供服务了
  • StartupProbe:启动探针,探测容器是否启动。

2.2探针方法

  • Exec 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
  • Grpc 使用 gRPC 执行一个远程过程调用。目标应该实现  gRPC 健康检查。如果响应的状态是 "SERVING",则认为诊断成功。
  • HttpGet 对容器的 IP 地址上指定端口和路径执行 HTTP GET 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
  • TcpSocket 对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。如果远程系统(容器)在打开连接后立即将其关闭,这算作是健康的。

3.Pod状态

  • Pending:pod已经被系统认可了,但是内部的container还没有创建出来。这里包含调度到node上的时间以及下载镜像的时间,会持续一小段时间。
  • Running:pod已经与node绑定了(调度成功),而且pod中所有的container已经创建出来,至少有一个容器在运行中,或者容器的进程正在启动或者重启状态。--这里需要注意pod虽然已经Running了,但是内部的container不一定完全可用。因此需要进一步检测container的状态。
  • Succeeded:这个状态很少出现,表明pod中的所有container已经成功的terminated了,而且不会再被拉起了。
  • Failed:pod中的所有容器都被terminated,至少一个container是非正常终止的。(退出的时候返回了一个非0的值或者是被系统直接终止)
  • Unknown:由于某些原因pod的状态获取不到,有可能是由于通信问题。 一般情况下pod最常见的就是前两种状态。而且当Running的时候,需要进一步关注container的状态

4.Container生命周期

  • Waiting:启动到运行中间的一个等待状态。
  • Running:运行状态。
  • Terminated:终止状态。 如果没有任何异常的情况下,container应该会从Waiting状态变为Running状态,这时容器可用。

但如果长时间处于Waiting状态,container会有一个字段reason表明它所处的状态和原因,如果这个原因很容易能标识这个容器再也无法启动起来时,例如ContainerCannotRun,整个服务启动就会迅速返回。(这里是一个失败状态返回的特性,不详细阐述)

Kubernetes 探针可以极大地提高服务的健壮性和弹性,并提供出色的最终用户体验。但是,如果您不仔细考虑如何使用这些探针,特别是如果您不考虑异常的系统动态(无论多么罕见),则有可能使服务的可用性变差,而不是变好。下面列举了探针使用的一些技巧和注意事项。

  • 对于提供 HTTP 协议(REST 服务等)的微服务, 始终定义一个 readinessProbe,用于检查的应用程序(Pod)是否已准备好接收流量。

  • 对于慢启动的应用,我们应该使用 startupProbe,来防止容器没有启动,就被 livenessProbe 杀死了。

  • 不要依赖外部依赖项(如数据存储)进行就绪/探活检查,因为这可能会导致级联故障

假如10 个 pod 的服务,数据库使用 Postgres,缓存使用 redis:当你的探针的路径依赖于工作的 redis 连接时,如果出现 redis 网络故障,则所有 10 个 Pod 都将“重启。这通常会产生影响比它应该的更糟。因为服务还能到 Postgres 拿去数据。 

只探测自己内部的端口,不要去探测外部 pod 的端口。探测器不应依赖于同一集群中其他 Pod 的状态,以防止级联故障。 

  • 需要明确知道使用 livenessProbe 的原因,否则不要为的 Pod 使用 livenessProbe
    • livenessProbe 可以帮助恢复假死的容器,但是当我们能控制我们的应用程序,出现意料之外的假死进程和死锁之类的故障,更好的选择是从应用内部故意崩溃以恢复到已知良好状态。
    • 失败的 livenessProbe 将导致容器重启,从而可能使与负载相关的错误的影响变得更糟:容器重启将导致停机(至少的应用程序的启动时间,例如 30s+),从而导致更多错误并为其他容器提供更多流量负载,导致更多失败的容器,等等
  • 如果同时使用 readinessProbe、livenessProbe,请不要为 readinessProbe、livenessProbe 设置相同的规范

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Window GDI+ API有BUG?GetBounds测不准?

文章目录 GraphicsPath的GetBounds测不准?方法一:GetBounds ()实战 方法二:GetBounds(Matrix)实战 GraphicsPath的GetBounds测不准?实战 .NET 版本的问题?C也一样,不是.NET的问题怀疑人生MiterLimit惹得祸完美结果结束…

MyBatis-Plus介绍及Spring Boot 3集成指南

我们每个Java开发者都在使用springbootmybatis开发时,我们经常发现自己需要为每张数据库表单独编写XML文件,并且为每个表都需要编写一套增删改查的方法,较为繁琐。为了解决这一问题,MyBatis-Plus应运而生。在本文中,我…

第七节:带你全面理解vue3: 其他响应式进阶API

前言: 针对vue3官网中, 响应式:进阶API 中, 我们在上一章中给大家讲解了shallowRef, shallowReactive, shallowReadonly几个API的使用. 本章主要对剩下的API 进行讲解, 我们先看一下官网中进阶API 都有那些 对于剩下这些API, 你需要了解他们创建目的, 是为了解决之前的API存在…

LLM多模态——GPT-4o改变人机交互的多模式 AI 模型应用

1. 概述 OpenAI 发布了迄今为止最新、最先进的语言模型 – GPT-4o也称为“全“ 模型。这一革命性的人工智能系统代表了一次巨大的飞跃,其能力模糊了人类和人工智能之间的界限。 GPT-4o 的核心在于其原生的多模式特性,使其能够无缝处理和生成文本、音频…

AWPortrait1.4更新,人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新的高度

AWPortrait1.4更新,人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新的高度 经过5个月,AWPortrait终于迎来了1.4。 本次更新基于1.3训练,使得人物的生成更加趋近真实感,将SD1.5人像的真实感提升到了一个新…

uview1.0 u-form表单回显校验不通过

提交到后端的数据,回显后不做任何修改无法通过表单校验 原因,u-form表单校验的类型默认为string,但是后端返回的是integer类型,导致无法通过校验 解决,既然后端返回的是整数形,那么我们就将校验规则的type…

【企业动态】东胜物联成为AWS硬件合作伙伴,助力实现边缘智能

近日,AIoT硬件设备供应商东胜物联与全球领先的云计算服务提供商亚马逊云(AWS)达成合作关系,共同致力于推动物联网技术的发展,为企业客户提供更智能、灵活的硬件解决方案,助力智能化升级和数字化转型。 作为…

Android studio关闭自动更新

Windows下: 左上角file - setting - Appearance & Behavier - system setting - update - 取消勾选

图书管理系统(Java版本)

文章目录 前言要求1.设置对象1.1.图书1.2.书架2.管理员3.功能的实现 2.搭建框架2.1.登录(login)2.2.菜单2.3.操作方法的获取 3.操作方法的实现3.1.退出系统(ExitOperation)3.2.显示图书(ShowOperation)3.3.查阅图书(FindOperation)3.4.新增图书(AddOperation)3.5.借出图书(Borr…

链游:区块链技术的游戏新纪元

随着区块链技术的快速发展,越来越多的行业开始探索与其结合的可能性,其中,游戏行业与区块链的结合尤为引人注目。链游,即基于区块链技术的游戏,正以其独特的优势,为玩家带来全新的游戏体验。本文将对链游进…

QQ技术导航源码附带交易系统

网站功能 QQ登录 友联自助交换 友情链接交易功能 多功能搜索 ico小图标本地化 网站图片本地化 蜘蛛日志 文章评论 网站评论 自助链接匿名提交站点,添加友链访问网站自动审核通过 VIP 会员等级 VIP 付费升级 单个文章或者站点付费快审 多背景图片可自定义背景图片…

200smart【编程入门】

说明 编程时,遇到困难就按【F1】 【I】输入 200smart 上限 i0.0~i31.7 255bit【255个输入点】 i0.0~i31.7 八进制 【布尔 bool 】 ib0~ib127 【单字节】 8bit iw0~iw127 …

springBoot+springSecurity基本认证流程

springBootspringSecurity认证流程 整合springSecurity 对应springboot版本&#xff0c;直接加依赖&#xff0c;这样版本不会错 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId…

SpringMVC接收请求参数的方式:

接收简单变量的请求参数 直接使用简单变量作为形参进行接收&#xff08;这里简单变量名称需要与接收的参数名称保持一致&#xff0c;否则需要加上RequestParam注解&#xff09;&#xff1a; 细节&#xff1a; 1&#xff1a;SpringMVC会针对常见类型&#xff08;八种基本类型及…

MQTT到串口的转发(node.js)

本文针对以下应用场景&#xff1a;已有通过串口通信的设备或软件&#xff0c;想要实现跨网的远程控制。 node.js安装 从 Node.js — Run JavaScript Everywhere下载LTS版本安装包&#xff0c;运行安装程序。&#xff08;傻瓜安装&#xff0c;按提示点击即可&#xff09; 设置环…

网络传输层

叠甲&#xff1a;以下文章主要是依靠我的实际编码学习中总结出来的经验之谈&#xff0c;求逻辑自洽&#xff0c;不能百分百保证正确&#xff0c;有错误、未定义、不合适的内容请尽情指出&#xff01; 文章目录 1.端口号的基础2.传输层两协议2.1.UDP 协议2.1.1.协议结构2.1.2.封…

CPP Con 2020:Type Traits I

先谈谈Meta Programming 啥是元编程呢&#xff1f;很简单&#xff0c;就是那些将其他程序当作数据来进行处理和传递的编程&#xff08;私人感觉有点类似于函数式&#xff1f;&#xff09;这个其他程序可以是自己也可以是其他程序。元编程可以发生在编译时也可以发生在运行时。…

LAMDA面试准备(2024-05-23)

有没有学习过机器学习&#xff0c;提问了 FP-Growth 相比 Apriori 的优点 1. 更高的效率和更少的计算量&#xff08;时间&#xff09; FP-Growth 通过构建和遍历 FP-树 (Frequent Pattern Tree) 来挖掘频繁项集&#xff0c;而不需要像 Apriori 那样生成和测试大量的候选项集。具…

5.23.2 深度学习提高乳房 X 光检查中乳腺癌的检测率

开发了一种深度学习算法&#xff0c;该算法可以使用“端到端”训练方法在筛查乳房 X 光检查中准确检测出乳腺癌&#xff0c;该方法有效地利用了具有完整临床注释或仅具有整个图像的癌症 标签 的训练数据集。 在这种方法中&#xff0c;仅在初始训练阶段才需要病变注释&#xff…

springboot vue 开源 会员收银系统 (2) 搭建基础框架

前言 完整版演示 前面我们对会员系统https://blog.csdn.net/qq_35238367/article/details/126174288进行了分析 确定了技术选型 和基本的模块 下面我们将从 springboot脚手架开发一套收银系统 使用脚手架的好处 不用编写基础的rabc权限系统将工作量回归业务本身生成代码 便于…