Saurabh Palatkar
Saurabh Palatkar

Reputation: 3384

Improve Docker build speed for Angular app

I've set up an Angular development workflow using Docker. However, building the docker and serving the Angular app is a bit slow and takes around ~7 minutes (considering all base images pre-downloaded).

./package.json:

{
  "scripts": {
    "ng": "ng",
    "docker-serve-dev": "docker-compose -f docker-compose.development.yml up --build",
  },
  "dependencies": {
    "@agm/core": "^1.0.0-beta.5",
    "@angular/animations": "^7.2.6",
    "@angular/cdk": "^7.3.3",
    "@angular/common": "^7.2.6",
    "@angular/compiler": "^7.2.6",
    "@angular/core": "^7.2.6",
    "@angular/forms": "^7.2.6",
    "@angular/http": "^7.2.6",
    "@angular/platform-browser": "^7.2.6",
    "@angular/platform-browser-dynamic": "^7.2.6",
    "@angular/router": "^7.2.6",
    "@asymmetrik/ngx-leaflet": "5.0.1",
    "@nebular/auth": "3.3.0",
    "@nebular/bootstrap": "3.3.0",
    "@nebular/security": "3.3.0",
    "@nebular/theme": "3.3.0",
    "@ng-bootstrap/ng-bootstrap": "^4.0.4",
    "@swimlane/ngx-charts": "^10.1.0",
    "angular-tree-component": "8.3.0",
    "angular2-chartjs": "0.5.1",
    "angular2-toaster": "^7.0.0",
    "bootstrap": "4.3.1",
    "chart.js": "^2.7.3",
    "ckeditor": "4.11.2",
    "classlist.js": "1.1.20150312",
    "core-js": "2.6.5",
    "echarts": "^4.1.0",
    "error-stack-parser": "^2.0.2",
    "eva-icons": "^1.1.1",
    "intl": "1.2.5",
    "ionicons": "2.0.1",
    "jwt-decode": "^2.2.0",
    "leaflet": "1.4.0",
    "lodash": "^4.17.11",
    "moment": "^2.24.0",
    "nebular-icons": "1.1.0",
    "ng-snotify": "^4.3.1",
    "ng2-ckeditor": "^1.2.2",
    "ng2-completer": "2.0.8",
    "ng2-slim-loading-bar": "^4.0.0",
    "ng2-smart-table": "1.4.0",
    "ngx-echarts": "^4.1.0",
    "normalize.css": "8.0.1",
    "pace-js": "1.0.2",
    "primeicons": "^1.0.0",
    "primeng": "^7.0.5",
    "roboto-fontface": "0.8.0",
    "rxjs": "6.4.0",
    "rxjs-compat": "6.4.0",
    "socicon": "3.0.5",
    "stacktrace-gps": "^3.0.2",
    "stacktrace-js": "^2.0.0",
    "tinymce": "4.5.7",
    "tslib": "^1.9.3",
    "typeface-exo": "0.0.61",
    "web-animations-js": "2.2.5",
    "zone.js": "^0.8.29"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.13.3",
    "@angular/cli": "^7.3.3",
    "@angular/compiler-cli": "^7.2.6",
    "@angular/language-service": "7.2.6",
    "@compodoc/compodoc": "^1.1.8",
    "@fortawesome/fontawesome-free": "^5.7.2",
    "@types/d3-color": "1.2.2",
    "@types/googlemaps": "^3.30.16",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "@types/leaflet": "1.4.3",
    "@types/node": "~8.9.4",
    "codelyzer": "^4.5.0",
    "conventional-changelog-cli": "2.0.12",
    "husky": "1.3.1",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.1.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-cli": "1.0.1",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "npm-run-all": "4.1.5",
    "prettier-tslint": "^0.4.2",
    "protractor": "~5.4.0",
    "rimraf": "^2.6.3",
    "stylelint": "9.10.1",
    "ts-node": "~7.0.0",
    "tslint": "~5.12.1",
    "tslint-language-service": "^0.9.9",
    "typescript": "~3.1.6"
  },
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": {
        "base": "$tslint5",
        "fileLocation": "relative"
      }
    }
  ]
}

./docker-compose.development.yml:

version: '3.4'

services:
  cc-ui-docker-service:
    container_name: cc-ui-dev-container
    image: cc-ui-dev-dev
    build:
      context: .
      dockerfile: .docker/development.dockerfile
    environment:
      NODE_ENV: development
    volumes:
      - './:/usr/share/app'
      - /app/node_modules/
    ports:
      - 4200:80
    ## set your startup file here
    command: ['sh', '-c', 'ng serve --host=0.0.0.0 --watch --poll=2000']

./.docker/development.dockerfile:

FROM node:10.15.1-alpine

# set working directory
RUN mkdir /usr/share/app
WORKDIR /usr/share/app

# add `/usr/share/app/node_modules/.bin` to $PATH
ENV PATH /usr/share/app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json /usr/share/app/package.json
COPY package-lock.json /usr/share/app/package-lock.json
RUN npm install
RUN npm install -g @angular/[email protected]

# add app
COPY . /usr/share/app
EXPOSE 80 443
CMD ["ng", "--host=0.0.0.0","--watch", "--poll=2000", "serve"]

How I can improve the build time?

Upvotes: 3

Views: 4833

Answers (3)

Keystone Jack
Keystone Jack

Reputation: 309

Instead of copying the entire node_modules folder into your container, try to only copy the package.json and after that run ”npm install”. The node_module folder doesn’t have to be copied over to the container since ”npm install” installs all the necessary modules in the container, it reads all dependencies from package.json.

This will reduce building time :)

Upvotes: 1

Cedric
Cedric

Reputation: 552

It's a good practice to use multi-stage builds when building images with Docker.

An example Dockerfile would be:

FROM node:10 as build
WORKDIR /home
COPY package.json package-lock.json .
RUN npm install
COPY . .
RUN npm build # or any other command to package

FROM nginx:alpine
COPY --from=build /home/dist/* /usr/share/nginx/html/

Thats it :)

Upvotes: 1

Kliment Ru
Kliment Ru

Reputation: 2137

You can to build an application outside the docker and copy only dist folder into nginx docker image.

After then you don't need to install node_modules evrey time.

Dockerfile example

FROM nginx:latest
ENV TZ=Europe/Moscow
COPY ./dist/my-app /usr/share/nginx/html
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf

nginx.conf example

server {
  server_name my-app;
  root /var/www/frontend/src;

  try_files $uri $uri/ index.html;
}

Upvotes: 3

Related Questions