diff --git a/Dockerfile b/Dockerfile index 079acabe..a2ceb988 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,37 +1,31 @@ #---------------------------------- -# Stage 1 +# Stage 1 - Build Environment #---------------------------------- -# Import docker image with maven installed -FROM maven:3.8.3-openjdk-17 as builder +# Use Maven with OpenJDK 17 to compile the application +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 +# Set the working directory in the container +WORKDIR /app -# Add labels to the image to filter out if we have multiple application running -LABEL app=bankapp +# Copy all project files to the working directory +COPY . /app -# Set working directory -WORKDIR /src - -# Copy source code from local to container -COPY . /src - -# Build application and skip test cases +# Build the project and skip tests for a faster build process RUN mvn clean install -DskipTests=true #-------------------------------------- -# Stage 2 +# Stage 2 - Production Environment #-------------------------------------- -# Import small size java image -FROM openjdk:17-alpine as deployer +# Use a lightweight OpenJDK 17 image to run the application +FROM openjdk:17-jdk-alpine -# Copy build from stage 1 (builder) -COPY --from=builder /src/target/*.jar /src/target/bankapp.jar +# Copy the application JAR from the builder stage to the target location +COPY --from=builder /app/target/*.jar /app/target/bankapp.jar -# Expose application port -EXPOSE 8080 +# Expose the application port (updated to 8000) +EXPOSE 8000 -# Start the application -ENTRYPOINT ["java", "-jar", "/src/target/bankapp.jar"] +# Define the command to run the application +ENTRYPOINT ["java", "-jar", "/app/target/bankapp.jar"] \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..2d7d7897 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,32 @@ +@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." + } + } + } +} diff --git a/README.md b/README.md index 3ddfdaac..d8bd99ce 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,370 @@ -## 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 +In this Project, 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**: Used this Repo + Shared library repo : https://github.com/Amitabh-DevOps/Jenkins-shared-libraries + +**Check Blog** : https://amitabhdevops.hashnode.dev/spring-boot-bank-jenkins + +> 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., `.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 -sudo apt update -sudo apt install docker-compose-v2 -y +ssh -i .pem ubuntu@ ``` -# -- Run docker-compose file present in the root directory of a project + +### Step 3: Update Each EC2 Instance + +Ensure both instances are up-to-date by running: + ```bash -docker compose up -d +sudo apt update && sudo apt upgrade -y ``` -# -- Access it on port 8080 + +### 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 - http://:8080 +sudo apt install docker-compose-v2 -y +docker --version +docker-compose --version ``` -> [!Important] -> If you face issues with exiting docker container while running docker compose, run ``` docker compose down``` and then ``` docker compose up -d ```. -# + +### 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://: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. + +--- + +## 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., `dev-server`). + + * Choose **Permanent Agent** and click **OK**. + +4. **Configure Node Settings**: + + * **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 private 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 10: 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 11: 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 12: Create the Jenkinsfile on GitHub + +In the GitHub 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 + +* **used shared library repo** : [https://github.com/Amitabh-DevOps/Jenkins-shared-libraries](https://github.com/Amitabh-DevOps/Jenkins-shared-libraries) + +* **Commit the Changes**: + + * Save and commit the `Jenkinsfile` to your GitHub repository. + + +--- + +### Step 13. 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://: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. + + + +--- + +### Step 14. 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 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://:8000 + ``` + + +--- + +### Step 15. 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. diff --git a/docker-compose.yml b/docker-compose.yml index f3977b3c..f751f013 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,43 +1,52 @@ version: "3.8" + services: mysql: image: mysql:latest container_name: mysql environment: - - MYSQL_ROOT_PASSWORD=Test@123 - - MYSQL_DATABASE=BankDB + MYSQL_ROOT_PASSWORD: Test@123 + MYSQL_DATABASE: BankDB volumes: - - ./mysql-data:/var/lib/mysql + - mysql-bankapp:/var/lib/mysql networks: - bankapp + restart: always healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pTest@123"] interval: 10s timeout: 5s retries: 3 - start_period: 30s - mainapp: - build: . - container_name: Bankapp + bankapp: + image: bankapp-mini + container_name: bankapp-mini environment: - - SPRING_DATASOURCE_USERNAME=root - - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - - SPRING_DATASOURCE_PASSWORD=Test@123 + SPRING_DATASOURCE_USERNAME: root + SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + SPRING_DATASOURCE_PASSWORD: Test@123 ports: - - "8080:8080" + - "8000:8000" depends_on: - mysql: - condition: service_healthy + - mysql networks: - bankapp restart: always - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s + + nginx: + image: nginx:1.23.3-alpine + container_name: nginx + ports: + - "8080:80" + volumes: + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf + depends_on: + - bankapp + networks: + - bankapp + +volumes: + mysql-bankapp: networks: bankapp: diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 00000000..6f333588 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:1.23.3-alpine + +COPY ./default.conf /etc/nginx/conf.d/default.conf diff --git a/nginx/default.conf b/nginx/default.conf new file mode 100644 index 00000000..781ad3a8 --- /dev/null +++ b/nginx/default.conf @@ -0,0 +1,17 @@ +upstream bankapp { + server bankapp:8000; # Use the correct service name from docker-compose.yml +} + +server { + listen 80; + + server_name localhost; + + location / { + proxy_pass http://bankapp:8000; # Use the service name 'bankapp' here as well + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 08663a63..e3f21bec 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,5 @@ spring.application.name=bankapp + # MySQL Database configuration spring.datasource.url=jdbc:mysql://localhost:3306/bankappdb?useSSL=false&serverTimezone=UTC spring.datasource.username=root @@ -9,3 +10,6 @@ spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect spring.jpa.show-sql=true + +# Set server port to 8000 +server.port=8000