Building & Deploying a Spring Boot App in Docker compose with CI/CD

This blog post will guide you through setting up a CI/CD pipeline for a Spring Boot banking application, streamlining the build, deployment, and integration process. Using Jenkins, Docker, and GitHub, we'll automate every step, ensuring efficient and reliable software delivery. You'll also discover how to utilize a multi-node Jenkins setup and shared libraries for seamless automatic deployments

Repository for this Project: https://github.com/Saiprasad-1727/Springboot-app-devops.git

Project Overview

This project involves creating a complete CI/CD pipeline that automates the deployment of a Spring Boot-based banking application. Here are the steps we will follow:

  1. Create AWS EC2 Instances to host Jenkins and Docker.

  2. Set up Jenkins to automate the CI/CD pipeline.

  3. Containerize the Spring Boot application using Docker.

  4. Use a multi-node Jenkins setup to deploy the application on a development server.

  5. Create a Jenkinsfile for automated builds and deployment.

Steps to Implement the Project

To set up a Jenkins Master-slave architecture on AWS, we will create two EC2 instances(t2.medium). The Jenkins Master instance will manage Jenkins, while the Jenkins slave instance, will host and deploy the Spring boot application.

Step 1: Create Two AWS EC2 Instances

We'll start by setting up two separate instances: one for the Jenkins Master and one for the Jenkins Slave.

  1. Log in to AWS:
    Go to the AWS Console and log in.

  2. Launch an EC2 Instance (Jenkins Master):

    • Go to the EC2 Dashboard and click on Launch Instance.

    • Select the Ubuntu 24.04 LTS AMI.

    • Choose t2.medium for the Jenkins Master instance.

    • Configure Security Group:

      • SSH (port 22) for remote access.

      • HTTP (port 80) to access Jenkins through the browser.

    • Click Review and Launch.

  3. Launch an EC2 Instance (Jenkins Agent):

    • Repeat the above steps, select t2.medium for the Jenkins Agent instance.

    • Use the same key pair as used for the Jenkins Master.

Step 2 : Connect to two EC2 instances and update

SSH into both instances using below command:

Update Each EC2 Instance

Ensure both instances are up to date by running:

ssh -i <your-key>.pem ubuntu@<your-ec2-public-ip>

sudo apt update && sudo apt upgrade -y

Step 3: Install Java on Both Instances

Jenkins requires Java, so install OpenJDK 17 on each instance:

sudo apt install openjdk-17-jre -y
java -version

Step 4: Install Jenkins (Only on Jenkins Master)

we are going to build and deploy the application on second server, so no need to install the jenkins server on machine 2

create a bash script with jenkins.sh and provide the executable permisssions to it

vi jenkins.sh
chmod +x jenkins.sh

---------------------------------------------------------------------------------------------
sudo apt-get install -y ca-certificates curl gnupg
curl -fsSL https://pkg.jenkins.io/debian/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 binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins -y
sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
------------------------------------------------

execute with below command

./jenkins.sh

with the above script we are going to install the Jenkins server.

Step 5: Install Docker and Docker-compose on Both Instances

create a bash script with docker.sh and provide the executable permisssions to it

 sudo apt install docker.io -y
 sudo usermod -aG docker $USER
 newgrp docker
sudo apt install docker-compose -y
docker --version
docker-compose --version

execute with below command

./docker.sh

Step 6: To access the Jenkins, enable the 8080 port for master instance

Edit the security group of your Jenkins Master instance:

  1. Go to the EC2 Dashboard, select Security Groups, and choose the security group associated with your EC2 instance.

  2. Click on Edit Inbound Rules and add a rule for Custom TCP Rule with port 8080.

  3. Access Jenkins in a web browser using http://<your-ec2-public-ip>:8080.

  4. Access Jenkins Admin Password

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

    Use this password to complete the initial setup in Jenkins by following the on-screen instructions.

Step 7: Generate public and private key in Master instance to create a multimode jenkins setup

  1. Generate a public and private key with ssh-keygen

    
     ubuntu@ip-172-31-20-236:~$ ssh-keygen
     Generating public/private ed25519 key pair.
     Enter file in which to save the key (/home/ubuntu/.ssh/id_ed25519):
     Enter passphrase (empty for no passphrase):
     Enter same passphrase again:
     Your identification has been saved in /home/ubuntu/.ssh/id_ed25519
     Your public key has been saved in /home/ubuntu/.ssh/id_ed25519.pub
     The key fingerprint is:
     SHA256:m5jirdY5AXnZ10BS0/LIwyjHc8ZgCf6oyDpuDvK7kYU ubuntu@ip-172-31-20-236
     The key's randomart image is:
     +--[ED25519 256]--+
     |      ...++.     |
     |     .  +.o..    |
     |     ..= * *     |
     |   .o +o* X o    |
     |  E .o.oS= .     |
     | . + ..o o       |
     |o = o.ooo        |
     |++ o.o+          |
     |=+++o...         |
     +----[SHA256]-----+
     ubuntu@ip-172-31-20-236:~$ cd .ssh/
     ubuntu@ip-172-31-20-236:~/.ssh$ ls
     authorized_keys  id_ed25519  id_ed25519.pub
     ubuntu@ip-172-31-20-236:~/.ssh$ ls -la
     total 20
     drwx------ 2 ubuntu ubuntu 4096 May  1 11:29 .
     drwxr-x--- 4 ubuntu ubuntu 4096 May  1 11:17 ..
     -rw------- 1 ubuntu ubuntu  389 May  1 07:11 authorized_keys
     -rw------- 1 ubuntu ubuntu  419 May  1 11:29 id_ed25519
     -rw-r--r-- 1 ubuntu ubuntu  105 May  1 11:29 id_ed25519.pub
     ubuntu@ip-172-31-20-236:~/.ssh$
    
  2. private key is used step 8

  3. copy the content .pub id_ed25519.pub and paste in authorized_keys in directory .ssh/ on machine2

Step 8: Creating a Development Server from Jenkins Agent Instance to Deploy Spring boot bank App

To add a new node in Jenkins:

  1. Log in to Jenkins.

  2. Go to Manage Jenkins > Manage Nodes and Clouds.

  3. Click New Node:

    • Node name: Enter a name for the Jenkins Agent (e.g., machine2 ).

    • Choose Permanent Agent and click OK.

  4. Configure Node Settings:

    • Make sure to create a directory named app on the agent machine

    • Remote root directory: /home/ubuntu/app

    • Labels: Add machine2

    • Usage: Choose Use this node as much as possible

  5. Under Launch method, select Launch agents via SSH:

    • Host: Enter the PUBLIC IP of your Jenkins Agent instance.

    • Credentials: Add credentials by selecting SSH Username with private key.

      • Use ubuntu for the username.

      • Add the private key of master machine’s associated with the key pair used for the Jenkins Agent EC2 instance.

    • Click Save and connect to the Jenkins Agent.

Step 9: Set Up Docker Hub Credentials in Jenkins

  1. Go to Manage Jenkins > Security > Credentials > System > Global credentials (unrestricted) and click Add Credentials.

  2. Set Kind to Username with password.

  3. Add your Docker Hub username and password and save , for password generate Personal Access Token on DockerHub.

Step 10: Create a Shared Library Repository

  1. Create a GitHub Repository:

    • Go to GitHub and create a new repository.

    • Name it something like Jenkins-shared-library

    • set it to Public or Private (based on your needs), and click Create Repository.

  2. Clone the Repository:

  • Clone the repository to your local machine:

    
      https://github.com/Saiprasad-1727/Jenkins-shared-library.git
    

    and add the groovy scripts as follows which we are going to use in declarative pipeline

  • clone.groovy

    Handles code cloning from a Git repository:

      def call(String url, String branch){
        git url:url , branch:branch
      }
    

    dockerbuild.groovy

    Builds a Docker image:

      def call(String imageName, String imageTag){
        sh "docker build -t ${imageName}:${imageTag} ."
      }
    

    dockerpush.groovy

    Pushes a Docker image to Docker Hub:

      def call(String credId, String imageName,String imageTag){
        withCredentials([usernamePassword(credentialsId:credId,
                                          usernameVariable:"dockerHubUser",
                                          passwordVariable:"dockerHubPass")]){
                          sh "docker login -u ${env.dockerHubUser} -p ${env.dockerHubPass}"
                          sh "docker image tag ${imageName}:${imageTag} ${env.dockerHubUser}/${imageName}:${imageTag}"
                          sh "docker push ${env.dockerHubUser}/${imageName}:${imageTag}"
                }
      }
    

    deploy.groovy

    Deploys a Docker container:

      def call(){
        sh "docker-compose down && docker-compose up -d"
      }
    

Step 11: Configure the Shared Library in Jenkins

  1. Access Jenkins:

    • Go to Manage Jenkins > Configure System.
  2. Add Global Pipeline Library:

    • Scroll to Global Pipeline Libraries and click Add.

    • Fill in the details:

      • Name: Shared (matches @Library('Shared') in your Jenkinsfile).

      • Default Version: main.

      • Retrieval Method: Modern SCM.

      • Source Code Management:

        • Select Git.

        • Add the repository URL:

              https://github.com/Saiprasad-1727/Jenkins-shared-library.git
          
        • Add credentials if required (e.g., GitHub token or SSH key).

  3. Save Configuration:

    • Click Save.

Step 12: Create the jenkins pipeline for continious integration and deployment

jenkins > new item > Enter an item name as springboot-banking-app > select pipeline option and ok

write the description as per your wish

go to pipeline option on left side and start writing declarative pipeline for ci/cd as below

@Library('shared') _
pipeline { 
    agent { label 'machine2'}
    stages{
        stage("code"){
            steps{
                clone("https://github.com/Saiprasad-1727/Springboot-app-devops.git","main")
                echo "code clonning done"
            }
        }
        stage("build the images"){
            steps{
                dockerbuild("bankapp","latest")
                echo "sucessfully build the image"
            }
        }
        stage("push to cdockerhub"){
            steps{
                dockerpush("dockerHubCred","bankapp","latest")
                echo "pushed sucessfully"
            }
        }
        stage("deploying the application"){
            steps{
                deploy()
            }
        }
    }
}

Click on Build Now and check the stage view, if any stage got error click on builds and the check the console output and verify the errors and try to correct the pipeline and any configuration.

outputs:

Conclusion

By following these steps, we have successfully set up a CI/CD pipeline to automate the deployment of your Springboot bank Application using Jenkins, GitHub, and Docker, shared libraries, multinode agent etc. This setup not only simplifies the deployment process but also enhances productivity.

Before you leave

If you enjoy the content I share, feel free to connect with me on Sai Prasad Annam there’s a lot more to explore, and I think you’ll find it intriguing!"

And feel free check out my devops projects publication Dashboard - Overview

1
Subscribe to my newsletter

Read articles from SAI PRASAD ANNAM directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

SAI PRASAD ANNAM
SAI PRASAD ANNAM

Hi there! I'm Sai Prasad Annam, an enthusiastic and aspiring DevOps engineer and Cloud engineer with a passion for integrating development and operations to create seamless, efficient, and automated workflows. I'm driven by the challenges of modern software development and am dedicated to continuous learning and improvement in the DevOps field.