docker,

Expose vs Publish ports in Docker

Dec 07, 2021 · 3 mins read · Post a comment

The general idea for communication between microservices (whatever is HTTP, message or event-driven communication) is related to certain protocols and ports on which each microservice listens for incoming requests. Since Docker is the most popular choice for building microservices in the local development stage, I’m going to distinguish between the two known and often confusing terms EXPOSE and publish ports.

Expose ports

EXPOSE is usually part of the Dockerfile and serves only as an information for the person or the team to know which port they should expect to open when building and running the container. Basically, a documentation in a way.

For instance, if we take the official Nginx Dockerfile, it ends with:

EXPOSE 80

STOPSIGNAL SIGQUIT

CMD ["nginx", "-g", "daemon off;"]

Step 1. Let’s try to run an Nginx container.

docker run --name webserver -d nginx

Step 2. Verify running container.

docker container ls

Output:

CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
03a415ae5c07   nginx     "/docker-entrypoint.…"   4 seconds ago   Up 4 seconds   80/tcp    webserver

Step 3. Test the connection from the host machine.

curl http://localhost

Expected output:

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

Step 4. Even if we add additional exposed port, the result will be the same.

docker run --name webserver-custom --expose 8888 -d nginx

Step 5. Verify the running container.

docker container ls

Expected output:

CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS              NAMES
5fbbbfdc1f40   nginx     "/docker-entrypoint.…"   3 seconds ago   Up 2 seconds   80/tcp, 8888/tcp   webserver-custom

Step 6. Test the connection from the host machine again, but this time use the other exposed port, in this case port 8888.

curl http://localhost:8888

Expected output:

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

Publish ports

Publishing container ports is enabled by --publish and -p flags. Using these flags, we are mapping ports, so we could easily expose a container service to the host machine.

Step 1. Let’s do it from the command line first.

docker run --name webserver -d -p 80:80 nginx

Step 2. Verify running container.

docker container ls

Expected output:

CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS                  PORTS                NAMES
c1d9f7590490   nginx     "/docker-entrypoint.…"   1 second ago   Up Less than a second   0.0.0.0:80->80/tcp   webserver

Step 3. Test the connection.

curl http://localhost

Expected output:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Note(s): Regarding docker-compose, you could publish ports by adding the configuration option ports. For instance:

version: '3.8'
services:
  webserver:
    image: nginx
    ports:
      - "80:80"

It’s worth to mention that, the Docker Compose stack creates its own default network where all services that are part of the stack are internally reachable.

Conclusion

TL;DR expose serves only as a documentation for the containers service listening port, while publish is actually exposing ports to external networks. Feel free to leave a comment below and if you find this tutorial useful, follow our official channel on Telegram.