How to expose multiple ports with Docker?


When we package any application using Docker then either we create Dockerfile or docker-compose.yaml, even you can create both the files and share the files with others. There is one important aspect in both the files .i.e. PORT.

Any container which you build and ship to other developers has to have one or more defined PORT on which it can run and expose the services. As a rule of thumb, there should be at least one PORT defined inside either Dockerfile or docker-compose.yaml. In some cases, the docker container can take some random port that is available inside the host machine in case you haven’t defined any specific port.

In this article we will start with a very basic example where we are going to expose a single port for the docker container then we are gonna add multiple ports to it. Later on, we are also gonna see how to use EXPOSE', –expose, -P, -p for publishing and exposing the ports for docker containers.

Here are the multiple ways to expose more than one port with a Docker container -

  1. Using ‘EXPOSE’ inside your Dockerfile for exposing a single port
  2. Using multiple ‘EXPOSE’ inside your Dockerfile for exposing more than one port
  3. docker-compose.yaml for exposing multiple ports
  4. -P(Upper case) to publish all expose ports randomly
  5. -p(Lower case) to publish on specific ports
  6. docker run command with –expose flag .e.g. - docker run –name mySpringBoot -d –expose=9090 mySpringBoot:latest
  7. Docker ports range
  8. Difference between EXPOSE and publish

1. Using ‘EXPOSE’ inside your Dockerfile for exposing a single port

Let us start with a very basic example of a Dockerfile in which we are going to use EXPOSE keyword for exposing a single port for running Spring Boot Microservice. I have taken Spring Boot as my base application for creating the docker container but you can take any application of your choice.

(*GitRepo - Here is a GitRepo for my project)

1.1 Here is my Dockerfile exposing single only single port -
 1FROM openjdk:8-jdk-alpine
 2
 3EXPOSE 9090
 4
 5ARG JAR_FILE=build/libs/*.jar
 6COPY ${JAR_FILE} app.jar
 7
 8RUN mkdir destination-dir-for-add
 9ADD sample.tar.gz /destination-dir-for-add
10
11ENTRYPOINT ["java","-jar","/app.jar"] 

As you can see in the above code snippet I am exposing only a single port 9090 inside my Dockerfile.


2. Using multiple ‘EXPOSE’ inside your Dockerfile for exposing more than one port

In the previous Step 1 we have seen how to EXPOSE single port, let us take the same example and add one more port so you will have your microservice running on two ports .i.e. - 9090, 9091

 1FROM openjdk:8-jdk-alpine
 2
 3EXPOSE 9090
 4EXPOSE 9091
 5
 6ARG JAR_FILE=build/libs/*.jar
 7COPY ${JAR_FILE} app.jar
 8
 9RUN mkdir destination-dir-for-add
10ADD sample.tar.gz /destination-dir-for-add
11
12ENTRYPOINT ["java","-jar","/app.jar"] 

Now in the same Dockerfile we have a couple of ports 9090, 9091 and now our microservice application will be serving the request on both the ports


2.1 Use port range for exposing multiple Docker PORTS

Now considering the previous example of Dockerfile, let us assume that you have to expose 10 different ports. Docker provides a port range that can be used for exposing multiple numbers of ports.

Here is an example Dockerfile for the port range -

 1FROM openjdk:8-jdk-alpine
 2
 3EXPOSE 9090-9091
 4
 5ARG JAR_FILE=build/libs/*.jar
 6COPY ${JAR_FILE} app.jar
 7
 8RUN mkdir destination-dir-for-add
 9ADD sample.tar.gz /destination-dir-for-add
10
11ENTRYPOINT ["java","-jar","/app.jar"] 

3. ‘docker-compose.yaml’ for exposing multiple ports

Now after looking into the Dockerfile in Step-1, Step-2, let see how we can use docker-compose.yaml for publishing the multiple ports.

Here is my docker-compose.yaml file in which I have defined two ports 9090,9091

 1version: '3'
 2
 3services:
 4  jhooq-springboot-container:
 5    image: jhooq-spring-boot-docker-compose:1
 6    build:
 7      context: ./
 8      dockerfile: Dockerfile
 9    volumes:
10      - /data/jhooq-springboot-container
11    ports:
12      - 9090
13      - 9091 

So this is how you are gonna create docker-compose.yaml for exposing multiple ports.

(*Note - Please do replace the docker image name before using the above mentioned docker-compose.yaml)


4. -P (Upper case) to publish all expose ports randomly

There are few more flags - -P,-p provided by Docker which can be used at run time when issuing the Docker command.

Let’s first start with -P flag - When you use -P flag in your docker command it will publish all exposed ports to the random ports on the host machine.

Here is an example command -

1docker run --name myspringbootapp -d -P jhooq-spring-boot-docker-compose:latest 

How docker is gonna process the command -

  1. In our dockerfile/docker-compose.yaml we configured two ports 9090, 9091
  2. While using -P we do not assign ports, we rely on -P flag at runtime and convert EXPOSE instructions in the Dockerfile to assign a specific port
  3. Using EXPOSE docker identifies all the ports which need to be exposed and later on all exposed ports are assigned with random port.
  4. The automatic port assigning also prevent the port conflicts

5. -p(Lower case) to publish on specific ports

If you want to assign some specific ports for your Docker container then -p would be the right choice for you. Always remember its -p (lower case).

Here is an example of the docker command using -p

1docker run --name myspringbootapp -d -p 90:9090 jhooq-spring-boot-docker-compose:latest 
  1. Irrespective of the -P (Upper case) here we need to explicitly mention the port.
  2. In the above docker run we have mapped port 9090 to run on 90

5.1 TCP UDP port binding

Here are some of the examples of Docker run commands using -p along with tcp/udp -

Docker Flag
-p 8080:80 Bind container’s TCP port 80 to host’s port 8080
-p 192.168.1.1:8080:80 Bing container’s TCP port 80 to host’s port 8080 for connections to host IP 192.168.1.1 . By default, Docker binds published container ports to the 0.0.0.0 IP address, which matches any IP address on the system
-p 8080:80/udp Bing container’s UDP port 80 to host’s port 8080
-p 8080:80/tcp -p 8080:80/udp Bind container’s UDP port 80 to host’s port 8080
-p 2346-2346:2346-2346/tcp Specify hostPort and containerPort as a range of ports. Note that the number of container ports specified in the range should be equivalent to the number of host ports specified in the rane
-p 2346-2346:2346/tcp Specify hostPort range only. In such a case containerPort must not be in a specific range. Container port will be published anywhere within the stated hostPort range

6. docker run_ command with _–expose_ flag .e.g. - docker run –name mySpringBoot -d –expose=9090 mySpringBoot:latest

Suppose if you want do start your docker container quickly then you can simply use the docker run command along with the -d, –expose flag.

Example docker command -

1docker run --name myspringbootapp -d --expose=8081 jhooq-spring-boot-docker-compose:latest

After running the above command you can verify the running docker container using the following command -

1docker ps

It should result following -

1CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2kd8kdh3kl394 jhooq-spring-boot-docker-compose:latest "java -jar /myspring.j…" 5 seconds ago Up 3 seconds 8080-8081/tcp myspringbootapp

7. Docker ports range - how to use port range in Docker?

There is one more feature provided by docker which is a port range, after docker 1.5 you can define the port range using EXPOSE 5000-6000.

Example -

1docker run --expose=5000-6000

Or you can use the -p flag to publish the range of the ports.

Example -

1docker run -p 7000-8000:7000-8000

8. Difference between EXPOSE and publish

Here are some key differences between the EXPOSE and -p

  1. If you do not use EXPOSE, -p then the service will not be exposed outside of the container and it can only be accessed from inside the container itself.

  2. If you use EXPOSE then again the services will not be exposed from outside but within the containers. So it can be used for inter-container communication

  3. If you use both EXPOSE, -p then you can access the container service from outside, so which means you can communicate within docker container as well as from outside also

If you EXPOSE and -p a port, the service in the container is accessible from anywhere, even outside Docker.

Anchor-17-feb-2021