我有一个 ASP.NET 9 应用程序在 Linux Docker 容器中运行。
使用此 dockerfile 制作:
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
# Install base components
RUN apt update && \
apt install -y curl htop nano
RUN curl -sSL https://get.docker.com/ | sh
# Set up the build env
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /source
# Install NuGet Packages
COPY "src/Dictus.AsrEvaluator.Backend/Dictus.AsrEvaluator.Backend.csproj" "src/Dictus.AsrEvaluator.Backend/Dictus.AsrEvaluator.Backend.csproj"
COPY "src/SunShared/Dictus.Sun.Shared/Dictus.Sun.Shared.csproj" "src/SunShared/Dictus.Sun.Shared/Dictus.Sun.Shared.csproj"
RUN dotnet restore "src/SunShared/Dictus.Sun.Shared/Dictus.Sun.Shared.csproj"
RUN dotnet restore "src/Dictus.AsrEvaluator.Backend/Dictus.AsrEvaluator.Backend.csproj"
# Build the app
COPY "src/" "src/"
ARG VersionSuffix=0
RUN dotnet publish "src/Dictus.AsrEvaluator.Backend/Dictus.AsrEvaluator.Backend.csproj" -c Release -o /app /p:VersionSuffix=$VersionSuffix
# Copy the app to the final build image
FROM base AS final
WORKDIR /app
COPY --from=build /app .
# Setup defaults
HEALTHCHECK CMD curl --max-time 10 --fail http://localhost:80/health || exit 1
ENV ASPNETCORE_HTTPS_PORTS=80
ENTRYPOINT ["dotnet", "Dictus.AsrEvaluator.Backend.dll"]
但偶尔它会完全挂起。
docker exec
进入 docker 容器并查看 dotnet 进程仍在运行。 dotnet 进程不使用任何 CPU,并且具有正常的大量 RAM 使用量。就像进程只是闲置一样。PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 263.8g 641220 196992 S 0.0 2.0 242:33.04 dotnet
我尝试从我的申请中获取一些信息。在 docker 容器内,我尝试安装并运行:
dotnet-counters monitor --process-id 1
dotnet-trace collect -p 1
dotnet-dump collect --process-id 1
他们都无法从我的申请中获取任何信息。
dotnet-trace collect
和dotnet-counters monitor
都完全挂起,我无法使用CTRL+C退出它们,我必须关闭终端。 dotnet-dump
永远不会创建任何内容或将任何内容写入其输出文件。
应用程序日志在挂起时停止,不提供任何附加信息。
偶尔我的应用程序会收到一份新工作。为了处理此作业,它准备了许多文件和文件夹,然后启动 2 个并行运行的子进程来完成作业。 当 2 个子进程运行时,主 ASP.NET 9 应用程序挂起。应用程序是否挂起是非常随机的。我可以运行几周而没有任何问题,然后突然挂起,或者可能只是挂起前几天。
ASP.NET 9 应用程序启动 2 个子进程并监听它们的 STDOUT 和 STDERR
ProcessStartInfo startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
FileName = "docker -v /job_data:/job_data run my_other_docker",
Arguments = arguments,
};
using Process process = new Process
{
StartInfo = startInfo,
EnableRaisingEvents = true
};
//Outputs
StringBuilder stdOut = new StringBuilder();
StringBuilder stdErr = new StringBuilder();
//Runs the command
process.Start();
ReadStream(process.StandardOutput, stdOut, progress, true);
ReadStream(process.StandardError, stdErr, progress, false);
while (!process.HasExited || !isReadStdOutDone || !isReadErrOutDone)
{
if (token.IsCancellationRequested)
{
process.Kill();
token.ThrowIfCancellationRequested();
}
await Task.Delay(100);
}
//Reads the output
string stdout = stdOut.ToString();
string stderr = stdErr.ToString();
private void ReadStream(
StreamReader stream,
StringBuilder read,
IProgress<string>? progress,
bool isStdOut)
{
Task.Run(async () =>
{
var line = CleanLogLine(await stream.ReadLineAsync());
while (line != null)
{
line = $"{name} - {line}";
read.AppendLine(line);
if (progress != null)
progress.Report(line);
line = CleanLogLine(await stream.ReadLineAsync());
}
if (isStdOut)
isReadStdOutDone = true;
else
isReadErrOutDone = true;
});
}
private string? CleanLogLine(string? line)
{
if (line != null &&
line.Count(x => x == '\b') > 1000)
{
line = line[0..1000];
}
return line;
}
我的应用程序在 2 个子进程运行时挂起。我可以看到两个子进程都成功完成。所以我怀疑问题出在子进程上。
dotnet-counters
等无法提供任何输出。如何继续调试并找出挂起的原因?
确保 docker 设置中有足够的线程余量,还要确保在使用后正确关闭线程,因为如果没有正确关闭,线程将停留并导致阻塞,最终由于资源占用而停止在 docker 中