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

ghz 1years ago ⋅ 6054 views

Question

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?


Answer

Basically, you have three (four) options:

  1. Neither specify EXPOSE nor -p

  2. Only specify EXPOSE

  3. Specify EXPOSE and -p

  4. Only specify -p which implicitly does EXPOSE

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

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

  7. If you EXPOSE and -p a port, the service in the container is accessible from anywhere, even outside Docker.

  8. 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. This is effectively same as 3).

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 (legacy feature), which basically is the inter-container communication I talked about.