diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..ae480cc6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +target/ +.git/ +.idea/ +*.iml +*.log +.env +.DS_Store \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 079acabe..9002d618 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,19 +3,14 @@ #---------------------------------- # Import docker image with maven installed -FROM maven:3.8.3-openjdk-17 as builder +FROM maven:3.8.3-openjdk-17 AS builder -# Add maintainer, so that new user will understand who had written this Dockerfile -MAINTAINER Madhup Pandey - -# Add labels to the image to filter out if we have multiple application running -LABEL app=bankapp # Set working directory -WORKDIR /src +WORKDIR /app # Copy source code from local to container -COPY . /src +COPY . /app # Build application and skip test cases RUN mvn clean install -DskipTests=true @@ -25,13 +20,13 @@ RUN mvn clean install -DskipTests=true #-------------------------------------- # Import small size java image -FROM openjdk:17-alpine as deployer +FROM openjdk:17-alpine AS deployer # Copy build from stage 1 (builder) -COPY --from=builder /src/target/*.jar /src/target/bankapp.jar +COPY --from=builder /app/target/*.jar /app/target/bankapp.jar # Expose application port EXPOSE 8080 # Start the application -ENTRYPOINT ["java", "-jar", "/src/target/bankapp.jar"] +ENTRYPOINT ["java", "-jar", "/app/target/bankapp.jar"] diff --git a/Jenkinsfile b/Jenkinsfile index aea12103..8ff2b15b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,30 +1,79 @@ -@Library("shared-library@DevOps") _ - +/* groovylint-disable-next-line CompileStatic */ pipeline { - agent {label 'runner_1'} - + agent { label 'agent-slave' } + environment { + VERSION = "${BUILD_NUMBER}" + } stages { - stage('Checkout code') { + stage('Code Clone') { steps { - codeCheckout('DevOps', 'https://github.com/joakim077/Springboot-BankApp.git') + echo 'Code Clone Stage' + git url: 'https://github.com/nkantamani2023/Springboot-BankApp.git', branch: 'DevOps' + timeout(time: 5, unit: 'MINUTES') + { + /* groovylint-disable-next-line DuplicateStringLiteral */ + git url: params.REPO_URL ?: 'https://github.com/nkantamani2023/Springboot-BankApp.git', + /* groovylint-disable-next-line DuplicateStringLiteral */ + branch: params.BRANCH ?: 'DevOps', + shallow: true + } } } - stage('build') { + stage('Code Build & Test') { steps { - buildImage("springboot-application") + echo 'Code Build Stage' + sh './mvnw clean test' + sh 'docker build -t bankapp .' } } - stage('Push Image') { + stage('Push To DockerHub') { steps { - pushImage("springboot-application") + withCredentials([usernamePassword( + credentialsId:'dockerhub-creds', + usernameVariable:'dockerHubUser', + passwordVariable:'dockerHubPass')]) { + sh 'echo $dockerHubPass | docker login -u $dockerHubUser --password-stdin' + sh "docker image tag bankapp:latest ${env.dockerHubUser}/bankapp:${VERSION}" + sh "docker push ${env.dockerHubUser}/bankapp:${VERSION}" + } } } - stage('Deploy'){ - steps{ - deploy() + stage('Deploy') { + environment { + COMPOSE_PROJECT_NAME = "${JOB_NAME}-${VERSION}" + MAX_RETRIES = 30 + RETRY_INTERVAL = 10 } + steps { + script { + // Graceful deployment with zero downtime + sh """ + docker compose -p ${COMPOSE_PROJECT_NAME} up -d --build + # Wait for service to be ready + for i in \$(seq 1 \$MAX_RETRIES); do + if curl -sf http://localhost:8080/actuator/health | grep -q '"status":"UP"'; then + echo "Service is healthy" + docker compose -p ${JOB_NAME}-previous down || true + exit 0 + fi + echo "Attempt \$i: Service not ready yet..." + sleep \$RETRY_INTERVAL + done + echo "Service failed to become healthy - rolling back" + docker compose -p ${COMPOSE_PROJECT_NAME} down + # Redeploy the previous version + docker compose -p ${JOB_NAME}-previous up -d + exit 1 + """ + } + } + } + } + post { + failure { + echo 'Deployment failed - initiating rollback' + sh "docker compose -p ${JOB_NAME}-previous up -d" } - } } diff --git a/README.md b/README.md index b21647fd..7aa90d50 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,157 @@ -## End-to-End Bank Application Deployment using DevSecOps on AWS EKS -- This is a multi-tier bank an application written in Java (Springboot). - -![Login diagram](images/login.png) -![Transactions diagram](images/transactions.png) - -### PRE-REQUISITES FOR THIS PROJECT: -- AWS Account -- AWS Ubuntu EC2 instance (t2.medium) -- Install Docker -- Install docker compose -# -### DEPLOYMENT: -| Deployments | Paths | -| -------- | ------- | -| Deployment using Docker and Networking | Click me | -| Deployment using Docker Compose | Click me | -| Deployment using Jenkins on EKS | Click me | -| Deployment using Argocd on EKS| Click me | - -# -### STEPS TO IMPLEMENT THE PROJECT -- **

Deployment using Docker

** - - Clone the repository - ```bash - git clone -b DevOps https://github.com/DevMadhup/Springboot-BankApp.git - ``` - # - - Install docker, docker compose and provide neccessary permission - ```bash - sudo apt update -y - - sudo apt install docker.io docker-compose-v2 -y - - sudo usermod -aG docker $USER && newgrp docker - ``` - # - - Move to the cloned repository - ```bash - cd Springboot-BankApp - ``` - # - - Build the Dockerfile - ```bash - docker build -t madhupdevops/springboot-bankapp . - ``` -> [!Important] -> Make sure to change docker build command with your DockerHub username. - # - - Create a docker network - ```bash - docker network create bankapp - ``` - # - - Run MYSQL container - ```bash - docker run -itd --name mysql -e MYSQL_ROOT_PASSWORD=Test@123 -e MYSQL_DATABASE=BankDB --network=bankapp mysql - ``` - # - - Run Application container - ```bash - docker run -itd --name BankApp -e SPRING_DATASOURCE_USERNAME="root" -e SPRING_DATASOURCE_URL="jdbc:mysql://mysql:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC" -e SPRING_DATASOURCE_PASSWORD="Test@123" --network=bankapp -p 8080:8080 madhupdevops/springboot-bankapp - ``` - # - - Verify deployment - ```bash - docker ps - ``` - # - - Open port 8080 of your AWS instance and access your application - ```bash - http://:8080 - ``` - ### Congratulations, you have deployed the application using Docker - # -- **

Deployment using Docker compose

** -- Install docker compose +# 🚀 Multi-Tier Bank Application Deployment +This repository contains an **End-to-End Multi-Tier Bank Application** built using **Java (Spring Boot)**. The application is containerized, enabling seamless deployment on AWS EC2 instances using tools like **Docker**, **Docker Compose**, **Jenkins**, and more. + +--- + +## 📌 Project Highlights + +- **Technology Stack**: Java, Spring Boot, MySQL, Docker, Jenkins, AWS +- **Deployment Options**: + - Docker Networking + - Docker Compose + - Jenkins-based CI/CD + +![App Architecture Diagram](images/login.png) +![Transaction Flow Diagram](images/transactions.png) + +--- + +## 🛠 Pre-requisites + +Ensure you have the following: +- **AWS Account** +- **Ubuntu EC2 Instance** (Recommended: `t2.medium`) +- **Installed Tools**: + - Docker +## 🏗 Deployment Steps + +### **

Deployment Using EC2 Instance

** + +#### SSH into Your EC2 instance + ```bash -sudo apt update -sudo apt install docker-compose-v2 -y +ssh -i "your pem- key" ubuntu@ec2-44-244-168-242.us-west ``` -# -- Run docker-compose file present in the root directory of a project + +Create a new Directory: ```bash -docker compose up -d +mkdir dir_name ``` -# -- Access it on port 8080 +Go into `cd dir_name` + +#### Clone the Repository +```bash +git clone -b DevOps https://github.com/nkantamani2023/Springboot-BankApp.git +``` ```bash - http://:8080 +cd Springboot-BankApp ``` -> [!Important] -> If you face issues with exiting docker container while running docker compose, run ``` docker compose down``` and then ``` docker compose up -d ```. +Install Docker +```bash +sudo apt update -y +``` +```bash +sudo apt install docker.io && docker-compose-v2 -y +``` +```bash +sudo usermod -aG docker $USER && newgrp docker +``` + +Build the Docker Image +```bash +docker build -t bankapp . +``` +Create Docker Network +```bash +docker network create bankapp +``` +Run MySQL Container +```bash +docker run -itd --name mysql \ +-e MYSQL_ROOT_PASSWORD=${DB_PASSWORD} \ +-e MYSQL_DATABASE=${DB_NAME} \ + --network=bankapp mysql + ``` +Run Application Container +```bash +docker run -itd --name BankApp \ + -e SPRING_DATASOURCE_USERNAME=${DB_USER} \ + -e SPRING_DATASOURCE_URL="jdbc:mysql://mysql:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC" \ + -e SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD} \ + --network=bankapp \ + --health-cmd="curl -f http://localhost:8080/actuator/health || exit 1" \ + --health-interval=30s \ + --restart=unless-stopped \ + --memory="512m" \ + --memory-swap="1g" \ + -p 8080:8080 bankapp + ``` +Access the Application +Open Port 8080 of your AWS EC2 instance. +Navigate to: http://:8080 +🎉 Congratulations! Your application is live. + +🌐 Future Enhancements +CI/CD pipeline with Jenkins (Guide). + + ![App pipeline flow Diagram](images/jenkins-pipeline.png) + Step 1: Go to the AWS EC2 instance and copy your master-node public ip address and paste it in the browser address-bar with port `8080` . + + Step 2: Go to AWS your master-node instaces and select security groups and go to add rule `8080` save this. +![Jenkins Output](images/jenkins-pipeline-op.png) +Step 3: Configure your pipeline. + +```groovy +pipeline{ + agent { label 'agent-slave' } + + stages{ + stage("Code Clone"){ + steps{ + echo "Code Clone Stage" + git url: "https://github.com/nkantamani2023/Springboot-BankApp.git", branch: "DevOps" + } + } + stage("Code Build & Test"){ + steps{ + echo "Code Build Stage" + sh "docker system prune -f" + sh "docker build -t bankapp ." + } + } + stage("Push To DockerHub"){ + steps{ + withCredentials([usernamePassword( + credentialsId:"dockerhub-creds", + usernameVariable:"dockerHubUser", + passwordVariable:"dockerHubPass")]){ + sh 'echo $dockerHubPass | docker login -u $dockerHubUser --password-stdin' + sh "docker image tag bankapp:latest ${env.dockerHubUser}/bankapp:latest" + sh "docker push ${env.dockerHubUser}/bankapp:latest" + } + } + } + stage("Deploy"){ + steps{ + script { + try { + sh "docker compose -f docker-compose.yml down" + sh "docker compose -f docker-compose.yml up -d --build" + sh "timeout 300 bash -c 'while ! curl -s http://localhost:8080/actuator/health; do sleep 5; done'" + } catch (Exception e) { + sh "docker compose -f docker-compose.yml down" + sh "docker compose -f docker-compose.yml up -d --build --force-recreate previous-version" + error "Deployment failed: ${e.message}" + } + } + } + } + } +} +``` + +Step 4: Navigate to bank app dashboard and click on `Build Now` button. +Step 5: Your Pipeline has been created -#### CICD pipeline [guide](cicd.md) +👨‍💻 Author: Kantamani diff --git a/images/jenkins-pipeline-op.png b/images/jenkins-pipeline-op.png new file mode 100644 index 00000000..6cd62291 Binary files /dev/null and b/images/jenkins-pipeline-op.png differ diff --git a/images/jenkins-pipeline.png b/images/jenkins-pipeline.png new file mode 100644 index 00000000..5d759b92 Binary files /dev/null and b/images/jenkins-pipeline.png differ