C#项目Docker部署关键在于选对基础镜像、正确暴露端口、避开Windows容器陷阱:用aspnet:8.0或runtime:8.0镜像,COPY发布产物到WORKDIR,设ASPNETCORE_URLS=http://*:80并-p映射端口。

直接说结论:C# 项目用 Docker 部署,核心不是“能不能”,而是“选对基础镜像 + 正确暴露端口 + 避开 Windows 容器陷阱”。.NET 6+ 的跨平台 SDK 镜像已足够稳定,但新手常卡在 dotnet publish 输出路径和 WORKDIR 不一致、或误用 mcr.microsoft.com/dotnet/sdk 当运行时镜像。
用哪个基础镜像?别混用 sdk 和 runtime
常见错误是拿 mcr.microsoft.com/dotnet/sdk:8.0 做最终运行镜像——它体积大(>700MB)、含编译工具、有安全风险。生产环境必须用 runtime 镜像。
-
mcr.microsoft.com/dotnet/aspnet:8.0:适合 ASP.NET Core Web 项目(已含运行时 + 托管依赖) -
mcr.microsoft.com/dotnet/runtime:8.0:适合控制台、Worker Service 等非 Web 场景 - 绝对不要在
Dockerfile的FROM行写sdk除非你真要在容器里编译(CI 场景除外)
Dockerfile 怎么写?关键三步不能少
一个最小可行的 ASP.NET Core Web API 的 Dockerfile 必须包含:发布产物拷贝、工作目录设定、端口暴露、启动命令。漏任意一步都会导致容器启动后无响应或 404。
- 先在项目根目录执行:
dotnet publish -c Release -o ./publish,确保输出路径和COPY指令匹配 -
COPY必须指定到容器内存在的路径,例如:COPY ./publish /app/,然后WORKDIR /app -
EXPOSE 80只是声明,真正生效靠ASPNETCORE_URLS=http://+:80环境变量或--urls参数 - 启动命令推荐:
ENTRYPOINT ["dotnet", "YourApp.dll"],不要用CMD—— 它容易被docker run参数覆盖
为什么 localhost 访问不到?端口和网络配置要对齐
容器内服务监听 http://+:80,不等于宿主机能通过 http://localhost:5000 访问。本质是端口映射没做或应用没监听正确地址。
- 运行容器时必须加
-p 5000:80,左边是宿主机端口,右边是容器内暴露的端口(即EXPOSE值) - ASP.NET Core 默认只监听
http://localhost:5000,需改配置:在Program.cs中加.UseUrls("http://*:80"),或设环境变量ASPNETCORE_URLS=http://*:80 - 若用 Docker Desktop for Windows,默认使用 WSL2 后端,
localhost是通的;但若用 Linux 主机或远程服务器,确认防火墙放行目标端口
调试失败怎么办?先看容器日志再查端口绑定
容器一闪而逝或健康检查失败,90% 是启动报错退出。别急着改代码,先定位根本原因。
- 运行后立刻执行:
docker logs <container-id>,重点看是否出现FileNotFoundException(DLL 缺失)、InvalidOperation(配置缺失)、或Address already in use(端口冲突) - 如果日志空白,说明进程根本没启动成功——检查
ENTRYPOINT中的 DLL 名称是否拼写正确,是否带了.dll后缀 - 进容器内部查端口:
docker exec -it <container-id> sh -c "netstat -tuln | grep :80",确认服务是否真在监听
最易被忽略的是:.NET 项目引用了 Windows-only 组件(如 System.Drawing.Common 在 Linux 容器中需额外安装 libgdiplus),或者 appsettings.json 里硬编码了本地路径(如 C:\temp)。这些不会在构建时报错,但运行时直接崩溃。


















