Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between "expose" and "publish" in Docker?

Tags:

docker

I'm experimenting with Dockerfiles, and I think I understand most of the logic. 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 8080 ... 

They then build an image from this 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? 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:

$ docker run -d an_image 

Is this possible?

like image 229
user1496984 Avatar asked Mar 01 '14 06:03

user1496984


People also ask

What does expose mean Docker?

The EXPOSE instruction exposes a particular port with a specified protocol inside a Docker Container. In the simplest term, the EXPOSE instruction tells Docker to get all its information required during the runtime from a specified Port. These ports can be either TCP or UDP, but it's TCP by default.

What is the difference between ports and expose Docker?

Expose is defined as:Only the internal port can be specified. Ports are not exposed to host machines, only exposed to other services.

Do I need expose in Dockerfile?

I don't think there's any need to use the EXPOSE instruction in your own Dockerfile if the docker image is simply a web app. You might want to use it when you are distributing your Dockerfile to others and letting them connect to the application.

What is publish port in Docker?

There's a difference between expose and publish. Expose means to open the port on the container side, publish means to open it on the Docker host to the outside world. For example, if your docker run command had -p 80:8080, it's exposing port 8080 on the container and publishing port 80 on the host.


2 Answers

Basically, you have three options:

  1. Neither specify EXPOSE nor -p
  2. Only specify EXPOSE
  3. Specify EXPOSE and -p

1) If you specify neither EXPOSE nor -p, the service in the container will only be accessible from inside the container itself.

2) If you EXPOSE a port, the service in the container is not accessible from outside Docker, but from inside other Docker containers. 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.

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),
  • 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.

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. This is because if a port is open to the public, it is automatically also open to other Docker containers. Hence -p includes EXPOSE. That's why I didn't list it above as a fourth case.

like image 50
Golo Roden Avatar answered Oct 02 '22 04:10

Golo Roden


Short answer:

  • EXPOSE is a way of documenting
  • --publish (or -p) is a way of mapping a host port to a running container port

Notice below that:

  • EXPOSE is related to Dockerfiles ( documenting )
  • --publish is related to docker run ... ( execution / run-time )

Exposing and publishing ports

In Docker networking, there are two different mechanisms that directly involve network ports: exposing and publishing ports. 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. 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. This tells Docker which ports to open on the container’s network interface. 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. 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.

from: Docker container networking

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

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. This creates a firewall rule which maps a container port to a port on the Docker host.

and can be found here: docs.docker.com/config/containers/container-networking/#published-ports

Also,

EXPOSE

...The EXPOSE instruction does not actually publish the port. 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






Service access when EXPOSE / --publish are not defined:

At @Golo Roden's answer it is stated that::

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

How to test this:

I've used the following Dockerfile. Basically, I start with ubuntu and install a tiny web-server:

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

I build the image as "testexpose" and run a new container with:

docker run --rm -it testexpose bash 

Inside the container, I launch a few instances of 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.


Further reading

Very detailed articles on the subject by Ivan Pepelnjak:

  • Exposed ports
  • Published ports
like image 45
tgogos Avatar answered Oct 02 '22 04:10

tgogos