zoukankan      html  css  js  c++  java
  • Docker-HealthCheck指令探测ASP.NET Core容器健康状态

    写在前面

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

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

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

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

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

    HealthCheck提供对外暴露程序运行状态的机制

    容器HEALTHCHECK指令

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

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

    通过在容器内运行shell命令来探测容器健康状态,Dockerfile以command的退出码表示容器健康状态

      0 指示容器健康

           1 指示容器不健康

           2 指示不使用这个退出码   

    (docker-compose.yml 也有相应的配置节完成HealthCheck)
    // 可定义轮询interval、探测超时timeout、 重试retries参数轮训探测
    HEALTHCHECK [OPTIONS] CMD command  

    Every Linux or Unix command executed by the shell script or user has an exit status. Exit status is an integer number. 0 exit status means the command was successful without any errors. A non-zero (1-255 values) exit status means command was a failure.  传送门

    故为方便对接Docker- HealcthCheck,以上CMD之后我们一般都接 || exit 1

    对于容器内Web应用,自然而然会联想到 使用端点访问的形式去探测容器应用: 应用端点返回成功对应返回0 ;返回失败对应返回1

    // shell将成功的退出状态(0)映射为真,任何失败退出/非0都映射为假, 这样做可以有条件的执行链接shell命令  http://www.dovov.com/0shelltruefalse1.html
    HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMD (curl -f http://localhost:5000/healthz) || exit 1

    探测命令在stdout或stderr 输出的任何内容 会在 容器Health Status中存储,可通过docker inspect [ContainerId] 查看HealthCheck状态节点。

    下面我们会将渐进式演示使用Docker平台的HEALTHCHECK指令对接 ASP.NET Core程序的健康检查能力。

     

    实现AspNetCore HealthCheck端点

      ASPNET Core在2.2版本内置了健康检查的能力: 终端中间件(满足该路径的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枚举字符串

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

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

    开源社区对HealthCheck的支持

     开源的企业级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指令不关注响应体, 只关注CMD命令的执行结果: 0  表示容器健康, 1 表示容器不健康, 所以不管以何种CMD ,我们都需要将CMD的结果转换为 0,1 

    ps: docker-compose.yml 文件中可参考如下配置:

       healthcheck:
          test: curl -u huangjun:Iampossword -f http://localhost/healthcheck || exit 1    # -u 指定了用于基本身份验证的用户名和密码
          interval: 1m30s
          timeout: 10s
          retries: 3

    容器HEALTHCHECK指令输出

        使用docker ps命令可查看容器的状态, 通过docker inspect [container_id] 查看容器HealthCheck的输出,容器启动输出:starting,一旦监测到成功的响应状态码,将会转换为healthy 并将会持续轮询检查。

    //---------截取自 docker inspect 【containerid】 输出--------------------------------

    "State": {
    "Status": "running",
    "Running": true,
    "Paused": false,
    "Restarting": false,
    "OOMKilled": false,
    "Dead": false,
    "Pid": 2645,
    "ExitCode": 0,
    "Error": "",
    "StartedAt": "2019-09-29T04:04:42.395037744Z",
    "FinishedAt": "0001-01-01T00:00:00Z",
    "Health": {
    "Status": "healthy",
    "FailingStreak": 0,
    "Log": [
    {
    "Start": "2019-09-29T12:06:12.400153719+08:00",
    "End": "2019-09-29T12:06:12.478927574+08:00",
    "ExitCode": 0,
    "Output": " % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 206 0 206 0 0 12030 0 --:--:-- --:--:-- --:--:-- 12875 {"status":"Healthy","totalDuration":"00:00:00.0080008","entries":{"sqlite":{"data":{},"duration":"00:00:00.0075454","status":"Healthy"},"redis":{"data":{},"duration":"00:00:00.0003594","status":"Healthy"}}}"
    },
    {
    "Start": "2019-09-29T12:07:42.479160725+08:00",
    "End": "2019-09-29T12:07:42.538163351+08:00",
    "ExitCode": 0,
    "Output": " % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 206 0 206 0 0 14312 0 --:--:-- --:--:-- --:--:-- 14714 {"status":"Healthy","totalDuration":"00:00:00.0081428","entries":{"sqlite":{"data":{},"duration":"00:00:00.0077286","status":"Healthy"},"redis":{"data":{},"duration":"00:00:00.0003531","status":"Healthy"}}}"
    },
    {
    "Start": "2019-09-29T12:09:12.53837533+08:00",
    "End": "2019-09-29T12:09:12.596907251+08:00",
    "ExitCode": 0,
    "Output": " % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 206 0 206 0 0 14001 0 --:--:-- --:--:-- --:--:-- 14714 {"status":"Healthy","totalDuration":"00:00:00.0085169","entries":{"sqlite":{"data":{},"duration":"00:00:00.0080190","status":"Healthy"},"redis":{"data":{},"duration":"00:00:00.0004430","status":"Healthy"}}}"
    }
    ]
    }
    },

    ......

    HealthChecks-UI 了解一下

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

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

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

    至此,本文内容完毕:

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

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

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

    +  linux shell 指令: http://www.dovov.com/0shelltruefalse1.html

    作者:JulianHuang

    码甲拙见,如有问题请下方留言大胆斧正;码字+Visio制图,均为原创,看官请不吝好评+关注,  ~。。~

    本文欢迎转载,请转载页面明显位置注明原作者及原文链接

     
  • 相关阅读:
    Bootstrip的相关介绍
    Django的ORM主外键约束实现
    Django基于ORM数据库配置
    Django的安装与配置
    ORM(关系对象映射)框架之面向对象
    pymysql模块的数据操作
    SQL语句实践
    mysql 数据库的基本操作语法
    算法训练 矩阵乘法
    算法训练 字串统计
  • 原文地址:https://www.cnblogs.com/JulianHuang/p/10837804.html
Copyright © 2011-2022 走看看