End-to-End CI/CD Pipeline for a Node.js App using GitHub Actions

Charan KumarCharan Kumar
4 min read

Introduction

In this blog post, I’ll walk you through building a complete CI/CD pipeline for a Node.js application using GitHub Actions. The pipeline covers:

  • Security scanning with Trivy and Gitleaks

  • Code quality analysis with SonarQube

  • Docker image build and push to Docker Hub

  • Docker image vulnerability scanning

  • Deployment to Kubernetes

All of this is automated using self-hosted GitHub Actions runners, enabling full control over the environment and resources.

Tools Used

TOOLSPURPOSE
Node.jsBackend application
GitHub ActionsCI/CD Workflow automation
SonarQubeStatic code analysis and quality gate checks
TrivySecurity scanning for vulnerabilities
GitleaksDetects secrets like tokens or passwords in code
DockerContainerizes the application
KubernetesContainer orchestration
Self-hosted GitHub RunnerFor running jobs inside the network

What Does This CI/CD Pipeline Workflow Do?

Here’s a high-level overview of the pipeline:

  1. Performs security checks using Trivy and Gitleaks

  2. SonarQube to analyse code quality

  3. Builds and pushes a Docker image to Docker Hub

  4. Deploys Application in to the Kubernetes cluster (in this project minikube)

Note: This entire workflow runs on the self-hosted runner and I used Minikube for creating the Kubernetes single node cluster.

Workflow Breakdown

Here’s a breakdown of each job defined in the CI/CD workflow :

Step 1: Security Scan

jobs:
  Security_scan:
    runs-on: self-hosted
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Trivy filesystem Scan
        run: trivy fs --format table .

      - name: Gitleaks Scan
        run: gitleaks detect source . -f json

This Job scans the file system and gives the information about known vulnerabilities and the secrets if any present in the project.

Checkout Code

  • For cloning the code into the GitHub Action runner machine. By using the actions/checkout action for the cloning the code.

Trivy Scan

  • Trivy scan is used for the scanning the file system to find the known vulnerabilities in the project.

Gitleaks Scan

  • Gitleaks is used to scan the code to check any accidentally committed secrets (like API keys or passwords).

Step 2: SonarQube Code Quality Analysis

  Sonar_scan:
    runs-on: self-hosted
    needs: Security_scan
    steps:
      - name: SonarQube Scan
        uses: SonarSource/sonarqube-scan-action@v5.1.0
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}

      - name: SonarQube Quality Gate Check
        uses: sonarsource/sonarqube-quality-gate-action@v1
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}

This job scans the code and provides a report on code quality.

SonarQube Scan

  • It performs a static code analysis of your project to detect bugs, vulnerabilities, code smells, security issues, and code coverage.

  • Generates a detailed report with metrics (e.g., technical debt, duplication, complexity).

SonarQube Quality Gate Check

  • Defines a set of pass/fail criteria that a project must meet to be considered "production-ready."

  • Determines if the code meets the required quality standards.

  • Fails the build(in CI/CD) if conditions are not met.

Note: Store your SONAR_TOKEN (secret) and SONAR_HOST_URL (variable) securely in your GitHub repository settings under Secrets and Variables.

Step 3: Docker Image Build and Push

Image_build:
    runs-on: self-hosted
    needs: Sonar_scan
    env:
          IMAGE_NAME: node-app
          IMAGE_TAG: latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
      - name: Docker Login
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Docker Setup Buildx
        uses: docker/setup-buildx-action@v3
      - name: Image Build and Push
        uses: docker/build-push-action@v6
        with:
          push: true
          tags: ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
      - name: Trivy image scan
        run: trivy image ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}

This job is to build and push the Docker image, and scan the Docker image using the Trivy image scan.

Docker Login

  • Using the action docker/login-action for login into Docker Hub or other image registry.

Buildx

  • Buildx is used for building the Docker image

Image Build and Push

  • This step is for building and pushing the docker image into the docker hub registry.

Trivy Image Scan

  • This step is used to scan the Docker image using the Trivy Image scan to find the vulnerabilities.

Note: Store your DOCKER_USERNAME (variable) and DOCKER_PASSWORD (secret) securely in your GitHub repository settings under Secrets and Variables.

Step 4: Kubernetes Deployment

  K8s_Deploy:
    runs-on: self-hosted
    needs: Image_build
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
      - name: Deploy to k8s
        run: kubectl apply -f ./kubernetes/.

This job is to apply Kubernetes manifest to deploy in to the cluster.

Deploy to k8s

  • Runs the command kubectl apply for deploying the application into the cluster

Conclusion

In this blog post, we explored how to set up a complete CI/CD pipeline for a Node.js application using GitHub Actions and a self-hosted runner. From running security scans with Trivy and Gitleaks to ensuring code quality with SonarQube, containerizing the application with Docker, and deploying it to Kubernetes, all the essential DevOps stages were covered.

What I Did Before

0
Subscribe to my newsletter

Read articles from Charan Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Charan Kumar
Charan Kumar