【云原生 | 从零开始学Kubernetes】十三、k8s的容器探测以及启动探测

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 许多应用程序经过长时间运行,最终过渡到无法运行的状态,除了重启,无法恢复。通常情况下,K8S 会发现应用程序已经终止,然后重启应用程序 pod。有时应用程序可能因为某些原因(后端服务故障等)导致暂时无法对外提供服务,但应用软件没有终止,导致 K8S 无法隔离有故障的 pod,调用者可能会访问到有故障的 pod,导致业务不稳定。K8S 提供 livenessProbe 来检测容器是否正常运行,并且对相应状况进行相应的补救措施。

存活性探测 livenessProbe 和就绪性探测 readinessProbe


livenessProbe:存活性探测


许多应用程序经过长时间运行,最终过渡到无法运行的状态,除了重启,无法恢复。通常情况下,K8S 会发现应用程序已经终止,然后重启应用程序 pod。有时应用程序可能因为某些原因(后端服务故障等)导致暂时无法对外提供服务,但应用软件没有终止,导致 K8S 无法隔离有故障的 pod,调用者可能会访问到有故障的 pod,导致业务不稳定。K8S 提供 livenessProbe 来检测容器是否正常运行,并且对相应状况进行相应的补救措施。


readinessProbe:就绪性探测


在没有配置 readinessProbe 的资源对象中,pod 中的容器启动完成后,就认为 pod 中的应用程序可以对外提供服务,该 pod 就会加入相对应的 service,对外提供服务。但有时一些应用程序启动后,需要较长时间的加载才能对外服务,如果这时对外提供服务,执行结果必然无法达到预期效果,影响用户体验。比如使用 tomcat 的应用程序来说,并不是简单地说 tomcat 启动成功就可以 对外提供服务的,还需要等待 spring 容器初始化,数据库连接上等等。


目前 LivenessProbe 和 ReadinessProbe 两种探针都支持下面三种探测方法:


1、ExecAction:在容器中执行指定的命令,如果执行成功,退出码为 0 则探测成功。


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


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


探针探测结果有以下值:


1、Success:表示通过检测。


2、Failure:表示未通过检测。


3、Unknown:表示检测没有正常进行。


Pod 探针相关的属性


探针(Probe)有许多可选字段,可以用来更加精确的控制 Liveness 和 Readiness 两种探针的行为


initialDelaySeconds: Pod 启动后首次进行检查的等待时间,单位“秒”。


periodSeconds: 检查的间隔时间,默认为 10s,单位“秒”。


timeoutSeconds: 探针执行检测请求后,等待响应的超时时间,默认为 1s,单位“秒”。


successThreshold:连续探测几次成功,才认为探测成功,默认为 1,在 Liveness 探针中必须为 1,最小值为 1。


failureThreshold: 探测失败的重试次数,重试一定次数后将认为失败,在 readiness 探针中,Pod 会被标记为未就绪,默认为 3,最小值为 1


两种探针区别:


ReadinessProbe 和 livenessProbe 可以使用相同探测方式,只是对 Pod 的处置方式不同:


readinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。


livenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。


Pod 探针使用示例


1、LivenessProbe 探针使用示例


通过 exec 方式做健康探测


[root@k8smaster node]# vim liveness-exec.yaml 
apiVersion: v1
kind: Pod 
metadata: 
  name: liveness-exec
  labels:
    app: liveness
spec: 
  containers:
  - name: liveness
    image: busybox
    args: #创建测试探针探测的文件 
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe: 
      initialDelaySeconds: 10 #延迟检测时间 
      periodSeconds: 5 #检测时间间隔 
      exec:
        command:
        - cat
        - /tmp/healthy
容器启动设置执行的命令
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600" 容器在初始化后,首先创建一个 /tmp/healthy 文件,然后执行睡眠命令,睡眠 30 秒,到时间后执行删除 /tmp/healthy 文件命令。而设置的存活探针检检测方式为执行 shell 命令,用 cat 命令输出 healthy 文件的内容,如果能成功执行这条命令,存活探针就认为探测成功,否则探测失败。在前 30 秒内,由于文件存在,所以存活探针探测时执行 cat /tmp/healthy 命令成功执行。30 秒后 healthy 文件被删除,所以执行命令失败,Kubernetes 会根据 Pod 设置的重启策略来判断,是否重启 Pod。
[root@k8smaster node]# kubectl apply -f liveness-exec.yaml 
pod/liveness-exec created
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
liveness-exec           1/1     Running   0          30s
[root@k8smaster node]# kubectl exec -it liveness-exec -- /bin/sh
/ # cd /tmp/
/tmp # ls
/tmp # 
#进入容器之后发现文件被删除了
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
liveness-exec           1/1     Running   1          2m54s
#然后过一会他就重启了 rest那里是1
[root@k8smaster node]# kubectl describe pods liveness-exec
 Warning  Unhealthy  5s (x7 over 2m50s)   kubelet, k8snode2  Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
#可以在详细信息看到找不到文件


通过 HTTP 方式做健康探测


[root@k8smaster node]# vim liveness-http.yaml 
apiVersion: v1
kind: Pod 
metadata: 
  name: liveness-http 
  labels:
    app: liveness
spec: 
  containers:
  - name: liveness
    image: mydlqclub/springboot-helloworld:0.0.1
    livenessProbe: 
      initialDelaySeconds: 20 #延迟检测时间 
      periodSeconds: 5 #检测时间间隔 
      timeoutSeconds: 10  #超时时间设置 
      httpGet:
        scheme: HTTP
        port: 8081 
    path: /actuator/health
      readinessProbe:   #就绪型探测
      initialDelaySeconds: 20
      periodSeconds: 5 
      timeoutSeconds: 10 
      httpGet:
        scheme: HTTP
        port: 8081 
        path: /actuator/health
上面 Pod 中启动的容器是一个 SpringBoot 应用,其中引用了 Actuator 组件,提供了 /actuator/health 健康检查地址,存活探针可以使用 HTTPGet 方式向服务发起请求,请求 8081 端口的 /actuator/health 路径来进行存活判断。
任何大于或等于 200 且小于 400 的代码表示探测成功,任何其他代码表示失败。如果探测失败,则会杀死 Pod 进行重启操作。 
httpGet 探测方式有如下可选的控制字段: 
scheme: 用于连接 host 的协议,默认为 HTTP。 
host:要连接的主机名,默认为 Pod IP,可以在 http request head 中设置 host 头部。 
port:容器上要访问端口号或名称。 
path:http 服务器上的访问 URI。 
httpHeaders:自定义 HTTP 请求 headers,HTTP 允许重复 headers。 
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS             RESTARTS   AGE
liveness-http           1/1     Running            0          35s
[root@k8smaster node]# kubectl logs liveness-http | grep 8081
2022-07-10 19:04:19.392  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2022-07-10 19:04:19.510  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2022-07-10 19:04:37.453  INFO 1 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat-1].[localhost].[/]     : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-07-10 19:04:37.453  INFO 1 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-07-10 19:04:37.458  INFO 1 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
[root@k8smaster node]# curl http://10.244.1.7:8081/actuator/health
{"status":"UP"}
[root@k8smaster node]# curl -I http://10.244.1.7:8081/actuator/health
HTTP/1.1 200 
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 10 Jul 2022 11:08:55 GMT
#返回200状态码,启动成功!


通过 TCP 方式做健康探测


[root@k8smaster node]# vim liveness-tcp.yaml 
apiVersion: v1
kind: Pod 
metadata: 
  name: liveness-tcp 
  labels:
    app: liveness
spec: 
  containers:
  - name: liveness
    image: nginx
    livenessProbe: 
      initialDelaySeconds: 15 
      periodSeconds: 20   
    tcpSocket: 
        port: 80
TCP 检查方式和 HTTP 检查方式非常相似,在容器启动 initialDelaySeconds 参数设定的时间后,kubelet 将发送第一个 livenessProbe 探针,尝试连接容器的 80 端口,如果连接失败则将杀死 Pod 重启容器。 
[root@k8smaster node]# kubectl apply -f liveness-tcp.yaml 
pod/liveness-tcp created
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
liveness-tcp            1/1     Running   0          19s


2、ReadinessProbe 探针使用示例


Pod 的 ReadinessProbe 探针使用方式和 LivenessProbe 探针探测方法一样,也是支持三种,只是一个是用于探测应用的存活,一个是判断是否对外提供流量的条件。比如Springboot 项目,设置 ReadinessProbe 探测 SpringBoot 项目的 8081 端口下的 /actuator/health 接口,如果探测成功则代表内部程序以及启动,就开放对外提供接口访问,否则内部应用没有成功启动,暂不对外提供访问,直到就绪探针探测成功。


两个也可以一起用。


[root@k8smaster node]# vim readiness-exec.yaml 
apiVersion: v1
kind: Service
metadata:
  name: springboot 
  labels:
    app: springboot
spec:
  type: NodePort
  ports:
  - name: server 
    port: 8080
    targetPort: 8080
    nodePort: 31180
  - name: management  
    port: 8081
    targetPort: 8081
    nodePort: 31181
  selector:
    app: springboot
--- 
apiVersion: v1 
kind: Pod 
metadata: 
  name: springboot
  labels:
    app: springboot
spec: 
  containers:
  - name: springboot
    image: mydlqclub/springboot-helloworld:0.0.1
    ports: 
    - name: server
      containerPort: 8080
    - name: management
      containerPort: 8081
    readinessProbe:
      initialDelaySeconds: 20
      periodSeconds: 5
      timeoutSeconds: 10
      httpGet:
        scheme: HTTP
        port: 8081
        path: /actuator/health
[root@k8smaster node]# kubectl apply -f readiness-exec.yaml 
service/springboot created
pod/springboot created
[root@k8smaster node]# kubectl get pods -o wide | grep springboot
springboot              1/1     Running   0          42s     10.244.1.9    k8snode2


pod的启动探测


Kubernetes 的三种探针


livenessProbe:用于探测容器是否运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其重启策略的影响决定是否重启。如果容器不提供存活探针,则默认状态为 Success。


readinessProbe:一般用于探测容器内的程序是否健康,容器是否准备好服务请求。如果就绪探测失败,endpoint 将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪 状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。


startupProbe: 探测容器中的应用是否已经启动。如果提供了启动探测(startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。 如果容器没有提供启动探测,则默认状态为成功 Success。


可以自定义在 pod 启动时是否执行这些检测,如果不设置,则检测结果均默认为通过,如果设置, 则顺序为 startupProbe>readinessProbe>livenessProbe。


为什么要用 startupProbe?


在 k8s 中,通过控制器管理 pod,如果更新 pod 的时候,会创建新的 pod,删除老的 pod,但是如果新的 pod 创建了,pod 里的容器还没完成初始化,老的 pod 就被删除了,会导致访问 service 或者 ingress 时候,访问到的 pod 是有问题的,所以 k8s 就加入了一些存活性探针:livenessProbe、就绪性探针 readinessProbe 以及启动探针 startupProbe。


startupProbe 是在 k8s v1.16 加入了 alpha 版,官方对其作用的解释是: 
Indicates whether the application within the Container is started. All other probes are disabled if a startup probe is provided, until it succeeds. If the startup probe fails, the kubelet kills the Container, and the Container is subjected to its restart policy. If a Container does not provide a startup probe, the default state is Success
翻译:判断容器内的应用程序是否已启动。如果提供了启动探测,则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器将服从其重启策略。如果容器没有提供启动探测,则默认状态为成功。


注意:不要将 startupProbe 和 readinessProbe 混淆。


什么时候会用 startupProbe 呢?


正常情况下,我们会在 pod template 中配置 livenessProbe 来探测容器是否正常运行,如果异常则会触发 restartPolicy 重启容器(因为默认情况下 restartPolicy 设置的是 always)


livenessProbe: 
  httpGet: 
    path: /test 
    prot: 80 
  failureThreshold: 1 
  initialDelay:10 
  periodSeconds: 10


上面配置的意思是容器启动 10s 后每 10s 检查一次,允许失败的次数是 1 次。如果失败次数超过 1 则会触发 restartPolicy。


但是有时候会存在特殊情况,比如服务 A 启动时间很慢,需要 60s。这个时候如果还是用上面的探针就会进入死循环,因为上面的探针 10s 后就开始探测,这时候我们服务并没有起来,发现探测失败就会触发 restartPolicy。这时候有的朋友可能会想到把 initialDelay 调成 60s 不就可以了?但是我们并不能保证这个服务每次起来都是 60s,假如新的版本起来要 70s,甚至更多的时间,我们就不好控制了。有的朋友可能还会想到把失败次数增加,比如下面配置:


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


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


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


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


上面的配置是只有 startupProbe 探测成功后再交给 livenessProbe。我们 startupProbe 配置的是 10*10s,也就是说只要应用在 100s 内启动都是 OK 的,而且应用挂掉了 10s 就会发现问题。


其实这种还是不能确定具体时间,只能给出一个大概的范围。我个人认为对服务启动时间的影响因素太多了,有可能是应用本身,有可能是外部因素,比如主机性能等等。我们只有在最大程度上追求高效、 稳定,但是我们不能保证 100%稳定,所以我们自己要做好监控有效性,告警的及时性,响应的快速性,处理的高效性。


K8s 的 LivenessProbe 和 ReadinessProbe 的启动顺序问题


LivenessProbe 会导致 pod 重启,ReadinessProbe 只是不提供服务。我们最初的理解是 LivenessProbe 会在 ReadinessProbe 成功后开始检查,但事实并非如此。


kubelet 使用存活探测器来知道什么时候要重启容器。例如,存活探测器可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)。这样的情况下重启容器有助于让应用程序在有问题的情况下可用。


kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量, 当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了,这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端,在 Pod 还没有准备好的时候,会从 Service 的负载均衡器中被剔除的。


kubelet 使用启动探测器(startupProbe)可以知道应用程序容器什么时候启动了。如果配置了这类探测器,就可以控制容器在启动成功后再进行存活性和就绪检查,确保这些存活,就绪探测器不会影响应用程序的启动。这可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。


真正的启动顺序


官方文档:Caution: Liveness probes do not wait for readiness probes to succeed. If you want to wait before executing a liveness probe you should use initialDelaySeconds or a startupProbe.


也就是 Liveness probes 并不会等到 Readiness probes 成功之后才运行,根据上面的官方文档,Liveness 和 readiness 应该是某种并发的关系。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
5天前
|
运维 安全 Cloud Native
"揭秘!Trivy——云原生时代的隐形安全侠,一键扫描,让容器镜像漏洞无所遁形,守护你的云端帝国坚不可摧!"
【8月更文挑战第14天】在云原生时代,容器技术如Docker与Kubernetes大放异彩,加速了应用部署。但容器化的普及也带来了安全挑战,尤其是镜像的安全性至关重要。Trivy,一款高效且轻量级的镜像安全扫描工具应运而生,成为开发者与运维人员的得力助手。它由Aqua Security开发,支持一键式全面扫描,能快速检测镜像中的漏洞与配置风险,并提供修复建议。Trivy采用Go语言编写,轻巧高效,支持多平台,并可轻松集成到CI/CD流程中,确保只有安全的镜像才能部署到生产环境。无论新手还是专家,Trivy都是构建安全可靠云环境的理想选择。
19 2
|
1天前
|
Prometheus Kubernetes 监控
揭秘Kubernetes的秘密武器库:十大工具让你的容器编排如虎添翼!探索这些神秘而强大的工具,它们将如何彻底改变你的Kubernetes体验?
【8月更文挑战第19天】在容器世界里,Kubernetes是部署与管理容器化应用的首选平台。为了增强其功能,本文精选了十大必备工具:Helm简化复杂应用部署;Prometheus监控系统与应用指标;Grafana提供数据可视化;Fluentd统一日志管理;Envoy实现服务间通信与控制;Calico确保网络连接安全;CoreDNS提升DNS服务性能;Velero保障数据安全与迁移;Argo Workflows执行复杂工作流;Istio强化服务网格功能。这些工具覆盖部署、监控、日志等多个方面,助力提升Kubernetes的效率与稳定性。
|
5天前
|
Kubernetes 安全 Serverless
Kubernetes云原生问题之在Serverless Container中,Pod运行如何解决
Kubernetes云原生问题之在Serverless Container中,Pod运行如何解决
33 5
|
4天前
|
Cloud Native 算法 持续交付
云原生之旅:从容器到微服务
在数字化时代的浪潮中,云原生技术如同一座灯塔,指引着企业航向灵活、高效的未来。本文将深入浅出地探索云原生的核心概念,包括容器化、微服务架构以及持续集成与持续部署(CI/CD),旨在为读者揭开云原生的神秘面纱,展现其在现代软件开发中的革命性影响。通过实际案例分析,我们将一同见证云原生技术如何助力企业实现快速迭代和高弹性的IT架构。
22 2
|
5天前
|
Kubernetes Cloud Native 安全
Kubernetes云原生问题之GKE Autopilot 与现有 Kubernetes 生态的兼容度如何解决
Kubernetes云原生问题之GKE Autopilot 与现有 Kubernetes 生态的兼容度如何解决
23 4
|
5天前
|
Kubernetes Cloud Native API
Kubernetes云原生问题之Kubernetes帮助业务应用较少关注底层基础设施差异如何解决
Kubernetes云原生问题之Kubernetes帮助业务应用较少关注底层基础设施差异如何解决
20 1
|
10天前
|
运维 Cloud Native Android开发
云原生之旅:容器化与微服务架构的融合之道安卓应用开发入门指南
本文将深入探讨云原生技术的核心要素——容器化和微服务架构,并揭示它们如何共同推动现代软件的开发与部署。通过实际案例分析,我们将看到这两种技术如何相辅相成,助力企业实现敏捷、可扩展的IT基础设施。文章旨在为读者提供一条清晰的道路,指引如何在云原生时代利用这些技术构建和优化应用。 本文将引导初学者了解安卓应用开发的基本概念和步骤,从安装开发环境到编写一个简单的“Hello World”程序。通过循序渐进的讲解,让读者快速掌握安卓开发的核心技能,为进一步深入学习打下坚实基础。
19 1
|
1天前
|
人工智能 Kubernetes 持续交付
Kubernetes环境下基于微服务架构的容器化AI应用部署与管理最佳实践
【8月更文第19天】随着AI技术的快速发展,越来越多的企业开始将AI应用部署到生产环境。然而,AI应用往往包含大量的组件和服务,这使得其部署和管理变得非常复杂。微服务架构和容器化技术(如Docker)结合Kubernetes集群管理,为解决这些问题提供了强大的工具。本文将介绍如何在Kubernetes环境中部署和管理基于微服务架构的容器化AI应用。
4 0
|
5天前
|
Kubernetes Cloud Native Devops
云原生之旅:从容器化到微服务的实践之路
随着云计算时代的深入发展,传统的软件开发与部署模式已逐渐不能满足现代业务的需求。云原生技术以其灵活性、可扩展性和高效率成为新的发展方向。本文将通过浅显易懂的语言,带领读者一探云原生世界的大门,从容器化技术的起步,到微服务架构的构建,再到DevOps文化的融入,逐步揭示云原生技术如何助力企业快速迭代和高效运维。无论你是云原生领域的新手,还是希望深化理解的开发者,这篇文章都将为你提供有价值的信息和启示。
11 0
|
5天前
|
运维 Kubernetes Cloud Native
Kubernetes云原生问题之GKE Autopilot 进行扩容和缩容如何解决
Kubernetes云原生问题之GKE Autopilot 进行扩容和缩容如何解决
25 0

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多