DEV Community

Pavan K Jadda for This is Angular

Posted on

7 2

Multi Stage Docker builds with Angular and Nginx

This blog post shows multi stage Dockerfile that builds and deploys Angular app in Nginx container

###### Install dependencies only when needed ######
FROM node:16-alpine AS builder
ARG CONFIGURATION='dev'

# Make /app as working directory
WORKDIR /app

# Copy package.json file
COPY package.json .

# Install dependencies
RUN npm install --legacy-peer-deps

# Copy the source code to the /app directory
COPY . .

# Build the application
RUN npm run build --  --output-path=dist --configuration=$CONFIGURATION --output-hashing=all


######  Use NgInx alpine image  ###### 
FROM nginx:stable-alpine

# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*

# Copy nginx config file
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf

# Copy dist folder fro build stage to nginx public folder
COPY --from=builder /app/dist /usr/share/nginx/html

# Start NgInx service
CMD ["nginx", "-g", "daemon off;"]


The above Dockerfile has 2 stages
  • Stage 1 - Install NPM dependencies and builds Angular project

  • Stage 2 - Builds docker image from dist directory generated by previous stage

Stage 1: Install dependencies and Build Angular project

  • We use Node 16 alpine image to build the project and it accepts CONFIGURATION build argument. You can override this during build based on your environment
docker build --build-arg CONFIGURATION=dev .
Enter fullscreen mode Exit fullscreen mode

and you can also define as many arguments as you like

  • Then make /app as working directory. All of the source code and files will be copies to /app directory inside Node container
WORKDIR /app
Enter fullscreen mode Exit fullscreen mode
  • Copy the package.json file to /app directory. This will enable Docker to cache the node_modules rather than building from scratch and sub sequent builds use these when package.json file is unchanged.
COPY package.json .
Enter fullscreen mode Exit fullscreen mode
  • Install dependencies using npm install command and specify flag —-legacy-peer-deps to prevent build errors in NPM 7+
RUN npm install --legacy-peer-deps
Enter fullscreen mode Exit fullscreen mode
  • Then copy the source code and build the project using npm run build
COPY . .
RUN npm run build --  --output-path=dist --configuration=$CONFIGURATION --output-hashing=all
Enter fullscreen mode Exit fullscreen mode
  • The built code will be present in /app/dist directory in Node container

Stage 2: Build Docker image

  • We use NgInx alpine stable image to serve Angular application in production

  • Remove existing HTML content using the command

RUN rm -rf /usr/share/nginx/html/*
Enter fullscreen mode Exit fullscreen mode
  • Copy the Nginx config file from source to /etc/nginx/nginx.conf directory. If you don’t have one, you can use the below one
    user nginx;
    worker_processes auto;
    
    error_log /var/log/nginx/error.log warn;
    pid /var/run/nginx.pid;
    
    events
    {
      worker_connections 1024;
    }
    
    http
    {
      upstream springbootapp
      {
        server pres_springboot:8080;
      }
    
      server
      {
        location /
        {
          #### Gzip Settings  ####
          gzip on;
          gzip_min_length   1100;
          gzip_vary         on;
          gzip_proxied      expired no-cache no-store private auth;
          gzip_types        text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
          gzip_comp_level   5;
    
          #### Serve Angular Application ####
          root /usr/share/nginx/html;
          try_files $uri $uri/ /index.html;
          add_header Cache-Control "no-store, no-cache, must-revalidate";
          proxy_http_version 1.1;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Forwarded-Port $server_port;
        }
    
        location /api
        {
          proxy_pass http://springbootapp;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For
          $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Host $host;
          proxy_set_header X-Forwarded-Server $host;
          proxy_set_header X-Forwarded-Port $server_port;
          proxy_set_header X-Forwarded-Proto $scheme;
        }
      }
    
      include /etc/nginx/mime.types;
      default_type application/octet-stream;
    
      log_format main '$remote_addr - $remote_user [$time_local] "$request" '
      '$status $body_bytes_sent "$http_referer" '
      '"$http_user_agent" "$http_x_forwarded_for"';
    
      access_log /var/log/nginx/access.log main;
      sendfile on;
      keepalive_timeout 30m;
      include /etc/nginx/conf.d/*.conf;
    }
    
    
    
  • Then Copy dist folder from build stage to nginx public folder
COPY — from=builder /app/dist /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode
  • At the end specify the NgInx start command. That’s it.

You can also split Stage 1 into two separate stages. One to install dependencies and the second one to build the Angular app :)

Retry later

Top comments (0)

Retry later
Retry later