# Automating CI/CD for a Spring Boot Banking Application with Jenkins, Docker, and GitHub

In this blog post, I will walk you through the process of setting up a **CI/CD pipeline** for a **Spring Boot banking application**. This pipeline will automate the build, deployment, and integration processes using **Jenkins**, **Docker**, and **GitHub**. You will learn how to leverage a **multi-node Jenkins architecture**, **shared libraries**, and **webhooks** for automatic deployments.

**Repository for this Project**: [https://github.com/Amitabh-DevOps/banking-app-project](https://github.com/Amitabh-DevOps/banking-app-project)

> Use the `dev` branch for the code related to this project.

---

## **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. **Integrate GitHub** for automatic deployment triggered by code changes.
    
5. **Use a multi-node Jenkins setup** to deploy the application on a development server.
    
6. Create a **Jenkinsfile** for automated builds and deployment.
    
7. **Set up webhooks** in GitHub to trigger Jenkins builds on code changes.
    

---

## Steps to Implement the Project

To set up a **Jenkins Master-Agent** architecture on AWS, we will create two EC2 instances. The Jenkins Master instance will manage Jenkins, while the Jenkins Agent instance, with higher resources, will host and deploy the Spring bootapplication.

### 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 Agent**.

1. **Log in to AWS**:  
    Go to the [AWS Console](https://aws.amazon.com/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.micro** for the Jenkins Master instance, eligible for the free tier.
        
    * 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, but select **t2.medium** for the Jenkins Agent instance.
        
    * Use the **same key pair** as used for the Jenkins Master.
        

> Note: For simplicity and consistency, it’s best to use the same key pair for both instances. This enables both instances to be accessed with a single private key file (e.g., `<your-key>.pem`), which is useful for managing both servers in a DevOps environment.

### Step 2: Connect to Each EC2 Instance

SSH into both instances using:

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

### Step 3: Update Each EC2 Instance

Ensure both instances are up-to-date by running:

```bash
sudo apt update && sudo apt upgrade -y
```

### Step 4: Install Java on Both Instances

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

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

### Step 5: Install Jenkins (Only on Jenkins Master)

1. **Install dependencies**:
    
    ```bash
    sudo apt-get install -y ca-certificates curl gnupg
    ```
    
2. **Add the Jenkins repository key**:
    
    ```bash
    curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
    ```
    
3. **Add Jenkins to APT sources**:
    
    ```bash
    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
    ```
    
4. **Install Jenkins**:
    
    ```bash
    sudo apt-get update
    sudo apt-get install jenkins -y
    ```
    
5. **Enable Jenkins to start on boot**:
    
    ```bash
    sudo systemctl enable jenkins
    sudo systemctl start jenkins
    ```
    
6. **Verify Jenkins status**:
    
    ```bash
    sudo systemctl status jenkins
    ```
    

### Step 6: Install Docker on Both Instances

1. **Install Docker**:
    
    ```bash
    sudo apt install docker.io -y
    ```
    
2. **Add Jenkins to the Docker group** (on both instances):
    
    ```bash
    sudo usermod -aG docker $USER
    ```
    
3. **Refresh Docker group membership**:
    
    ```bash
    newgrp docker
    ```
    

### Step 7: Install Docker Compose on Both Instances

```bash
sudo apt install docker-compose-v2 -y
docker --version
docker-compose --version
```

### Step 8: Configure Jenkins Security Groups for Web Access

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`.
    

### Step 9: Retrieve Jenkins Admin Password

Retrieve the initial admin password:

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

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

---

### Step 10: 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 &gt; Manage Nodes and Clouds**.
    
3. Click **New Node**:
    
    * **Node name**: Enter a name for the Jenkins Agent (e.g., `dev-server`).
        
    * Choose **Permanent Agent** and click **OK**.
        
4. **Configure Node Settings**:
    
    * Make sure to create a directory named **bankapp** on the agent machine
        
    * **Remote root directory**: `/home/ubuntu/bankapp`
        
    * **Labels**: Add `dev-server`
        
    * **Usage**: Choose **Only build jobs with label expressions matching this node**.
        
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 associated with the key pair used for the Jenkins Agent EC2 instance.
            
    * Click **Save** and connect to the Jenkins Agent.
        

---

### Step 11: Set Up Docker Hub Credentials in Jenkins

1. Go to **Manage Jenkins &gt; Security &gt; Credentials &gt; System &gt; 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 12: Create a Shared Library Repository**

1. **Create a GitHub Repository**:
    
    * Go to [GitHub](https://github.com) and create a new repository.
        
    * Name it something like `Jenkins-shared-library`.
        
    * Add a description, 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:
        
        ```bash
        git clone https://github.com/Amitabh-DevOps/Jenkins-shared-library.git
        ```
        
    * Navigate into the directory:
        
        ```bash
        cd Jenkins-shared-library
        ```
        
3. **Set Up the Folder Structure**:
    
    * Create the `vars` directory to store your shared library functions:
        
        ```bash
        mkdir vars
        ```
        
    * The structure should look like this:
        
        ```plaintext
        Jenkins-shared-library/
        └── vars/
        ```
        

---

### **Step 13: Add** `.groovy` Scripts

Inside the `vars` directory, create the following `.groovy` files.

#### `clone.groovy`

Handles code cloning from a Git repository:

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

---

#### `dockerbuild.groovy`

Builds a Docker image:

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

---

#### `dockerpush.groovy`

Pushes a Docker image to Docker Hub:

```plaintext
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:

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

---

### **Step 14: Commit and Push Changes**

1. **Add and Commit the File**[**s**:](https://github.com)
    
    ```bash
    git add .
    git commit -m "Added shared library scripts for Jenkins pipeline."
    ```
    
2. **Push to GitHub**:
    
    ```bash
    git push origin main
    ```
    

---

### **Step 15: Configure the Shared Library in Jenkins**

1. **Access Jenkins**:
    
    * Go to **Manage Jenkins** &gt; **Configure System**[.](https://github.com)
        
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:
                
                ```plaintext
                https://github.com/Amitabh-DevOps/Jenkins-shared-library.git
                ```
                
            * Add credentials if required (e.g., GitHub token or SSH key[).](https://github.com)
                
3. **Save Configuration**:
    
    * Click **Save**.
        

---

### Step 16: Create the Jenkinsfile on GitHub

In the GitHub main Application repository, create a `Jenkinsfile` containing the pipeline script:

```yaml
@Library('Shared')_

pipeline{
    agent {label 'dev-server'}
    
    stages{
        stage("Code"){
            steps{
                clone("https://github.com/Amitabh-DevOps/banking-app-project.git","dev")
                echo "Code clonning done."
            }
        }
        stage("Build"){                                                             
            steps{
                dockerbuild("bankapp-mini","latest")
                echo "Code build bhi hogaya."
            }
        }
        stage("Push to DockerHub"){
            steps{
                dockerpush("dockerHub","bankapp-mini","latest")
                echo "Push to dockerHub is also done."
            }
        }
        stage("Deplying"){
            steps{
                deploy()
                echo "Deployment bhi done."
            }
        }
    }
}
```

This script pulls the code from GitHub, builds and pushes a Docker image to Docker Hub, and deploys it on the Jenkins Agent instance.

* This script includes multiple stages: cloning the code from GitHub, building the Docker image, pushing it to Docker Hub, and deploying the container.
    
* This script allows to used shared library repo which is stored on my github profile
    
* **<mark>used shared library repo</mark>** <mark>: </mark> [<mark>https://github.com/Amitabh-DevOps/Jenkins-shared-libraries</mark>](https://github.com/Amitabh-DevOps/Jenkins-shared-libraries)
    
* **Commit the Changes**:
    
    * Save and commit the `Jenkinsfile` to your GitHub repository.
        

---

### Step 17: Create a Jenkins Pipeline Job

1. **Create a New Job**:
    
    * From the Jenkins dashboard, click on **New Item**.
        
    * Enter a name (e.g., `Springboot bank CI/CD`), select **Pipeline**, and click **OK**.
        
2. **Configure GitHub Integration**:
    
    * In the **General** section, check the **GitHub project** option.
        
    * Provide the URL of your GitHub repository.
        
3. **Pipeline**:
    
    * Under **Pipeline**, select **Pipeline script from SCM**.
        
    * Set **SCM** to **Git** and provide the Git repository URL.
        
    * Choose the `dev` branch and set **Script Path** to `Jenkinsfile`.
        

---

### Step 18. Set Up Webhooks for Automatic Deployment

To trigger the Jenkins pipeline automatically on code changes, set up webhooks in your GitHub repository.

1. **Go to GitHub Repository Settings**:
    
    * Navigate to your GitHub repository, and click on **Settings**.
        
2. **Set Up Webhooks**:
    
    * In the left sidebar, click on **Webhooks** and then **Add webhook**.
        
    * Enter the **Payload URL**:
        
    
    ```http
    http://<your-ec2-public-ip>:8080/github-webhook/
    ```
    
    * Set **Content type** to default one and enable **Just the push event**.
        
    * Click on **Add webhook** and wait for it to show a green tick, indicating successful setup.
        
3. ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598430233/b52bede3-87d5-4fe8-8eda-f23cd695cc62.png align="center")
    

---

### Step 19. Build the Project in Jenkins

1. **Trigger the First Build**:
    
    * Go back to the Jenkins dashboard and click on the **Build Now** button for your pipeline job.
        
    * This action will initiate the pipeline and deploy your Spring boot application.
        
2. **Access the Application**:
    
    * To allow incoming traffic to your application, go to your **Jenkins Agent** EC2 security group and add an inbound rule for **port 8000**.
        
    * After the build completes successfully, visit your deployed Spring boot application at:
        
    
    ```http
    http://<your-ec2-public-ip>:8000     # Ip should be Jenkins agents not Jenkins master
    ```
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731599527361/9b66fdf5-4e14-484b-b7d6-f220e658b9fa.png align="center")

---

### Step 20. Automatic Deployment

From this point on, any changes you make and push to the GitHub repository will automatically trigger Jenkins to run the pipeline, rebuild the Docker image, and redeploy the application. This completes the CI/CD setup for your Springboot bank Application.

---

## Conclusion

By following these steps, you 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 by ensuring that every code change is automatically tested and deployed.

# <mark>Output Images of Project ( Which I have done while practicing CI/CD for this Project which ensure that it works properly)</mark>

1. making changes on github to see it works properly or not :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598408986/c42e266a-c8b4-43aa-bc99-aad753cb02fd.png align="center")
    
2. Checking if it triggers build on jenkins or not :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598487272/8a4c9bf6-d06b-4f36-8e70-3bbc9d7763b4.png align="center")
    
3. Building the stages on Jenkins :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598528763/943cdc17-1cb2-4e4c-9895-4a8cf26b4912.png align="center")
    
4. It successfully builds the all stages :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598570562/418a750f-6955-4a1b-85a2-0f458bcef855.png align="center")
    
5. Checking the features of Application whether it is working or not :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598799762/98db5190-8ad3-432a-abcb-07ec9345ddc4.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598809507/884bd385-9d5d-428e-a5d0-2395590bb29f.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598817870/e465d608-3e2e-4ab9-ad8e-aa9704b03c39.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598824900/9bd926b1-dd34-47ff-b849-f80c7a944b4f.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598829825/95a758ee-cd62-40c2-9900-86e1f09f52e9.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598834963/b4a343ef-68d7-42a1-b8a4-cb4a409fc7a8.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598840736/6662080d-16ac-4647-878e-e42383bd6c08.png align="center")
    
6. Adding some of a images that show lot of error to complete this project :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598888484/46ed9ccf-65fb-4737-be5a-8e059620db6f.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598895311/19bf503a-9328-4071-aafe-b9d00abfc822.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598944273/23252f7c-3de1-40b7-8b1d-4f25e6ddd70c.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598951041/94a35a4f-4946-4e69-9fcd-f3dd0e0260d1.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1731598958620/13f08b05-28cc-4aad-b63c-a514c83d4343.png align="center")
