Ultimate CI/CD Pipeline: Building and Deploying a Java Spring Boot Application with Jenkins, Docker, SonarQube, Argo CD, Helm, and Kubernetes

Anshika MishraAnshika Mishra
5 min read

In this blog, we will walk you through creating an end-to-end CI/CD pipeline for a Java Spring Boot application. This pipeline will automate the process from building the application to deploying it on Kubernetes using Jenkins, Docker, SonarQube for static code analysis, Argo CD for continuous deployment, Helm for Kubernetes deployment, and Kubernetes for orchestrating containerized applications.

We will cover the entire process, step by step, starting from the code repository to the final production deployment. This pipeline will automate and streamline the entire software delivery lifecycle, ensuring faster and more efficient deployments with minimal manual intervention.

Prerequisites

Before we start, make sure you have the following tools and configurations in place:

  1. Java Application Code: Hosted on a Git repository.

  2. Jenkins Server: To automate the CI/CD pipeline.

  3. Kubernetes Cluster: To deploy the application.

  4. Helm: Package manager for Kubernetes.

  5. Argo CD: For continuous deployment to Kubernetes.

  6. SonarQube: For static code analysis.

Step 1: Setup Jenkins Pipeline

Install Necessary Jenkins Plugins

To create a functional CI/CD pipeline in Jenkins, we first need to install the following plugins:

  • Git Plugin: For fetching the source code from the Git repository.

  • Maven Integration Plugin: For building the Java application using Maven.

  • Pipeline Plugin: For defining the pipeline stages.

  • Kubernetes Continuous Deploy Plugin: To deploy the application to Kubernetes.

Create a New Jenkins Pipeline

  1. In Jenkins, create a new pipeline job and configure it with the Git repository URL for the Java application.

  2. Add a Jenkinsfile to the Git repository to define the pipeline stages.

Define the Pipeline Stages

The pipeline will consist of the following stages:

  1. Checkout Source Code: Fetch the code from the Git repository.

  2. Build Java Application: Use Maven to compile and build the Java application.

  3. Run Unit Tests: Execute unit tests using JUnit and Mockito.

  4. SonarQube Static Code Analysis: Run SonarQube analysis to check for code quality.

  5. Package Application: Package the application into a JAR file.

  6. Deploy to Test Environment: Use Helm to deploy the application to a test environment on Kubernetes.

  7. User Acceptance Testing (UAT): Run user acceptance tests on the deployed application.

  8. Promote to Production: Use Argo CD to promote the application to the production environment.

Jenkinsfile for Pipeline

groovyCopyEditpipeline {
  agent {
    docker {
      image 'anshikaf5/maven-anshika-docker-agent:v1'
      args '--user root -v /var/run/docker.sock:/var/run/docker.sock' // mount Docker socket to access the host's Docker daemon
    }
  }
  stages {
    stage('Checkout') {
      steps {
        sh 'echo passed'
      }
    }
    stage('Build and Test') {
      steps {
        sh 'ls -ltr'
        sh 'cd java-maven-sonar-argocd-helm-k8s/spring-boot-app && mvn clean package'
      }
    }
    stage('Static Code Analysis') {
      environment {
        SONAR_URL = "http://34.201.116.83:9000"
      }
      steps {
        withCredentials([string(credentialsId: 'sonarqube', variable: 'SONAR_AUTH_TOKEN')]) {
          sh 'cd java-maven-sonar-argocd-helm-k8s/spring-boot-app && mvn sonar:sonar -Dsonar.login=$SONAR_AUTH_TOKEN -Dsonar.host.url=${SONAR_URL}'
        }
      }
    }
    stage('Build and Push Docker Image') {
      environment {
        DOCKER_IMAGE = "anshika/ultimate-cicd:${BUILD_NUMBER}"
        REGISTRY_CREDENTIALS = credentials('docker-cred')
      }
      steps {
        script {
            sh 'cd java-maven-sonar-argocd-helm-k8s/spring-boot-app && docker build -t ${DOCKER_IMAGE} .'
            def dockerImage = docker.image("${DOCKER_IMAGE}")
            docker.withRegistry('https://index.docker.io/v1/', "docker-cred") {
                dockerImage.push()
            }
        }
      }
    }
    stage('Update Deployment File') {
        environment {
            GIT_REPO_NAME = "End-to-End-CICD-Project"
            GIT_USER_NAME = "anshikamishra03"
        }
        steps {
            withCredentials([string(credentialsId: 'github', variable: 'GITHUB_TOKEN')]) {
                sh '''
                    git config user.email "anshika.mishra@gmail.com"
                    git config user.name "anshikamishra03"
                    BUILD_NUMBER=${BUILD_NUMBER}
                    sed -i "s/replaceImageTag/${BUILD_NUMBER}/g" java-maven-sonar-argocd-helm-k8s/spring-boot-app-manifests/deployment.yml
                    git add java-maven-sonar-argocd-helm-k8s/spring-boot-app-manifests/deployment.yml
                    git commit -m "Update deployment image to version ${BUILD_NUMBER}"
                    git push https://${GITHUB_TOKEN}@github.com/${GIT_USER_NAME}/${GIT_REPO_NAME} HEAD:main
                '''
            }
        }
    }
  }
}

Step 2: Dockerfile for the Application

We need to create a Dockerfile for containerizing the Java Spring Boot application. The Dockerfile will ensure that the application runs seamlessly within a container.

dockerfileCopyEdit# Use an official JDK image
FROM adoptopenjdk/openjdk11:alpine-jre

# Set the working directory
WORKDIR /opt/app

# Copy the packaged JAR file
COPY target/spring-boot-web.jar app.jar

# Define the entry point
ENTRYPOINT ["java","-jar","app.jar"]

Step 3: Kubernetes and Helm Configuration

Once the application is packaged into a Docker image, we need to deploy it to Kubernetes using Helm. Helm helps us package and manage Kubernetes resources.

Deployment YAML (deployment.yml)

yamlCopyEditapiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-app
  labels:
    app: spring-boot-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-boot-app
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
      - name: spring-boot-app
        image: anshikaf5/ultimate-cicd:${BUILD_NUMBER}
        ports:
        - containerPort: 8080

Service YAML (service.yml)

yamlCopyEditapiVersion: v1
kind: Service
metadata:
  name: spring-boot-app-service
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
  selector:
    app: spring-boot-app

ArgoCD Configuration

ArgoCD helps us automate the deployment process to Kubernetes. We define an ArgoCD configuration file (argocd-basic.yml) that creates a connection between ArgoCD and Kubernetes for continuous deployment.

yamlCopyEditapiVersion: argoproj.io/v1alpha1
kind: ArgoCD
metadata:
  name: example-argocd
  labels:
    example: basic
spec:
  server:
    service:
      type: NodePort

Step 4: SonarQube Integration

SonarQube is integrated into the pipeline for static code analysis. It helps ensure the quality of the code by identifying bugs, vulnerabilities, and code smells.

To set up SonarQube locally:

  1. Install SonarQube and start the service on your local machine.

  2. Configure the Maven build to integrate with SonarQube for code analysis.

bashCopyEdit# Install SonarQube
sudo apt update && sudo apt install unzip -y
adduser sonarqube
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-10.4.1.88267.zip
unzip sonarqube-10.4.1.88267.zip
chown -R sonarqube:sonarqube /opt/sonarqube
chmod -R 775 /opt/sonarqube
cd /opt/sonarqube/bin/linux-x86-64
./sonar.sh start

You can now access the SonarQube server at http://localhost:9000.

Step 5: Access the Application

Once the CI/CD pipeline has completed successfully, you can access the application. There are two ways to run it:

  1. Locally (using Java 11):

     bashCopyEditjava -jar target/spring-boot-web.jar
    

    Access the application on http://localhost:8080.

  2. Docker: Build the Docker image:

     bashCopyEditdocker build -t ultimate-cicd-pipeline:v1 .
    

    Run the container:

     bashCopyEditdocker run -d -p 8010:8080 -t ultimate-cicd-pipeline:v1
    

    Access the application on http://localhost:8010.

Conclusion

This comprehensive blog outlines the creation of an end-to-end CI/CD pipeline for a Java Spring Boot application. We used Jenkins, Docker, SonarQube, Argo CD, Helm, and Kubernetes to automate the build, test, and deployment process. By implementing this pipeline, we can ensure a smooth, continuous delivery of applications with minimal manual intervention.

Whether you're working on a Java-based application or any other technology, this approach can be adapted to suit your needs and streamline your software delivery process.

0
Subscribe to my newsletter

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

Written by

Anshika Mishra
Anshika Mishra

Passionate about DevOps, I focus on automating processes and optimizing system performance using tools like Docker, Kubernetes, Terraform, and Ansible. With experience in CI/CD, cloud infrastructure, and container management, I aim to improve efficiency, security, and scalability in every project I work on.