In this post, I will show you how can you easily build an existing web app developed with Angular, React or Vue; inside a Docker container, so that you can have a Docker Image, in the cloud, that can be used in a production environment.
Docker is the most widely-used provider to create containers. Containers are isolated processes that allow running applications by sharing system resources, such as the file system, resulting in more efficiency. This avoids the need to use multiple virtual machines to test applications in different environments, since containers can share the same operating system kernel. Not only is Docker important for development, but also for the deployment of software. In fact, my previous post focused on giving a better understanding of containers.
Step by step guide to deploy a web app in a Docker Container
he following tools need to be installed on your system:
- Github: will be getting existing to-do apps from a Github repo.
- Docker community Edition: this tool will allow us to use Docker on Windows or MAC platforms.
- The text editor of your choice, I recommend you to use the Visual Studio Code IDE.
1.Downloading and compiling the apps
You can find all the intricacies of each application in their readme.md file.
Clone the web app of you choice from the Github repo. Then, by running the following commands, the app will be built and the output artifacts will always be stored in the /dist folder.
I would suggest using the Web Server extension for Chrome to see your bundled app working in the browser. In the extension, just set the output /dist folder (from the angular app) as the parent output folder:
In this case, the to-do app should then be working in http://127.0.0.1:8887. Next, let’s create a docker image with it
2.Configuring a Nginx image
Will be using Ngnix, which will act as our reverse proxy web server to process our app requests. Nginx will provide a lightweight image after running our Docker container.
We need to configure the Nginx image by adding a custom Nginx configuration file, that will help the Nginx server to redirect all requested URLs to the same domain.
Add the following nginx-to-do-app.conf file in the root folder of your prefered app:
All requests made from the base URL will be associated to the /usr/share/nginx/html directory, which is where the app will reside; the index.html page of our project will be served by default; and finally, any not found page will be redirected to the index page as well. The server will listen from the high traffic, standard port 80.
3. Configuring a Docker Image
Since we are using the Node.js packages to build our app, we will create an image from a Node.js Docker repository. Also we need to run all the necessary commands for building the app when we create the image. The process is simple since each of our apps was created using the most appropriate CLI (angular-cli, vue-cli, and create-react-app). In fact, every single CLI I used is based on Node.js. Let’s add a Dockerfile in the to-do-app folder (see comments in the file for more details):
From the Docker files, you can see that they are using the Docker multi-stages builds feature. This means that we initiate more than one stage in the same Dockerfile: the first one generates the build, and the other sets up the app using the Nginx web server image. That way we have the possibility to use only what we need from the original docker images (node and nginx), resulting in a really efficient output custom image that we can easily distribute to the cloud.
It’s worth pointing out a couple of things: both the node and the nginx images are using the alpine distribution, which means having a faster and light-weight output image build. Also, we don’t necessarily need to use npm commands since the Docker team decided to include Yarn in their official node image.
When we copy the code to the ng-app folder we don’t need to copy the node modules directory. In order to do that, we are going to also add a .dockerignore file (similar to a .gitignore file for git) in the app’s root directory:
4. Build your Image and run your container with it
Finally, we need to first build our image with the following command:
-t relates to the name of the container: for instance, orlando1409/to-do-app. And the dot(.) indicates that the Dockerfile is found in the current directory. In our case will use the Docker Hub registry to store our images. So, orlando1409 corresponds to my user name, for that registry.
After that, run your image:
-p binds the port 80 of the container to the port 80 of the host machine. This mapping process also refers to the port forwarding method.
5.Pushing and pulling the container image to and from the cloud using a container registry
In order to store the docker images in the cloud, we can use one of the many container registries on market. I’m using Docker Hub, in this case:
However I could have used GitLab Container Registry as well. The following are the commands for each of the images:
Navigate to localhost (default ports 81, 82 or 83), and… awesome! you will see your app ready just as if you had it in a production environment.
6. Running the three images using Docker Compose
Docker Compose is a tool for defining and running multi-container Docker applications.
With Compose, we will use a docker-compose.yml file to configure the application service, in this case we will use it for our three web apps. The docker-compose up command will run all of the containers from the configuration. Don’t forget to stop your containers before, if they are already running.
Bonus: Passing environment variables to the container
For each of the Angular, React and Vue repos I created two extra branches: dev and prod where you can find the additional Docker configuration that is needed to run each of the containers in different stages. This could be useful, when you want your web app to consume a development database, avoiding testing over sensitive or production data.