最稳路径是dotnet publish + 多阶段dockerfile:用sdk镜像构建、runtime/aspnet镜像运行,主版本严格对齐(如全用8.0),entrypoint必须指向publish输出的.dll而非.csproj,并设aspnetcore_urls=http://+:80、workdir匹配copy路径、.dockerignore排除bin/obj等。

直接说结论:C# 项目 Docker 化部署,最稳的路径是 dotnet publish + 多阶段 Dockerfile,用 sdk 镜像构建、runtime 或 aspnet 镜像运行,主版本号必须严格对齐(如都用 8.0),否则容器一启动就报 Could not load file or assembly 或 JSON 序列化异常。
ENTRYPOINT 必须指向 .dll,不是 .csproj
常见错误是写成 ENTRYPOINT ["dotnet", "MyApp.csproj"] —— 容器里没有 SDK,.csproj 不是可执行体。真正该用的是 publish 输出目录里的 .dll 文件(文件名默认与项目名一致,除非改过 AssemblyName)。
-
dotnet publish -c Release -o ./publish执行后,确认./publish/MyApp.dll存在 -
Dockerfile中最后阶段的COPY --from=build-env /app/publish .后,WORKDIR必须设为/app,再写ENTRYPOINT ["dotnet", "MyApp.dll"] - 如果项目是 ASP.NET Core Web API,默认监听
http://localhost:5000,容器内需改成http://+:5000,否则宿主机映射不到
SDK 和 Runtime 镜像版本不一致会直接启动失败
镜像标签里的主版本号(如 8.0)必须完全一致。混用 sdk:8.0 和 aspnet:7.0 是高频翻车点,错误信息通常是 It was not possible to find any compatible framework version 或 Microsoft.AspNetCore.App 共享框架缺失。
- Web 项目优先选
mcr.microsoft.com/dotnet/aspnet:8.0-jammy(含 Kestrel 优化和 HTTPS 支持) - 控制台或 Worker Service 用
mcr.microsoft.com/dotnet/runtime:8.0-jammy - 永远不要用
latest标签——它可能跨主版本,破坏构建确定性 - 验证方式:
docker run --rm <your-image> dotnet --list-runtimes</your-image>,看输出是否含Microsoft.AspNetCore.App 8.0.x
ASPNETCORE_ENVIRONMENT 和端口配置在容器里常被忽略
本地 appsettings.Development.json 不会自动加载;没设 ASPNETCORE_ENVIRONMENT 环境变量,配置就回退到默认值,数据库连接串、密钥全错位。
- 启动容器时加
-e ASPNETCORE_ENVIRONMENT=Production(或对应环境名) - 端口暴露靠
EXPOSE 80声明 +ASPNETCORE_URLS=http://+:80环境变量共同生效,只写EXPOSE不够 - 宿主机访问需映射:如容器内监听
80,运行时必须docker run -p 5000:80,左边是宿主机端口 - 敏感配置别硬编码进
Dockerfile,改用--env-file或挂载外部appsettings.json
不设 .dockerignore 会导致镜像臃肿甚至泄露密钥
docker build 默认把整个上下文目录打包上传,含 bin/、obj/、.git/、.user,上传慢、层大、还可能带入本地 NuGet 缓存路径或用户密钥。
- 在项目根目录建
.dockerignore,至少包含:.git、bin/、obj/、.vs/、.user、.env -
RUN rm -rf /app/obj没用——这些文件已存在于上层镜像层,rm不会减小最终镜像体积 - 检查构建日志里
Sending build context to Docker daemon后面的大小,超过 100MB 就大概率漏了 ignore - 相对路径问题也藏在这儿:开发时写的
"Uploads/image.jpg"在容器里变成/Uploads/image.jpg,应统一用Path.Combine(Directory.GetCurrentDirectory(), "Uploads", "image.jpg")
最易被忽略的其实是 WORKDIR 和 COPY 路径的匹配关系,以及 ASPNETCORE_URLS 的监听地址必须带 +(即 http://+:80),而不是 localhost 或 127.0.0.1 —— 这个细节不改,容器就对外不可达。











