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
Dockerfileor use--exposeand then publish it with the-Pflag. 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
Dockerfileor use--exposeand then publish it with the-p 80:80flag. 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:80in 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:80to 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.