ASP.NET与ASP.NET Core容器在Windows Docker中的端口访问差异疑问
我基于以下镜像创建了两个容器:
- ASP.NET Core:
mcr.microsoft.com/dotnet/aspnet:8.0.0-windowsservercore-ltsc2019 - ASP.NET:
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2016
运行容器的命令:
docker run -d -p 8080:8080 aspcore docker run -d -p 9090:9090 asp
ASP.NET Core容器可通过http://localhost:8080访问,但ASP.NET容器无法通过http://localhost:9090访问。执行docker ps -a查看端口映射:
- ASP.NET Core:
0.0.0.0:8080->8080/tcp - ASP.NET:
80/tcp, 0.0.0.0:9090->9090/tcp
实际ASP.NET容器只能通过Hyper-V虚拟适配器的IP(如http://172.20.235.45/)的80端口访问,即使构建镜像时添加EXPOSE 9090也没用。简言之:
- ASP.NET Core容器:可通过
http://localhost:8080和http://172.20.235.46:8080访问 - ASP.NET容器:仅能通过
http://172.20.235.45/访问
请问为何会出现这种差异?是否与微软构建基础镜像的方式有关?
这种差异确实和微软构建两种ASP.NET基础镜像的方式直接相关,核心原因在于容器内Web服务绑定的端口和网络行为不同:
ASP.NET Core镜像的网络配置
微软官方的ASP.NET Core镜像默认会将Kestrel服务器绑定到0.0.0.0:8080(或通过环境变量ASPNETCORE_URLS指定),这意味着服务会监听容器内所有网络接口的8080端口。当你用-p 8080:8080映射端口时,Docker会把宿主机的8080端口转发到容器的8080端口,此时localhost:8080能直接访问,本质是宿主机的端口转发生效了。ASP.NET Framework镜像的网络配置
ASP.NET Framework依赖IIS运行,微软官方的mcr.microsoft.com/dotnet/framework/aspnet:4.8镜像默认将IIS绑定到容器内的80端口,且IIS仅监听容器的内部网络接口(而非0.0.0.0)。你执行docker run -p 9090:9090 asp时,容器内根本没有服务在9090端口监听,所以这个端口映射完全无效。
你看到的docker ps -a里0.0.0.0:9090->9090/tcp只是Docker记录了你的端口映射指令,但容器内没有进程占用9090端口,自然无法通过localhost:9090访问。而通过Hyper-V虚拟IP的80端口能访问,是因为容器内的IIS确实在80端口提供服务,你直接访问了容器的内部IP和默认端口。
EXPOSE指令的作用误区
EXPOSE只是镜像的元数据,用来声明容器可能会使用的端口,它不会实际修改容器内服务的监听端口,也不会自动完成端口映射。所以添加EXPOSE 9090对ASP.NET容器的服务监听行为没有任何影响。解决ASP.NET容器的localhost访问问题
要让ASP.NET容器能通过localhost访问,你需要执行正确的端口映射命令:
docker run -d -p 9090:80 asp
此时就能通过http://localhost:9090访问容器内的IIS服务。
内容的提问来源于stack exchange,提问作者Frank Martin

