《.NET 5.0 背锅案》第1集:验证 .NET 5.0 正式版 docker 镜像问题
今天我们分析了博客站点的2次故障(故障一、故障二),发现一个巧合的地方,.NET 5.0 正式版的 docker 镜像是在11月10日提前发布上线的。
而在11月10日下午4点左右,由于 CI 服务器磁盘空间用完,我们进行了磁盘清理,删除了 CI 服务器上的所有镜像,清理之前 CI 服务器上 .NET 5.0 镜像版本对应的是 .NET 5.0 RC 2,所以11月10日晚上发布博客站点时,CI 服务器重新下载了镜像,这时正好下载了 .NET 5.0 正式版的 docker 镜像,所以发布时博客系统的镜像是基于 .NET 5.0 正式版(发布时会在CI服务器上生成应用的生产环境镜像)。
现在可以进入这2个发布版本的镜像进行验证
$ docker run -t blog-web:2.3.101 dotnet --info Host (useful for support): Version: 5.0.0 Commit: cf258a14b7 $ docker run -t blog-web:2.3.102 dotnet --info Host (useful for support): Version: 5.0.0 Commit: cf258a14b7
Commit: cf258a14b7 对应的正是 .NET 5.0 正式版。
对比一下11月10日之前生成的镜像
$ docker run -t blog-web:2.3.100 dotnet --info Host (useful for support): Version: 5.0.0-rc.2.20475.5 Commit: c5a3f49c88
不仅 Commit 不一样,而且 Version 中包含 rc.2。
所以这2次故障时用的都是基于 .NET 5.0 正式版的镜像,而且11月10日至11月12日期间,我们只进行了2次发布,2次都出现了故障。
如果片面地从这个巧合来看,似乎故障与 .NET 5.0 正式版镜像有关,这时你可能立马提出疑问,同样是基于 .NET 5.0 正式版的镜像,为什么今天早上发布没有出现故障?
根据我们的分析判断,故障的触发与发布时的并发请求量有关,2次故障时的发布时间分别是在 20:30 与 19:30 左右,这2个发布时间点的并发量差不多,而今天早上发布时并发量要小很多,而且我们其他并发量不大的应用升级到 .NET 5.0 没有出现过这个问题,所以今天早上发布正常很可能是因为没有到达触发故障的并发量。
另外,今天早上发布时我们已经将博客项目依赖的下面这些 nuget 包升级到 .NET 5.0 正式版对应的版本,昨天晚上在处理故障时也进行过这个升级发布尝试,但没有解决问题,与故障关联的可能性很小,但从中可以得到的信息是故障时项目代码是基于 .NET 5.0 RC 2,生产环境部署的 runtime 是基于 .NET 5.0 正式版。
Microsoft.Extensions.Primitives System.Interactive.Async Microsoft.Extensions.Http Microsoft.Extensions.Logging.Abstractions System.ServiceModel.Primitives Microsoft.EntityFrameworkCore.SqlServer Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation System.Text.Encoding.CodePages
虽然正式版 runtime 镜像造成这个故障的可能性很小,但考虑到问题的诡异性,我们不想放过一个蛛丝马迹,所以准备今天晚上再次发布试试,计划的发布时间是21:30,但是由于今天是周五,晚上的并发请求量比前2次故障期间小一些,即使没有出现问题,也不能说明100%没问题,但至少可以知道在周五晚上的并发量下不会触发问题。
附博客项目所使用的 Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base WORKDIR /app EXPOSE 80 EXPOSE 443 RUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list RUN apt-get update && apt-get install -y curl FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build WORKDIR /src COPY src/*.sln src/*.props src/NuGet.config ./ COPY src/*/*.csproj ./ RUN for file in $(ls *.csproj); do mkdir -p ${file%.*}/ && mv $file ${file%.*}/; done RUN dotnet restore "BlogServerCore.sln" COPY src/. . RUN dotnet build "BlogServerCore.sln" -c Release --no-restore FROM build AS publish WORKDIR /src/BlogServer.WebApi RUN dotnet publish "BlogServer.WebApi.csproj" -c Release -o /app/publish --no-build FROM base AS final WORKDIR /app COPY --from=publish /app/publish . RUN echo "dotnet BlogServer.WebApi.dll" > run.sh HEALTHCHECK --interval=5s --timeout=20s \ CMD curl -fs -o /dev/null localhost/alive || exit 1