Dockerize Angular App By Multi stage Docker Build

VinothKumar P
5 min readSep 1, 2020

In this post I would like to show you how to build and run your Angular application in a Docker container, then we are going to see a multi-stage Docker build which will make the container lighter and our work more automated.

For the demonstration purpose I have taken an Open source Github Code as the sample code.But if you want to use your project you can go with it, all the steps will be the similar as for my app.

$ git clone https://github.com/VinothKumar-DevOps/aston-villa-app.git

Now you have the code in your local and enter into that. Make sure that you have installed Node.js & Angular CLI on your local PC.

Now we are ready to compile an Angular app.Open the terminal in the root folder of the app :

$ ng build --prod

Post the build we can see the folder named as dist/aston-villa-app in which all compiled files are present.

After that create a new file called Docker file that will be located in the project’s root folder. It should have these following lines:

FROM nginx:1.17.1-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY /dist/aston-villa-app /usr/share/nginx/html

This sample Docker file will tell Docker to instruct 3 things:

  • First to fetch a nginx Docker image from Docker Hub which is tagged with 1.17.1-alpine ,
  • After that copy-paste the default nginx configuration file,
  • At last copy-paste the compiled application (As we done it in previous step) to the container.

Our default nginx configuration file looks as follows ( location must be in the same directory as Dockerfile):

events{}
http {
include /etc/nginx/mime.types;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
}

In the above file we config the server where the app be hosted , port details etc.,

Finally, Get back to the terminal and use this command:

$ docker build -t av-app-image .

To check the images built after the above command use : docker images

Run the image which we have created recently and check its output

$ docker run --name av-app -d -p 8080:80 av-app-image

Name the container as (--name av-app-container), then make sure that it will run in the background (-d), After this map container port to your local (-p 8080:80) and at last choose a Docker base image to be that you’ve just created.

Check the container is running:

Confirm that we have a done a correct Job! http://localhost:8080/.

Hope the above process seems easy , wasn’t it? But it is a multi step process along with time consuming and chances error-prone.

Lets see how we can do the process better ? Can we include compile process into docker build? Is it good practice to do? let’s try!

As mentioned in the title we are going to introduce Multi-stage Docker build.

It was introduced in 17.05 Docker version and useful for creating smaller container without loosing the readability of a Docker template(Dockerfile) , In this way we separate building docker image into smaller stages where previous stage can be used in next stage.

This is how we are going to implement : Two stages

  • Compile the source code into Prod ready output,
  • Run compiled app in a Docker image.

Only compiled output is parked into the second stage so we preserving the container size.

As of now we didn't introduce second stage , first we will shape stage1.

In order to compilethe source code we are going with different Docker image as a base image, which contains Node.js. The part of Dockerfile that covers building the base image.

FROM node:12.7-alpine AS build
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

In order to build efficient Docker image we can add to the project root additional file named .dockerignore. This will works as same as .gitignore and where we can define files and directories which docker needs to omit. In our case we donot want to add files from node_modules and dist folders.

dist
node_modules

Now we are ready to add both Docker stages into one and we get this as below:

### STAGE 1: Build ###
FROM node:12.7-alpine AS build
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

### STAGE 2: Run ###

FROM nginx:1.17.1-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build /usr/src/app/dist/aston-villa-app /usr/share/nginx/html

We have added --from=build flag to tell Docker that it needs to copy compiled files from build stage (also the source path have changed, because files are located in a different folder).

Back to a terminal, first we need to create a Docker image:

$ docker build -t av-app-ms-image .

Now run the app with different port:

$ docker run --name av-app-ms-container -d -p 8888:80 av-app-ms-image

And if you now enter http://localhost:8888/ you’ll see that it’s running!

--

--

VinothKumar P

Cloud DevOps Engineer 3 at Amadeus Labs| AWS/Azure Cloud ☁️ | DevSecOps | Docker | Kubernetes