Docker Tip #59: Difference between Exposing and Publishing Ports
You can expose ports by using EXPOSE in your Dockerfile, --expose on the command line but there's also publishing ports too.
When you put EXPOSE 80
(or any port you want) in your Dockerfile
that’s
going to tell Docker that your container’s service can be connected to on port
80.
It doesn’t set up any networking properties. You can think of it more like
a runtime configuration option that’s explicitly stated in your Dockerfile
to
act as nothing more than documentation on which port(s) your service listens on.
That “documentation” is presented to you when you do a docker container ls
.
The exposed port will be in the PORTS
column, and it’s also available when
you inspect a container.
You can also expose a port using --expose 80
from the docker container run --expose 80 ...
command, but you would only want to do this if you don’t have
EXPOSE
defined in your Dockerfile
, but depending on what you want to do,
you may not need to expose anything.
Allowing Containers to Talk to Each Other Internally
Containers on the same network can talk to each other regardless of whether or
not you exposed or published your ports back to the Docker host with -p
.
This is useful for services like Postgres or Redis. These are things you typically wouldn’t want accessible from the internet, but you would want them accessible to your web application containers running on the same Docker network.
If you check out the official Docker images for Postgres and Redis, you’ll notice
they set up EXPOSE 5432
(Postgres) and EXPOSE 6379
(Redis) in their
Dockerfile
already. They did that as a best practice to inform you on which
port is being used.
Allowing Containers to Talk to Each Other + the Outside World
In this case, you have a few options:
You can expose a port through your
Dockerfile
or use--expose
and then publish it with the-P
flag. This will bind the exposed port to your Docker host on a random port (verified by runningdocker container ls
).You can expose a port through your
Dockerfile
or use--expose
and then publish it with the-p 80:80
flag. This will bind the exposed port to your Docker host on port 80, and it expects the exposed port is 80 too (adjust as necessary withHOST:CONTAINER
).You can ignore exposing anything and just use
-p 80:80
in which case this doubles as both exposing AND publishing the port. Everyone from the outside world will be able to connect.You can use
-p 127.0.0.1:80:80
to do the same as #2 / #3 except now only your local Docker host will be able to connect, not everyone. This is useful if you had let’s say nginx running on your Docker host and you wanted it to be able to connect to a container.
What Should You Do?
I think it’s a good idea to always use EXPOSE
in your Dockerfile
if your
service listens on a port because it explicitly states what port the service
uses. Then you can optionally publish a port back to your Docker host with -p
so the outside world can connect to your service.