1. 程式人生 > >容器HEALTHCHECK指令對接ASP.NETCore健康檢查能力

容器HEALTHCHECK指令對接ASP.NETCore健康檢查能力

diag cmd 命令 host 所有 技術 rest yml ddr

技術分享圖片 寫在前面

HealthCheck 不僅是對應用程序內運行情況、數據流通情況進行檢查, 還包括應用程序對外部服務或依賴資源的健康檢查。

健康檢查通常是以暴露應用程序的HTTP端點的形式 實施,可用於配置健康探測的的場景有 :

  • 容器或負載均衡時 探測應用的狀態, 例如:容器探測到應用unhealthy可 終止後續的滾動部署或者重啟容器;負載均衡器探測到實例healthyunt能將請求路由到健康的運行實例。

  • 對應用程序種依賴的第三方服務進行健康探測,比如redis、database、外部服務接口

  • 內存、硬盤、網絡等物理依賴資源的探測

HealthCheck提供一種 告知外部應用運行狀態的機制

容器HEALTHCHECK指令

  一般情況下我們很容易知道容器正在運行[running], 但容器作為相對獨立的應用執行環境,有時候並不知道容器是否以預期的方式正確運作[working]

Dockerfile/ docker-compose.yml文件提供的 HEALTHCHECK指令提供了探測容器正確工作的輪訓機制,輪訓內容可由應用自身決定。

該指令定義輪詢參數interval、探測超時參數timeout、 重試參數retries 進行不間斷探測容器:

// 通過在容器內運行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枚舉字符串

③ 將每次健康檢查的結果寫入HealthReport對象。

作為企業級項目,存在對Web項目物理資源和服務依賴的健康檢查需求, 這裏我們為避免重復造輪子,引入了開源的力量。

技術分享圖片 開源社區對HealthCheck的支持

 開源的企業級AspNetCore.Diagnostics.HealthChecks系列組件,該系列組件支持多種物理資源和服務依賴的健康檢查,支持報告推送,支持友好的檢查報告UI(支持後臺輪訓檢查)、支持webhook通知。

下面的步驟演示了對web程序HTTP請求、Redis、Sqlite等服務進行健康檢查的端點配置

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

② startup中配置並啟用健康檢查

// 以下代碼截取自 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,包含所有檢查項的詳細檢查結果
                });

註意

 上文在Dockerfile中配置的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        Up 24 hours (healthy)   80/tcp               eqidmanager_app_1

容器HEALTHCHECK指令對接ASP.NETCore健康檢查能力