Integrate CI/CD for Azure NodeJS App using Github Actions

Sidharath Sharma
6 min readSep 8, 2024

--

Nowadays, if you are in DevOps, you must have heard of CI/CD. It’s a commonly used term in DevOps.This article covers why, how, and where we can configure that in this article

CI/CD

What does CI/CD mean?

CI/CD, which stands for continuous integration and continuous delivery/deployment, aims to streamline and accelerate the software development lifecycle.

Continuous integration (CI) refers to the practice of automatically and frequently integrating code changes into a shared source code repository. Continuous delivery and/or deployment (CD) is a 2 part process that refers to the integration, testing, and delivery of code changes. Continuous delivery stops short of automatic production deployment, while continuous deployment automatically releases the updates into the production environment.

Now we understand what is CI/CD but let’s jump to our next question that

How can we build a CI/CD pipeline?

Various platforms provide support to create CI/CD pipeline. Some of the commonly used platforms are:

  • GitHub Actions
  • Azure DevOps
  • AWS CodePipeline
  • Jenkins

In this article, will discuss How to create a CI/CD pipeline for NodeJs Applications running on Azure Web Service using GitHub Actions?

I am assuming you already created an Azure Web App Service, If not will cover that in a separate article.

Setup a GitHub Actions Pipeline

In the context of CI/CD (Continuous Integration/Continuous Deployment), a pipeline is a series of automated steps that software goes through from development to production

Steps involved in setting up a Pipeline:

  1. Code Repository: Push your code to any cloud Repository like GitHub or BitBucket. Here, I am using the GitHub Repository.
  2. Branch Creation: Best practice is to create at least two different branches each for production and development. The thumb rule here is to create pipelines according to the environment. I will be using just two branches to keep this article concise.
  3. Workflow file creation: Now let’s create a config file for CD generally it’s a YML file, you don’t need to create it from scratch as Github gives a nice template (you have to tweak it a bit).
    Go to Actions -> Search Azure -> there you see “Deploy Nodejs to Azure web app” (you can search for any template for CI/CD like AWS/GCP or another platform, just to stick with our case I am looking for Azure
GitHub Actions

4. Configuration: Configure your file according to your requirements, as it’s done here. There are some inline comments so you can understand better.

name: CI/CD Azure app servie (Node JS App)
on:
push:
branches:
- dev # to deploy in dev env
- prod # to deploy in prod env
workflow_dispatch: # to trigger workflow manually if needed

env:
AZURE_WEBAPP_NAME: medium-github-app
AZURE_WEBAPP_PACKAGE_PATH: '.'
NODE_VERSION: '16.x'

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Node.js # initial setup
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

# this is important install all the dependencies,
# run build this would transpile TS to JS
# run test to run unit test cases
# include other scripts you might want to run here like linting etc.
- name: npm install, build, and test
run: |
npm install
npm run build --if-present
npm run test --if-present

# This is optional but it improves the performance
# specially if your project has large number of files
# In our case we have installed all the node_modules and uploading them
# Zip will reduce the upload time multifold
- name: Zip artifact for deployment
run: zip release.zip ./* -r

# finally upload the artifacts
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v3
with:
name: node-app
path: release.zip

# we have two environments to take care of
# first configure dev deployment
deploy-dev:
runs-on: ubuntu-latest
# this would make dependency of this task
# on the "build" task (job #1) to succeed
needs: build

# There are environments you can setup in github actions
# this would tell github to pick 'DEV' environment to get env variables/secrets
# more on this in next point (point 5 of the article)
environment:
name: 'DEV'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

# download artifacts (uploaded in last activity of build job)
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v3
with:
name: node-app

# since it was zipped before upload, hence unzip after download
- name: Unzip artifacts for deployment
run: unzip release.zip

# finally the deployment to Azure app service
- name: 'Deploy to Azure WebApp'
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
# this is coming from configured env variable for 'DEV'
app-name: ${{ env.APP_NAME }}
# this is also coming from configured env variable for 'DEV'
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_DEV }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}

# here everything is similar to job #2
# only change is, it is referring to 'PROD' env instead of 'DEV'
deploy-prod:
runs-on: ubuntu-latest
# first finish build (job #1) and deploy-dev (job #2)
needs: [build, deploy-dev]
# env 'PROD' configured here
environment:
name: 'PROD'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

steps:
- name: Download artifact from build job
uses: actions/download-artifact@v3
with:
name: node-app

- name: Unzip artifacts for deployment
run: unzip release.zip

- name: 'Deploy to Azure WebApp'
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: ${{ env.APP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}

5. Environment Creations: The idea is to create a separate environment in GitHub to manage rules for separate environments

You can go to Settings -> Environments -> New environment
I have already configured two of them ‘PROD’ and ‘DEV’ same is referred in yml file (were I put comment “# more on this in next point (point 5 of the article”)

GitHub Environment creations

6. Publish Profile: Now the question is, how this actions pipeline know where to deploy?
The answer lies in the env configuration, if you look at the ‘deploy to web app’ task you will find two properties that we are fetching from environments,

APP_NAME:Name of your web-app in Azure
AZURE_WEBAPP_PUBLISH_PROFILE : Publish profile of your Azure web app.

APP_NAME is easily to locate let’s discuss about AZURE_WEBAPP_PUBLISH_PROFILE, to get this,
follow on Azure Portal:
<App name> -> Deployment -> Deployment Center -> Manage Publish Profile

Download ‘Manage publish profile’ and open it in any test editor, copy the whole content, and set it as secret in Github environments with the name AZURE_WEBAPP_PUBLISH_PROFILE.

Keep in mind you would have one set of ‘DEV’ and one set of ‘PROD’, so get AZURE_WEBAPP_PUBLISH_PROFILE from each Azure web app (dev and prod) and configure it in GitHub Actions.

7. Trigger pipeline: That’s all, now create a PR and commit to the prod or dev branch, it would trigger the CI/CD and do the deployment for you, isn’t that easy!

8. Protection Rule: The above pipeline will run on every push to the prod and dev branch, we do not want each ‘dev’ branch push should deploy in ‘prod’ as well which is disastrous.

To avoid this we can setup some protection rules to deploy in prod environment when we push code in prod branch, let’s see how we can do it Go to below path,
Setting-> Environments -> <your env> -> Deployment branches
This would look something like the below snippet

Allow only prod branch to trigger deployment

This change will take care of it.

That’s all after configuring the pipeline you are all set to run your first CI/CD deployment. If you have any queries please let me know in the comments.

PS: We can also add an approval every time we deploy to a particular environment. Let me know in comments if you want that flow too will try to cover it in the next article

| Thanks For Reading, Follow Me For More

References

  1. https://www.redhat.com/en/topics/devops/what-is-ci-cd

--

--

No responses yet