写在前面

         HealthCheck 不仅是对应用程序内运行情况、数据流通情况进行检查, 还包括应用程序对外部服务或依赖资源的健康检查。

健康检查通常是以暴露应用程序的HTTP端点的形式 实施,可用于配置健康探测的的场景有 :

*
容器或负载均衡器 探测应用状态,执行既定策略,例如:容器探测到应用unhealthy可终止后续的滚动部署或者重启容器
;负载均衡器探测到实例unhealthy能将请求路由到健康的运行实例。

*
对应用程序种依赖的第三方服务进行健康探测,比如redis、database、外部服务接口

*
内存、硬盘、网络等物理依赖资源的探测

HealthCheck提供一种 告知外部应用运行状态的机制。

 

容器HEALTHCHECK指令

  一般情况下我们很容易知道容器正在运行[running], 但容器作为相对独立的应用执行环境,有时候并不知道容器是否以预期的方式正确运作[working]

Dockerfile文件提供的 HEALTHCHECK指令提供了探测容器正确工作的轮询机制,轮询内容可由应用自身决定。

该指令定义轮询参数interval、探测超时参数timeout、 重试参数retries 进行不间断探测容器,(docker-compose.yml
也有相应的配置节完成 HealthCheck)
// 通过在容器内运行shell命令来探测容器健康状态, 命令返回值0表示容器healthy, 命令返回值1表示unhealthy EALTHCHECK
[OPTIONS] CMD command

对于容器内Web应用,自然而然会想到使用暴露HTTP端点的方式去探测,并将error response认定为unhealthy
// 容器每隔5min请求应用程序的http://localhost(重试3次),成功响应则返回0,错误响应则返回1 HEALTHCHECK
--interval=5m --timeout=3s --retries=3 CMD curl -f http://localhost:5000/healthz
|| exit 1
下面我们会将渐进式演示 使用Docker平台的HEALTHCHECK指令对接 ASP.NET Core程序的健康检查能力。

 

 ASP.NET Core 实现HealthCheck端点

  ASPNET Core在2.2版本内置了健康检查的能力, 使用的是一个HealthCheck Middleware,
该中间件是一个终端中间件,满足该路径的url请求,将会被该中间件处理。
public void ConfigureServices(IServiceCollection services) {
services.AddHealthChecks(); }public void Configure(IApplicationBuilder app,
IHostingEnvironment env) { app.UseHealthChecks("/healthcheck"); }
  请求/healthcheck端点, 程序会进行健康检查逻辑并响应输出, 默认的行为:

     ① 对healthy、degraded状态返回200 OK 响应码; 对于unhealthy返回503 Service
Unavailable 响应码

     ② 响应体只会包含简单的HealthStatus
<https://docs.microsoft.com/dotnet/api/microsoft.extensions.diagnostics.healthchecks.healthstatus>
枚举字符串

     ③ 将每次健康检查的结果写入HealthReport对象。

   作为企业级项目,存在对Web项目物理资源和服务依赖的健康检查需求, 这里我们为避免重复造轮子,引入了开源的力量。

 

 开源社区对HealthCheck的支持

 开源的企业级AspNetCore.Diagnostics.HealthChecks
<https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks>
系列组件,该系列组件支持多种物理资源和服务依赖的健康检查,支持报告推送,支持友好的检查报告UI(支持后台轮训检查)、支持webhook通知。

下面的步骤演示了对web程序HTTP请求、Redis、Sqlite等服务进行健康检查的端点配置

    ① 引入AspNetCore.HealthChecks.Redis 、 AspNetCore.HealthChecks.Sqlite nuget库

    ② Startup.cs配置并启用健康检查
// 以下代码截取自 Startup.ConfigureServices方法,对swagger服务地址、redis、sqlte进行健康检查
services.AddHealthChecks().AddAsyncCheck("Http", async () => { using
(HttpClient client =new HttpClient()) { try { var response = await
client.GetAsync("http://localhost:5000/swagger"); if (!
response.IsSuccessStatusCode) {throw new Exception("Url not responding with 200
OK"); } } catch (Exception) { return await
Task.FromResult(HealthCheckResult.Unhealthy()); } }return await
Task.FromResult(HealthCheckResult.Healthy()); }) .AddSqlite(
sqliteConnectionString: Configuration.GetConnectionString("sqlite"),
healthQuery:"select count(*) as count from ProfileUsageCounters;", name: "sqlite
", failureStatus: HealthStatus.Degraded, tags: new string[] { "db", "sqlite", "
sqlite" } ) .AddRedis(Configuration.GetConnectionString("redis"), "redis",
HealthStatus.Unhealthy,new string[] { "redis", "redis" }) .Services .AddMvc();
// 以下代码截取自Startup.Configure方法: 启用/healthz作为检查端点 app.UseHealthChecks("/healthz"
).UseMvcWithDefaultRoute(); //这里仍然只会响应 200/503状态码+简单的HealthStatus枚举值
     小技巧:你也可以使用UseHealthChecks()扩展方法修改默认的响应输出, 这里我们可引入HealthChecks.UI.Client
nuget package输出更加详细的的HealthReport
app.UseHealthChecks("/healthz", new HealthCheckOptions() { Predicate = _ =>
true, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse //
该响应输出是一个json,包含所有检查项的详细检查结果 });
注意

    上文配置的HEALTHCHECK 指令: 

       HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMD curl -f
http://localhost:5000/healthz || exit 1

      并不关注响应体输出,依然对于success response 返回0, error response返回1。

    

 测试容器的HEALTHCHECK输出

    使用docker ps命令可查看容器的状态, 通过docker inspect [container_id] 查看容器HealthCheck的输出
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0111ea10581f
eqidmanager_proxy"nginx -g 'daemon ..." 24 hours ago Up 24 hours 0.0.0.0:80->80/
tcp eqidmanager_proxy_1 8e96a0e8b993 eqidmanager_app"dotnet EqidManage..." 24
hours ago Up24 hours (healthy) 80/tcp eqidmanager_app_1
   容器在启动的时候是starting, 一旦监测到成功的响应状态码,将会转换为healthy 并将会持续轮询检查。

 

 附加知识点

   抛开Docker的HEALTHCHECK指令、负载均衡器的轮询机制不谈,我们的Web自身也可以进行 轮询健康检查并给出告警。

就我们上面的Web 实例来说,我们只对外提供的是一个 /healthcheck 检查端点,引入HealthChecks.UI.dll
将会在前端生成友好的HealthReport 界面, 该库支持后台轮询检查、支持webhook 通知。

这里就不展开说明,自行前往AspNetCore.Diagnostics.HealthChecks
<https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks>查看相应文档,效果如下:

 

至此,本文内容完毕:

   -  使用ASP.NETCore 框架实现一个稍复杂的HealthCheck端点 /healthz

    - 使用docker的HEALTHCHECK 指令对接Web程序健康检查端点

(完成以上步骤,为实现容器自愈打下基础, 请关注后续博文)

 
作者:JulianHuang <https://www.cnblogs.com/JulianHuang/>
<https://www.cnblogs.com/myzony/>
感谢您的认真阅读,如有问题请大胆斧正;觉得有用,请下方或加关注。

本文欢迎转载,但请保留此段声明,且在文章页面明显位置注明本文的作者及原文链接。

 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信