You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器中.NET 6控制台应用的健康检查最佳实践

.NET 6 控制台Docker容器应用的健康检查最佳实践

问题描述

我有一个打包在Docker容器中的简单.NET 6控制台应用,代码示例如下:

using Microsoft.Extensions.Configuration;

var builder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables();

var configuration = builder.Build();

var baseAddress = configuration.GetValue<string>("BASE_ADDRESS");

Console.WriteLine($"Hello, World! {baseAddress}");

Web应用可以通过/health端点实现健康检查,但控制台应用没法用这种方式,想咨询针对这类控制台应用实施健康检查的最佳实践。


实用解决方案

方案1:Docker原生进程存活检查

如果你的控制台应用是长期运行的守护进程式,最简单的方式是直接通过Docker的HEALTHCHECK指令验证进程是否存活:
在Dockerfile中添加:

HEALTHCHECK --interval=30s --timeout=3s \
  CMD pgrep -f "你的应用程序名.exe" || exit 1

针对.NET跨平台场景,也可以用通用进程检查:

HEALTHCHECK --interval=30s --timeout=3s \
  CMD ps aux | grep dotnet | grep -v grep || exit 1

优点:零代码侵入,配置简单;缺点:只能检查进程是否存在,无法感知应用内部健康状态(比如依赖服务是否可达)。

方案2:应用内生成状态文件,Docker读取状态

如果需要检查应用内部健康状态(比如数据库连接、外部API可用性),可以在控制台应用中定期执行健康检查逻辑,将结果写入状态文件,再让Docker读取这个文件判断健康状态。

修改后的应用代码示例:

using Microsoft.Extensions.Configuration;
using System;
using System.Net.Http;
using System.Threading;

var builder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables();

var configuration = builder.Build();
var baseAddress = configuration.GetValue<string>("BASE_ADDRESS");

// 启动后台线程定期执行健康检查
var healthCheckThread = new Thread(() =>
{
    while (true)
    {
        bool isHealthy = CheckExternalServiceHealth(baseAddress);
        // 将状态写入Docker可访问的文件路径
        File.WriteAllText("/tmp/health_status", isHealthy ? "OK" : "FAILED");
        Thread.Sleep(TimeSpan.FromSeconds(30));
    }
});
healthCheckThread.IsBackground = true;
healthCheckThread.Start();

Console.WriteLine($"Application started. Base address: {baseAddress}");
// 模拟应用长期运行
Thread.Sleep(Timeout.Infinite);

// 自定义健康检查逻辑,替换为你的实际检查项
bool CheckExternalServiceHealth(string address)
{
    try
    {
        using var client = new HttpClient();
        var response = client.GetAsync(address).Result;
        return response.IsSuccessStatusCode;
    }
    catch
    {
        return false;
    }
}

对应的Dockerfile配置:

HEALTHCHECK --interval=30s --timeout=3s \
  CMD cat /tmp/health_status | grep -q "OK" || exit 1

方案3:引入健康检查库,暴露轻量HTTP端点

可以借助Microsoft.Extensions.Diagnostics.HealthChecks库,在控制台应用中启动一个极简HTTP服务器,提供和Web应用一致的/health端点,适配外部监控系统的检查逻辑。

步骤1:安装依赖NuGet包

dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks
dotnet add package Microsoft.AspNetCore.Server.Kestrel

步骤2:修改应用代码

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        config.SetBasePath(Directory.GetCurrentDirectory())
              .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
              .AddEnvironmentVariables();
    })
    .ConfigureServices((context, services) =>
    {
        var baseAddress = context.Configuration.GetValue<string>("BASE_ADDRESS");
        // 注册健康检查项
        services.AddHealthChecks()
                .AddCheck("base_address_connectivity", () =>
                {
                    try
                    {
                        using var client = new HttpClient();
                        var response = client.GetAsync(baseAddress).Result;
                        return response.IsSuccessStatusCode 
                            ? HealthCheckResult.Healthy("Base address reachable") 
                            : HealthCheckResult.Unhealthy("Base address returned non-success status");
                    }
                    catch (Exception ex)
                    {
                        return HealthCheckResult.Unhealthy($"Failed to connect: {ex.Message}");
                    }
                });
    })
    .Build();

// 启动独立的HTTP服务器暴露健康端点
var webHost = WebHost.CreateDefaultBuilder()
    .UseKestrel(options => options.ListenLocalhost(5000))
    .Configure(app =>
    {
        app.Map("/health", async context =>
        {
            var healthCheckService = context.RequestServices.GetRequiredService<IHealthCheckService>();
            var result = await healthCheckService.CheckHealthAsync();
            context.Response.StatusCode = result.Status == HealthStatus.Healthy ? StatusCodes.Status200OK : StatusCodes.Status503ServiceUnavailable;
            await context.Response.WriteAsync(result.Status.ToString());
        });
    })
    .Build();

// 并行启动主机和HTTP服务器
await Task.WhenAll(host.RunAsync(), webHost.RunAsync());

对应的Dockerfile配置:

EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:5000/health || exit 1

方案选择建议

  • 仅需确认进程存活:选方案1,零成本实现;
  • 需要内部状态检查但不想引入HTTP服务:选方案2,轻量灵活;
  • 需要适配外部监控系统的HTTP端点规范:选方案3,和Web应用检查逻辑统一。

内容的提问来源于stack exchange,提问作者Roman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:56:33