为什么在 Docker 中 aspnet core 启动端口是 80?

132

TL;DR: 为什么aspnet core应用程序在Docker镜像中运行时在端口80上运行,但在Docker镜像外部的5000端口上运行。

详细说明:

我按照以下链接中的aspnet core / docker教程进行操作: https://learn.microsoft.com/en-us/dotnet/core/docker/building-net-docker-images

在该页面的一半处,我按照指示使用以下命令启动应用程序:

dotnet run

除其他外,这会打印出以下内容:

Now Listening on: http://localhost:5000

好的,这正是我所期望的。教程中接下来要做的事情是从 Docker 镜像中启动完全相同的应用程序。

docker build -t aspnetapp .
docker run -it --rm -p 5000:80 --name aspnetcore_sample aspnetapp

这导致
Now listening on: http://[::]:80

等一下,什么?为什么aspnet core应用程序在80端口运行?当我直接从机器上运行它时,它是在5000端口上运行的。没有进行任何配置文件更改。

我怀疑这与基础docker镜像有关,但我还不够熟练以跟踪此问题。


6
在这行命令中 docker run -it --rm -p 5000:80 --name aspnetcore_sample aspnetapp,你将 Docker 容器内部的端口5000映射到了外部的端口80。也就是说,当你访问容器的IP地址时,它会将你的请求转发至5000端口。请注意,此命令为Docker运行命令,而不是解释说明。 - Jamie Taylor
这在教程页面上有解释,直接在 此部分 提供的代码下方进行了说明。 - Jamie Taylor
1
@JamieTaylor 没错,但是消息“now listening on ...”并不是在说外部端口5000,而是指容器内部的内部端口,正如你所说,已映射到容器外部的端口5000。 - omajid
1
@JamieTaylor,omajid是正确的,这只告诉我我正在将内部端口80映射到外部端口5000。这个选择会导致更多的混淆。问题是为什么内部端口是80?他们应该使用一个不同于5000的数字来作为外部示例,以突出我们不是在谈论与之前示例相同的端口。 - Phillip Scott Givens
5个回答

184

microsoft/aspnetcore-build容器是在microsoft/aspnetcore容器的基础上构建的。这个dockerhub页面说:

关于端口的说明

此映像将ASPNETCORE_URLS环境变量设置为http://+:80,这意味着如果您未在应用程序中明确设置URL(例如,在Program.cs中使用app.UseUrl),则应用程序将在容器内部的端口80上侦听。

因此,这个容器在主动设置端口80。您可以在Dockerfile中进行覆盖,如下:

ENV ASPNETCORE_URLS=http://+:5000

另外,值得注意的是,由于您使用的docker命令,无论您直接运行应用程序还是在容器中运行,都可以通过http://localhost:5000访问应用程序。


非常感谢!我认为如果他们使用“-p 5001:80”来强调我们不是在谈论之前的同一端口,那么这将是一个更好的例子。 - Phillip Scott Givens
@PhillipScottGivens 也许你现在已经知道了,但是默认情况下端口5001用于使用SSL(https)运行应用程序。我理解你最初的困惑,但正如答案所指出的那样,ASPNETCORE_URLS决定了应用程序侦听的端口。 - Sudhanshu Mishra
3
你好,我在Dockerfile中使用了"ENV ASPNETCORE_URLS http://+5000",但在使用docker-compose启动容器时仍然看到"Now listening on: http://[::]:80"。我看到以下信息:Step 4/7 : ENV ASPNETCORE_URLS http://+5000 Step 6/7 : EXPOSE 5000.但是在使用"docker-compose up"后,我仍然看到相同的信息:"Now listening on: http://[::]:80"。 - Rroman
1
@Rroman docker-compose down,删除所有相关的镜像,然后重新构建。 - Danrley Pereira
1
答案中的 dockerhub 链接 ("The dockerhub page for that says") 带我到一个没有提到端口或 ASPNETCORE_URLS 的页面。然而,这里有一个包含相同信息的页面(但它看起来不是官方的):https://hub.docker.com/r/ostusa/aspnetcore有人知道这种行为是否仍然被正式记录在任何地方吗? - Andrew
官方文档中已经暗示:“将本地机器上的端口5000映射到容器中的端口80。” - omajid

24

如果没有Dockerfile,您可以使用Docker参数设置Docker容器之外的任何端口。(.NET Core 3.1, .NET 5, .NET 6, .NET 7+)

docker run -it --rm -p 5000:80 -p 5001:443 -e ASPNETCORE_HTTPS_PORT=https://+:5001
           -e ASPNETCORE_URLS=http://+:5000 --name aspnetcore_sample aspnetapp

更多细节:

https://github.com/dotnet/dotnet-docker/blob/17c1eec582e84ba9cbea5641cd9cc13fe1a41c39/samples/run-aspnetcore-https-development.md?plain=1#L85

https://github.com/dotnet/dotnet-docker/blob/5926a01d44bd47b6202ba71e30f9faa08fad1aec/samples/run-in-sdk-container.md?plain=1#L109


12

如果您使用的是.NET Core 2.2或更高版本,则应该使用另一张图片:mcr.microsoft.com/dotnet/core/aspnet:2.2。在这种情况下,指定ENV ASPNETCORE_URLS=http://+:5000是无效的。您仍然可以通过在Programs.cs文件中使用UseUrls("http://*:5000")来强制应用程序侦听5000端口。


不知道这个,浪费了很多时间。谢谢。 - Carlo Luther

8

Windows Networking Stack Limitation对Windows Docker容器造成严重限制。

参考视频
docker run -it --rm -p ${host_computer_port}:${container_port} --name ${container_name} ${image_name}

命令示例:

docker run -it --rm -p 5000:8090 --name dockerwebapp9172020c dockerwebapp9172020

以上命令是什么意思?

你的机器端口(5000)被映射到容器端口(8090),这并不意味着运行在容器中的应用程序正在监听端口:8090。请参见下面的Docker文件,了解如何将容器端口映射到应用程序端口。

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1903 AS base
WORKDIR /app
EXPOSE 8090
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-nanoserver-1903 AS build
WORKDIR /src
COPY ["DockerWebApp/DockerWebApp.csproj", "DockerWebApp/"]
RUN dotnet restore "DockerWebApp/DockerWebApp.csproj"
COPY . .
WORKDIR "/src/DockerWebApp"
RUN dotnet build "DockerWebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "DockerWebApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV ASPNETCORE_URLS http://*:8090
ENTRYPOINT ["dotnet", "DockerWebApp.dll"]

测试

Windows 网络堆栈限制将不允许直接运行以下命令。

http://localhost:5000

让我们来看第一个解决方案。

解决方案-1 直接命中容器。(在PowerShell或命令提示符下使用以下命令)

ps c:/>docker inspect f31e8add55af

从“NETWORKS”节点找到容器的IP地址,并在浏览器中运行该命令。

http://{container IP}:8090

解决方法2:来自Windows主机

首先找到您的计算机IP地址。

c:\>ipconfig

一旦您找到了机器的IP地址,请运行以下命令。

http://{Your Machine IP}:5000

由于5000被映射到容器端口(8090),而asp.net core应用程序也在容器内监听8090端口。

参考:Windows容器和Docker: 101


6

其他答案中的一些链接是针对旧版本或不再存在。以下适用于v6。

所有mcr.microsoft.com/dotnet/aspnet镜像都在这里。假设您正在使用alpine版本。

aspnet镜像基于runtime镜像,如此处所示

runtime镜像基于runtime-deps镜像,如此处所示

runtime-deps镜像基于amd64/alpine镜像,如此处所示(旧版本,但具有相同的结构)。并设置ENV ASPNETCORE_URLS=http://+:80,如此处所示,这意味着容器正在侦听端口80。


这就是原因!供以后参考:在VS2022的容器窗口中,检查“环境”选项卡以获取当前设置。 - Lionet Chen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接