本篇已加入《.NET Core on K8S学习实践系列文章索引》,可以点击查看更多容器化技术相关系列文章。

一、关于K8S中的Health Check

  所谓Health Check,就是健康检查,即防微杜渐。K8S是一个编排引擎可以帮助我们快捷地部署容器集群,如果部署上错误的容器导致服务崩溃,通常情况下我们都会通过一些高可用机制进行故障转移。但是,前提条件是有健康检查。

  K8S自然帮我们考虑到了这个问题,健康检查是K8S的重要特性之一,默认有健康检查机制,此外还可以主动设置一些自定义的健康检查。

  默认情况下,每个容器启动时都会执行一个进程,由Dockerfile中的CMD或ENTRYPOINT指定。如果进程退出时的返回码不为0,则认为容器发生了故障,K8S会根据重启策略(restartPolicy)重启容器。

  例如下面这个例子,它模拟了容器发生故障的场景,注意下面配置文件中的args选项的定义:

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: edc-healthcheck-demo
  5. labels:
  6. test: healthcheck
  7. spec:
  8. restartPolicy: OnFailure
  9. containers:
  10. - name: healthcheck
  11. image: busybox
  12. imagePullPolicy: IfNotPresent
  13. args:
  14. - /bin/sh
  15. - -c
  16. - sleep ; exit

  其中 sleep 10; exit 1代表启动10秒之后就非正常退出(返回码不为0),然后通过kubectl创建Pod:

  1. kubectl apply -f health-check.yaml

  过一段时间后查看Pod的状态,如下图所示:

  

  可以看到,该容器已经重启了2次。也可以看出,restartPolicy简单直接暴力有效,不由感叹重启大法好!

  但是,也要正视一个问题:必须等到进程退出后的返回值是非零才会触发重启策略,不能直接监测容器是否是健康

  那么,K8S中有没有更好的机制能够实现智能一点的健康检查呢?答案就是使用Liveness与Readinesss。

二、Liveness探测

2.1 Liveness初体验

一句话Liveness:如果检测有问题(如果健康检查失败),重启pod!至于怎么检测,你说了算(自定义判断容器是否健康的条件)!  

  Liveness提供了一些重要的参数:

  1. initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒,看运行的服务而定。
  2. periodSeconds:执行探测的频率,默认是10秒,最小1秒。
  3. timeoutSeconds:探测超时时间,默认1秒,最小1秒。
  4. successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功,默认是1,对于liveness必须是1,最小值是1
  5. failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1.

  下面实践一个小例子创建一个Pod:

  1. #command自己定义,例子为 /tmp/healthy 不存在则认为pod有问题,大家根据实际业务来自定义。
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. labels:
  6. test: liveness
  7. name: liveness-demo
  8. spec:
  9. containers:
  10. - name: liveness
  11. image: busybox
  12. args:
  13. - /bin/sh
  14. - -c
  15. - touch /tmp/healthy; sleep ; rm -rf/tmp/healthy; sleep
  16. livenessProbe:
  17. exec:
  18. command:
  19. - cat
  20. - /tmp/healthy
  21. initialDelaySeconds:
  22. periodSeconds:

  这里启动pod后会创建文件夹 /tmp/healthy,30秒后删除,在我们的设置中,如果 /tmp/healthy 存在,则认为容器处于正常状态,否则认为发生故障。

  需要注意的就是livenessProbe部分的定义了:

  (1)探测方法:通过cat命令查看/tmp/healthy是否存在;如果返回值为0,则探测成功;否则,探测失败;

  (2)initialDelaySeconds: 10 => 容器启动10秒之后开始执行liveness探测;

  (3)periodSeconds: 5 => 每5秒执行一次liveness探测;如果连续执行3次探测都失败,那么就会杀掉并重启容器;

  下面快速地验证一下:

  (1)kubectl创建demo

  1. kubectl apply -f liveness-demo.yaml

  (2)查看pod日志

  1. kubectl describe pod liveness-demo

  结果如下图所示:

  

  30秒之后,/tmp/healthy 被删除了,liveness探测失败,又过了几十秒,重复探测均失败后,开启了重启容器。

  

2.2 Liveness探针

  上面的例子使用的是Liveness的exec探针,此外K8S还有几种其他类型的探针:

  • exec:在容器中执行一个命令,如果命令退出码返回0则表示探测成功,否则表示失败
  • tcpSocket:对指定的容IP及端口执行一个TCP检查,如果端口是开放的则表示探测成功,否则表示失败
  • httpGet:对指定的容器IP、端口及路径执行一个HTTP Get请求,如果返回的状态码在 [200,400)之间则表示探测成功,否则表示失败

  针对tcpSocket的例子:这里会检测80端口是否可以正常访问;

  1. #检测80端口是否联通
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. labels:
  6. test: readiness
  7. name: readiness-tcp
  8. spec:
  9. containers:
  10. - name: readiness
  11. image: nginx
  12. readinessProbe:
  13. failureThreshold:
  14. tcpSocket:
  15. port:
  16. initialDelaySeconds:
  17. periodSeconds:
  18. successThreshold:
  19. timeoutSeconds:

  针对httpGet的例子:这里会检测index.html文件是否可以正常访问;

  1. #访问80端口的index.html文件是否存在
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. labels:
  6. test: readiness
  7. name: readiness-httpget
  8. spec:
  9. containers:
  10. - name: readiness
  11. image: nginx
  12. readinessProbe:
  13. failureThreshold:
  14. httpGet:
  15. path: /index.html
  16. port:
  17. scheme: HTTP
  18. initialDelaySeconds:
  19. periodSeconds:
  20. successThreshold:
  21. timeoutSeconds:

三、Readiness探测

3.1 Readiness初体验

一句话Readiness:如果检查失败,K8S会将该Pod从服务代理的分发后端去除,不再让其接客(分发请求给该Pod)。如果检测成功,那么K8S就会将容器加入到分发后端,重新对外接客(对外提供服务)。  

  下面继续以上面Liveness的例子来实践一下:

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. labels:
  5. test: readiness
  6. name: readiness-demo
  7. spec:
  8. containers:
  9. - name: readiness
  10. image: busybox
  11. args:
  12. - /bin/sh
  13. - -c
  14. - touch /tmp/healthy; sleep ; rm -rf/tmp/healthy; sleep
  15. readinessProbe:
  16. exec:
  17. command:
  18. - cat
  19. - /tmp/healthy
  20. initialDelaySeconds:
  21. periodSeconds:

  readinessProbe的配置语法与livenessProbe完全一致,但执行后的效果却不一样,见下图所示:

  

  可以看出:

  (1)刚被创建时,其READY状态为不可用;

  (2)15秒(initialDelaySeconds + periodSeconds = 10 + 5 = 15)之后,第一次进行Readiness探测成功,其READY状态变为可用。

  (3)30秒之后,/tmp/healthy被删除,连续3次Readiness探测均失败后,其READY状态又变为了不可用。

  此外,我们也可以通过 kubectl describe pod readiness-demo 查看到更想起的日志信息。

3.2 与Liveness的对比

  Liveness与Readiness都是K8S的Health Check机制,Liveness探测是重启容器,而Readiness探测则是将容器设置为不可用,不让其再接受Service转发的请求。

  Liveness与Readiness是独立执行的,二者无依赖,可以单独使用也可以同时使用。

四、Health Check在K8S中的应用

4.1 在Scale Up中的应用

  对于多副本应用,当执行Scale Up操作时,新的副本会作为后端服务加入到Service的负载均衡列表中。但是,很多时候应用的启动都需要一定的时间做准备(比如加载缓存、连接数据库等等),这时我们可以通过Readiness探测判断容器是否真正就绪,从而避免将请求发送到还未真正就绪的后端服务。

  下面一个示例YAML配置文件定义了Readiness探测,重点关注readinessProbe部分:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: edc-webapi-deployment
  5. namespace: aspnetcore
  6. spec:
  7. replicas:
  8. selector:
  9. matchLabels:
  10. name: edc-webapi
  11. template:
  12. metadata:
  13. labels:
  14. name: edc-webapi
  15. spec:
  16. containers:
  17. - name: edc-webapi-container
  18. image: edisonsaonian/k8s-demo:1.2
  19. ports:
  20. - containerPort:
  21. imagePullPolicy: IfNotPresent
  22. readinessProbe:
  23. httpGet:
  24. scheme: HTTP
  25. path: /api/health
  26. port:
  27. initialDelaySeconds:
  28. periodSeconds:
  29.  
  30. ---
  31.  
  32. apiVersion: v1
  33. kind: Service
  34. metadata:
  35. name: edc-webapi-service
  36. namespace: aspnetcore
  37. spec:
  38. type: NodePort
  39. ports:
  40. - nodePort:
  41. port:
  42. targetPort:
  43. selector:
  44. name: edc-webapi

  对于readinessProbe部分:

  (1)schema指定了协议,这里是HTTP协议,也可以是HTTPS协议;

  (2)path指定访问路径,这里是我们自定义的一个Controller中的接口:简单地返回一个状态码为200的响应;

  1. [Produces("application/json")]
  2. [Route("api/Health")]
  3. public class HealthController : Controller
  4. {
  5. [HttpGet]
  6. public IActionResult Get() => Ok("ok");
  7. }

  (3)port指定端口,这里是容器的端口80;

  (4)initialDelaySeconds和periodSeconds指定了容器启动10秒之后开始探测,然后每隔5秒执行探测,如果发生3次以上探测失败,则该容器会从Service的负载均衡中移除,直到下次探测成功后才会重新加入。

4.2 在Rolling Update中的应用

  假设现在有一个正常运行的多副本应用,我们要对其进行滚动更新即Rolling Update,K8S会逐步用新Pod替换旧Pod,结果就有可能发生这样的一个场景:当所有旧副本被替换之后,而新的Pod由于人为配置错误一直无法启动,因此整个应用将无法处理请求,无法对外提供服务,后果很严重!

  因此,Readiness探测还提供了用于避免滚动更新中出现这种情况的一些解决办法,比如maxSurge和maxUnavailable两个参数,用来控制副本替换的数量。

  继续以上面的YAML配置文件为例,重点关注strategy部分:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: edc-webapi-deployment
  5. namespace: aspnetcore
  6. spec:
  7. strategy:
  8. rollingupdate:
  9. maxSurge: %
  10. maxUnavailable: %
  11. replicas:
  12. selector:
  13. matchLabels:
  14. name: edc-webapi
  15. template:
  16. metadata:
  17. labels:
  18. name: edc-webapi
  19. spec:
  20. containers:
  21. - name: edc-webapi-container
  22. image: edisonsaonian/k8s-demo:1.2
  23. ports:
  24. - containerPort:
  25. imagePullPolicy: IfNotPresent
  26. readinessProbe:
  27. httpGet:
  28. scheme: HTTP
  29. path: /api/health
  30. port:
  31. initialDelaySeconds:
  32. periodSeconds:
  33.  
  34. ---
  35.  
  36. apiVersion: v1
  37. kind: Service
  38. metadata:
  39. name: edc-webapi-service
  40. namespace: aspnetcore
  41. spec:
  42. type: NodePort
  43. ports:
  44. - nodePort:
  45. port:
  46. targetPort:
  47. selector:
  48. name: edc-webapi

  (1)maxSurge : 25% => 控制滚动更新过程中副本总数超过预期(这里预期是10个副本 replicas: 10)的上限,可以是数值也可以是百分比,然后向上取整。这里写的百分比,默认值是25%;

  如果预期副本数为10,那么副本总数的最大值为RoundUp(10 + 10 * 25%)=13个。

  (2)maxUnavailable : 25% => 控制滚动更新过程中不可用的副本(这里预期是10个副本 replicas: 10)占预期的最大比例,可以是数值也可以是百分比,然后向下取整,同样地默认值也是25%;

  如果预期副本总数为10,那么可用的副本数至少要为10-roundDown(10 * 25%)=10-2=8个。

  综上看来,maxSurge的值越大,初始创建的新副本数量就越多;maxUnavaliable值越大,初始销毁的旧副本数量就越多;

五、小结

  本文探索了K8S中的默认健康检查机制以及Liveness和Readiness两种各有特点的探测机制,并通过一些小例子进行了说明。不过由于笔者也是初学,对于这一块没有过多实践经验,因此也是讲的比较粗浅,也希望以后能够有更多的实际经验分享与各位。

参考资料

(1)CloudMan,《每天5分钟玩转Kubernetes

(2)李振良,《一天入门Kubernets教程

(3)马哥(马永亮),《Kubernetes快速入门

(4)华仔,《[译]Kubernetes最佳实践:使用Readiness和Liveness探测做Health Check

(5)benjanmin杨,《K8S中的Health Check

(6)条子在洗澡,《K8S健康性检查-探测

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

ASP.NET Core on K8S深入学习(6)Health Check的更多相关文章

  1. ASP.NET Core on K8S深入学习(7)Dashboard知多少

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 在第二篇<部署过程解析与Dashboard>中介绍了如何部署Das ...

  2. ASP.NET Core on K8S 入门学习系列文章目录

    一.关于这个系列 自从2018年底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发现运维工 ...

  3. ASP.NET Core on K8S深入学习(1)K8S基础知识与集群搭建

    在上一个小系列文章<ASP.NET Core on K8S学习初探>中,通过在Windows上通过Docker for Windows搭建了一个单节点的K8S环境,并初步尝试将ASP.NE ...

  4. ASP.NET Core on K8S深入学习(2)部署过程解析与Dashboard

    上一篇<K8S集群部署>中搭建好了一个最小化的K8S集群,这一篇我们来部署一个ASP.NET Core WebAPI项目来介绍一下整个部署过程的运行机制,然后部署一下Dashboard,完 ...

  5. ASP.NET Core on K8S深入学习(3)Deployment

    上一篇<部署过程解析与安装Dashboard>中我们了解K8S的部署过程,这一篇我们来了解一下K8S为我们提供的几种应用运行方式:Deployment.DaemonSet与Job,它们是K ...

  6. ASP.NET Core on K8S深入学习(4)你必须知道的Service

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 前面几篇文章我们都是使用的ClusterIP供集群内部访问,每个Pod都有一个 ...

  7. ASP.NET Core on K8S深入学习(5)Rolling Update

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.什么是Rolling Update? 为了服务升级过程中提供可持续的不中断 ...

  8. ASP.NET Core on K8S深入学习(9)Secret & Configmap

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.Secret 1.1 关于Secret 在应用启动过程中需要一些敏感信息, ...

  9. ASP.NET Core on K8S深入学习(10)K8S包管理器Helm

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.关于Helm 1.1 为何需要Helm? 虽然K8S能够很好地组织和编排容 ...

  10. ASP.NET Core on K8S深入学习(8)数据管理

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 在Docker中我们知道,要想实现数据的持久化(所谓Docker的数据持久化即 ...

随机推荐

  1. org json 和 fast json 掺杂使用引起的错误

    1. 取值的不同 当所取得key不存在时: org json 会抛异常 fast json 会返回null 示例: com.alibaba.fastjson.JSONObject fastJson = ...

  2. 6种微服务RPC框架,你知道几个?

    开源 RPC 框架有哪些呢? 一类是跟某种特定语言平台绑定的,另一类是与语言无关即跨语言平台的. 跟语言平台绑定的开源 RPC 框架主要有下面几种. Dubbo:国内最早开源的 RPC 框架,由阿里巴 ...

  3. 《Dotnet9》系列-开源C# WPF控件库强力推荐

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  4. 比较typeof与instanceof

    相同点: JavaScript中typeof和instanceof常用来判断一个变量是否为空,或者是什么类型的. 不同点: typeof的定义和用法: 返回值是一个字符串,用来说明变量的数据类型. 细 ...

  5. 【高可用架构】用Nginx实现负载均衡(三)

    前言 在上一篇,已经用Envoy工具统一发布了Deploy项目代码.本篇我们来看看如何用nginx实现负载均衡 负载均衡器IP 192.168.10.11 [高可用架构]系列链接:待部署的架构介绍 演 ...

  6. 开源框架 openFrameworks

    转自:https://www.cnblogs.com/lidabo/p/9134174.html 此处仅供学习,版权属原作者: 作为一个图形图像方向的研究生,我经常都在和 OpenGL .OpenCV ...

  7. vue 中 px转vw的用法

    下面介绍最简单的用法 1 下载依赖 npm install postcss-import postcss-loader postcss-px-to-viewport --save-dev 2 在项目根 ...

  8. Android 再次打开APP进入按Home键退出时的界面(thisTaskRoot)

    问题 Android 设置页面的启动模式为 singletask 之后,当按Home 退出时,再重新打开应用,还会进入首启动页.就会造成一些应用需要重新登录,当前页数据丢失等问题 解决 去除启动页的 ...

  9. deinit 没执行

    写了一个自定义的UIView,其中包含代理       然后设置UIViewController为此UIView的代理       结果UIViewController里的deinit没执行,导致内存 ...

  10. Python—类和实例对象

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...