.NET Core Worker Service如何在不使用HTTP的情况下提供健康检查端点?
可行方案总览
有两种成熟方案满足需求,均不需要引入ASP.NET Core HTTP服务器组件,完全复用.NET标准健康检查生态,开销极低,分别适配K8s的命令探针和TCP探针。
方案1:适配K8s命令探针(推荐,开销最低)
原理是给程序增加专用健康检查启动参数,触发时不启动Worker服务,直接调用健康检查逻辑,用进程退出码标识健康状态,K8s exec探针直接执行该命令即可。
实现步骤
- 安装核心依赖包(不需要ASP.NET Core相关健康检查包):
Install-Package Microsoft.Extensions.Diagnostics.HealthChecks - 调整
Program.cs逻辑,区分正常启动和健康检查模式:using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { // 注册你自己的队列消费Worker服务 services.AddHostedService<QueueConsumerWorker>(); // 注册标准健康检查,可添加任意自定义检查逻辑 services.AddHealthChecks() // 示例:队列连接检查、磁盘空间检查,支持标签分类 .AddCheck<QueueConnectionHealthCheck>("queue_conn", tags: new[] { "liveness", "readiness" }) .AddCheck<DiskSpaceHealthCheck>("disk_space", tags: new[] { "readiness" }); }) .Build(); // 健康检查模式 if (args.Length > 0 && args[0] == "--health-check") { var healthCheckService = host.Services.GetRequiredService<HealthCheckService>(); // 可根据标签过滤检查项,实现存活性、就绪性检查分离 var result = await healthCheckService.CheckHealthAsync(); // 健康返回退出码0,不健康返回1 Environment.Exit(result.Status == HealthStatus.Healthy ? 0 : 1); } // 正常启动Worker服务 await host.RunAsync(); - K8s探针配置(Deployment的容器配置段):
livenessProbe: exec: command: ["dotnet", "你的程序集名称.dll", "--health-check"] initialDelaySeconds: 10 periodSeconds: 30 failureThreshold: 3 readinessProbe: exec: command: ["dotnet", "你的程序集名称.dll", "--health-check"] initialDelaySeconds: 5 periodSeconds: 10
该方案无任何常驻额外开销,不需要开放端口,逻辑完全可控,支持所有标准健康检查特性。
方案2:适配K8s TCP探针
原理是在Worker进程中启动一个极轻量的TCP监听器,收到连接请求时先执行健康检查,健康则保持连接,不健康直接断开,K8s TCP探针通过端口连通性判断健康状态。
实现步骤
- 健康检查服务注册逻辑和方案1一致
- 新增TCP健康探针服务:
public class TcpHealthProbeService : BackgroundService { private readonly HealthCheckService _healthCheckService; private readonly TcpListener _tcpListener; public TcpHealthProbeService(HealthCheckService healthCheckService, IConfiguration config) { _healthCheckService = healthCheckService; // 监听端口可通过配置自定义,默认用10500 var port = config.GetValue<int>("HealthProbe:Port", 10500); _tcpListener = new TcpListener(IPAddress.Any, port); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _tcpListener.Start(); while (!stoppingToken.IsCancellationRequested) { var client = await _tcpListener.AcceptTcpClientAsync(stoppingToken); _ = ProcessClientAsync(client, stoppingToken); } _tcpListener.Stop(); } private async Task ProcessClientAsync(TcpClient client, CancellationToken stoppingToken) { try { var result = await _healthCheckService.CheckHealthAsync(stoppingToken); if (result.Status != HealthStatus.Healthy) { client.Close(); return; } // 健康则保持连接1秒后断开,适配探针检测逻辑 await Task.Delay(1000, stoppingToken); } finally { client.Dispose(); } } } - 在
Program.cs中注册TCP探针服务:services.AddHostedService<TcpHealthProbeService>(); - K8s探针配置:
livenessProbe: tcpSocket: port: 10500 initialDelaySeconds: 10 periodSeconds: 30 readinessProbe: tcpSocket: port: 10500 initialDelaySeconds: 5 periodSeconds: 10
该方案仅占用一个低开销的TCP端口,比引入HTTP服务器的资源占用低90%以上,适合不方便使用exec探针的场景。
内容的提问来源于stack exchange,提问作者silent
相关产品推荐
相关产品推荐

