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

.NET8应用迁移后Kestrel在AKS环境无法启动求助

.NET 3.1迁移至.NET 8后AKS环境下Kestrel无法启动排查

将应用从.NET 3.1迁移到.NET 8后,本地开发机及Docker环境运行正常,但部署到托管Kubernetes服务(AKS)后,Kestrel始终无法启动。已在Appsettings.json中配置Kestrel,且AppSettings.Staging.json无相关覆盖配置,同时开启了全跟踪日志用于排查。

相关配置内容

Appsettings.json

{
  "Logging": {
    "LogLevel": {
      "*": "Trace"
    }
  },
  "Kestrel": {
    "EndPoints": {
      "Http": {
        "Url": "http://0.0.0.0:80"
      },
      "gRPC": {
        "Url": "http://0.0.0.0:81",
        "Protocols": "Http2"
      }
    }
  },
  "AllowedHosts": "*"
}

Program.cs

public class Program{
    public static readonly string Namespace = typeof(Startup).Namespace!;
    public static readonly string AppName = Namespace[(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1)..];

    protected Program(){}

    public static async Task<int> Main(string[] args)
    {
        ILogger<Program> logger = null;
        try
        {
            var host = CreateWebHostBuilder(args).Build();
            logger = host.Services.GetRequiredService<ILogger<Program>>();
            logger.LogInformation("Starting web host ({ApplicationContext})...", Program.AppName);
            await host.RunAsync();
            return 0;
        }
        catch (Exception ex)
        {
            logger?.LogError(ex, "Program terminated unexpectedly ({ApplicationContext})!", Program.AppName);
            return 1;
        }
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
               .CaptureStartupErrors(false)
               .UseStartup<Startup>()
               .ConfigureLogging((context, builder) =>
               {
                   builder.AddSerilog();
               });
}

Startup.Configure方法

public void Configure(
    IApplicationBuilder app,
    IWebHostEnvironment env,
    IApiVersionDescriptionProvider provider,
    VeredasDbContext dbContext,
    IAuditInjector auditInjector)
{
    app.UseCors(builder =>
    {
        builder.AllowAnyOrigin();
        builder.AllowAnyMethod();
        builder.AllowAnyHeader();
        builder.WithExposedHeaders("X-Authorization-Token");
    });

    app.UseWhen(
        context => !context.Request.Path.StartsWithSegments("/hc"),
        appBuilder =>
        {
            appBuilder.UseApiLogMiddleware();
            appBuilder.UseRenewableAuthTokenMiddleware();
        });

    if (!env.IsEnvironment("IntegrationTest"))
    {
        app.UseSwaggerConfig(provider, env);

        // Apply migration if necessary
        using var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
        dbContext.ApplyMigrations();
        auditInjector.Inject(dbContext).GetAwaiter().GetResult();
    }
    app.UseStaticFiles();
    app.UseRouting();
    app.UseJwt();
    app.ConfigureLocalization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapGrpcService<GrpcServices.ProcessService>();
        endpoints.MapGrpcService<GrpcServices.FundService>();

        if (!CurrentEnvironment.IsEnvironment("IntegrationTest"))
        {
            endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
            {
                Predicate = _ => true,
                ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
            });
            endpoints.MapHealthChecks("/readiness", new HealthCheckOptions
            {
                Predicate = r => r.Name.Contains("self"),
            });
        }
    });

    this.Logger.LogInformation("Done");
}

应用启动日志

info: MyApp.Api.Startup[0]
      Done
dbug: Microsoft.EntityFrameworkCore.Infrastructure[10407]
      'MyDbContext' disposed.
dbug: Microsoft.EntityFrameworkCore.Database.Connection[20007]
      Disposing connection to database 'db_staging' on server ''.
dbug: Microsoft.EntityFrameworkCore.Database.Connection[20008]
      Disposed connection to database 'db_staging' on server '' (0ms).
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[62]
      User profile is available. Using '/root/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.

问题现象

从日志可见,应用已执行到Configure方法末尾的"Done"日志,但始终未出现Kestrel正常启动时的监听日志:

Hosting environment: Staging
Content root path: /app
Now listening on: http://0.0.0.0:81
Now listening on: http://0.0.0.0:80

排查方向

  • 检查AKS Pod资源限制:查看Pod的CPU/内存配额是否不足,导致Kestrel启动被阻塞。通过kubectl describe pod <pod-name>查看资源使用和事件。
  • 验证Kestrel配置加载:在Program.Main中添加日志,输出Configuration.GetSection("Kestrel").Value,确认配置是否被正确读取。
  • 排查端口占用:进入Pod内部执行netstat -tulpn,检查80/81端口是否被其他进程占用。
  • 修复同步调用异步代码:Configure方法中auditInjector.Inject(dbContext).GetAwaiter().GetResult()属于同步阻塞异步操作,在.NET 8环境下可能引发死锁,建议改为异步启动流程(将Configure改为ConfigureAsync,并调整启动逻辑)。
  • 检查Serilog过滤规则:确认Serilog未过滤Kestrel相关日志(Microsoft.AspNetCore.Server.Kestrel),即使appsettings中设置了*:Trace,Serilog可能有单独的过滤器配置。
  • 查看Pod终止事件:确认Pod是否被Kubernetes重启,比如OOMKilled(内存溢出)等情况,通过kubectl get events或Pod描述信息查看。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 23:13:09