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

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

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

...
EXPOSE 8080
...


,然后在运行时发布与上述相同的端口图像:

$ docker build -t an_image - < Dockerfile


或使用

发布所有端口
$ docker run -d -p 8080 an_image


在端口中公开端口的意义是什么Dockerfile,是否仍要发布?是否需要先公开一个端口,然后再不发布它?实际上,我想在创建映像时指定要在Dockerfile中使用的所有端口,然后不再麻烦它们,只需使用以下命令即可运行它们:

$ docker run -d -P an_image


这可能吗?

#1 楼

基本上,您有三个选择:


既不指定EXPOSE也不指定-p

仅指定EXPOSE

指定EXPOSE-p


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

2)如果您通过EXPOSE端口,不能从Docker外部访问容器中的服务,而可以从其他Docker容器内部访问容器中的服务。

3)如果将EXPOSE-p用作端口,则可以从任何地方访问容器中的服务,甚至可以从Docker外部访问。

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


选择主机端口取决于主机,因此不属于Dockerfile(否则取决于主机),
并且通常可以从其他容器访问容器中的服务。

文档中明确指出:


EXPOSE指令公开了以下端口在链接内使用。


它还为您提供了链接容器的方法,这基本上就是我所说的容器间通信。

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

评论


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

–吉里
2014年4月4日5:45

“如果您未指定任何一个”,如果您明确指出“那些”是指EXPOSE和-p,而不是前面的三个要点,将很有用。让我有点困惑。

– Pithikos
2014年8月8日在9:24

docs不再声明“ EXPOSE指令公开了供链接使用的端口”。

–罗琳·霍希斯坦(Lorin Hochstein)
17年2月4日在6:57

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

–mc0e
18年7月31日在2:21

您的答案似乎过时了。编辑答案以指出这一事实并链接到下面的@tgogos答案(在撰写此评论时)可能会有所帮助,链接:stackoverflow.com/questions/22111060 / ...

–全能骆驼Moha
18年11月21日在15:11



#2 楼

简短的答案:


EXPOSE是一种记录方式


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



下面的注意事项:


EXPOSEDockerfiles相关(记录)

--publishdocker run ...(执行/运行时)相关。


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


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


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


来自:Docker容器网络
2019年10月更新:上面的文本不再在docs中,而是此处的存档版本: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
... EXPOSE指令实际上并未发布端口。它是构建映像的人员和运行容器的人员之间的一种文档,有关打算发布哪些端口的信息。
来自:Dockerfile参考


未定义EXPOSE / --publish时的服务访问:
@Golo Roden回答说::

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

也许在编写答案时就是这种情况,但是现在看来,即使您不使用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的主页。

进一步阅读
Ivan Pepelnjak关于该主题的非常详尽的文章:

暴露的端口
已发布的端口


评论


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

–卢克W
18年1月16日在20:57

EXPOSE实际上确实在做一些事情,而不仅仅是文档。如果使用-P标志运行,它将发布“所有公开的端口到随机端口”。

– papiro
7月21日4:30

#3 楼

请参阅官方文档参考: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上公开指定的容器端口。

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

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

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

如果始终在-p上使用docker run,则不需要q43 12079q,但是如果您使用EXPOSE,则您的EXPOSE命令可能会更简单,如果您不在乎主机上将公开哪个端口,或者确定只能加载一个容器,则docker run可能会很有用。

评论


这是对的。当Dockerfile中有EXPOSE端口号时,请记住调用以-P运行的docker。

–蔡坤宇
4月15日9:04

#4 楼

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

来源:github commit

评论


imo措辞选择不佳?如果只是记录,他们可以选择...我不知道,但是任何东西都会大声笑。

–dtc
12月4日,0:07

#5 楼

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


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


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

#6 楼

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

EXPOSE 8090

它将做什么,它将本地主机端口8090映射到集装箱港口8090