CI/CD for Node.js Application using Google Cloud

Pavan Pss
11 min readJan 30, 2021

Introduction

Are you looking to implement a DevOps pipeline and test the flow of your Node.js application through the CI/CD pipeline for deploying it on Kubernetes on Google Cloud Platform?

Then this article might be of interest to you. This post will help you to create a Kubernetes deployment of your Node.js application via a CI/CD pipeline involving Github, Jenkins, Docker, and Kubernetes.

Important Notes

1. The steps described here are only for sample testing/demo purpose

2. Do not use this configuration for a Production environment

3. I am using the root user

DevOps Pipeline

The following diagram describes the end to end flow for the DevOps pipeline involving tools: Github, Jenkins, and Docker. The subsequent sections provide detailed steps to implement this flow in the Google Cloud Platform.

Fig 1. DevOps Flow

DevOps Flow Steps:

1) Developers develop the code. This source code is managed by Version Control Systems like GitHub, GitLab, Etc. I am using GitHub here.

2) Developers push the code to the repository and any changes made to the code are committed to the repository.

3) Jenkins pulls the code from the repository and creates a build-out of the code using the tools like Maven, Ant, Node.js, Etc. I am using Node.js as I have written the code in Node.js.

4) Jenkins executes the pipeline to create a Docker image out of the build. Docker automates the deployment of applications inside software containers. The newly created Docker image will be pushed into DockerHub.

5) Kubernetes pulls the image from DockerHub and deploys the application on a Kubernetes cluster.

Prerequisites

I am using GCP to demonstrate the DevOps Flow. Following are the prerequisites.

1) You need a virtual machine with internet connectivity on GCP.

2) You also need to have a DockerHub account in order to push the image into the Docker registry.

3) Perform all the operations as a root user.

Git Repository Structure

I created a simple Node.js weather application for this demonstration purpose. The application code is hosted in a Git repository (https://github.com/psspavan96/NodejsDevOps_Pipeline) with the following directory structure:

/

-views/

index.ejs

Dockerfile

Jenkinsfile

server.js

Let’s look at these files in detail

The views directory contains an HTML markup file with plain JavaScript

The Dockerfile contains commands to assemble an image of your application

The Jenkinsfile contains a pipeline script, specifying the steps to execute the job

The server.js file contains a basic Node.js application that creates an HTTP server on port 3000 and returns a message depending on the visited path.

Implementation Steps

Following are the high-level implementation steps to realize the CI/CD Pipeline and establish the flow.

Step 1: Installing and Setting up GoogleCloud SDK on your local machine

To install and setup GoogleCloud SDK on your local machine. Please refer to the following link:

Step 2: Create Google VM(Ubuntu) Instance

Before creating a VM Instance, a service account needs to be created for accessing the Kubernetes cluster. In order to create a service account go to Navigation Menu > IAM & Admin > Service Accounts as shown below:

Firstly, click on “CREATE SERVICE ACCOUNT” to create the service account. Secondly, Once the account is created, you need to add a role. The role is Kubernetes Engine Admin. Click on Continue and Done.

Once your service account is created, go to the terminal/Command Prompt on your local computer and execute the following command for creating the instance:

gcloud compute instances create <your-instance-name> — machine-type=<your-machine-type> — zone=<your-compute-zone> — image=ubuntu-1604-xenial-v20201210 — image-project=ubuntu-os-cloud — service-account=<your-service-account> — scopes=https://www.googleapis.com/auth/cloud-platform — subnet “default”

For more information on how to create an instance using the command line. Please refer to the link below:

https://cloud.google.com/sdk/gcloud/reference/compute/instances/create

Once your instance is created. Go to Navigation Menu > Compute Engine > VM Instances to check your running instance. Once the instance is created, click on the instance (Click on instance name). Click on Edit, under Firewalls category, click on “Allow HTTP traffic” and “Allow HTTPS traffic” as shown below:

Click on save to save the changes.

Once the instance is created. Connect to VM instance using SSH as shown below.

Step 3: Creating Firewall Rules

To access Jenkins, you need to open the Firewall for port 8080.

Go to Firewall under VPC network in Networking section of navigation in GoogleCloud

Create a firewall with the following values:

a) Enter the name of the firewall

b) Ensure the network, priority, direction of traffic, action on match, targets is default, 1000, ingress, allow and specified target tags respectively.

c) For Target tags — enter http-server, https-server

d) For Source filter — IP ranges and 0.0.0.0/0 in Source IP ranges(Traffic is only allowed from sources within these IP address ranges)

e) For Protocols and ports — Select Specified protocols and ports option and under tcp enter 8080.

Now hit Create. It will take a couple of minutes to create a Firewall rule.

Step 4: Java Installation

Go back to your compute instance and SSH into the server through the browser.

Once you are connected to the server, execute the following commands to switch to the superuser and then install JDK.

sudo su

sudo apt update

sudo apt install default-jdk-headless

Check the java version using the “java -version” command and ensure that it is 1.8 or higher.

Step 5: Jenkins Installation

*Note: What is a GPG key?

GPG is the Gnu Privacy Guard, an implementation of OpenPGP (Open Pretty Good Privacy). It is an encryption technique that was originally developed for use in e-mail exchanges which is used in various applications such as code signing for Linux code repositories and source code repositories like GitHub.

a) Download and install the necessary GPG key with the command

wget -q -O — https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -

b) Add the necessary repository with the command:

sudo sh -c ‘echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list’

c) Add the universe repository with the command:

sudo add-apt-repository universe

d) Update apt with the command

sudo apt-get update

e) Install Jenkins using the command

sudo apt-get install jenkins -y

f) Allow the installation to complete.

g)To start jenkins use the command:

sudo systemctl start jenkins

h) To view the status use the command:

sudo systemctl status jenkins

Step 6: Accessing Jenkins and installing plugins

Open a web browser and point it to (Jenkins Server) “http://{Public_IP}:8080" (where Public_IP(External IP in Google VM Instance is the IP address of the hosting server)) below:

You will then be prompted to copy and paste a password that was created during the Jenkins installation.

To retrieve that password, go back to the VM Instance terminal and issue the command

cat /var/lib/jenkins/secrets/initialAdminPassword

Enter the password and click Continue

You will be given the 2 options either To install suggested plugins from Jenkins or To install your own plugins as below:

Click on “Install suggested plugins”. Once the plugins are installed, The Jenkins server will also ask you to create a first admin user. To keep it simple, Click on “skip and continue as admin”.

Check the instance configuration and click on Save and Finish

It is always a good practice to change the password after the first login. In order to change the password. To Change admin password, Go to Admin > Configure > Password

To configure Java Path

Go to Manage Jenkins > Global Tool Configuration > JDK. Set the Name as JAVA_HOME and copy the path. To get the JAVA_HOME path, go to your instance and type the following command:

which java

Copy the path and paste it.

a) Once you’ve unlocked Jenkins, you can then finish the installation by installing and configuring the plugins required for the flow in a similar manner. Install the below plugins:

i)Docker
ii)Docker Pipeline

iii) Node.js (Version 12.0.0)

In order to install the plugins go to Manage Jenkins > Manage Plugins. Go to the Available tab and install the plugins. Install the plugins without restart

Step 7: Docker Installation

a) SSH into your VM instance, First, update your existing list of packages using the commands below:

sudo su

sudo apt update

b) Next, install a few prerequisite packages which let apt use packages over HTTPS using the command:

sudo apt install apt-transport-https ca-certificates curl software-properties-common

c) Then add the GPG key for the official Docker repository to your system using the command

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

d) Add the Docker repository to APT sources using the command:

sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable”

e) Next, update the package database with the Docker packages from the newly added repo using the command:

sudo apt update

f) To Make sure you are about to install from the Docker repo instead of the default Ubuntu repo use the command:

apt-cache policy docker-ce

g) Install docker using the command:

sudo apt install docker-ce

h) To check whether docker is running or not use the command:

sudo systemctl status docker

Step 8: Install kubectl

You need to install “kubectl” to access the Google Kubernetes Engine cluster from your VM Instance. To install kubectl on your VM Instance, please refer to the following link:

https://kubernetes.io/docs/tasks/tools/install-kubectl/

Step 9: Testing the execution of code (On local machine)

Clone the repository from GitHub on to your Jenkins server using the command:

git clone https://github.com/psspavan96/NodejsDevOps_Pipeline

Go to the folder “NodejsDevOps_Pipeline” from your command prompt/terminal(using cd command). The folder consists of the following programs and files:

Index.ejs Program

Server.js Program

Dockerfile

Before executing the program, make sure that you have installed node and npm modules. In case, if you didn’t install using the following commands:

sudo apt-get install npm

sudo apt-get install nodejs

Once the json file is created, we need to install request package by using the following command:

npm install request — save

After the installation is done, to install dependencies, use the following command:

npm install

After installing the dependencies, in order to test the application, use the command “npm start”. After the command is executed, you should be able to successfully access the application at http://localhost:3000

Step 10: Creating a Jenkins Job to test your Node application

a) Log in to your Jenkins server and Click on New Item.

b) Enter the project name and Select Pipeline.

c) Scroll down, under the Pipeline subheading. Select Pipeline Script option and Paste the script given below in the pipeline section of the Jenkins Job:

pipeline {

agent any

tools {nodejs “Node”}

stages {

stage(‘Cloning Git’) {

steps {

git ‘https://github.com/psspavan96/NodejsDevOps_Pipeline'

}

}

stage(‘Install dependencies’) {

steps {

sh ‘npm install’

}

}

stage(‘Install request’) {

steps {

sh ‘npm install request — save’

}

}

stage(‘Start App’) {

steps {

sh ‘npm start’

}

}

}

}

d) Click Apply and Save

e) Once the configuration is done, click on Build now to build the job.

f) Once the build is successful, you should be able to successfully access the application at http://{Public_IP}:3000

Step 11: Creating a Docker image and Kubernetes deployment

Note: Before proceeding with the steps below, go to Manage Jenkins > Manage Credentials > Jenkins > Global Credentials >Add Credentials and add your DockerHub credentials.

Go to your VM instance terminal from your browser and execute the following command before proceeding with the following steps:

chmod 777 /var/run/docker.sock

a) Open terminal/Command Prompt on your local machine and execute the following set of commands:

gcloud config set project <your-project-id> // Setting a default project
gcloud config set compute/zone <your-compute/zone> // Setting a default compute zone
gcloud container clusters create <your-cluster-name> --num-nodes=1 // Creating a cluster

b) Log in to your Jenkins server and Click on New Item.

c) Enter the project name and Select Pipeline.

d) Click on Poll SCM and enter the desired cron to poll the SCM. Here, I have given “* * * * *” which means the Jenkins polls the SCM every minute of every hour of every day of every month and every day of the week.

e) Scroll down, under the Pipeline subheading. Select Pipeline Script option and Paste the script given below in the pipeline section of the Jenkins Job:

pipeline {

environment {

registry = “your docker registry”

registryCredential = ‘your registry credentials*’

dockerImage = ‘’

}

agent any

tools {nodejs “Node” }

stages {

stage(‘Cloning Git’) {

steps {

git ‘https://github.com/psspavan96/NodejsDevOps_Pipeline'

}

}

stage(‘Building image’) {

steps{

script {

dockerImage = docker.build registry + “:$BUILD_NUMBER”

}

}

}

stage(‘Deploy Image’) {

steps{

script {

docker.withRegistry( ‘’, registryCredential ) {

dockerImage.push()

}

}

}

}

stage(‘Deploy to GKE’) {

steps{

script {

sh ‘gcloud container clusters get-credentials <your-cluster> — zone <your-compute/zone> — project <your-project-id>’

sh ‘kubectl create deployment <your-deployment-name$BUILD_NUMBER> — image=<your-docker-registry>:$BUILD_NUMBER> — port=3000’

sh ‘kubectl expose deployment <your-deployment-name$BUILD_NUMBER> — name=<your-service-name$BUILD_NUMBER> — type=LoadBalancer — port=3000’

}

}

}

}

}

Note: To get your docker registry credentials, go to Manage Jenkins > Manage Credentials, you will find your DockerHub ID, specify the ID under the registryCredential as shown below:

e) Click Apply and Save

f) Once the configuration is done, click on Build now to build the job.

g) Once the build is successful, you should see a docker image present in your docker registry.

f) Once the build is successful, Go to Navigation Menu > Kubernetes Engine > Clusters. Connect to the cluster and execute the command “kubectl get deployments” to view all the deployments in the cluster and “kubectl get svc” to view the services in the cluster.

g) Now, to access the application, use the link http://{External_IP}:3000 where External_IP is the IP of the service in the Kubernetes cluster as shown below:

h) The application webpage is as below:

i) Jenkins will periodically check the Git repository for new changes committed to code. As soon as Jenkins detects the changes, it pulls the code from the repository, creates a new build-out of it, and deploys the same to the Kubernetes environment as shown below:

You may use a scheduled cron job to detect and delete Kubernetes deployments running the previous version of the application. Alternatively, you can update the pipeline to delete the previous deployments.

References:

[1] https://codeburst.io/build-a-weather-website-in-30-minutes-with-node-js-express-openweather-a317f904897b

[2] https://nodejs.org/docs/latest-v12.x/api/

[3] https://kubernetes.io/docs/reference/kubectl/cheatsheet/

[4]https://kubernetes.io/docs/concepts/workloads/controllers/deployment

[5] https://kubernetes.io/docs/concepts/services-networking/service/

[6]https://cloud.google.com/sdk/gcloud/reference/compute/instances/create

[7] https://cloud.google.com/kubernetes-engine/docs/quickstart

[8]https://cloud.google.com/sdk/gcloud/reference/container/clusters/create

--

--