Why use EXPOSE in Dockerfile -- since you can bind to all ports anyways I can docker run -p 3000:3000 image without EXPOSEing that port in the container (see below). If that's true, then why bother putting EXPOSE in the Dockerfile? Is it just for communication to image users? Because I don't know of a functional reason to EXPOSE ports if they are all bindable anyways.



Here are the steps showing me binding to a port in a container despite the fact it is not EXPOSEd

$ cat Dockerfile
FROM alpine
RUN apk add nodejs npm vim
COPY webserver /webserver
CMD [ "node", "/webserver/index.js" ]


$ docker build .
Sending build context to Docker daemon  1.931MB
Step 1/4 : FROM alpine
 ---&gt; 11cd0b38bc3c
Step 2/4 : RUN apk add nodejs npm vim
 ---&gt; Using cache
 ---&gt; 4270f8bdb201
Step 3/4 : COPY webserver /webserver
 ---&gt; Using cache
 ---&gt; 67f4cda61ff0
Step 4/4 : CMD [ "node", "/webserver/index.js" ]
 ---&gt; Using cache
 ---&gt; 1df8f9024b85
Successfully built 1df8f9024b85


$ curl localhost:4400
curl: (7) Failed to connect to localhost port 4400: Connection refused


$ docker run -d -p 4400:3000 1df8f9024b85
7d0e6c56f8ad8827fe72830a30c1aac96821104b8ea111291ca39e6536aad8fd


$ curl localhost:4400
Hello World!


$
Docker's EXPOSE documentation addresses this specific point:


  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. To actually publish the port when running
  the container, use the -p flag on docker run to publish and map
  one or more ports, or the -P flag to publish all exposed ports and
  map them to high-order ports.


Pay attention to the last sentence, if you expose multiple ports then -P becomes useful to avoid setting multiple -p on the command line.