CI/CD Workflow for Deploying a Spring Boot Application with MongoDB on Kubernetes (Amazon EKS)

Project Overview

  • Application: A Spring Boot application configured to connect with a MongoDB database.

  • Objective: To automate the CI/CD workflow for building, testing, and deploying the application in a Kubernetes cluster (Amazon EKS), ensuring seamless integration between the Spring Boot app and MongoDB.

GITHUB REPOSITORY

Steps:

Step 1 - Launch an Ubuntu(22.04) T2 Large Instance

Step 2 - Install Jenkins, Docker and Trivy.

Step 3- create sonarqube container.

Step 4- Install Plugins for Docker , Sonarqube, Kubernetes, Aws.

Step 5 - Create a Pipeline Project in Jenkins using a Declarative Pipeline

Step 6 - Docker Image Build and Push

Step 7- Deploy the image using Docker

Step 8- Kubernetes (Amazon EKS) Setup. (ClickHere)

step 9- Jenkins on your Kubernetes (EKS) cluster ,taking control of the master node.

step10- Setting Up Slack Notifications in Jenkins

step 11 - Deploying the Spring Boot Mongo Application to EKS (Amazon Elastic Kubernetes Service)

Install Jenkins

Connect to your console, and enter these commands to Install Jenkins

vi jenkins.sh # run in root user
#!/bin/bash
sudo apt update -y
#sudo apt upgrade -y
wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | tee /etc/apt/keyrings/adoptium.asc
echo "deb [signed-by=/etc/apt/keyrings/adoptium.asc] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list
sudo apt update -y
sudo apt install temurin-17-jdk -y
/usr/bin/java --version
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
                  /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
                  https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
                              /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update -y
sudo apt-get install jenkins -y
sudo systemctl start jenkins
sudo systemctl status jenkins
sudo chmod 777 jenkins.sh
./jenkins.sh    # this will installl jenkins

Once Jenkins is installed, you will need to go to your AWS EC2 Security Group and open Inbound Port 8080, since Jenkins works on Port 8080.

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Install Docker in Jenkins

sudo apt-get update
sudo apt-get install docker.io -y
sudo usermod -aG docker $USER   # ubuntu or ec2-user 
newgrp docker
sudo chmod 777 /var/run/docker.sock

Install Trivy in jenkins

vi trivy.sh
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy -y

To verify Trivy is installed correctly:

trivy --version

Create a Sonarqube Container using Docker.

Enable 9000 port in the security group.

docker run -d --name sonar -p 9000:9000 sonarqube:lts-community

http://<PublicIP>:9000

Enter username: admin and password: admin

Update Your SonarQube Password

SonarQube Dashboard:

Install Plugins for Docker, Sonarqube, Kubernetes, Aws

Docker-Related Plugins:

  • Docker

  • Docker Pipeline

  • Docker Build step

SonarQube-Related Plugins:

  • SonarQube Scanner

  • Quality Gates Plugin

Install the AWS Credentials Plugin:

  • To interact with an EKS cluster from Jenkins, you typically need to AWS Credentials Plugin

Kubernetes-Related Plugins:

  • Kubernetes Plugin

  • Kubernetes CLI Plugin

Install Maven in Jenkins

  • Navigate to Manage Jenkins > Global Tool Configuration.

  • Under the Maven section, click Add Maven. Provide meaningful name

Configuring SonarQube Authentication Token in Jenkins

  • Manage Jenkins > Configure System.

  • Scroll down to the SonarQube servers section.

  • Click on Add SonarQube.

    • Name: Give a name to your SonarQube server (e.g., SonarQube).

    • Server URL: Enter the URL of your SonarQube server (e.g., http://your-sonarqube-server-url).

    • Authentication Token: Choose the credential you added earlier from the dropdown list.

    • If you haven't added the credentials yet, you can add them directly from the SonarQube servers configuration section:

  • Click on "Add" next to the dropdown list.

  • Select "Jenkins" (or the appropriate credentials domain).

  • Choose "Secret text" as the kind of credentials.

  • Enter your SonarQube token in the Secret field.

  • Provide an ID and Description to identify the token.

  • Click Add to save the credentials.

Choose the credential you added earlier from the dropdown list and save

Configuring Docker Authentication Token in Jenkins

provide : Read , Write , Delete Access permissions , then click on generate

Step 1: Add Docker Authentication Token in Jenkins

  1. Go to Manage Jenkins > Manage Credentials.

  2. Click on "Add Credentials".

  3. In the Kind dropdown, select "Secret text".

  4. Secret: Paste your Docker Authentication Token.

  5. Description: Add a descriptive name to easily recognize the token.

  6. Click "OK" to save the credentials

If you get docker login failed error while running pipeline

 sudo usermod -aG docker jenkins
 sudo systemctl restart jenkins
pipeline {
    agent any

    tools {
        maven 'maven'
    }
    stages {
        // Checkout Code
        stage('Checkout') {
            steps {
                git branch: 'feature', 
                    credentialsId: '33e5e605-33c2-45d2-8c7d-4a94a80eb1ef', 
                    url: 'https://github.com/KandlaguntaVenkataSivaNiranjanReddy/spring-boot-mongo-docker-kkfunda.git'
            }
        }

        // Build the Maven Project
        stage('Build') {
            steps {
                sh "mvn clean package"
            }
        }

        // File System Security Scan using Trivy
        stage('File System Trivy Scan') {
            steps {
                script {
                    def status = sh(script: "trivy fs --format table -o trivy-fs-report.html .", returnStatus: true)
                    if (status != 0) {
                        error "Trivy scan failed with exit code ${status}"
                    } else {
                        echo "Trivy scan completed successfully."
                    }
                }
            }
        }

        // Code Quality Analysis with SonarQube
        stage('SonarQube') {
            steps {
                withSonarQubeEnv('sonar') {
                    sh """
                    mvn sonar:sonar \
                        -Dsonar.projectKey=spring-boot-mongo \
                        -Dsonar.projectName='Spring Boot Mongo Project' \
                        -Dsonar.host.url=http://18.175.240.114:9000/
                    """
                }
            }
        }

        // Build Docker Image and Tag
        stage('Build & Tag Docker Image') {
            steps {
                script {
                    withDockerRegistry(credentialsId: '985fdb56-2bc9-4fc7-b69d-0c3dfddee456') {
                        sh "docker build -t niranjanreddy1231/mongospring:latest ."
                    }
                }
            }
        }

        // Push Docker Image to Registry
        stage('Push Docker Image') {
            steps {
                script {
                    withDockerRegistry(credentialsId: '985fdb56-2bc9-4fc7-b69d-0c3dfddee456') {
                        sh "docker push niranjanreddy1231/mongospring:latest"
                    }
                }
            }
        }
    }
}

Setting Up the EKS Cluster and Nodes: Click Here for a Step-by-Step Guide

Steps to Take Control of the EKS Master Plane in Jenkins

  1. Install AWS CLI:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
sudo apt install unzip -y
unzip awscliv2.zip

After these steps, you’ll just need to run:

sudo ./aws/install

Verify the installation:

aws --version

  1. Install kubectl:

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

kubectl version --client
  • curl -LO ... downloads the latest stable version of kubectl from the Kubernetes website.

  • sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl moves kubectl to the /usr/local/bin/ directory with appropriate permissions.

  1. Configure AWS CLI:
  • Run aws configure to set up your AWS credentials and default region:

      aws configure
    

  • Enter your AWS Access Key,Secret Access Key Default Region(e.g., ap-south-1), and Output Format (e.g., json).

  1. Update kubectl to Connect to Your EKS Cluster:
  • Use AWS CLI to update the kubectl configuration for your EKS cluster:

      aws eks update-kubeconfig --region <region> --name <cluster-name>
    

    Replace <region> and <cluster-name> with your specific EKS cluster details

  • verify that your cluster has been successfully created or updated.

      aws eks list-clusters
    
  • Replace <region> and <cluster-name> with your specific EKS cluster details

cat /home/ubuntu/.kube/config

This command displays the contents of the kubeconfig file, which is used by kubectl to manage your Kubernetes cluster.

Jenkins on your Kubernetes (EKS) cluster successfully, taking control of the master node.

Add AWS Credentials in Jenkins

  • Go to Manage Jenkins page, click on "Manage Credentials”

    Now, under (global) or in a specific domain if required, click on (Global credentials (unrestricted))

  • Select the AWS Credentials Type:

  • In the Kind dropdown, select "AWS Credentials".

Fill in the AWS Credentials:

  • ID: Provide a unique name for the credentials (e.g., aws-eks-cred).

  • Access Key ID: Enter your AWS_ACCESS_KEY_ID.

  • Secret Access Key: Enter your AWS_SECRET_ACCESS_KEY.

Setting Up Slack Notifications in Jenkins

Create a Slack Channel

  1. In your Slack workspace, create a new channel for Jenkins notifications.

    • Example: #jio-project.
  2. This will be the channel where Jenkins sends its notifications.

Add the Jenkins CI App in Slack

  1. Go to the Slack App Directory and search for Jenkins CI.

  2. Select the app and click Add to Slack.

  • Follow the prompts to authorize the app and select the channel you created for notifications.

  • Slack will generate a token or webhook URL for integration.

Install the Slack Plugin in Jenkins

  1. Open your Jenkins dashboard and go to Manage Jenkins > Plugins

Configure Slack in Jenkins

  1. Go to Manage Jenkins > Configure System.

  2. Scroll to the Slack section

Workspace: Enter Your Slack workspace name.

  • click Add Credentials.

  • Select Secret text as the kind.

  • Paste the Slack Bot Token (starts with xoxb-...) into the Secret field.

Deploying the Spring Boot Mongo Application to EKS (Amazon Elastic Kubernetes Service)


pipeline {
    agent any

    tools {
        maven 'maven'
    }

    environment {
        AWS_DEFAULT_REGION = 'ap-south-1'  // Set default AWS region
    }

    stages {
        // Checkout Code
        stage('Checkout') {
            steps {
                git branch: 'feature', 
                    credentialsId: '33e5e605-33c2-45d2-8c7d-4a94a80eb1ef', 
                    url: 'https://github.com/KandlaguntaVenkataSivaNiranjanReddy/spring-boot-mongo-docker-kkfunda.git'
            }
        }

        // Build the Maven Project
        stage('Build') {
            steps {
                sh "mvn clean package"
            }
        }

        // File System Security Scan using Trivy
        stage('File System Trivy Scan') {
            steps {
                script {
                    def status = sh(script: "trivy fs --format table -o trivy-fs-report.html .", returnStatus: true)
                    if (status != 0) {
                        error "Trivy scan failed with exit code ${status}"
                    } else {
                        echo "Trivy scan completed successfully."
                    }
                }
            }
        }

        // Code Quality Analysis with SonarQube
        stage('SonarQube') {
            steps {
                withSonarQubeEnv('sonar') {
                    sh """
                    mvn sonar:sonar \
                        -Dsonar.projectKey=spring-boot-mongo \
                        -Dsonar.projectName='Spring Boot Mongo Project' \
                        -Dsonar.host.url=http://18.175.240.114:9000/
                    """
                }
            }
        }

        // Build Docker Image and Tag
        stage('Build & Tag Docker Image') {
            steps {
                script {
                    withDockerRegistry(credentialsId: '985fdb56-2bc9-4fc7-b69d-0c3dfddee456') {
                        sh "docker build -t niranjanreddy1231/mongospring:latest ."
                    }
                }
            }
        }

        // Push Docker Image to Registry
        stage('Push Docker Image') {
            steps {
                script {
                    withDockerRegistry(credentialsId: '985fdb56-2bc9-4fc7-b69d-0c3dfddee456') {
                        sh "docker push niranjanreddy1231/mongospring:latest"
                    }
                }
            }
        }

        // Configure AWS EKS Access
        stage('Setup KubeConfig') {
            steps {
                withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', 
                                  credentialsId: 'aws-eks-cred']]) {
                    script {
                        sh """
                        aws eks update-kubeconfig --region ap-south-1 --name EKS-Demo
                        """
                    }
                }
            }
        }

        // Deploy to Kubernetes Cluster
        stage('Deploy to Kubernetes') {
            steps {
                withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', 
                                  credentialsId: 'aws-eks-cred']]) {
                    script {
                        sh """
                        export KUBECONFIG=/var/lib/jenkins/.kube/config
                        kubectl apply -f springappmongo.yaml -n test-ns --validate=false
                        """
                    }
                }
            }
        }

        // Verify Deployed Pods
        stage('Verify Pods') {
            steps {
                withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', 
                                  credentialsId: 'aws-eks-cred']]) {
                    script {
                        sh "kubectl get pods -n test-ns"
                    }
                }
            }
        }
    }
     post {
        always {
            script {
                slackSend(
                    channel: "#jio-project", // Slack channel for notifications
                    color: currentBuild.result == 'SUCCESS' ? 'good' : 'danger', // Green for success, red for failure
                    message: """
                    *Job*: '${env.JOB_NAME}'  
                    *Build*: #${env.BUILD_NUMBER}  
                    *Status*: ${currentBuild.result}  
                    *Details*: <${env.BUILD_URL}|Click here>
                    """
                )
            }
        }
    }
}

To Be Continued...

In the next section, we will explore how to integrate Helm for deploying our Mongo Spring Boot application on Kubernetes using Jenkins and Helm. Stay tuned for more!

12
Subscribe to my newsletter

Read articles from Kandlagunta Venkata Siva Niranjan Reddy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kandlagunta Venkata Siva Niranjan Reddy
Kandlagunta Venkata Siva Niranjan Reddy