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?
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.
Source: github commit
The
EXPOSE
allow you to define private (container) and public (host) ports to expose at image build time for when the container is running. 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.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 ).
You can use
-p
indocker run
to control what public port the exposed container ports will be connectable.Anyway, If you do not use
EXPOSE
nor-p
, no ports will be exposed.If you always use
-p
atdocker run
you do not needEXPOSE
but if you useEXPOSE
yourdocker 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.Most people use docker compose with networks. The documentation states:
Which means that if you use networks for communication between containers you don't need to worry about exposing ports.
Short answer:
EXPOSE
is a way of documenting--publish
(or-p
) is a way of mapping a host port to a running container portNotice below that:
EXPOSE
is related toDockerfiles
( documenting )--publish
is related todocker run ...
( execution / run-time )Also,
Service access when
EXPOSE
/--publish
are not defined:At @Golo Roden's answer it is stated that::
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
, thehost
and othercontainers
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:I
build
the image as "testexpose" andrun
a new container with:Inside the container, I launch a few instances of
mini-httpd
:I am then able to use
curl
from the host or other containers to fetch the home page ofmini-httpd
.Basically, you have three options:
EXPOSE
nor-p
EXPOSE
EXPOSE
and-p
1) If you do not 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:
The documentation explicitly states:
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 notEXPOSE
, Docker does an implicitEXPOSE
. This is because if a port is open to the public, it is automatically also open to other Docker containers. Hence-p
includesEXPOSE
. That's why I didn't list it above as a fourth case.