In this post, we are going to look at how to deploy an angular app using docker. Docker containers can be used to simplify the process of developing, testing and deploying your app into different environments. With docker containers, you can be assured that the application will run the same no matter the environment in which it is deployed.
In this demo, we are going to build a docker image for deploying an angular app to two different environments. One for production and the other for staging. Our demo application is going to have 3 environments – development, staging and production. We will be using the development environment locally for developing and testing using ng serve. While the other two environments are deployed remotely. If you don’t know how to setup environments in angular, you can checkout this post I did earlier. Without further ado.
How it works
Once you are ready to deploy on either environment – staging or production, we are going to use a dockerfile to specify how our deployment image with our built app is going to be build. A dockerfile
is a special file that contains instructions on how to build our docker image. Since we need to automate the build process as much as possible, we are going to be building the angular app together with docker image.
First, we are going to pull a NodeJS (node:8.X.X) from docker hub and use it to build our angular application. Then, we will copy our compiled angular application inside the dist
directory to our deployment container. Our deployment image will be a nginx alpine image – as you might have guessed using nginx proxy server. We will also need to copy the configuration to redirect all paths to index.html and compress our server output.
Getting Started
To make things simple, we will have two dockerfiles for each of our deployment environments. They will have some minor differences such as the target environment when building our angular application. We are going to be using a multi stage docker build, where in stage 1, we will create a docker image to build our angular application.
And then in the second stage we copy the results of the first stage and use it build and create a super light deployment docker image. This allows our final image to only contain the important files for deployment without any development files and tools being carried over. You can learn more about docker multistage build here.
First, we need to create a new directory called .docker
in the root of our angular workspace. Inside it we are going to create three files. Two dockerfiles (prod.dockerfile
and staging.dockerfile
) and a nginx (nginx.conf
) configurations file.
Nginx Configurations
In this configuration file, we are going to have rules for redirecting all paths to index.html and add rules to compress content before being sent to the browser. You can replace this with apache or any other web server you are familiar with. Just make sure the configuration files are okay for your server and copy them in the correct directory inside your final image. Inside the nginx configuration file (nginx.conf), add the following content:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
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;
location / {
try_files $uri $uri/ /index.html;
}
}
}
Creating the Dockerfiles
Both dockerfiles will be the same, with some minor differences. For instance, the staging dockerfile will build targeting staging environment while the production will build with the prod flag. It is also possible to use the same dockerfile for both, but I find separating them doesn’t hurt. It also allows me to experiment with the staging version before making the final changes to the production one. This is all up to you. We are going to separate the dockerfiles into two sections, staging 1 and stage 2. As I said earlier, stage 1 will build the angular application and stage two will create a docker image for deployment.
Stage 1
First we need a base image to build our first docker image on, since we are building using NodeJS, we will use node:8.11.4 docker image. Feel free to use any version of NodeJS you are comfortable with.
FROM node:8.11.4 as node
Next, we declare a working directory inside our image and then copy our angular workspace into the directory.
WORKDIR /app
COPY . .
Next, we need to install our @angular/cli and if you are a fan of Yarn like me, install it too.
RUN npm i yarn
RUN yarn global add @angular/cli@latest
Next, install the dependencies for your project by running either yarn install
or npm install
depending on the package manager you are using. And finally, it’s time to build your angular application. For staging environment, we will use the following command:
RUN ng build --configuration=staging
While for production environment, we will use the following command:
RUN ng build –prod
And now let’s move to stage two.
Stage 2
In this stage, we are going to base our image on nginx:alpine image.
FROM nginx:alpine
And then, copy all build artefacts to /usr/share/nginx/html directory and copy the nginx.conf to the /etc/nginx/conf.d/default.conf.
COPY --from=node /app/dist/angular-docker-deployment /usr/share/nginx/html
COPY --from=node /app/.docker/nginx.conf /etc/nginx/conf.d/default.conf
NB: One thing to note for those using Angular 5, copy the DIST directory instead of the project name directory inside the DIST directory.
COPY --from=node /app/dist /usr/share/nginx/html
You can check out both docker files here.
Building Docker Images
And finally, you can build your image by running the following command at the root of your angular workspace: Windows:
docker build --rm -f .docker\staging.dockerfile -t webapp:latest .
Linux and Mac:
docker build --rm -f .docker/staging.dockerfile -t webapp:latest .
Replace webapp:latest
with your preferred image name and add your image tag after colons. To build a production image, replace .docker\staging.dockerfile
with .docker\prod.dockerfile
. Windows:
docker build --rm -f .docker\prod.dockerfile -t webapp:latest .
Linux and Mac:
docker build --rm -f .docker/prod.dockerfile -t webapp:latest .
And your docker image is ready for deployment. In the next post, I will cover how to deploy your docker image once you have built it. Sample Code You can find the whole code for this post here.