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


517

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

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

...
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

这可能吗?

Answers:


731

基本上,您有三个选择:

  1. 既不指定EXPOSE也不-p
  2. 只指定 EXPOSE
  3. 指定EXPOSE-p

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

2)如果您EXPOSE使用端口,则无法从Docker外部访问容器中的服务,而可以从其他Docker容器内部访问容器中的服务。因此,这对于容器间的通信很有用。

3)如果你EXPOSE-p一个端口,在容器中的服务是从任何地方访问,甚至泊坞窗外面。

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

  • 选择主机端口取决于主机,因此不属于Dockerfile(否则,将取决于主机),
  • 通常,只要可以从其他容器访问某个容器中的服务就足够了。

文档明确指出:

EXPOSE指令公开了供链接使用的端口。

它还为您指出了如何链接容器,这基本上就是我所说的容器间通信。

PS:如果可以-p,但是不这样做EXPOSE,Docker会执行隐式EXPOSE。这是因为如果某个端口向公众开放,那么它也会自动向其他Docker容器开放。因此-p包括EXPOSE。这就是为什么我没有将其列为第四种情况。


57
我认为您对EXPOSE的看法不正确。从其他容器,您可以访问所有容器端口而无需暴露它们。我试过了 这里的问题是容器IP地址是不可预测的。我相信该链接用于指定您要连接的容器(因此您链接到特定的容器IP),而不是启用连接。
吉里(Jiri)2014年

7
“如果你不指定任何的那些”,将你澄清与“那些”你的意思是有用的EXPOSE-p,而不是先例的三个要点。让我有点困惑。
2014年

4
为了完整起见,此答案还应该解决第四个可能的情况:您没有指定EXPOSE,但您确实指定了-p。据我了解,如果您始终使用-p并运行单个容器,则EXPOSE可以忽略,但是在使用-P或时它变得有用/必要--link。(而且由于您不知道其他人将如何使用您的图像,因此EXPOSE应在任何公共图像中指定。)
GrandOpener 2016年

6
docs不再声明“ EXPOSE指令公开了供链接使用的端口”。
洛林·霍希斯坦

11
下注,因为这基本上是不正确的。公开基本上是文档,不使用它并不限制访问。如果有人依靠它来限制访问权限,这是一个扎堆的误解。
mc0e '18

166

简短答案:

  • EXPOSE是的一种方式文档化
  • --publish(或-p)是一种方式映射一个主机端口到正在运行的容器口

请注意以下几点:

  • EXPOSEDockerfiles记录)有关
  • --publishdocker run ...执行/执行阶段)有关

公开和发布端口

在Docker网络中,有两种直接涉及网络端口的不同机制:公开端口和发布端口。这适用于默认桥接网络和用户定义的桥接网络。

  • 您可以使用EXPOSEDockerfile中的关键字或docker run的--expose标志公开端口。公开端口是一种记录使用了哪些端口的方式,但实际上并没有映射或打开任何端口。公开端口是可选的。

  • 您可以使用--publish--publish-all标志发布端口docker run。这告诉Docker在容器的网络接口上打开哪些端口。发布端口后30000,除非您在运行时指定要映射到主机上的端口,否则它将映射到主机上可用的高阶端口(高于)。在构建映像时(在Dockerfile中),您无法指定要映射到主机上的端口,因为无法保证端口将在运行映像的主机上可用

来自:Docker容器网络

2019年10月更新:以上文本不再在文档中,而是此处的存档版本:docs.docker.com/v17.09/engine/userguide/networking/#exposed-and-publishing-ports

也许当前文档如下:

发布的端口

默认情况下,创建容器时,它不会将其任何端口发布到外界。要使端口可用于Docker外部的服务或未连接到容器网络的Docker容器,请使用--publish-p标志。这将创建一个防火墙规则,该规则将容器端口映射到Docker主机上的端口。

并可以在这里找到:docs.docker.com/config/containers/container-networking/#published-ports

也,

暴露

...该EXPOSE指令实际上并未发布端口。它充当构建映像的人员和运行容器的人员之间的一种文档类型,有关打算发布哪些端口的信息。

来自:Dockerfile参考






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

@Golo罗登的回答更说明::

“如果不指定任何内容,则只能从容器本身内部访问任何地方的容器中的服务。”

也许这是在答案被写入时的情况,但现在看来,即使你不使用EXPOSE或者--publish,在host和其他containers同网络将能够访问你可能是容器内启动服务。

如何测试:

我已经使用了以下内容Dockerfile。基本上,我从ubuntu开始并安装一个小型Web服务器:

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


16
现在这是正确的答案。似乎,接受的答案基于先前的版本。
路加W

您用于卷曲的主机端口是什么?
头脑风暴

我使用了容器的IP(类似172.17.0.2)和我提到的所有端口。如果您在Mac / Windows上使用Docker,则网络连接会有所不同。没有docker0桥梁。
tgogos

当发布带有“ -P”标志的所有EXPOSEd端口时,如何得知主机上使用了哪个端口?
sixty4bit

1
@ sixty4bit看一下这个问题:我如何找出Docker选择了哪个随机端口?
tgogos

9

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

EXPOSE允许你定义私有(容器)和公共(主机)端口,在图像生成时暴露在容器运行,如果您运行的容器-P

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

public端口和协议是可选的,如果未指定public端口,则docker将在主机上选择一个随机端口以在Dockerfile上公开指定的容器端口。

最好不要指定public port,因为每个主机仅限制一个容器(第二个容器将抛出一个已使用的端口)。

您可以使用-pin docker run来控制暴露的容器端口可连接的公共端口。

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

如果你总是使用-pdocker run你不需要EXPOSE,但如果你用EXPOSE你的docker run命令可能会更简单,EXPOSE如果你不关心什么端口将主机被暴露可能是有用的,或者如果你只是一个容器的肯定将被载入。


这是对的。当Dockerfile中有EXPOSE portNumber时,请记住调用以-P运行的docker。
蔡瑜瑜

6

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

资料来源:github commit


3

大多数人将docker compose与网络结合使用。该文档指出:

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

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


-5

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

EXPOSE 8090

它将做什么将本地主机端口8090映射到容器端口8090

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.