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

这可能吗?

原文由 user1496984 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 545
2 个回答

基本上,您有三(四)个选项:

  1. 既不指定 EXPOSE 也不指定 --- -p

  2. 只指定 EXPOSE

  3. 指定 EXPOSE-p

  4. 仅指定 -p 隐式执行 EXPOSE

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

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

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

  8. 如果你这样做 -p ,但不这样做 EXPOSE ,Docker 会隐含 EXPOSE 。这是因为如果一个端口对公众开放,它也会自动对其他 Docker 容器开放。因此 -p 包括 EXPOSE 。这实际上与 3) 相同。

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

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

文档 明确指出:

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

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

原文由 Golo Roden 发布,翻译遵循 CC BY-SA 4.0 许可协议

简短的回答:

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

请注意以下:

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

来自: Dockerfile 参考


EXPOSE / --publish 时的服务访问:

@Golo Roden 的 回答中指出:

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

也许在编写答案时就是这种情况,但现在看来,即使您不使用 EXPOSE--publishhost 和同一网络的其他 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 关于该主题的非常详细的文章:

原文由 tgogos 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进