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

在Docker中,'公开'(EXPOSE)端口仅用于文档化,不会实际映射或打开端口,而'发布'(publish)端口会将容器端口映射到主机端口,使其对外部服务可用。如果不指定或使用,则服务只能从容器内部访问。若只使用EXPOSE,其他Docker容器可以进行容器间通信。使用docker run的-p或-P标志可发布端口,后者会自动分配主机端口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文翻译自:What is the difference between “expose” and “publish” in Docker?

I'm experimenting with Dockerfiles, and I think I understand most of the logic. 我正在试验Dockerfile,我想我了解大多数逻辑。 However, I don't see the difference between "exposing" and "publishing" a port in this context. 但是,在这种情况下,我看不到“公开”和“发布”端口之间的区别。

All the tutorials I have seen first include the EXPOSE command in the Dockerfile: 我首先看过的所有教程都在EXPOSE中包含EXPOSE命令:

...
EXPOSE 8080
...

They then build an image from this Dockerfile: 然后,他们从此Dockerfile构建映像:

$ docker build -t an_image - < Dockerfile

And then publish the same port as above when running the image: 然后在运行映像时发布与上述相同的端口:

$ docker run -d -p 8080 an_image

or publish all ports using 或使用以下命令发布所有端口

$ docker run -d -P an_image

What is the point of exposing a port in the Dockerfile, if it will be published anyway? 如果仍要发布端口,则在Dockerfile中公开端口有什么意义? Would there ever be a need to expose a port first, and not publish it later? 是否需要先公开一个端口,然后再不发布它? Effectively, I would like to specify all the ports that I will use in the Dockerfile when creating the image, and then not bother with them again, running them simply with: 实际上,我想指定在创建映像时将在Dockerfile中使用的所有端口,然后不再麻烦它们,只需使用以下命令运行它们:

$ docker run -d an_image

Is this possible? 这可能吗?


#1楼

参考:https://stackoom.com/question/1Um60/Docker中的-公开-和-发布-有什么区别


#2楼

Basically, you have three options: 基本上,您有三个选择:

  1. Neither specify EXPOSE nor -p 既不指定EXPOSE也不指定-p
  2. Only specify EXPOSE 只指定EXPOSE
  3. Specify EXPOSE and -p 指定EXPOSE-p

1) If you specify neither EXPOSE nor -p , the service in the container will only be accessible from inside the container itself. 1)如果您未指定EXPOSE-p ,则只能从容器本身内部访问容器中的服务。

2) If you EXPOSE a port, the service in the container is not accessible from outside Docker, but from inside other Docker containers. 2)如果EXPOSE端口,则无法从Docker外部访问容器中的服务,而可以从其他Docker容器内部访问容器中的服务。 So this is good for inter-container communication. 因此,这对于容器间的通信很有用。

3) If you EXPOSE and -p a port, the service in the container is accessible from anywhere, even outside Docker. 3)如果使用EXPOSE并使用-p端口,则可以从任何地方访问容器中的服务,甚至可以从Docker外部访问。

The reason why both are separated is IMHO because: 两者分开的原因是恕我直言,因为:

  • choosing a host port depends on the host and hence does not belong to the Dockerfile (otherwise it would be depending on the host), 选择主机端口取决于主机,因此不属于Dockerfile(否则,将取决于主机),
  • and often it's enough if a service in a container is accessible from other containers. 通常,只要可以从其他容器访问某个容器中的服务就足够了。

The documentation explicitly states: 文档明确指出:

The EXPOSE instruction exposes ports for use within links. EXPOSE指令公开了供链接使用的端口。

It also points you to how to link containers , which basically is the inter-container communication I talked about. 它还为您指出了如何链接容器 ,这基本上就是我所说的容器间通信。

PS: If you do -p , but do not EXPOSE , Docker does an implicit EXPOSE . PS:如果您执行-p ,但不执行EXPOSE ,则Docker会执行隐式EXPOSE This is because if a port is open to the public, it is automatically also open to other Docker containers. 这是因为如果某个端口向公众开放,那么它也会自动向其他Docker容器开放。 Hence -p includes EXPOSE . 因此, -p包括EXPOSE That's why I didn't list it above as a fourth case. 这就是为什么我没有将其列为第四种情况。


#3楼

The EXPOSE allow you to define private (container) and public (host) ports to expose at image build time for when the container is running. EXPOSE允许您定义专用(容器)端口和公用(主机)端口,以在映像构建时针对容器运行时公开。 The public port is optional, if not a public port is specified, a random port will be selected on host by docker to expose the specified container port on Dockerfile. 公共端口是可选的,如果未指定公共端口,则docker将在主机上选择一个随机端口以在Dockerfile上公开指定的容器端口。

A good pratice is do not specify public port, because it limits only one container per host ( a second container will throw a port already in use ). 最好不要指定public port,因为每个主机仅限制一个容器(第二个容器将抛出一个已使用的端口)。

You can use -p in docker run to control what public port the exposed container ports will be connectable. 您可以在docker run使用-p来控制暴露的容器端口可连接的公共端口。

Anyway, If you do not use EXPOSE nor -p , no ports will be exposed. 无论如何,如果您既不使用EXPOSE也不使用-p ,则不会暴露任何端口。

If you always use -p at docker run you do not need EXPOSE but if you use EXPOSE your docker run command may be more simple, EXPOSE can be useful if you don't care what port will be expose on host, or if you are sure of only one container will be loaded. 如果你总是使用-pdocker run你不需要EXPOSE但如果你使用EXPOSE你的docker run命令可能更简单, EXPOSE如果你不关心什么端口将主机被暴露可能是有用的,或者如果你是确保只装载一个容器。


#4楼

Most people use docker compose with networks. 大多数人将docker compose与网络结合使用。 The documentation states: 文档指出:

The Docker network feature supports creating networks without the need to expose ports within the network, for detailed information see the overview of this feature). Docker网络功能支持创建网络,而无需暴露网络中的端口,有关详细信息,请参阅此功能概述。

Which means that if you use networks for communication between containers you don't need to worry about exposing ports. 这意味着,如果您使用网络在容器之间进行通信,则无需担心暴露端口。


#5楼

You expose ports using the EXPOSE keyword in the Dockerfile or the --expose flag to docker run. 您可以在Dockerfile中使用EXPOSE关键字或--expose标志公开端口,以使docker run。 Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports. 公开端口是一种记录使用哪些端口的方式,但实际上并没有映射或打开任何端口。 Exposing ports is optional. 公开端口是可选的。

Source: github commit 资料来源: github commit


#6楼

Short answer: 简短答案:

  • EXPOSE is a way of documenting EXPOSE文档化的一种方式
  • --publish (or -p ) is a way of mapping a host port to a running container port --publish (或-p )是一种 主机端口 映射到正在运行的容器端口的方法

Notice below that: 请注意以下几点:

  • EXPOSE is related to Dockerfiles ( documenting ) EXPOSE有关Dockerfiles归档
  • --publish is related to docker run ... ( execution / run-time ) --publish--publish docker run ...执行/运行时 )有关

Exposing and publishing ports 公开和发布端口

In Docker networking, there are two different mechanisms that directly involve network ports: exposing and publishing ports. 在Docker网络中,有两种直接涉及网络端口的不同机制:公开端口和发布端口。 This applies to the default bridge network and user-defined bridge networks. 这适用于默认桥接网络和用户定义的桥接网络。

  • You expose ports using the EXPOSE keyword in the Dockerfile or the --expose flag to docker run. 您可以在EXPOSE中使用EXPOSE关键字或--expose标志公开端口,以使EXPOSE run。 Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports . 公开端口是一种记录使用了哪些端口的方式, 但实际上并没有映射或打开任何端口 Exposing ports is optional. 公开端口是可选的。

  • You publish ports using the --publish or --publish-all flag to docker run . 您使用--publish--publish-all标志将端口发布到--publish docker run This tells Docker which ports to open on the container's network interface. 这告诉Docker在容器的网络接口上打开哪些端口。 When a port is published, it is mapped to an available high-order port (higher than 30000 ) on the host machine, unless you specify the port to map to on the host machine at runtime. 发布端口后,除非您在运行时指定要映射到主机上的端口,否则它将映射到主机上可用的高阶端口(高于30000 )。 You cannot specify the port to map to on the host machine when you build the image (in the Dockerfile), because there is no way to guarantee that the port will be available on the host machine where you run the image . 在构建映像时(在Dockerfile中),您无法指定要映射到主机上的端口,因为无法保证端口将在运行映像的主机上可用

from: Docker container networking 来自: Docker容器网络

Update October 2019 : the above piece of text is no longer in the docs but an archived version is here: docs.docker.com/v17.09/engine/userguide/networking/#exposing-and-publishing-ports 2019年10月更新 :以上文本不再包含在文档中,但此处为存档版本: docs.docker.com/v17.09/engine/userguide/networking/#exposed-and-publishing-ports

Maybe the current documentation is the below: 也许当前文档如下:

Published ports 发布的端口

By default, when you create a container, it does not publish any of its ports to the outside world. 默认情况下,创建容器时,它不会将其任何端口发布到外界。 To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag. 要使端口可用于Docker外部的服务或未连接到容器网络的Docker容器,请使用--publish-p标志。 This creates a firewall rule which maps a container port to a port on the Docker host. 这将创建一个防火墙规则,该规则将容器端口映射到Docker主机上的端口。

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

Also, 也,

EXPOSE 暴露

...The EXPOSE instruction does not actually publish the port . ... EXPOSE指令实际上并未发布端口 It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. 它充当构建映像的人员和运行容器的人员之间的一种文档类型,有关打算发布哪些端口的信息。

from: Dockerfile reference 来自: Dockerfile参考






Service access when EXPOSE / --publish are not defined: EXPOSE / --publish时的服务访问:

At @Golo Roden's answer it is stated that:: @Golo Roden的回答是:

"If you do not specify any of those, the service in the container will not be accessible from anywhere except from inside the container itself." “如果不指定任何内容,则只能从容器本身内部访问任何地方的容器中的服务。”

Maybe that was the case at the time the answer was being written, but now it seems that even if you do not use EXPOSE or --publish , the host and other containers of the same network will be able to access a service you may start inside that container. 也许在编写答案时就是这种情况,但是现在看来,即使您不使用EXPOSE--publish ,同一网络中的host和其他containers也将能够访问您可以启动的服务在那个容器里。

How to test this: 如何测试:

I've used the following Dockerfile . 我使用了以下Dockerfile Basically, I start with ubuntu and install a tiny web-server: 基本上,我从ubuntu开始并安装一个小型Web服务器:

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

I build the image as "testexpose" and run a new container with: 我将映像build为“ testexpose”,并使用以下命令run新容器:

docker run --rm -it testexpose bash

Inside the container, I launch a few instances of mini-httpd : 在容器内,我启动了一些mini-httpd实例:

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

I am then able to use curl from the host or other containers to fetch the home page of mini-httpd . 然后,我可以使用主机或其他容器中的curl来获取mini-httpd的主页。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值