Dockerize Your Angular App How to write a multi-stage dockerfile to build an angular application using docker without the DevOps team Nitsan Zohar - Front End Tech Lead, Next Insurance After spending seven years (and counting) with Angular, Nitsan knows the heart of the beast, earning his experience through a series of challenging frontend systems. Currently, he is obsessed with the build process and performance. In his spare time he likes to complain, and denies his mid-life crises.
Hi everybody. Let's start with the question. Who are you in the audience? Wonderful ration on Docker. See, there's almost nobody so little about me. Me. My name is. I'm a quantum tech with Max insurance. More than eleven years experience as developer, last revenues in Angular and Angular GS. Of course in the last day I focused more on the info style for Angular. I have two kids and one wife. Only one you can see my Twitter and my LinkedIn. So the agenda for today we'll start with some basic Docker. What is Docker? Why Docker Docker Technology, Docker Architecture and Docker Five example and I will finish with some demo of Docker one. So what is Docker? Docker is an open platform for developing, shipping and running application Doku enable you to bundle application and its dependencies and shift everything out as one package which then can be deployed. So why to use Docker? In my opinion, there are a lot of reasons why to use Docker. I will name a few. First onboarding and develop an example for onboarding. You usually need to wait to read a long document, maybe some read my file, then you need to install all the dependencies for example MySQL then import all the schemes, maybe you need to change the Port, you need to set all the configuration, then you need to install some back end service and configure also. And of course you usually need to install some global health and add tokens to your environment. With Docker it's very simple. You just need to Docker one your MySQL Docker one, your back end service and your environment is ready. Isolate environment. Docker containers are lightweight and contains everything you need to one application, so you do not need to rely on what currently installed on your app. For example, if one of the Docker on your machine needs no GS version eight, but your currently version is the last version, there is no problem. The Docker holds all the dependencies in salary. First Deployment Docker continuous are known for decreasing deployment time. We recently switched to a Docker deploy in one of our services. Let's see the results before the Docker in our pipeline, we have nine minutes to deploy production and nine minutes to deploy staging total of 19 minutes with Docker. The deploy time was one and a half minutes so it save us 15 minutes in each one ability to run anywhere. Docker will eliminate the work on my machine. If the application work on your development machine, it can run infaction the same way on another machine. And microservices and scaling Docker is a great solution for microservices. Each service can run on a different Docker container and you also scale up if you need more withhold let's understand some basic concepts in Docker file. Docker file is a text document that contains instructions to assemble an image. Docker Image is a read only template that contain a set of instructions for creating containers that can run on the Tokyo platform. Tokyo container is a unit of software, can package up code any dependencies so the application could work. Let's talk about architecture. Docker to understand how it works. You can see Docker client, Docker server and Docker registry. Docker used client server architecture. The Docker client talk to the Docker server, also called Docker engine. Using a Restful API, the Docker DMA, which is a part of the Docker engine, does the heavy lifting of building running Docker container. For example, if you want to start Docker service with Ubuntu, Redis or NGINX, for example, you want the Docker pull command, the Docker pull download the image from the registry. The registry is like a bank of images. It downloads the image to the Docker server. Thank you. And when you want to do one command and it will want the Docker image into the Docker container. My application is a small application. In order to play with the Docker file, I've texted on my app. My app is angular twelve with two pages, three components and three services. My server file is not working with one file of Fpspit. Let's see them on application. So this is the application. This is the admin form. You can choose file shortcut, the demo file with seven names. I can change the URL, I can change the button text and I can change also the color. So this is the workflow I can export and the window is so this is the first Docker file. Let's understand some selection of the Docker. First, each Docker file starts with a form instruction. The form takes the base image. In my case because my server is not 14, I took the Note 14 Alpine version. The Alpine is the smallest version which holds only the core file of the node. Then I'm setting the rocket directory. My app will be in the app folder one with the NPM installed. First I'm copying the package log. Json to my app folder, then one with the NPM install. Then I'm copying the project file. The current project is actually my repo. Then I'm building the server side. My server is taxpayer so I need to build it and also of course build the angular side with the NPM on build and open the Port of the node. This is the Port of the node. And last thing at the entry point when I will run the Docker with Docker one it will start the NPM start. This will start my node. So in this first Docker file my bill time was almost four and a half minutes. The NPM install time was 89 seconds and the image size is 552 Megs. This is a lot of very small application. See I have only two pages in small server side. So our goal we have two goals. One of them is to reduce the image size and the second one is to improve the document build time to reduce the image size I found out that there is a document that excludes files and directories that match the patterns very similar to get ignore when I add this file and this is the list of the folders. For example, I don't need saccos folder, I don't need the distance in the model because I'm one in the NPM install in the NPM builds. To improve the Docker build time, I found out that the two longest operations was one of them is the NPM install and the second is the NPM one build. To improve the NPM install, I found out that I can use the NPM clean install with two flags that we prefer offline and no audit, and it can save up to 53 faster than NPM installed in a clean workspace on every build. Because my pattern is a clean workspace, this should help about NPM one bill. Angular is already optimized, but as you already in the other tops. The next version of Angular just been released. I check it on the RC one version and the time of improving from 55 seconds to 35 seconds. It's improvement of 36%. So in the next version of my Docker file, the first thing that I add the Docker with no file, and the second I add the NPM with a clean stall and the two flags you can see the changes in the blue folder. I didn't update Angular to the next version because I checked it on the outset version and I don't want to open the algorithm. So the time was the improvement 37%. The NPM installed 28% of improvements and also the image size is the same percent. But I found out that the non model is the PDF folder. It's the same. How can I improve the Node models folder? I guess some of you already know that Nodemodels is the biggest object in the universe. How can we improve it in our Docker image? I found out that I can use the NPM print production. The NPM print production will remove all the Dev dependencies from my Note module folder. For example, I don't need all the tests, I don't need all the Angular desk and all the cycles. For example, I can remove it. So let's add a command after the bill because the bill needs all the depth dependencies when my mother's folder should be smaller. But when I check it I saw that the build time took me 8% more. It's okay because I had instructions, but the image size is the same. Why is it the same? The reason is the same is the Docker layers. Docker image consists on several layers. One of those layers, each layer is an image itself. Each layer stores the changes compared to the image it's based on. Each instruction in Docker file results a layer except for multi stage build, and each layer skip build steps which has no change. This is the local cache. So what is Motistage build? Motistage builds enable you to create smaller images with better caching. And for me it was a game changer. So in the next version of the Docker file I change it to multistage build. Each instruction in the Docker creates a layer. For example the form is a layer, the work is layer, the copy is layer, and so on. Each layer stores the changes compared to the last layer so the image gets bigger with each layer. When you want a form command it will emit all the layers and the image will contain only the last stage of the. So in my example you can see there is the first stage, the bill stage, I'm doing the NPM install and the bill and the second stage is from the form, not 14. Again this version I can have analyzed to the first stage as builder and I can copy files from the first stage to the second stage. So with this version my build time is now only two minutes and 28 minutes. This is an improvement of 18% and the image size is now only 56 mega. The last bullet is about the Docker cash. When you understand it, you can use it. So in the next version of my docu file I removed the copy of all of my repo and I copy only the relevant files and folders. For example I copy first I copy only the server side and then I bill it. Then I copied the client side of the folder of the angular and the relevant file that I need for the bill anyone in the bill and this will improve the cache because if there is a change in another file before for example if you change the README file you lost all the cache. But after this change you will have the Docker cache because you copy only the relevant folder. So the build time is the same, the image tag is the same, but now the second bill is only two and a half seconds because of the Docker cache. So I was happy. My Docker image is small, my build time is fast. I think I was done. But then I talked with somebody from our DevOps and he told me don't want continue as a root. Attacker is able to invoke with the user wants the application process. The default user of the Docker file is boot. When you start an application on the Docker file without changing the user and the attacker can gain access to all of your Docker file, you can change the user to username the base image of node counts with user node then the second thing you need to do is to change ownership of the folders and now the build time is the same, name size is the same, but you're almost secured unit test. Every developer loves to write unit tests, so let's add them to our Docker file. First you need to add the home so we will be able to run the unit test. Second you need to add the environment of the home build and then you need to add the NPM one test I did before the bill because if my test is failing I don't have reason to run the bill. You just need to also add four flags in the command config of homeless let's see demo. This is the last Docker file you can see the chromium you can see the NPM install with the two flags you can see the improvement of the cache copy the server side the server folder one in the server build copy the client side with the files of the build one in the client unit tests one in the build click the non models from the devDependencies starting the new stage of the motive stage changing the user to node change the ownership of the folder to the node user and start the entry point. Let's see I will build the Docker the Docker command is Docker build I will build it to my local machine. That's right. So because I already wanted my Docker with the cache it took me only 2.2 seconds. Those are all the layers you can see also the cache in each of the lines. Let's start the Docker. This is the one Docker command I'm running on both 80 on my local loft. Check it. It's on the Docker command. Now my Docker is running on my local machine. Let's go to local loss and this is the application on my local machine on Docker working the same. Let's see now we will go winner. Now the winner is again. I will show that it can be different just not picking some takeaway. First try Docker for me it was really fun. Second use motive stage B for me as I said it was a game changer and always try to improve. I thought in the first version of my Docker that I have a Docker and it was ready and I always found a way to improve it. Thank you.