Mapping ports in Compute Engine with Docker

Viewed 2663

I have a docker image running on Google Compute Engine. The image contains a Spring Boot application running on port 9000.

It is exposes on http://<ip>:9000 and I can access is without any problems. I am trying to configure the exposed port to be 80 in order to configure DNS record to point just to the IP address.

My question is how to achieve that because the documentation left me confused. I am using the online GCP console (web interface) for the deployment and there is no field to specify docker run -p 9000:80 command which would solve my issue (if there is, please correct me).

So do I need to remap the port in the Spring Boot settings? Or inside the Docker container? Or am I suppose to configure some forwarding rules in GCP? Thanks for the clarification!

My DOCKER file looks as follows:

FROM gcr.io/distroless/java
VOLUME /tmp
ADD build/libs/*.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT ["java","-jar","app.jar"]

I am using the Container optimized OS from GCP.

4 Answers

tldr : you can't

When you deploy a container in compute engine in this way, docker network is in host network mode, which means that (doc) : a container shares the host's network stack and all interfaces from the host are available to the container.

So compute engine will directly expose container port, on his own interface. So you have to configure your container to expose correct port.

You'll want to setup a reverse proxy (like nginx) in the same container that will proxy from port 80 to port 9000. Once this is setup, you should open the firewall to port 80 and close the firewall on 9000/wherever else.

You'll need to change your image so the entrypoint is a script you create which starts up both the proxy AND your java process. If either process fails, your script should die and therefore your container as well. When your container dies, the Container Optimized OS will restart it.

As a ROUGH outline (you will need to do your research on nginx):

Dockerfile

.... whatever ....
COPY nginx.conf /etc/nginx/nginx.conf
COPY startup.sh .
RUN chmod 777 startup.sh
ENTRYPOINT ./startup.sh

startup.sh

(see here -n option requires >= bash 4.3)

#! /bin/bash

{ nginx; } &
{ java -jar app.jar; } &
wait -n
pkill -P $$

nginx.conf

daemon off;

http {

  server {
    listen 80;
    server_name _;

    location / {
      proxy_pass http:localhost:9000;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }
  }
}

Edit

Added the daemon off; line to the above nginx.conf file so nginx will not daemonize. This allows the startup script to stop when nginx stops.

Use App Engine flexible environment with a custom runtime instead. App Engine flexible environment is specifically designed to run containers on Compute Engine. All you have to do is make sure that your Spring Boot app listens on port 8080, and the Dockerfile includes the line "EXPOSE 8080". See custom runtimes documentation.

I solved my issue by mapping the Spring Boot port to port 80 in the production profile.

This allows me to map the DNS records to raw IP address without having to do any extra configuration.

Related