ChatGPT解决这个技术问题 Extra ChatGPT

Docker 中的“公开”和“发布”有什么区别?

我正在试验 Dockerfiles,我想我理解了大部分逻辑。但是,在这种情况下,我看不出“公开”和“发布”端口之间的区别。

我首先看到的所有教程都在 Dockerfile 中包含 EXPOSE 命令:

...
EXPOSE 8080
...

然后他们从这个 Dockerfile 构建一个镜像:

$ docker build -t an_image - < Dockerfile

然后在运行镜像的时候发布和上面一样的端口:

$ docker run -d -p 8080 an_image

或使用发布所有端口

$ docker run -d -P an_image

如果无论如何都会发布,那么在 Dockerfile 中公开端口有什么意义?是否需要先公开一个端口,然后再发布它?实际上,我想指定创建映像时将在 Dockerfile 中使用的所有端口,然后不再打扰它们,只需使用以下命令运行它们:

$ docker run -d an_image

这可能吗?


K
KYDronePilot

基本上,您有三个选择:

既不指定 EXPOSE 也不指定 -p 只指定 EXPOSE 指定 EXPOSE 和 -p

1) 如果您既不指定 EXPOSE 也不指定 -p,则容器中的服务将只能从容器本身内部访问。

2)如果您EXPOSE一个端口,容器中的服务不能从 Docker 外部访问,但可以从其他 Docker 容器内部访问。所以这有利于容器间的通信。

3)如果你EXPOSE-p一个端口,容器中的服务可以从任何地方访问,甚至在Docker之外。

两者分开的原因是恕我直言,因为:

选择主机端口取决于主机,因此不属于 Dockerfile(否则将取决于主机),

如果容器中的服务可以从其他容器访问,通常就足够了。

documentation 明确指出:

EXPOSE 指令公开端口以供在链接中使用。

它还为您指出如何link containers,这基本上是我谈到的容器间通信。

PS:如果你做-p,但不做EXPOSE,Docker 会做一个隐含的EXPOSE。这是因为如果一个端口对公众开放,它也会自动对其他 Docker 容器开放。因此 -p 包括 EXPOSE。这就是为什么我没有将其列为第四种情况。


我认为您对 EXPOSE 不正确。从其他容器,您可以访问所有容器端口而不暴露它们。我试过了。这里的问题是容器 IP 地址是不可预测的。我相信该链接用于指定您要连接的容器(因此您链接到特定的容器 IP),而不是启用连接。
“如果您未指定其中任何一个”,如果您澄清“那些”是指 EXPOSE-p 而不是前面的三个要点,将会很有用。让我有点困惑。
文档不再声明“EXPOSE 指令公开端口以供在链接中使用”。
否决票,因为这基本上是不正确的。 Expose 基本上是文档,不使用它不会限制访问。如果有人依赖它来限制访问,这是一个危险的误解。
看来您的答案已经过时了。编辑答案以指出这一事实并链接到下面的@tgogos 答案可能会有所帮助(在撰写此评论时),链接:stackoverflow.com/questions/22111060/…
t
tgogos

简短的回答:

EXPOSE 是一种记录方式

--publish(或-p)是一种将主机端口映射到正在运行的容器端口的方法

请注意以下:

EXPOSE 与 Dockerfiles 相关(文档化)

--publish 与 docker run ...(执行/运行时)有关

暴露和发布端口 在 Docker 网络中,有两种不同的机制直接涉及网络端口:暴露和发布端口。这适用于默认桥接网络和用户定义的桥接网络。您可以使用 Dockerfile 中的 EXPOSE 关键字或 --expose 标志向 docker run 公开端口。公开端口是一种记录使用了哪些端口的方法,但实际上并不映射或打开任何端口。暴露端口是可选的。您使用 --publish 或 --publish-all 标志将端口发布到 docker run。这告诉 Docker 在容器的网络接口上打开哪些端口。发布端口时,它会映射到主机上可用的高位端口(高于 30000),除非您在运行时指定要映射到的主机上的端口。构建映像时(在 Dockerfile 中),您无法在主机上指定要映射到的端口,因为无法保证该端口在您运行映像的主机上可用。来自:Docker 容器网络 2019 年 10 月更新:上述文本不再在文档中,但存档版本在此处:docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing- ports 也许当前的文档如下: 发布的端口 默认情况下,当你创建一个容器时,它不会向外界发布它的任何端口。要使端口可用于 Docker 外部的服务或未连接到容器网络的 Docker 容器,请使用 --publish 或 -p 标志。这将创建一个防火墙规则,将容器端口映射到 Docker 主机上的端口。可以在这里找到:docs.docker.com/config/containers/container-networking/#published-ports

还,

EXPOSE ...EXPOSE 指令实际上并不发布端口。它充当构建映像的人和运行容器的人之间的一种文档类型,关于打算发布哪些端口。来自:Dockerfile 参考

未定义 EXPOSE / --publish 时的服务访问:

@Golo Roden's 的回答中指出:

“如果您不指定其中任何一项,则容器中的服务将无法从容器本身内部以外的任何地方访问。”

可能在写答案的时候是这样,但现在看来,即使不使用EXPOSE--publish,同一网络的host和其他containers也可以访问您可以在该容器内启动的服务。

如何测试这个:

我使用了以下 Dockerfile。基本上,我从 ubuntu 开始并安装一个小型网络服务器:

FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd

build 将图像作为“testexpose”并run 使用以下新容器:

docker run --rm -it testexpose bash

在容器内,我启动了几个 mini-httpd 实例:

root@fb8f7dd1322d:/# mini_httpd -p 80
root@fb8f7dd1322d:/# mini_httpd -p 8080
root@fb8f7dd1322d:/# mini_httpd -p 8090

然后我可以使用主机或其他容器中的 curl 来获取 mini-httpd 的主页。

进一步阅读

Ivan Pepelnjak 撰写的关于该主题的非常详细的文章:

暴露的端口

已发布的端口


现在这是正确答案。看来,接受的答案是基于以前的版本。
EXPOSE 确实做了一些事情,而不仅仅是文档。如果您使用 -P 标志run,它会发布“all exposed ports to random ports”。
根本不发布端口的部分是错误的。我刚刚尝试过,但它不起作用,我不希望它起作用。我也在 compose 中尝试了类似的方法,在同一网络上使用服务名称,但这也不起作用。此外,根据 papiro 的评论,EXPOSE 确实对 -P 有影响。
部分:未定义 EXPOSE / --publish 时的服务访问 仍然有效并且按上述方式工作(我刚刚再次对其进行了测试)。也许您在 docker for Windows 或 Mac 上尝试过(网络更复杂)?在 Linux VM 上,它完全按照编写的方式工作,示例是完整且可验证的。
B
BBaysinger

请参阅官方文档参考:https://docs.docker.com/engine/reference/builder/#expose

EXPOSE 允许您定义私有(容器)和公共(主机)端口,以便在容器运行时在映像构建时公开如果运行容器-P

$ docker help run
...
  -P, --publish-all                    Publish all exposed ports to random ports
...

公共端口和协议是可选的,如果没有指定公共端口,docker 会在主机上随机选择一个端口,将指定的容器端口暴露在 Dockerfile 上。

一个好的做法是不要指定公共端口,因为它只限制每个主机一个容器(第二个容器将抛出一个已经在使用的端口)。

您可以使用 docker run 中的 -p 来控制公开的容器端口可连接的公共端口。

无论如何,如果您不使用 EXPOSE(在 docker run 上使用 -P)或 -p,则不会暴露任何端口。

如果您总是在 docker run 处使用 -p,则不需要 EXPOSE,但如果您使用 EXPOSE,您的 docker run 命令可能会更简单,如果您不在乎哪个端口会使用 EXPOSE,那么 EXPOSE 会很有用暴露在主机上,或者如果您确定只会加载一个容器。


这是对的。当 Dockerfile 中有 EXPOSE portNumber 时,记得使用 -P 调用 docker run。
我希望这篇文章中的语言对于像我这样对某些概念较新的人来说更清楚一些。
BBaysinger,你想澄清什么概念?
m
mzalazar

您可以使用 Dockerfile 中的 EXPOSE 关键字或 --expose 标志向 docker run 公开端口。公开端口是一种记录使用了哪些端口的方法,但实际上并不映射或打开任何端口。暴露端口是可选的。

来源:github commit


糟糕的措辞选择imo?如果只是记录,他们本可以选择...我不知道,但要公开大声笑。
h
herm

大多数人使用 docker compose 和网络。 documentation 指出:

Docker 网络功能支持创建网络而无需暴露网络内的端口,有关详细信息,请参阅此功能的概述)。

这意味着如果您使用网络在容器之间进行通信,则无需担心暴露端口。


A
Arınç Alp Eren

EXPOSE 关键字让所有者可以通知其他人容器将主要使用哪些端口。

即使您没有在 EXPOSE 中指定端口,您也可以发布任何端口。

例如,我们使用暴露端口 1234 的 nginx 映像创建 Dockerfile

FROM nginx:latest
EXPOSE 1234

并建造它

码头工人构建 -t 端口测试。

并通过将 80 端口发布到 localhost:80 来运行它

docker run -p 80:80 端口测试

当你去 localhost:80 时,你会看到 nginx 默认页面。 Nginx default page


但不幸的是,这并不能回答是否有办法利用镜像中实际公开的端口,而无需在容器创建期间明确发布它。答案是:“是的,您可以使用 'docker run' 的 -P 选项来发布 Dockerfile 中的所有 EXPOSEd 端口”
M
Mansur Ul Hasan

EXPOSE 用于映射本地端口容器端口,即:如果您在 docker 文件中指定暴露,例如

EXPOSE 8090

它将 localhost 端口 8090 映射到容器端口 8090 会做什么