Deploying a NodeJS Application Using GitHub Actions
By: Gayal Dassanayake
Tags: Deployment, Cicd, Nodejs, Github Actions, Hosting

CI/CD

Deploying a NodeJS Application Using GitHub Actions

There are several really good Continuous Integration, Continuous Deployment(CI/CD) tools that are currently available in the marketplace. Jenkins, Travis CI, Circle CI are very popular CI/CD tools. However, GitHub presents their own simple and effective solution for CICD; GitHub Actions.

Today, I will demonstrate how to deploy a NodeJS application using GitHub Actions.

You will need a NodeJS application to be hosted, and a server as a hosting environment.

What are GitHub Actions?

GitHub actions can be used to automate the processes of a repository. A process that is automated is known as a workflow. Each workflow is created in a separate YAML file. GitHub Docs explain the functionality of GitHub Actions as,

“Automate, customize, and execute your software development workflows right in your repository with GitHub Actions. You can discover, create, and share actions to perform any job you’d like, including CI/CD, and combine actions in a completely customized workflow.”

Time to Get Started!

Let us try to create a GitHub action for an application to run a test suite and deploy on a server. Here, I am using a GitHub repository that contains a simple NodeJS application and attempting to host it in a self-hosted remote server.

Step 1: Generating the workflow template

Go to your repository and click on the Actions tab. There, you will see GitHub already suggesting you some workflow templates. It is not mandatory to select a template. We will use the set up a workflow yourself option to create a workflow from scratch. You will be directed to a YAML file in /.github/workflows directory with the following script inside.

Before getting into the actual task, it would be better if you could read through the script and the associated comments to get an idea of the structure of the workflow. If you need to have an in-depth explanation of workflow syntax, GitHub has really good documentation.

Step 2: Customizing Basic Workflow Configurations

By now, you should have a rough understanding of the workflow. Next, we will go ahead and change it to match our requirement; that is to automatically deploy the repository once new changes are pushed into it. In the process of doing so, I will explain what each line does.

Let’s keep the name of the workflow as it is.

We will change the content of the on to trigger the workflow only when there is a push to the master branch.

I am going to rename the first and only job in our workflow as deploy .

Currently, the runner or the environment that the workflow runs on is specified as ubuntu-latest . This says to execute the workflow on a GitHub hosted Ubuntu latest environment (Ubuntu 18.04 LTS at the time of writing the article). But as we are going to host it in our own server, we are going to replace ubuntu-latest with self-hosted .

We can create a tab by the name strategy inside the job deploy . A strategy is used to define a matrix of variations of the environment in which we run the job. For our job, we will use node version 12.

Step 3: Configuring the Steps of the Job

Now that we have mentioned all the basic configuration details, it is time to provide the workflow with tasks to perform or steps .

As the first step, we are going to use actions. An action is a reusable unit of code that can be used across multiple scripts. Here, we are going to use public actions from the GitHub Actions organization. The name of an action has the format of {owner}/{repo}@{ref} .

The first action is actions/checkout@v2. This action checks out the repository so that the workflow can access it.

The second action is actions/setup-node@v1. This sets up the hosting environment with the node version of our choice. But if you have NodeJS installed in the node environment, this is not mandatory. We have to provide the node version that we need to set up using the with key.

Step 4: Committing the Workflow File

Let us add a few more steps to install dependencies and run test scripts, if there are any.

The complete YAML file should look like this.

Now, you can commit the created YAML file if you created it in GitHub. You need to commit and push to the remote repo if you did it in the local environment. As our workflow gets triggered when a push is done, the workflow will start but fail.

Step 5: Setting Up the Runner

Now that we have a complete GitHub Action, we need to create a self-hosted runner to deploy our application. Self-hosted runners are highly configurable and can be run on our own server. For more information, check out the GitHub Documentation.

Go to the Settings tab of the repository and select Actions on the left side drawer. When you scroll to the bottom, you will see a section named Self-hosted runners . Go ahead and click Add runner .

On the next page, select the operating system and the architecture of the server. I will be selecting Linux and X64 .

Then log in to your server and copy and paste the code in the Download and Configure sections.

The following commands will download and extract the runner package into the directory actions-runner

Now we will configure the runner.

You will be asked to input the name of the runner and the name of the work folder. Use any convenient name. I have used cicdtest-cicd as the work folder name.

If you run the ./run.sh command, you will see that the runner is actively listening for any jobs. But we will set up the runner to run in the background later.

Step 6: Starting the NodeJS Application

Now let us run the previously failed action using the Re-run jobs button in the Actions tab in the GitHub repo.

If you log into the server, you can see that your repository is cloned inside the cicdtest directory, and npm dependencies are installed. Now it’s simply a matter of starting the server.

For that, we are using a tool called PM2. It is a great process manager that manages applications on behalf of us. If you do not have PM2 already installed, please go through their official quickstart guide.

Now that you have installed PM2, type the following command to start your Node application.

You can see that NodeApp is online . Here, name is the name that you give to your application. index.js is the entry point of my application. Yours could be different.

Now, we need to make sure that our runner is running and listening for jobs in the background. For that, enter into the actions-runner directory and execute the svc.sh script.

Step 7: Adding Restart Command

Next, we can add an instruction to our GitHub actions to restart the application every time we push into the master branch.

Then, push this to the remote master.

Now, if you go to the actions tab of GitHub, you can see that your action has been completed!!!

Log in to the server and check the status of the NodeApp with PM2 status. Hopefully, it will be online.