Hi, today we are going to learn how to deploy a simple angular application on a docker container with the help of Nginx web server.
We will create a multi-stage dockerfile for creating a docker image of a simple angular application, which then will be hosted on a docker container using NGINX.
Technologies we will interact with –
- Angular Framework
So, let’s pour a hot cup of coffee and let’s begin 🙂
Initializing an angular application for dockerizing
If your system is already configured with angular-CLI then that’s great else you can just visit this and set it up in no time.
Once angular-CLI is set up on your machine, you can run this command to initialize a new angular app
ng new yourAngApp
Or you can also just clone this repo.
Have a look inside the directory you just created, you will see a lot of files. So, don’t freak out, we won’t be going in-depth on how angular works in this short tutorial.
Creating a docker image with a dockerfile
We now have files that are needed to place inside a container, but how do we do that? For that, we first need to create a docker image and for creating a docker image we need a dockerfile.
What’s a Dockerfile and Docker image?
Docker image is kind of a blueprint that contains all the information to set up a docker container. This image defines what OS is to be used, what kind of software/applications are to be installed, and what directories exist inside the container.
To create this image we somewhat need a special file named “dockerfile“. It is always at the root of your application directory.
Just hit this command on your terminal at the application root directory that you created above
touch Dockerfile .dockerignore
Let’s go one line at a time and understands the commands written in the Dockerfile
FROM – Base Image
The first line of any Dockerfile is always the “FROM” statement. Every docker image needs a base image to act upon, it’s like telling your system to which operating system to load once you start it. Technically this is an image only containing the base operating system. Using “FROM” command, we can choose the operating system our image is based on, which in turn tells what OS our container will be executed on.
Also, we need to define the version of the base image. While you can be lazy and just choose :latest, this is not desired in most cases, because you want to prevent any unwanted and uncontrollable changes to your image. Instead, we define a fixed release for our image.
For this tutorial, we are using node image version 12.7 based on alpine distribution.
FROM node:12.7-alpine AS build
Since we are creating a multi-stage Dockerfile, this image will only be used in first stage. In first stage we are compiling the angular application, in second stage we will output the compiled app using the Nginx web server.
We have given the first stage a reference name – build, so as we can refer to it from another stage.
WORKDIR – specifying work directory
Using the WORKDIR command, we define our current path inside of the container. This is important for other commands which use the relative path. In this case, we choose a directory called “/usr/src/app”.
COPY – copying application
Next command is COPY command, which basically tells what it does from its name only. Here we are copying two files to our work directory that we created in above step.
COPY package.json package-lock.json ./
RUN – executing shell commands
The RUN command basically executes shell based commands inside the container. If you want to install a specific library/software/application/program you will use this command, just like we do it in a normal linux based system. Here, we are force cleaning the cache of node otherwise it can throw an error of core-js being outdated and installing the node packages from the package.json that we copied earlier.
RUN npm cache clean --force
RUN npm i
After this, we are again copying the files into the image by running this command
COPY . .
We do so in separate steps because this way we can take advantage of Docker caching each step (also called layer). That way subsequent builds of the image will be faster, in case the package.json did not change.
Lastly in the first stage of the Dockerfile of our angular application, we will build our angular application by running this command
RUN npm run build
Don’t forget .dockerignore file
We can’t just copy everything in our image, that’s why we have dockerignore file to ignore certain folders and files that may or can lead to complex problems. Therefore we just ignore them right here, right now!
Add dist and node_modules folder inside the .dockerignore file
Hence, stage one of the dockerfile is now completed for our angular application. Your dockerfile should look like this now –
We have the compiled version of our angular application inside the docker image. Now, we just need to serve these files using a NGINX web server.
For defining the a new stage inside the dockerfile we just use the “FROM” command and this time import the official nginx image as a base image for the second stage.
### STAGE 2: Run ### FROM nginx:1.17.1-alpine
Afterward, we copy the dist-output from our first image (called build, remember?) to our new image. Precisely into the NGINX public folder.
COPY --from=build /usr/src/app/dist/dockerizedAngularApp /usr/share/nginx/html
Note – Do note the project name, as ‘ng build or npm run build’ will create the directory structure like this /dist/your-project-name. Therefore, if you have created your angular app like this
– ng new myapp
Then the ‘ng build or npm run build’ will generate your app compiled files in this directory /dist/myapp/
And voila, we have successfully created a multi-stage dockerfile.
Creating a container out of the docker image
We have the blueprint of the container, we just need to know to create the container or how to run that container?
Before this, let’s ask our self’s what’s a docker container?
"A container image is a lightweight, stand-alone, executable package of a piece of software that includes everything needed to run it: code, runtime, system tools, system libraries, settings." - docker.com
The main advantage of a Docker container over a regular virtual machine is, that container can share resources (like the image). This allows containers to run in large clusters with a minimal resource-overhead.
Using Dockerfile to build the docker image
At project root, open up the terminal and fire up this command
docker build -t dockerized-angular-app-multistage-image .
With the -t argument, we define the name of the image. You can have anything here instead of the mentioned one above ‘dockerized-angular-app-multistage-image‘. The second argument (“.”) defines the location of the Dockerfile. This command can take a while because images have to be downloaded and the angular app has to be compiled.
Running/executing the container
Once image is created, execute this
docker run --name dockerized-angular-app-multistage-image -d -p 8080:80 dockerized-angular-app-multistage-image
With -p we define a port mapping. Basically, we define that the port 80 of our container should be exposed to the port 8080 of our host machine. With –name we define the name of the container. In this case “angular-container”. With -d we detach and let Docker create the container in the background. The last argument is the name of the image (“angular”) we want to use.
And, voila you have successfully dockerized your angular application. Just visit this address in any browser – http://localhost:8080/
- Setting up multi-stage dockerfile for creating a docker image.
- Understanding different commands used to create a dockerfile.
- Basic overview of the docker commands to spin up a container, creating a image from dockerfile and angular-CLI commands.
That’s all for now folks. I hope you have learned something from this blog. If you liked it then please hit the thumbs up and share it with your friends, family or colleagues. Also, please help me improve by giving healthy feedback (below comments). Follow me to get updates on more interesting blogs.
Visit Knoldus blogs for more angular related topics.