skip to Main Content

This is the fist time I am writing a Dockerfile. I have an application in Angular that connects to different backends (Spring Boot Rest services). I mean to say the spring boot application has been deployed in many different sites/locations. They all have different URLs. These Rest services are already there (I didn’t write these rest services). I was getting CORS error when I tried to call these Rest services. So I had to us the below xyx.proxy.conf.json

Below is the configurations I have:

package.json

  "scripts": {
    "ng": "ng",
    "start:localhost": "ng serve --proxy-config localhost.proxy.conf.json",
    "start:site1qa": "ng serve --proxy-config site1qa.proxy.conf.json",
    "start:site2qa": "ng serve --proxy-config site2qa.proxy.conf.json",
    "start:site1prod": "ng serve --proxy-config site1qa.proxy.conf.json",
    "start:site2prod": "ng serve --proxy-config site2prod.proxy.conf.json",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e --proxy-config site1qa.proxy.conf.json"
  },

site1qa.proxy.conf.json Note: I must have to use proxy as I am getting CORS error

{
  "/RestWeb/*": {
    "target": "http://site1qa:8005",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug"
  }
}

Angular Service.ts

  findAllByModelYear(): Observable<string[]> {
    return this.httpClient.get<string[]>('/RestWeb/model/findAllModelYearCodes');
  }

I tested the application using below commands in my local pointing to different backends like this:

npm run start:localhost
OR
npm run start:site1qa
OR
npm run start:site2prod

My current Dockerfile is like this:

# Stage 1: Compile and Build angular codebase

# Use official node image as the base image
FROM node:latest as build

# Set the working directory
WORKDIR /usr/local/app

# Add the source code to app
COPY ./ /usr/local/app/

# Install all the dependencies
RUN npm install

# Generate the build of the application
RUN npm run build

# Stage 2: Serve app with nginx server

# Use official nginx image as the base image
FROM nginx:latest

# Copy the build output to replace the default nginx contents.
COPY --from=build /usr/local/app/dist/my-projectt /usr/share/nginx/html

# Expose port 80
EXPOSE 80

Currently am I build like this:

docker build -t dockerangular .

And run like this:

docker run -it -p 8000:80 --name angulardocker1 my-first-app

Question:

How do I pass argument (while building and/or running the application), so I can connect to different sites (as mentioned in package.json i.e. using xyx.proxy.conf.json)

2

Answers


  1. Since you seem to use NGINX as HTTP server, you can use the proxy_pass directive for the proxy purpose.

    Also, you can create your own NGINX template configuration files, i.e. during bootstrap NGINX looks in the /etc/nginx/templates/ folder, and if any .template files are present, NGINX outputs the result of executing envsubst to /etc/nginx/conf.d, for example:

    If you place a file in /etc/templates/default.conf.template, that contains variable references like this:

    listen  ${MY_NGINX_PORT};
    

    the output would go to /etc/nginx/conf.d/default.conf and look like this (let’s say MY_NGINX_PORT is 8080):

    listen 8080;
    

    Ref: https://hub.docker.com/_/nginx

    The solution:

    Since NGINX’s default configuration file, located in /etc/nginx/conf.d/default.conf, contains a very simple setup, you can create a template file and let NGINX use it to override the default conf file during bootstrap:

    /etc/templates/default.conf.template –(would become after envsubst)–> /etc/nginx/conf.d/default.conf

    1. Create a file named nginx-default.conf.template and fill it with this content and then put it in your project root folder:
    server {
        listen       80;
        server_name  _;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    
        location /RestWeb/ {
            proxy_pass ${REMOTE_API_URL};
        }
    }
    

    Note the /RestWeb/ path and the ${REMOTE_API_URL} custom environment variable, i.e. any request starting with the /RestWeb/ path will be seamlessly proxied to the ${REMOTE_API_URL}, just like ng cli / webpack’s proxy dev server does.

    1. Adjust your Dockerfile as follows:
    ...
    # Add this line right before `EXPOSE 80`
    COPY nginx-default.conf.template /etc/nginx/templates/default.conf.template
    ...
    
    1. Next time you pass the environment variable REMOTE_API_URL to docker run, its value will be used automatically when the NGINX server starts up, e.g.
    docker run -p 8000:80 -e REMOTE_API_URL="http://site1qa:8005" my-first-app
    

    or for a secure API:

    docker run -p 8000:80 -e REMOTE_API_URL="https://site1prod:8005" my-first-app
    

    A few tips

    • You don’t need EXPOSE 80. It is only for documentation purposes, and does actually nothing.

    • Avoid using the latest version of Docker images, like nginx:latest or node:latest. The latest, as the name suggests, always points to the latest version.

      • With every docker build instruction the respective image with the latest version will be pulled from the Docker Hub, which, however, may not be what you actually want/need. Imagine, today the current version of node is 12 and after a few days/weeks version 13 comes out and with the tag node:latest you would pull it and use it under the hood. And that would be risky, because it could possibly break something
      • So it is better to stick to a particular version and increase the version yourself over time after you have tested the new version through (e.g. you can use node:14-alpine and nginx:1.19.9-alpine. See the Docker Hub for more tags)
    • These are equivalent:

      WORKDIR /usr/local/app
      COPY ./ /usr/local/app/
      
      WORKDIR /usr/local/app
      COPY ./ .
      

    See: https://docs.docker.com/engine/reference/builder/#workdir

    • Modify your Dockerfile as follows to utilize the Docker layer caching mechanism to make subsequent Docker builds run faster
    ...
    WORKDIR /usr/local/app
    COPY package.json .
    RUN npm install
    COPY . .
    RUN npm run build
    ...
    

    See: Why COPY package*.json ./ precedes COPY . .?

    Login or Signup to reply.
  2. Did you try to add the site1qa.proxy.conf.json to angular.json file like this?:

    "serve": {
              "builder": "@angular-devkit/build-angular:dev-server",
              "options": {
                "browserTarget": "projectname:build",
                "proxyConfig": "./site1qa.proxy.conf.json"
              },
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search