Understanding Ports and Docker

What is a port?

A computer has a maximum of 65,535 ports and each one is identified by it's number. Some ports are special and are recognised across the industry for specific uses, such as port 25 for email or ports 80 and 443 for websites.

A port is basically a gateway open on a computer for communication to happen. In order for data to move through a port that port needs to be 'open' and something needs to be listening on it to receive the data.

A operating system can have an application 'listening' on a port, then when something opens a connection to that port and sends data, the listening application will receive it.

In Windows you can see what's happening on ports by typing the following in a command prompt:

netstat -ano

This will give you a long list of ports currently in use on your machine:

  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       1068
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:2179           0.0.0.0:0              LISTENING       4224
  TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       5584
  TCP    0.0.0.0:17500          0.0.0.0:0              LISTENING       5028

On the left you can see Proto. This is the protocol on the port and it'll be one of their TCP or UDP. Local Address shows the port that is in use. On the last column you can see PID this is the process ID of the application listening on the given port.

To see what application is listening on a given port you can get the PID and use it in the following command on Windows:

tasklist | findstr <pid>

This will return the application for the given process ID. This is really useful to find out what application is using a port on your computer. Try it, you might be surprised with what you find.

Binding Ports in Docker

Docker uses ports for most communication between containers. The Docker engine can request ports on the host operating system and bind them to ports on running containers. Both the host operating system and Docker maintain their own list of available ports. Only one application can run on a given port at any time.

Be aware that a port on the host operating system does not automatically map to a port within Docker. So for instance, port 5000 on the host operating system is not port 5000 within the Docker container.

As an example let's say I have a Docker image I want to run. We'll use nginx, a powerful, fast, open-source hosting platform. When I tell Docker that I want to create a container from this image I can also specify the ports to bind.

Nginx's default listening port in a container is 80 so we'll use that as an example, however the port the container is bound to can really be anything as it's inside the Docker engine. As long as the application running in the container is listening on that port we're good to go.

docker run -p <host-port>:<container-port> -d <image-name>

Example:
docker run -p 5000:80 -d nginx

The above example is saying I want docker to pull down and run the nginx image mapping the host port 5000 to the container port 80. (nginx by default listens on port 80 in a container.)

So for this to work my host must have port 5000 free and the image nginx must be listening on port 80 (the default behaviour for nginx). If all of these things are working then any request to http://localhost:5000 on the host machine will route through to port 80 on the Docker container and return the nginx instance. Try it now then navigate to http://localhost:5000. You should see the nginx landing page.

Remember that even if the ports are mapped correctly in Docker, the application running in the container still has to be listening on the port you've specified (in this case 80). Even if Docker is routing the traffic correctly, if the application isn't listening it's not going to work.

You don't need to worry too much about the port inside the Docker container you just need to make sure that it's mapped correctly to a port on the host so that it can be accessed. Multiple containers can run on the same machine in Docker on separate ports and nginx can route the requests to the individual containers based on the hostname or other conditions. I'll cover this functionality in a future post.

Happy porting!