Tech Incent
Angular

Dockerize angular app with example

dockerize-angular-app

In this article, I will show you, A complete tutorial to build an Angular application to docker production-ready image with multi-stages. And I will also run this angular docker image in a docker container.

Final this project-related files and directories structure …

.
├── dist
│   └── docker-angular-app
├── Dockerfile
├── nginx
│   └── default.conf
├── package.json
├── package-lock.json
├── ...
└── ...

Create a angular project

In this article, I am using the fresh new angular app. But If you have any existing angular then you skip this part and you can use your existing angular application.

ng new docker-angular-app
cd docker-angular-app

Build Dockerfile

In the project directory, Create Dockerfile with no extension and first latter capital.

# STAGE 1: Build app

# Step 1: Pull node offical image
FROM node:16.13.2-alpine as builder

# Step 2: Define working dir for builder container
WORKDIR /usr/local/app

# Step 3: Copy package.json and package-lock.json files
COPY package*.json ./

# Step 4: Install dependancy 
RUN npm install

# Step 5: Copy all source code
COPY . .

# Step 6: Generate build of application 
RUN $(npm bin)/ng build --configuration=production --source-map=false

# STAGE 2: Setup Server

# Step 7: Pull nginx image
FROM nginx:1.21.5-alpine

# Step 8: Copy default nginx config
COPY nginx/default.conf /etc/nginx/conf.d/default.conf

# Step 9: Copy builded application source code
COPY --from=builder /app/dist/docker-angular-app /usr/share/nginx/html

# step 10: Expose container port 80
EXPOSE 80

# Step 11: Switch nginx deamon off
# Note: If your container serve multiple service than don't daemon off. 
CMD nginx -g "daemon off;"

That is a docker snippet, I use to build for angular application to the docker image. This docker snippet has a multi-stage build.

Stage #1: Build this angular app to production ready code

Step 1: FROM node:16.13.2-alpine as builder

Pulling node runtime image, Initialize the new build stage. In my case, I used node 16.13.2 alpine version. It’s better to use your machine node version which is the angular app developed. In the development case, some developers use the node’s latest version. Which is not for production.

In the snippet, I have used the alpine version, which is lightweight more than the row node version

Step 2: WORKDIR /usr/local/app

Sets the default working directory for the present building container. After this instruction is executed, If this directory doesn’t exist, this directory will be created. the subsequent steps in the Dockerfile

The defined directory(usr/local/app) is inside the container which has its own independent file system

Step 3: COPY package*.json ./

Copy the source application dependency files (package.json and package-lock.json) on the host machine to the specified working directory(usr/local/app)

Step 4: RUN npm install

In the working directory run command, “npm install” to install all application dependencies.

Step 5: COPY . .

Copy all the current directory source codes excluding folder or directory which is defined on the .dockerigone file.

Multiple building dependencies install problem understanding*

Note: It’s solved in this snippet code.

imagine you are building the app for the first time, and it is ok to install all the dependencies. But you change a source code related to the angular app (not related to any dependencies) and then push again to build the image. and the run process installs all dependencies again. You probably don’t want to install the dependency unless some dependency is added or removed.

When your execution process copies all files and directories, Install dependency. that problem will be happen

This snippet code, step 3: copy package.json and package-lock.json which are application dependencies related. Then step 4: install dependencies and step 5: copy all source codes.

This execution process solve multiple build install dependencies, that’s used
Step 6: RUN $(npm bin)/ng build --configuration=production --source-map=false

Executes the angular build in a new layer on top of the base node image. After this instruction is executed, the build output is stored under usr/local/app/dist/docker-angular-app and the compiled image will be used for the subsequent steps in the Dockerfile

Stage #2: Serving the angular production ready app to nginx server

Step 7: FROM nginx:1.21.5-alpine

Initialize final or secondary build stage. nginx:1.21.1.5-alpine image as the base image for executing subsequent instructions relevant to nginx configuration

Step 8: COPY nginx/default.conf /etc/nginx/conf.d/default.conf

Copy our own Nginx configuration file for the angular application to the docker Nginx server image.

Note: make sure your Nginx file is “nginx” directory. Or If it is inside others directory, so make sure you use right your configuration path

Step 9: COPY –from=builder /app/dist/docker-angular-app /usr/share/nginx/html

Copies the build output generated production-ready static resource in stage 1 (--from=builder) to replace the default Nginx HTML contents.

Important Note: Angular builds production-ready static resources into ./dist/[project name]. In this example, the project name is docker-angular-app so the output directory is docker-angular-app. So make sure! you use your project name.

Step 10: EXPOSE 80

Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports

Step 11: CMD nginx -g "daemon off;"

I use Nginx daemon off. Because for microservices, the directive tells Nginx to stay in the foreground. For the microservices, the best practice is for one container = one process. So one container server has only one service.

When normal production on a server, I use the default Nginx daemon on; So the Nginx server will start in the background. In this way, Nginx and other services are running and talking to each other. In this case, one server runs many services.

.dockerignore file

If you had used git, then you are so familiar with the .gitignore file. The .dockerignore file is very similar to the .gitignore file. It allows specifying a list of files or directories that Docker is to ignore during the build process. Most importantly, the .dockerignore can help you reduce the size of the image and dramatically speed up the build process.

# compiled output
/dist
/tmp
/out-tsc

# dependencies
/node_modules

# IDEs and editors
/.idea

# IDE - VSCode
.vscode/*

# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

Nginx configuration

This is a custom Nginx configuration snippet for our production-ready angular app.

Make sure you are using the right root path, which is a copy production-ready static resource in the container nginx path.

Create docker-angular-app/nginx/default.conf file in nginx separate folder.

server {
  listen 80;

  sendfile on;

  default_type application/octet-stream;

  gzip on;
  gzip_http_version 1.1;
  gzip_disable      "MSIE [1-6]\.";
  gzip_min_length   256;
  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   9;

  root /usr/share/nginx/html;

  location / {
    try_files $uri $uri/ /index.html =404;
  }

  location /health {
    return 200 'I am live :)';
  }
}

Docker build image

docker build -t image_name:tag .
docker build -t angular-app:latest .

Check docker images

docker images

Run docker image

docker run --name container_name -d -p local_machine_port:container_port image_name:tag
docker run --name docker-angular-container -d -p 4000:80 angular-app:latest

Note: nginx configuration file lister port(80) must be same of container port(80)

Check docker containers

The below command shows the running containers of docker

docker ps

Below command shows all inactive containers

docker ps -aq

Related posts

Angular bootstrap date picker example

Sajal Mia

Angular code (JSON, YAML, TypeScript) editor example

Sajal Mia

How to add chart js in angular?

Sajal Mia

Explained RxJs switchMap operator with example

Sajal Mia

Angular Search and pagination with example

Sajal Mia

How to implement angular router resolver?

Sajal Mia