HealthCheck 不只是對應用程序內運行狀況、數據流通狀況進行檢查, 還包括應用程序對外部服務或依賴資源的健康檢查。前端
健康檢查一般是以暴露應用程序的HTTP端點的形式 實施,可用於配置健康探測的的場景有 :git
① 容器或負載均衡器 探測應用狀態,執行既定策略,例如:容器探測到應用unhealthy可終止後續的滾動部署或者重啓容器;負載均衡器探測到實例unhealthy能將請求路由到健康的運行實例。github
② 對應用程序種依賴的第三方服務進行健康探測,好比redis、database、外部服務接口 web
③ 內存、硬盤、網絡等物理依賴資源的探測redis
HealthCheck提供對外暴露程序運行狀態的機制。sql
通常狀況下咱們很容易知道容器正在運行[running], 但容器做爲相對獨立的應用執行環境,有時候並不知道容器是否以預期的方式正確運做[working]docker
Dockerfile HEALTHCHECK指令提供了探測容器以預期工做的輪詢機制,輪詢內容可由應用自身決定。shell
經過在容器內運行shell命令來探測容器健康狀態,Dockerfile以command的退出碼錶示容器健康狀態:json
0 指示容器健康api
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
// 容器每隔5min請求web程序的http://localhost(重試3次)
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程序的健康檢查能力。
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項目物理資源和服務依賴的健康檢查需求, 這裏咱們爲避免重複造輪子,引入了開源的力量。
開源的企業級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
使用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\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r100 206 0 206 0 0 12030 0 --:--:-- --:--:-- --:--:-- 12875\n{\"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\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r100 206 0 206 0 0 14312 0 --:--:-- --:--:-- --:--:-- 14714\n{\"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\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r100 206 0 206 0 0 14001 0 --:--:-- --:--:-- --:--:-- 14714\n{\"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\"}}}"
}
]
}
},
......
拋開Docker的HEALTHCHECK指令、負載均衡器的輪詢機制不談,咱們的Web自身也能夠進行 輪詢健康檢查並給出告警。
就咱們上面的Web 實例來講,咱們只對外提供的是一個 /healthcheck 檢查端點,引入HealthChecks.UI.dll 將會在前端生成友好的HealthReport 界面, 該庫支持後臺輪詢檢查、支持webhook 通知。
這裏就不展開說明,自行前往AspNetCore.Diagnostics.HealthChecks查看相應文檔,效果以下:
至此,本文內容完畢:
- 使用ASP.NETCore 框架實現一個稍複雜的HealthCheck端點 /healthz
- 使用docker的HEALTHCHECK 指令對接Web程序健康檢查端點
(完成以上步驟,爲實現容器自愈打下基礎, 請關注後續博文)
碼甲拙見,若有問題請下方留言大膽斧正;碼字+Visio製圖,均爲原創,看官請不吝好評+關注, ~。。~
本文歡迎轉載,請轉載頁面明顯位置註明原做者及原文連接。