3

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)

SK.
  • 1,390
  • 2
  • 28
  • 59
  • You might want to take a look at the ```ENTRYPOINT``` instruction you can set as a last line in your dockerfile. With that you can specify an array of command and arguments, and at runtime just add any arguments to it that you need. See also this [topic](https://stackoverflow.com/questions/21553353/what-is-the-difference-between-cmd-and-entrypoint-in-a-dockerfile) – Chai Apr 02 '21 at 21:17

2 Answers2

2

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 . .?

Kenan Güler
  • 1,868
  • 5
  • 16
  • I haven't gotten a chance to test this. For now I have given up vote, once I test it I will accept the answer. thanks a lot – SK. Apr 12 '21 at 00:31
0

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"
          },
Nederxus
  • 65
  • 1
  • 5
  • then how to configure multiple site url and what will be the Dockerfile build command ? Can you pls give me more details. – SK. Apr 12 '21 at 00:28