Today you will learn how we can package our static html Angular app in a Docker container running Nginx. By packaging our app in a Docker container we will benefit from the fact that we will have some immutable infrastructure for our app. Immutability will give you many benefits when it boils down to maintaining a platform. Things that can not change state also can’t lead to surprises in a later stage. Immutability is also well known in functional programming languages. I won’t list all the advantages over here, but I encourage you to enrich your knowledge on immutability in Software development. It will teach you to look at software from a different perspective.
For the rest of this article I assume you have a running Docker environment. In case you don’t you might want to check out this article, which describes how to setup your Docker development environment.
As the purpose of this article isn’t on how to write an Angular app we are going to clone an existing sample application from github.com.
We will be adding a Dockerfile in the root of the repo. This Dockerfile will be used to configure a ready to deploy image. A Dockerfile contains so called instructions which define your image.
As you can see we are copying all the files from our dist/prod folder and we are also replacing the Nginx configuration with our own tweaked configuration. In the nginx.conf we could for example configure custom caching policies for our web app. In this article I won’t go into detail on how to configure Nginx. In case you don’t have any knowledge on configuring Nginx, just remove that last line and go with the default configuration. It is just there as an example, to show you we can influence our infrastructure configuration to be completely tuned for the app we are going to run. You now should have this special feeling in your veins, called DevOps. ;-) Do you feel it?
For build performance we can also include a .dockerignore file in the root of the project. This file can be used in a similar way as .gitignore to specify the patterns you want to ignore during the build process.
Have a look at Dockerfile reference docs to know more about all the available INSTRUCTIONS and how the .dockerignore can be used.
Now in order to package the static webpage as a Docker image, we simply build our webpage using the
npm run build.prod command, which was already available in the sample project (see scripts section in package.json). This command will output all static assets in the dist/prod folder. Next we will use the
docker build command to build the container based on our Dockerfile (remember we copy the static assets into the
So far we have a immutable container which we can deploy to our servers, publish on a registry etc. Imagine we would have our continuous integration server publish the built container on our Docker registry. That way the infra team can take it further from there and deploy the desired version of the container on your production / test environment. Either manually or using a continuous delivery server. For more information on the
docker build command, have a look at the Docker build reference docs.
Obviously we can also run the container our self using the following command.
Lets decompose this command to fully understand what is happening over here.
--name angular2-sample-app-nginxruns the image we build in previous step. Note that we gave it this name in previous step, when we where building the image.
-v /nginx-logs:/var/log/nginxmaps the folder on the host /nginx-logs to the folder on the container /var/log/nginx. This way we will have access to the logs on our host.
-p 8080:80maps port 8080 on our host to port 80 on the container (port Nginx is running on). This way we will be able to access the webpage from our host on port 8080.
-druns the container in detached mode. Detached mode means that the container will run in the background until the child process (Nginx) exits.
angular2-sample-app1is the name of the running instance of the container. We could for example run multiple instances and put a load balancer in front of it.
For more information on the
docker run command, have a look at the Docker run reference docs.
By adding a Dockerfile to our project we can easily package our solution as immutable infrastructure which can be deployed as is. Using the port mapping feature we can decide on which port the service will be available (in our example case 8080). Furthermore we used a volume mapping in order to have access to the logs of the container.
You know the basics of using a container now. In order to dig in deeper on using Docker containers I hereby also list the urls referred to earlier in this article:
Thanks for reading this article. Looking forward to your feedback.