1. Overview
In Docker, it's important to know which ports a containerized application is listening on. We also need a way to access the application from outside the container.
To address those concerns, Docker enables us to expose and publish the ports.
In this article, we'll learn about both exposing and publishing ports. We'll use a simple Nginx web server container as an example.
2. Exposing Ports
An exposed port is a piece of metadata about the containerized application. In most cases, this shows which ports the application is listening to. Docker itself does not do anything with an exposed port. However, when we launch a container, we can use this metadata when publishing the port.
2.1. Expose With Nginx
Let's use the Nginx web server to try this out.
If we take a look at the Nginx official Dockerfile, we'll see that port 80 is exposed with the following command:
EXPOSE 80
Port 80 is exposed here because it's the default port for the http protocol. Let's run the Nginx container on our local machine and see if we can access it through port 80:
$ docker run -d nginx
The above command will use Nginx's latest image and run the container. We can double-check that the Nginx container is running with the command:
$ docker container ls
This command will output some information about all running containers, including Nginx:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cbc2f10f787f nginx "/docker-entrypoint..." 15 seconds ago Up 15 seconds 80/tcp dazzling_mclean
Here we see 80 under the port section. Since port 80 is exposed, we might think that accessing localhost:80 (or just localhost) will display the Nginx default page, but that's not the case:
$ curl http://localhost:8080
... no web page appears
Though the port is exposed, Docker has not opened it to the host.
2.2. Ways to Expose Ports
There are two main ways to expose ports in Docker. We can do it in the Dockerfile with the EXPOSE command:
EXPOSE 8765
Alternatively, we can also expose the port with the –expose option when running a container:
$ docker run --expose 8765 nginx
3. Publishing Ports
For a container port to be accessible through the docker host, we need to publish it.
3.1. Publish With Nginx
Let's run Nginx with a mapped port:
$ docker run -d -p 8080:80 nginx
The above command will map port 8080 of the host to port 80 of the container. The general syntax for the option is:
-p <hostport>:<container port>
If we go to localhost:8080, we should get Nginx's default welcome page:
$ curl http://localhost:8080
StatusCode : 200
StatusDescription : OK
Content : <!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
... more HTML
Let's list all running containers:
$ docker container ls
Now we should see that the container has a port mapping:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
38cfed3c61ea nginx "/docker-entrypoint..." 31 seconds ago Up 30 seconds 0.0.0.0:8080->80/tcp dazzling_kowalevski
Under the ports section, we have the 0.0.0.0:8080->80/tcp mapping.
Docker, by default, added 0.0.0.0 non-routable meta-address for the host. It means that the mapping is valid for all addresses/interfaces of the host.
3.2. Restricting Container Access
We can restrict access to the container, based on the host IP address. Rather than allowing access to the container from all the interfaces (which 0.0.0.0 does), we can specify the host IP address within the mapping.
Let's limit access to the container to traffic from just the 127.0.0.1 loopback address:
$ docker run -d -p 127.0.0.1:8081:80 nginx
In this case, the container is only accessible from the host itself. This uses the extended syntax for publishing, which includes an address binding:
-p <binding address>:<hostport>:<container port>
4. Publish All Exposed Ports
The exposed port metadata can be useful for launching a container as Docker gives us the ability to publish all exposed ports:
$ docker run -d --publish-all nginx
Here, Docker binds all exposed ports in the container to free random ports on the host.
Let's look at the containers this command launches:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a23e78732ce nginx "/docker-entrypoint..." 6 minutes ago Up 6 minutes 0.0.0.0:32768->80/tcp pedantic_curran
As we expected, Docker chose a random port (32768 in this case) from the host and mapped it to the exposed port.
5. Conclusion
In this article, we learned about exposing and publishing the ports in Docker.
We also discussed that the exposed port is metadata about the containerized application, whereas publishing a port is a way to access the application from the host.
The post Difference Between “expose” and “publish” in Docker first appeared on Baeldung.