Deploying a Dockerized Angular App with Github Actions

Deploying a Dockerized Angular App with Github Actions

In this article we will discover the DevOps movement step by step, we will talk about the fundamental concepts then we will make a basic pipeline with GitHub actions to deploy an Angular 6 app, so let’s go.

What is DevOps?

DevOps is used to remove the conflict between the developers' team and the operations team to work together. This conflict is removed by adding a set of best practices, rules, and tools. The DevOps workflow is defined with a set of steps :

Image for post

Image for post

Plan

This is the first step, where the team defines the product goals and phases, also defining deadlines and assigning tasks to every team member, this step is the root of the whole workflow. the team uses many methodologies like scrum and agile.

Code:

After planning, there is the code when the team converts the ideas to code. every task must be coded and merged to the main app, here we use an SCM to organize the collaboration to make a clean code and have a full code history to make a rollback in case of failure.

Build:

After coding, we push the code to Github or Gitlab ( SCM ) and we make the build, usually, we use docker images for packaging. also, we can build the code to be a Linux package like deb, rpm … or even zip files, also there is a set of tests like unit tests and integration tests. this phase is critical!

Test:

The build was succeeded, no it’s time to deploy the build artifacts to the staging server when we apply a set of manual and automated tests ( UAT ).

Release:

it’s the final step for the code work, so we make a release and announce a stable version of our code that is fully functional! also, we can tag it with a version number.

Deploy:

A pre-prod or a production server is the target now, to make our app up and running

Operate:

It’s all about infrastructure preparation and environment set up with some tools like terraform for IaaC, Ansible for configuration management, and security stuff configurations …

Monitor:

The performance is very important, so we install and configure some monitoring tools like ELK, Nagios, and datadog to get all information about the applications like CPU and memory usage …

Deploying an angular app

In this example, we will deploy a simple angular app on two environments.

  • On VPS ( OVH provider) as a development server.
  • on Heroku as a staging server.

So you must have a VPS and a Heroku account to continue with me.

The application repository is here : Github repo.

  1. Clone the project with git clone https://github.com/hatembentayeb/angular-devops
  2. run npm install && ng serve to run the app locally

Preparing the deployment for Heroku

Nginx is a popular and powerful web server that can be used to serve a large variety of apps based on python, angular, and react …

I will go through an optimization process to produce a clean and lightweight docker container with the best practices as much as I can.

Writing the Dockerfile

First, we will prepare the Dockerfile to be deployed to the Heroku cloud, so there are some tricks to make it work smoothly, make sure that you have an account and simply click new to create an app :

Image for post

Image for post

create a Heroku app

Make sure to give a valid name for your app, then go to your account settings and get your API_KEY that we will use in the pipeline file:

Image for post

Image for post

getting API key

let’s take a look at the dockerfile of the app:

This Dockerfile is split into two stages :

  • Builder stage: The name of the stage is builder, it is a temporary docker container that produces an artifact which is the dist/ folder created by ng build --prod that compiles our project to produce a single HTML page and some *js & *.css. The base images that are used here are trion/ng-cli that contains all requirements to run an angular up and it’s accessible for public use in the Docker-hub, the public docker registry. Make sure to install all app requirement packages with npm ci, the ci command is used often in the continuous integration environments because it is faster than npm install.
  • Final stage: The base image for this stage is nginx:1.17.5 and simply we copy the dist/ folder from the builder stage to the /var/share/nginx/html folder in the nginx container with the command COPY --from=builder ... There are additional configurations required to run the app, we need to configure nginx, there is a file named default.conf.template that contains a basic nginx configuration so we copy it to the container under /etc/nginx/conf.d/default.conf.template , this file has the $PORT variable that has to be changed when building the docker image in the Heroku environment. The default.conf.template :
server {                         
listen $PORT default_server;

location / {                           
include  /etc/nginx/mime.types;                                                      root   /usr/share/nginx/html/;
index  index.html index.htm;       
}                                                                       }</span>

Also, make sure to copy the nginx.conf under the /etc/nginx/nginx.conf, you are free to change and modify 😃, but for now I will use the default settings. The last command is a little bit confusing so let’s break it down :

CMD /bin/bash -c “envsubst ‘\$PORT’ < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf” && nginx -g ‘daemon off;’</span>

/bin/bash -c ‘ command’: This command will run a Linux command with the bash shell. → envsubst: It is a program that substitutes the values of environment variables, so it will replace the $PORT from the Heroku environment and replace it in the default.conf.template file with its value, this variable is given by Heroku and attached to your app name, then we rename the template with default.conf which is recognized by nginx. → nginx -g ‘daemon off;’: The daemon off; directive tells Nginx to stay in the foreground. For containers, this is useful as the best practice is for one container = one process. One server (container) has only one service.

Preparing the deployment for the VPS on OVH

We will use the VPS as a development server so no need for a docker now we will use ssh for this after all make sure to have a VPS, ssh credentials, and a public IP.

I assume you have nginx installed, if not try to do it, it is simple 😙

In this tutorial I will be using the sshpass command, it is powerful and suitable for CI environments. You can install it with: apt-get install sshpass -y .

lets deploy the app to our server from the local machine, navigate to the repo and run ng build --prod , then navigate to dist/my-first-app folder and type this command :

sshpass  scp -v -p <password>  -o stricthostkeychecking=no -r *.* root@<vps-ip>:/usr/share/nginx/html</span>

If you don’t want to hardcode the password in the command line try to set the SSHPASS variable with your password like this export SSHPASS=" password" and replace -p with -e to use the environment variable.

Now all things are almost done! great 😃 ! let’s prepare the pipeline in the GitHub actions which is a fast and powerful ci system provided by GitHub inc.

Under the project root folder create the file main.yml in the github/wokflows folder, this directory is hidden so must start with a point like this: .github/workflows/main.yml

Preparing the pipeline

let’s take a look at the pipeline steps and configurations :

.github/workflows/main.yml

  • Block 1: In this block, we define the workflow name and the actions that must be performed to start the build, test, and deployment. and of course, you have to specify the branch of your repo (by default master ).
  • Block 2: The jobs keyword has to sub-keywords build and steps, the build define the base os for the continuous integration environment, in this case, we will use ubuntu-latest, also we define the node-version as a matrix that allows us to use multiple node versions in the list, in this case, we need only 12.x. The steps allow us to define the workflow steps and configurations ( build, test, deploy...).
  • Block 3 : actions/checkout@v1 is used to clone the app code in the ci env. this action is provided by GitHub. Let's define a cache action with the name cache node modules, the name is up to you 😃, then we use a predefined action called actions/cache@v1 and specify the folders that we want to cache.
  • Block 4: Installing and configuring the node run-time with an action called actions/node-setup@v1 and pass to it the desired node version that we already defined.
  • Block 5: The show will begin now! let’s configure the build and the deployment to the VPS. Create two environment variables SSHPASS for the sshpass command and define the server address, make sure to define these values on the GitHub secrets under setting on the top of your repo files. Under the run keyword put your deployment logic. so we need the sshpass command and the angular cli to be installed, then install all required packages and build the app with the production mode --prod, next, navigate to the dist/my-first-app folder and run the sshpass command with a set of arguments to remove the older app in the server and deploy the new code.
  • Block 6: Now Heroku is our target, so define also two env. variables, the Heroku registry URL and the API KEY to gain access to the registry using docker, next we need to define a special variable HEROKU_API_KEY that is used by Heroku cli, next, we login to the Heroku container and build the docker image then we pushed to the registry. we need to specify the target app in my case I named it angulardevops. After deploying the docker image we need to release it and tell the Heroku dynos to run our app on a Heroku server, using 1 server web=1, note that web is the name of the docker image that we already pushed.

We are almost done! now try to make a change in the app code and push it to GitHub, the workflow will start automatically 🎉 🎉 😄 !

Image for post

Image for post

You can view the app here: https://angulardevops.herokuapp.com/

Image for post

Image for post

Finally, this tutorial is aimed to help developers and DevOps engineers to deploy an Angular app, I hope it is helpful 😍. for any feedback please contact me!

If this post was helpful click the clap button as much as possible 😃.

Thank you 😃