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

Posted

技术标签:

【中文标题】Docker 中的“公开”和“发布”有啥区别?【英文标题】:What is the difference between "expose" and "publish" in Docker?Docker 中的“公开”和“发布”有什么区别? 【发布时间】:2014-04-02 09:26:54 【问题描述】:

我正在试验 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

这可能吗?

【问题讨论】:

【参考方案1】:

基本上,您有三个选择:

    既不指定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 答案(在撰写此评论时)可能会有所帮助,链接:***.com/questions/22111060/…【参考方案2】:

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

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

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

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

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

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

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

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

【讨论】:

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

大多数人将 docker compose 与网络一起使用。 documentation 声明:

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

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

【讨论】:

【参考方案4】:

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

来源:github commit

【讨论】:

imo 措辞选择不当?如果只是记录,他们本可以选择...我不知道,除了公开哈哈。【参考方案5】:

简答:

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

注意以下:

EXPOSEDockerfiles 相关(documenting--publishdocker run ... 相关(执行/运行时

暴露和发布端口

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

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

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

来自:Docker container networking

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 指令实际上并未发布端口。它充当构建映像的人和运行容器的人之间的一种文档,关于打算发布哪些端口。

来自:Dockerfile reference


未定义 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关于该主题的非常详细的文章:

Exposed ports Published ports

【讨论】:

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

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

EXPOSE 8090

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

【讨论】:

以上是关于Docker 中的“公开”和“发布”有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

在VB.NET中do while和while有啥区别?

docker中的图层和图像有啥区别?

do(onNext:) 和 subscribe(onNext:) 有啥区别?

在 Docker 中,容器和镜像有啥区别? [复制]

nvidia/cuda 公开源中的devel和runtime有啥区别

need do sth.和need to do sth.有啥区别?