diff --git a/.env b/.env new file mode 100644 index 00000000..2713429f --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +DUSER=joakim077 +IMAGE=springboot-application diff --git a/GitOps/Jenkinsfile b/GitOps/Jenkinsfile index 3760609d..7828a675 100644 --- a/GitOps/Jenkinsfile +++ b/GitOps/Jenkinsfile @@ -18,7 +18,7 @@ pipeline { stage('Git: Code Checkout') { steps { script{ - code_checkout("https://github.com/DevMadhup/Springboot-BankApp.git","DevOps") + code_checkout("https://github.com/LondheShubham153/Springboot-BankApp.git","DevOps") } } } @@ -35,9 +35,9 @@ pipeline { stage("Update: Kubernetes manifest"){ steps{ script{ - dir('k8s'){ + dir('kubernetes'){ sh """ - sed -i -e s/springboot-bankapp.*/springboot-bankapp:${params.BACKEND_DOCKER_TAG}/g deployment.yml + sed -i -e 's|trainwithshubham/bankapp-eks:.*|trainwithshubham/bankapp-eks:${params.DOCKER_TAG}|g' bankapp-deployment.yaml """ } } @@ -59,7 +59,7 @@ pipeline { git commit -m "Updated K8s Deployment Docker Image Version" echo "Pushing changes to github: " - git push https://github.com/DevMadhup/Springboot-BankApp.git DevOps + git push https://github.com/LondheShubham153/Springboot-BankApp.git DevOps ''' } } @@ -70,7 +70,7 @@ pipeline { always { script { emailext attachLog: true, - from: '8007930568pandey@gmail.com', + from: 'trainwithshubham@gmail.com', subject: "BankApp Application has been updated and deployed - '${currentBuild.result}'", body: """ @@ -87,9 +87,9 @@ pipeline { """, - to: '8007930568pandey@gmail.com', + to: 'trainwithshubham@gmail.com', mimeType: 'text/html' } } } -} \ No newline at end of file +} diff --git a/Ingress.md b/Ingress.md new file mode 100644 index 00000000..87bfa2f9 --- /dev/null +++ b/Ingress.md @@ -0,0 +1,34 @@ +# Nginx Ingress Controller + +1) Apply the Required RBAC (Role-Based Access Control) and Service Account + + - Create a service account for the NGINX Ingress Controller and assign it the necessary permissions. + ```bash + kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml + ``` +This will create all the necessary resources for the NGINX Ingress Controller, including: +- Service accounts +- ClusterRoles and ClusterRoleBindings +- Deployments +- Services +- ConfigMaps +- Ingress Class +--- + +2) Verify Ingress Controller Installation + - After applying the YAML file, verify that the NGINX Ingress Controller is installed and running. + ```bash + kubectl get pods -n ingress-nginx + ``` +This should show the ingress-nginx-controller pods running. + +--- + +3) Expose the NGINX Ingress Controller (Optional) + - If you want to access the Ingress controller externally (e.g., via LoadBalancer), the ingress-nginx-controller service should be of type LoadBalancer. + +To modify the service type, you can run: +```bash +kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec": {"type": "LoadBalancer"}}' +``` +This will expose the NGINX Ingress Controller via a LoadBalancer, allowing you to access your applications from outside the cluster. diff --git a/Jenkinsfile b/Jenkinsfile index 3ddaedc9..96e1e341 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -23,7 +23,7 @@ pipeline { stage('Git: Code Checkout') { steps { script{ - code_checkout("https://github.com/DevMadhup/Springboot-BankApp.git","DevOps") + code_checkout("https://github.com/LondheShubham153/Springboot-BankApp.git","DevOps") } } } @@ -47,7 +47,7 @@ pipeline { stage("SonarQube: Code Analysis"){ steps{ script{ - sonarqube_analysis("Sonar","BankApp","BankApp") + sonarqube_analysis("Sonar","bankapp","bankapp") } } } @@ -59,11 +59,11 @@ pipeline { } } } - + stage("Docker: Build Images"){ steps{ script{ - docker_build("BankApp","${params.DOCKER_TAG}","madhupdevops") + docker_build("bankapp","${params.DOCKER_TAG}","madhupdevops") } } } @@ -71,7 +71,7 @@ pipeline { stage("Docker: Push to DockerHub"){ steps{ script{ - docker_push("BankApp","${params.DOCKER_TAG}","madhupdevops") + docker_push("bankapp","${params.DOCKER_TAG}","madhupdevops") } } } diff --git a/README-K8S.md b/README-K8S.md new file mode 100644 index 00000000..7554262f --- /dev/null +++ b/README-K8S.md @@ -0,0 +1,441 @@ +# Bank Application - Deployment on Kubernetes + +## Tech stack used in this project: +- GitHub (Code) +- Docker (Containerization) +- Jenkins (CI) +- OWASP (Dependency check) +- SonarQube (Quality) +- Trivy (Filesystem Scan) +- ArgoCD (CD) +- AWS EKS (Kubernetes) +- Helm (Monitoring using grafana and prometheus) + +### Steps to deploy: + +### Pre-requisites: +- root user access +```bash +sudo su +``` +# +> [!Note] +> This project will be implemented on North California region (us-west-1). + +- Create 1 Master machine on AWS (t2.medium) and 29 GB of storage. +# +- Open the below ports in security group +![image](https://github.com/user-attachments/assets/4e5ecd37-fe2e-4e4b-a6ba-14c7b62715a3) + +- Create EKS Cluster on AWS +- IAM user with **access keys and secret access keys** +- AWSCLI should be configured (Setup AWSCLI) + ```bash + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + sudo apt install unzip + unzip awscliv2.zip + sudo ./aws/install + aws configure + ``` + +- Install **kubectl**(Setup kubectl ) + ```bash + curl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.19.6/2021-01-05/bin/linux/amd64/kubectl + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin + kubectl version --short --client + ``` + +- Install **eksctl**(Setup eksctl) + ```bash + curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp + sudo mv /tmp/eksctl /usr/local/bin + eksctl version + ``` + +- Create EKS Cluster + ```bash + eksctl create cluster --name=bankapp \ + --region=us-west-1 \ + --version=1.30 \ + --without-nodegroup + ``` +- Associate IAM OIDC Provider + ```bash + eksctl utils associate-iam-oidc-provider \ + --region us-west-1 \ + --cluster bankapp \ + --approve + ``` +- Create Nodegroup + ```bash + eksctl create nodegroup --cluster=bankapp \ + --region=us-west-1 \ + --name=bankapp \ + --node-type=t2.medium \ + --nodes=2 \ + --nodes-min=2 \ + --nodes-max=2 \ + --node-volume-size=29 \ + --ssh-access \ + --ssh-public-key=eks-nodegroup-key + ``` +> [!Note] +> Make sure the ssh-public-key "eks-nodegroup-key is available in your aws account" +- Install Jenkins +```bash +sudo apt update -y +sudo apt install fontconfig openjdk-17-jre -y + +sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \ + https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key + +echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \ + https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ + /etc/apt/sources.list.d/jenkins.list > /dev/null + +sudo apt-get update -y +sudo apt-get install jenkins -y +``` + +- After installing Jenkins, change the default port of jenkins from 8080 to 8081. Because our bankapp application will be running on 8080. + - Open /usr/lib/systemd/system/jenkins.service file and change JENKINS_PORT environment variable +![image](https://github.com/user-attachments/assets/6320ae49-82d4-4ae3-9811-bd6f06778483) + - Reload daemon + ```bash + sudo systemctl daemon-reload + ``` + - Restart Jenkins + ```bash + sudo systemctl restart jenkins + ``` +# + +- Install docker + +```bash +sudo apt install docker.io -y +sudo usermod -aG docker ubuntu && newgrp docker +``` +# +- Install and configure SonarQube +```bash +docker run -itd --name SonarQube-Server -p 9000:9000 sonarqube:lts-community +``` +# +- Install Trivy +```bash +sudo apt-get install wget apt-transport-https gnupg lsb-release -y +wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - +echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list +sudo apt-get update -y +sudo apt-get install trivy -y +``` +# +- Install and Configure ArgoCD + - Create argocd namespace + ```bash + kubectl create namespace argocd + ``` + - Apply argocd manifest + ```bash + kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml + ``` + - Make sure all pods are running in argocd namespace + ```bash + watch kubectl get pods -n argocd + ``` + - Install argocd CLI + ```bash + curl --silent --location -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.4.7/argocd-linux-amd64 + ``` + - Provide executable permission + ```bash + chmod +x /usr/local/bin/argocd + ``` + - Check argocd services + ```bash + kubectl get svc -n argocd + ``` + - Change argocd server's service from ClusterIP to NodePort + ```bash + kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}' + ``` + - Confirm service is patched or not + ```bash + kubectl get svc -n argocd + ``` + - Check the port where ArgoCD server is running and expose it on security groups of a k8s worker node + ![image](https://github.com/user-attachments/assets/a2932e03-ebc7-42a6-9132-82638152197f) + - Access it on browser, click on advance and proceed with + ```bash + : + ``` + ![image](https://github.com/user-attachments/assets/29d9cdbd-5b7c-44b3-bb9b-1d091d042ce3) + ![image](https://github.com/user-attachments/assets/08f4e047-e21c-4241-ba68-f9b719a4a39a) + ![image](https://github.com/user-attachments/assets/1ffa85c3-9055-49b4-aab0-0947b95f0dd2) + - Fetch the initial password of argocd server + ```bash + kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo + ``` + - Username: admin + - Now, go to User Info and update your argocd password +# +## Steps to add email notification +- Go to your Jenkins Master EC2 instance and allow 465 port number for SMTPS +# +- Now, we need to generate an application password from our gmail account to authenticate with jenkins + - Open gmail and go to Manage your Google Account --> Security +> [!Important] +> Make sure 2 step verification must be on + + ![image](https://github.com/user-attachments/assets/5ab9dc9d-dcce-4f9d-9908-01095f1253cb) + + - Search for App password and create a app password for jenkins + ![image](https://github.com/user-attachments/assets/701752da-7703-4685-8f06-fe1f65dd1b9c) + ![image](https://github.com/user-attachments/assets/adc8d8c0-8be4-4319-9042-4115abb5c6fc) + +# +- Once, app password is create and go back to jenkins Manage Jenkins --> Credentials to add username and password for email notification +![image](https://github.com/user-attachments/assets/2a42ec62-87c8-43c8-a034-7be0beb8824e) + +# +- Go back to Manage Jenkins --> System and search for Extended E-mail Notification +![image](https://github.com/user-attachments/assets/bac81e24-bb07-4659-a251-955966feded8) +# +- Scroll down and search for E-mail Notification and setup email notification +> [!Important] +> Enter your gmail password which we copied recently in password field E-mail Notification --> Advance + +![image](https://github.com/user-attachments/assets/14e254fc-1400-457e-b3f4-046404b66950) +![image](https://github.com/user-attachments/assets/7be70b3a-b0dc-415c-838a-b1c6fd87c182) +![image](https://github.com/user-attachments/assets/cffb6e1d-4838-483e-97e0-6851c204ab21) + +# +- Go to Jenkins and click on Manage Jenkins --> Plugins --> Available plugins install the below plugins: + - OWASP + - SonarQube Scanner + - Docker + - Pipeline: Stage View +# +- Configure OWASP, move to Manage Jenkins --> Plugins --> Available pluginsb> +![image](https://github.com/user-attachments/assets/da6a26d3-f742-4ea8-86b7-107b1650a7c2) + +- After OWASP plugin is installed, Now move to Manage jenkins --> Tools +![image](https://github.com/user-attachments/assets/3b8c3f20-202e-4864-b3b6-b48d7a604ee8) +# +- Login to SonarQube server and create the credentials for jenkins to integrate with SonarQube + - Navigate to Administration --> Security --> Users --> Token + ![image](https://github.com/user-attachments/assets/86ad8284-5da6-4048-91fe-ac20c8e4514a) + ![image](https://github.com/user-attachments/assets/6bc671a5-c122-45c0-b1f0-f29999bbf751) + ![image](https://github.com/user-attachments/assets/e748643a-e037-4d4c-a9be-944995979c60) + +# +- Now, go to Manage Jenkins --> credentials and add Sonarqube credentials: +![image](https://github.com/user-attachments/assets/0688e105-2170-4c3f-87a3-128c1a05a0b8) +# +- Go to Manage Jenkins --> Tools and search for SonarQube Scanner installations: +![image](https://github.com/user-attachments/assets/2fdc1e56-f78c-43d2-914a-104ec2c8ea86) +# +- Go to Manage Jenkins --> credentials and add Docker credentials to push updated the updated docker image to dockerhub. +![image](https://github.com/user-attachments/assets/77402c9c-fc2f-4df7-9a06-09f3f4c38751) + +# +- Again, add Github credentials to push updated code from the pipeline: +![image](https://github.com/user-attachments/assets/4d0c1a47-621e-4aa2-a0b1-71927fcdaef4) +> [!Note] +> While adding github credentials add Personal Access Token in the password field. +# +- Go to Manage Jenkins --> System and search for SonarQube installations: +![image](https://github.com/user-attachments/assets/ae866185-cb2b-4e83-825b-a125ec97243a) +# +- Now again, Go to Manage Jenkins --> System and search for Global Trusted Pipeline Libraries:Login to SonarQube server, go to Administration --> Webhook and click on create +![image](https://github.com/user-attachments/assets/16527e72-6691-4fdf-a8d2-83dd27a085cb) +![image](https://github.com/user-attachments/assets/a8b45948-766a-49a4-b779-91ac3ce0443c) +# + +# +- Go to Master Machine and add our own eks cluster to argocd for application deployment using cli + - Login to argoCD from CLI + ```bash + argocd login 52.53.156.187:32738 --username admin + ``` +> [!Tip] +> 52.53.156.187:32738 --> This should be your argocd url + + ![image](https://github.com/user-attachments/assets/7d05e5ca-1a16-4054-a321-b99270ca0bf9) + + - Check how many clusters are available in argocd + ```bash + argocd cluster list + ``` + ![image](https://github.com/user-attachments/assets/76fe7a45-e05c-422d-9652-bdaee02d630f) + - Get your cluster name + ```bash + kubectl config get-contexts + ``` + ![image](https://github.com/user-attachments/assets/c9afca1f-b5a3-4685-ae24-cc206a3e3ef1) + + - Add your cluster to argocd + ```bash + argocd cluster add Madhup@bankapp.us-west-1.eksctl.io --name bankapp-eks-cluster + ``` + > [!Tip] + > Madhup@bankapp.us-west-1.eksctl.io --> This should be your EKS Cluster Name. + + ![image](https://github.com/user-attachments/assets/1061fe66-17ec-47b7-9d2e-371f58d3fd90) + + - Once your cluster is added to argocd, go to argocd console Settings --> Clusters and verify it + ![image](https://github.com/user-attachments/assets/6aebb871-4dea-4e09-955a-a4aa43b8f4ef) + + +# +- Go to Settings --> Repositories and click on Connect repo +![image](https://github.com/user-attachments/assets/cc8728e5-546b-4c46-bd4c-538f4cd6a63d) +![image](https://github.com/user-attachments/assets/e665203d-0ebe-4839-af9e-f5866dce5e1b) +![image](https://github.com/user-attachments/assets/b9b869c3-698b-4303-83cc-9ccec66542a3) + +> [!Note] +> Connection should be successful + +- Create BankApp-CI job +![image](https://github.com/user-attachments/assets/17467b79-3110-470a-87a2-2bbfe197551b) +![image](https://github.com/user-attachments/assets/51d79ab0-e1f4-4c4d-a778-0c28119f5da9) + +- Create BankApp-CD job, same as CI job. +# +- Provide permission to docker socket so that docker build and push command do not fail +```bash +chmod 777 /var/run/docker.sock +``` +![image](https://github.com/user-attachments/assets/e231c62a-7adb-4335-b67e-480758713dbf) + +- Now, go to Applications and click on New App + +![image](https://github.com/user-attachments/assets/d5b08e06-6256-4f46-afdc-fc43a9e44562) + +> [!Important] +> Make sure to click on the Auto-Create Namespace option while creating argocd application + +![image](https://github.com/user-attachments/assets/6a828910-41ba-4f0c-af05-19297321a41b) +![image](https://github.com/user-attachments/assets/a3aa1d22-50ef-4eb1-97fe-9c3ffb504fc3) + +- Congratulations, your application is deployed on AWS EKS Cluster +![image](https://github.com/user-attachments/assets/03f3b69a-d6e0-42ad-992e-11124e7d0898) + +- Open port 30080 on worker node and Access it on browser +```bash +:30080 +``` +- Email Notification +![image](https://github.com/user-attachments/assets/407f94ed-bf67-441a-bd28-881b6b8739b2) + +# +## How to monitor EKS cluster, kubernetes components and workloads using prometheus and grafana via HELM (On Master machine) +-

Install Helm Chart

+```bash +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 +``` +```bash +chmod 700 get_helm.sh +``` +```bash +./get_helm.sh +``` + +# +- Add Helm Stable Charts for Your Local Client +```bash +helm repo add stable https://charts.helm.sh/stable +``` + +# +- Add Prometheus Helm Repository +```bash +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +``` + +# +- Create Prometheus Namespace +```bash +kubectl create namespace prometheus +``` +```bash +kubectl get ns +``` + +# +- Install Prometheus using Helm +```bash +helm install stable prometheus-community/kube-prometheus-stack -n prometheus +``` + +# +- Verify prometheus installation +```bash +kubectl get pods -n prometheus +``` + +# +- Check the services file (svc) of the Prometheus +```bash +kubectl get svc -n prometheus +``` + +# +- Expose Prometheus and Grafana to the external world through Node Port +> [!Important] +> change it from Cluster IP to NodePort after changing make sure you save the file and open the assigned nodeport to the service. + +```bash +kubectl edit svc stable-kube-prometheus-sta-prometheus -n prometheus +``` +![image](https://github.com/user-attachments/assets/90f5dc11-23de-457d-bbcb-944da350152e) +![image](https://github.com/user-attachments/assets/ed94f40f-c1f9-4f50-a340-a68594856cc7) + +# +- Verify service +```bash +kubectl get svc -n prometheus +``` + +# +- Now,let’s change the SVC file of the Grafana and expose it to the outer world +```bash +kubectl edit svc stable-grafana -n prometheus +``` +![image](https://github.com/user-attachments/assets/4a2afc1f-deba-48da-831e-49a63e1a8fb6) + +# +- Check grafana service +```bash +kubectl get svc -n prometheus +``` + +# +- Get a password for grafana +```bash +kubectl get secret --namespace prometheus stable-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo +``` +> [!Note] +> Username: admin + +# +- Now, view the Dashboard in Grafana +![image](https://github.com/user-attachments/assets/d2e7ff2f-059d-48c4-92bb-9711943819c4) +![image](https://github.com/user-attachments/assets/647b2b22-cd83-41c3-855d-7c60ae32195f) +![image](https://github.com/user-attachments/assets/cb98a281-a4f5-46af-98eb-afdb7da6b35a) + + +# +## Clean Up +- Delete eks cluster +```bash +eksctl delete cluster --name=bankapp --region=us-west-1 +``` + +# diff --git a/README.md b/README.md index 3ddfdaac..2f49958e 100644 --- a/README.md +++ b/README.md @@ -4,91 +4,442 @@ ![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 +## Tech stack used in this project: +- GitHub (Code) +- Docker (Containerization) +- Jenkins (CI) +- OWASP (Dependency check) +- SonarQube (Quality) +- Trivy (Filesystem Scan) +- ArgoCD (CD) +- AWS EKS (Kubernetes) +- Helm (Monitoring using grafana and prometheus) + +### Steps to deploy: + +### Pre-requisites: +- root user access +```bash +sudo su +``` # -### 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 | +> [!Note] +> This project will be implemented on North California region (us-west-1). +- Create 1 Master machine on AWS (t2.medium) and 29 GB of storage. # -### STEPS TO IMPLEMENT THE PROJECT -- **

Deployment using Docker

** - - Clone the repository +- Open the below ports in security group +![image](https://github.com/user-attachments/assets/4e5ecd37-fe2e-4e4b-a6ba-14c7b62715a3) + +- Create EKS Cluster on AWS +- IAM user with **access keys and secret access keys** +- AWSCLI should be configured (Setup AWSCLI) + ```bash + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" + sudo apt install unzip + unzip awscliv2.zip + sudo ./aws/install + aws configure + ``` + +- Install **kubectl**(Setup kubectl ) + ```bash + curl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.19.6/2021-01-05/bin/linux/amd64/kubectl + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin + kubectl version --short --client + ``` + +- Install **eksctl**(Setup eksctl) ```bash - git clone -b DevOps https://github.com/DevMadhup/Springboot-BankApp.git + curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp + sudo mv /tmp/eksctl /usr/local/bin + eksctl version ``` - # - - Install docker, docker compose and provide neccessary permission + +- Create EKS Cluster ```bash - sudo apt update -y + eksctl create cluster --name=bankapp \ + --region=us-west-1 \ + --version=1.30 \ + --without-nodegroup + ``` +- Associate IAM OIDC Provider + ```bash + eksctl utils associate-iam-oidc-provider \ + --region us-west-1 \ + --cluster bankapp \ + --approve + ``` +- Create Nodegroup + ```bash + eksctl create nodegroup --cluster=bankapp \ + --region=us-west-1 \ + --name=bankapp \ + --node-type=t2.medium \ + --nodes=2 \ + --nodes-min=2 \ + --nodes-max=2 \ + --node-volume-size=29 \ + --ssh-access \ + --ssh-public-key=eks-nodegroup-key + ``` +> [!Note] +> Make sure the ssh-public-key "eks-nodegroup-key is available in your aws account" +- Install Jenkins +```bash +sudo apt update -y +sudo apt install fontconfig openjdk-17-jre -y - sudo apt install docker.io docker-compose-v2 -y +sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \ + https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key + +echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \ + https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ + /etc/apt/sources.list.d/jenkins.list > /dev/null + +sudo apt-get update -y +sudo apt-get install jenkins -y +``` - sudo usermod -aG docker $USER && newgrp docker - ``` - # - - Move to the cloned repository +- After installing Jenkins, change the default port of jenkins from 8080 to 8081. Because our bankapp application will be running on 8080. + - Open /usr/lib/systemd/system/jenkins.service file and change JENKINS_PORT environment variable +![image](https://github.com/user-attachments/assets/6320ae49-82d4-4ae3-9811-bd6f06778483) + - Reload daemon ```bash - cd Springboot-BankApp + sudo systemctl daemon-reload ``` - # - - Build the Dockerfile + - Restart Jenkins ```bash - docker build -t madhupdevops/springboot-bankapp . + sudo systemctl restart jenkins ``` -> [!Important] -> Make sure to change docker build command with your DockerHub username. - # - - Create a docker network +# + +- Install docker + +```bash +sudo apt install docker.io -y +sudo usermod -aG docker ubuntu && newgrp docker +``` +# +- Install and configure SonarQube +```bash +docker run -itd --name SonarQube-Server -p 9000:9000 sonarqube:lts-community +``` +# +- Install Trivy +```bash +sudo apt-get install wget apt-transport-https gnupg lsb-release -y +wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - +echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list +sudo apt-get update -y +sudo apt-get install trivy -y +``` +# +- Install and Configure ArgoCD + - Create argocd namespace ```bash - docker network create bankapp + kubectl create namespace argocd ``` - # - - Run MYSQL container + - Apply argocd manifest ```bash - docker run -itd --name mysql -e MYSQL_ROOT_PASSWORD=Test@123 -e MYSQL_DATABASE=BankDB --network=bankapp mysql + kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml ``` - # - - Run Application container + - Make sure all pods are running in argocd namespace ```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 + watch kubectl get pods -n argocd ``` - # - - Verify deployment + - Install argocd CLI ```bash - docker ps + curl --silent --location -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.4.7/argocd-linux-amd64 ``` - # - - Open port 8080 of your AWS instance and access your application + - Provide executable permission ```bash - http://:8080 + chmod +x /usr/local/bin/argocd ``` - ### Congratulations, you have deployed the application using Docker - # -- **

Deployment using Docker compose

** -- Install docker compose + - Check argocd services + ```bash + kubectl get svc -n argocd + ``` + - Change argocd server's service from ClusterIP to NodePort + ```bash + kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}' + ``` + - Confirm service is patched or not + ```bash + kubectl get svc -n argocd + ``` + - Check the port where ArgoCD server is running and expose it on security groups of a k8s worker node + ![image](https://github.com/user-attachments/assets/a2932e03-ebc7-42a6-9132-82638152197f) + - Access it on browser, click on advance and proceed with + ```bash + : + ``` + ![image](https://github.com/user-attachments/assets/29d9cdbd-5b7c-44b3-bb9b-1d091d042ce3) + ![image](https://github.com/user-attachments/assets/08f4e047-e21c-4241-ba68-f9b719a4a39a) + ![image](https://github.com/user-attachments/assets/1ffa85c3-9055-49b4-aab0-0947b95f0dd2) + - Fetch the initial password of argocd server + ```bash + kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo + ``` + - Username: admin + - Now, go to User Info and update your argocd password +# +## Steps to add email notification +- Go to your Jenkins Master EC2 instance and allow 465 port number for SMTPS +# +- Now, we need to generate an application password from our gmail account to authenticate with jenkins + - Open gmail and go to Manage your Google Account --> Security +> [!Important] +> Make sure 2 step verification must be on + + ![image](https://github.com/user-attachments/assets/5ab9dc9d-dcce-4f9d-9908-01095f1253cb) + + - Search for App password and create a app password for jenkins + ![image](https://github.com/user-attachments/assets/701752da-7703-4685-8f06-fe1f65dd1b9c) + ![image](https://github.com/user-attachments/assets/adc8d8c0-8be4-4319-9042-4115abb5c6fc) + +# +- Once, app password is create and go back to jenkins Manage Jenkins --> Credentials to add username and password for email notification +![image](https://github.com/user-attachments/assets/2a42ec62-87c8-43c8-a034-7be0beb8824e) + +# +- Go back to Manage Jenkins --> System and search for Extended E-mail Notification +![image](https://github.com/user-attachments/assets/bac81e24-bb07-4659-a251-955966feded8) +# +- Scroll down and search for E-mail Notification and setup email notification +> [!Important] +> Enter your gmail password which we copied recently in password field E-mail Notification --> Advance + +![image](https://github.com/user-attachments/assets/14e254fc-1400-457e-b3f4-046404b66950) +![image](https://github.com/user-attachments/assets/7be70b3a-b0dc-415c-838a-b1c6fd87c182) +![image](https://github.com/user-attachments/assets/cffb6e1d-4838-483e-97e0-6851c204ab21) + +# +- Go to Jenkins and click on Manage Jenkins --> Plugins --> Available plugins install the below plugins: + - OWASP + - SonarQube Scanner + - Docker + - Pipeline: Stage View +# +- Configure OWASP, move to Manage Jenkins --> Plugins --> Available pluginsb> +![image](https://github.com/user-attachments/assets/da6a26d3-f742-4ea8-86b7-107b1650a7c2) + +- After OWASP plugin is installed, Now move to Manage jenkins --> Tools +![image](https://github.com/user-attachments/assets/3b8c3f20-202e-4864-b3b6-b48d7a604ee8) +# +- Login to SonarQube server and create the credentials for jenkins to integrate with SonarQube + - Navigate to Administration --> Security --> Users --> Token + ![image](https://github.com/user-attachments/assets/86ad8284-5da6-4048-91fe-ac20c8e4514a) + ![image](https://github.com/user-attachments/assets/6bc671a5-c122-45c0-b1f0-f29999bbf751) + ![image](https://github.com/user-attachments/assets/e748643a-e037-4d4c-a9be-944995979c60) + +# +- Now, go to Manage Jenkins --> credentials and add Sonarqube credentials: +![image](https://github.com/user-attachments/assets/0688e105-2170-4c3f-87a3-128c1a05a0b8) +# +- Go to Manage Jenkins --> Tools and search for SonarQube Scanner installations: +![image](https://github.com/user-attachments/assets/2fdc1e56-f78c-43d2-914a-104ec2c8ea86) +# +- Go to Manage Jenkins --> credentials and add Docker credentials to push updated the updated docker image to dockerhub. +![image](https://github.com/user-attachments/assets/77402c9c-fc2f-4df7-9a06-09f3f4c38751) + +# +- Again, add Github credentials to push updated code from the pipeline: +![image](https://github.com/user-attachments/assets/4d0c1a47-621e-4aa2-a0b1-71927fcdaef4) +> [!Note] +> While adding github credentials add Personal Access Token in the password field. +# +- Go to Manage Jenkins --> System and search for SonarQube installations: +![image](https://github.com/user-attachments/assets/ae866185-cb2b-4e83-825b-a125ec97243a) +# +- Now again, Go to Manage Jenkins --> System and search for Global Trusted Pipeline Libraries:Login to SonarQube server, go to Administration --> Webhook and click on create +![image](https://github.com/user-attachments/assets/16527e72-6691-4fdf-a8d2-83dd27a085cb) +![image](https://github.com/user-attachments/assets/a8b45948-766a-49a4-b779-91ac3ce0443c) +# + +# +- Go to Master Machine and add our own eks cluster to argocd for application deployment using cli + - Login to argoCD from CLI + ```bash + argocd login 52.53.156.187:32738 --username admin + ``` +> [!Tip] +> 52.53.156.187:32738 --> This should be your argocd url + + ![image](https://github.com/user-attachments/assets/7d05e5ca-1a16-4054-a321-b99270ca0bf9) + + - Check how many clusters are available in argocd + ```bash + argocd cluster list + ``` + ![image](https://github.com/user-attachments/assets/76fe7a45-e05c-422d-9652-bdaee02d630f) + - Get your cluster name + ```bash + kubectl config get-contexts + ``` + ![image](https://github.com/user-attachments/assets/c9afca1f-b5a3-4685-ae24-cc206a3e3ef1) + + - Add your cluster to argocd + ```bash + argocd cluster add Madhup@bankapp.us-west-1.eksctl.io --name bankapp-eks-cluster + ``` + > [!Tip] + > Madhup@bankapp.us-west-1.eksctl.io --> This should be your EKS Cluster Name. + + ![image](https://github.com/user-attachments/assets/1061fe66-17ec-47b7-9d2e-371f58d3fd90) + + - Once your cluster is added to argocd, go to argocd console Settings --> Clusters and verify it + ![image](https://github.com/user-attachments/assets/6aebb871-4dea-4e09-955a-a4aa43b8f4ef) + + +# +- Go to Settings --> Repositories and click on Connect repo +![image](https://github.com/user-attachments/assets/cc8728e5-546b-4c46-bd4c-538f4cd6a63d) +![image](https://github.com/user-attachments/assets/e665203d-0ebe-4839-af9e-f5866dce5e1b) +![image](https://github.com/user-attachments/assets/b9b869c3-698b-4303-83cc-9ccec66542a3) + +> [!Note] +> Connection should be successful + +- Create BankApp-CI job +![image](https://github.com/user-attachments/assets/17467b79-3110-470a-87a2-2bbfe197551b) +![image](https://github.com/user-attachments/assets/51d79ab0-e1f4-4c4d-a778-0c28119f5da9) + +- Create BankApp-CD job, same as CI job. +# +- Provide permission to docker socket so that docker build and push command do not fail +```bash +chmod 777 /var/run/docker.sock +``` +![image](https://github.com/user-attachments/assets/e231c62a-7adb-4335-b67e-480758713dbf) + +- Now, go to Applications and click on New App + +![image](https://github.com/user-attachments/assets/d5b08e06-6256-4f46-afdc-fc43a9e44562) + +> [!Important] +> Make sure to click on the Auto-Create Namespace option while creating argocd application + +![image](https://github.com/user-attachments/assets/6a828910-41ba-4f0c-af05-19297321a41b) +![image](https://github.com/user-attachments/assets/a3aa1d22-50ef-4eb1-97fe-9c3ffb504fc3) + +- Congratulations, your application is deployed on AWS EKS Cluster +![image](https://github.com/user-attachments/assets/03f3b69a-d6e0-42ad-992e-11124e7d0898) + +- Open port 30080 on worker node and Access it on browser +```bash +:30080 +``` +- Email Notification +![image](https://github.com/user-attachments/assets/407f94ed-bf67-441a-bd28-881b6b8739b2) + +# +## How to monitor EKS cluster, kubernetes components and workloads using prometheus and grafana via HELM (On Master machine) +-

Install Helm Chart

+```bash +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 +``` +```bash +chmod 700 get_helm.sh +``` +```bash +./get_helm.sh +``` + +# +- Add Helm Stable Charts for Your Local Client +```bash +helm repo add stable https://charts.helm.sh/stable +``` + +# +- Add Prometheus Helm Repository +```bash +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +``` + +# +- Create Prometheus Namespace +```bash +kubectl create namespace prometheus +``` +```bash +kubectl get ns +``` + +# +- Install Prometheus using Helm ```bash -sudo apt update -sudo apt install docker-compose-v2 -y +helm install stable prometheus-community/kube-prometheus-stack -n prometheus ``` + # -- Run docker-compose file present in the root directory of a project +- Verify prometheus installation ```bash -docker compose up -d +kubectl get pods -n prometheus ``` + # -- Access it on port 8080 +- Check the services file (svc) of the Prometheus ```bash - http://:8080 +kubectl get svc -n prometheus ``` + +# +- Expose Prometheus and Grafana to the external world through Node Port > [!Important] -> If you face issues with exiting docker container while running docker compose, run ``` docker compose down``` and then ``` docker compose up -d ```. +> change it from Cluster IP to NodePort after changing make sure you save the file and open the assigned nodeport to the service. + +```bash +kubectl edit svc stable-kube-prometheus-sta-prometheus -n prometheus +``` +![image](https://github.com/user-attachments/assets/90f5dc11-23de-457d-bbcb-944da350152e) +![image](https://github.com/user-attachments/assets/ed94f40f-c1f9-4f50-a340-a68594856cc7) + +# +- Verify service +```bash +kubectl get svc -n prometheus +``` + +# +- Now,let’s change the SVC file of the Grafana and expose it to the outer world +```bash +kubectl edit svc stable-grafana -n prometheus +``` +![image](https://github.com/user-attachments/assets/4a2afc1f-deba-48da-831e-49a63e1a8fb6) + +# +- Check grafana service +```bash +kubectl get svc -n prometheus +``` + +# +- Get a password for grafana +```bash +kubectl get secret --namespace prometheus stable-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo +``` +> [!Note] +> Username: admin + +# +- Now, view the Dashboard in Grafana +![image](https://github.com/user-attachments/assets/d2e7ff2f-059d-48c4-92bb-9711943819c4) +![image](https://github.com/user-attachments/assets/647b2b22-cd83-41c3-855d-7c60ae32195f) +![image](https://github.com/user-attachments/assets/cb98a281-a4f5-46af-98eb-afdb7da6b35a) + + +# +## Clean Up +- Delete eks cluster +```bash +eksctl delete cluster --name=bankapp --region=us-west-1 +``` + # diff --git a/cicd.md b/cicd.md new file mode 100644 index 00000000..140e1696 --- /dev/null +++ b/cicd.md @@ -0,0 +1,118 @@ +#### CICD Workflow +- Cloning the Project code from GitHub. +- Build docker image and push it to docker hub. +- Pull image from docker hub and deploy application using docker compose . + + ![Login diagram](images/flow.png) +#### Creating CICD pipeline + + 1. #### Install Jenkins and access on port 8080 + ```bash + http://:8080 + # Development environment only + http://:8080 + + # Production environment (recommended) + # Access through reverse proxy with HTTPS + https:///jenkins + ``` + Login and install Suggested Plugins. + +2. #### Jenkins Configuration. + - SetUp Agent + - Agents are used for distribute the builds in parallel execution + ![Agent](images/agent.png) + + - Install Docker and docker-compose:V2 on worker node and add the user who is executing the Jenkins job into the docker group. because we are going to deploy application in worker node itself. + + **Note** Security Considerations for Docker Setup. When configuring Docker for Jenkins: + + - Avoid adding the Jenkins user to the Docker group, as it grants root-level access. + - Use Rootless Docker to run Docker daemons and containers without root privileges. [Official Guide](https://docs.docker.com/engine/security/rootless/). + - Configure sudo for Docker commands: + - Grant specific permissions in the sudoers file. + - Use sudo in your pipeline scripts to execute Docker commands. + - Implement access control mechanisms using Docker authorization plugins or socket proxies. + + + + - Configure Shared Library + - Configure the task effectively in centralized manner. + - Configure shared library for your Jenkins Server Navigate through Dashboard > Manage Jenkins > System, and add Global Trusted Pipeline Libraries. (Modern SCM) + + ![Shared-library](images/shared_library.png) + + + - Configure Crendentials. + - Credentials that are requied during job execution. + - e.g. DockerHub credentials for push and pull images. + + ![Shared-library](images/credentials.png) + +3. #### Create a Pipeline, Execute Job and Configure Webhook + + - Configure Pipeline. + - Configure job to get pipeline from SCM. + ![pipeline](images/pipeline.png) + - Build Job and Check + - Build the Job + - Configure WebHook and poll SCM. + - Webhook Configuration + + 1. **Install GitHub Plugin** + - Go to `Manage Jenkins > Manage Plugins > Available`. + - Search for **GitHub Integration Plugin**, install, and restart Jenkins if needed. + + 2. **Configure Jenkins Job** + - In job configuration, enable **GitHub hook trigger for GITScm polling** under **Build Triggers**. + + 3. **Set Up Webhook in GitHub** + - Go to `Repository > Settings > Webhooks > Add webhook`. + - Configure: + - **Payload URL**: `http://:8080/github-webhook/` + - **Content type**: `application/json` + - **Events**: Select **push** or others as needed. + - (Optional) Add a secret token for security. + + 4. **Test Webhook** + - Push changes to the repo and verify the job is triggered. + - Check webhook status under **Recent Deliveries** in GitHub. + + - SCM Polling Configuration + + 1. **Enable SCM Polling** + - In job configuration, select **Poll SCM** under **Build Triggers**. + - Add a cron expression in **Schedule**: + - Every 5 minutes: `H/5 * * * *` + - Every 15 minutes: `H/15 * * * *` + + 2. **Test Polling** + - Push changes to the repo and wait for the next polling interval. + - Verify in **Polling Log** under the Jenkins job dashboard. + + + - Key Notes + + - **Webhooks vs Polling**: + - Webhooks are immediate and resource-efficient. + - Polling introduces delays and higher resource usage. + + - **Security**: + - Use SSL/TLS for GitHub-Jenkins communication. + - Ensure Jenkins is accessible via the firewall. + + - **Jenkins Pipeline**: + - Ensure `Jenkinsfile` is correctly configured to check out the repo and branch. + + + + + + + + + + + + +#### Nginx and HTTPS [guide](nginx.md) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index f3977b3c..34642a09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: - MYSQL_ROOT_PASSWORD=Test@123 - MYSQL_DATABASE=BankDB volumes: - - ./mysql-data:/var/lib/mysql + - bankapp-volume:/var/lib/mysql networks: - bankapp healthcheck: @@ -18,7 +18,7 @@ services: start_period: 30s mainapp: - build: . + image: ${DUSER}/${IMAGE} container_name: Bankapp environment: - SPRING_DATASOURCE_USERNAME=root @@ -41,3 +41,6 @@ services: networks: bankapp: + +volumes: + bankapp-volume: \ No newline at end of file diff --git a/helm/README.md b/helm/README.md new file mode 100644 index 00000000..22814095 --- /dev/null +++ b/helm/README.md @@ -0,0 +1,49 @@ +# HELM + +## Installing Helm +```bash +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 +chmod 700 get_helm.sh +./get_helm.sh +``` +**NOTE** This Helm chart assumes that you already have installed Ingress Cotroller, Metrics Server and VPA CRD + + +- Ingress Controller + ```bash + helm upgrade --install ingress-nginx ingress-nginx \ + --repo https://kubernetes.github.io/ingress-nginx \ + --namespace ingress-nginx --create-namespace + ``` +- Metrics Server for HPA + ```bash + helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ + helm upgrade --install metrics-server metrics-server/metrics-server + ``` + ```bash + kubectl edit deployments.apps metrics-server + ## add these two enteries at: spec.template.spec.containers[0].args + # - --kubelet-insecure-tls + # - --kubelet-preferred-address-types=InternalIP,Hostname,ExternalIP + ``` +- VPA Custom Resource definition (CRD). + ```bash + kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/vpa-release-1.0/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml + + kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/vpa-release-1.0/vertical-pod-autoscaler/deploy/vpa-rbac.yaml + ``` + +## Run the SpringBoot Bankapp using helm +Install Bankapp from helm chart. +```bash +helm install bankapp bankapp/ +``` + +You can install it for multiple environments by changing values in `values.yaml` file +```bash +helm install bankapp-dev bankapp/ --set namespace=dev-namespace --set bankapp_svc.nodePort=30081 +``` + +Happy Helming! + + diff --git a/helm/bankapp/Chart.yaml b/helm/bankapp/Chart.yaml new file mode 100644 index 00000000..d8c225e2 --- /dev/null +++ b/helm/bankapp/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: bankapp +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" \ No newline at end of file diff --git a/helm/bankapp/templates/NOTES.txt b/helm/bankapp/templates/NOTES.txt new file mode 100644 index 00000000..664d510d --- /dev/null +++ b/helm/bankapp/templates/NOTES.txt @@ -0,0 +1,6 @@ + +Now you can access Bankapp using NodePort service. + +open browser and hit the URL: HTTP://:{{ default "30080" .Values.bankapp_svc.nodePort}} + +Additionally, you can configure Ingress for better traffic routing diff --git a/helm/bankapp/templates/configMap.yml b/helm/bankapp/templates/configMap.yml new file mode 100644 index 00000000..095e4de5 --- /dev/null +++ b/helm/bankapp/templates/configMap.yml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.configmap.name }} + namespace: {{ default "bankapp-namespace" .Values.namespace }} +data: + MYSQL_DATABASE: {{ .Values.configmap.data.MYSQL_DATABASE }} + SPRING_DATASOURCE_URL: jdbc:mysql://{{ .Values.db_statefulset.name }}-0.{{ .Values.db_statefulset.name }}-headless.{{ default "bankapp-namespace" .Values.namespace }}.svc.cluster.local:3306/{{ .Values.configmap.data.MYSQL_DATABASE }}?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + SPRING_DATASOURCE_USERNAME: {{ .Values.configmap.data.SPRING_DATASOURCE_USERNAME }} + diff --git a/helm/bankapp/templates/deployment.yml b/helm/bankapp/templates/deployment.yml new file mode 100644 index 00000000..9501ac23 --- /dev/null +++ b/helm/bankapp/templates/deployment.yml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.app_deployment.name }} + namespace: {{ default "bankapp-namespace" .Values.namespace }} + labels: + app: {{ .Values.app_deployment.name }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Values.app_deployment.name }} + template: + metadata: + labels: + app: {{ .Values.app_deployment.name }} + spec: + initContainers: + - name: "wait-for-{{ .Values.db_statefulset.name }}" + image: busybox:1.28 + command: ['sh', '-c', 'until nc -z {{ .Values.db_statefulset.name }}-0.{{ .Values.db_statefulset.name }}-headless 3306; do echo waiting for mysql; sleep 5; done;'] + containers: + - name: {{ .Values.app_deployment.name }} + image: {{ .Values.image.app }} + ports: + - containerPort: 8080 + env: + - name: SPRING_DATASOURCE_URL + valueFrom: + configMapKeyRef: + name: {{ .Values.configmap.name }} + key: SPRING_DATASOURCE_URL + - name: SPRING_DATASOURCE_USERNAME + valueFrom: + configMapKeyRef: + name: {{ .Values.configmap.name }} + key: SPRING_DATASOURCE_USERNAME + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: SPRING_DATASOURCE_PASSWORD + livenessProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /actuator/health + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 5 + resources: + requests: + memory: {{ .Values.app_deployment.mem_req}} + cpu: {{ .Values.app_deployment.cpu_req}} + limits: + memory: {{ .Values.app_deployment.mem_limit}} + cpu: {{ .Values.app_deployment.cpu_limit}} diff --git a/helm/bankapp/templates/hpa.yaml b/helm/bankapp/templates/hpa.yaml new file mode 100644 index 00000000..44eebe9c --- /dev/null +++ b/helm/bankapp/templates/hpa.yaml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: "{{ .Values.app_deployment.name }}-hpa" + namespace: {{ default "bankapp-namespace" .Values.namespace }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Values.app_deployment.name }} + minReplicas: {{ .Values.hpa.min_replica }} + maxReplicas: {{ .Values.hpa.max_replica }} + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.hpa.cpu_utilizatoion }} # Average % of CPU utilization diff --git a/helm/bankapp/templates/ingress.yml b/helm/bankapp/templates/ingress.yml new file mode 100644 index 00000000..305f0c22 --- /dev/null +++ b/helm/bankapp/templates/ingress.yml @@ -0,0 +1,20 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: "{{ .Values.app_deployment.name }}-ingress" + namespace: {{ default "bankapp-namespace" .Values.namespace }} + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + rules: + - host: bankapp.local # add + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: "{{ .Values.app_deployment.name }}-service" + port: + number: {{ default "8080" .Values.bankapp_svc.port}} + diff --git a/helm/bankapp/templates/mysqlService.yml b/helm/bankapp/templates/mysqlService.yml new file mode 100644 index 00000000..ddb566b6 --- /dev/null +++ b/helm/bankapp/templates/mysqlService.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Values.db_statefulset.name }}-headless" + namespace: {{ default "bankapp-namespace" .Values.namespace }} + labels: + app: {{ .Values.db_statefulset.name }} +spec: + clusterIP: None + selector: + app: {{ .Values.db_statefulset.name }} + ports: + - protocol: TCP + port: {{ default "3306" .Values.mysql_svc.port}} + targetPort: {{ default "3306" .Values.mysql_svc.targetPort}} \ No newline at end of file diff --git a/k8s/mysqlStatefulSet.yml b/helm/bankapp/templates/mysqlStatefulSet.yml similarity index 52% rename from k8s/mysqlStatefulSet.yml rename to helm/bankapp/templates/mysqlStatefulSet.yml index 3b1c80e3..ad094aa3 100644 --- a/k8s/mysqlStatefulSet.yml +++ b/helm/bankapp/templates/mysqlStatefulSet.yml @@ -1,39 +1,39 @@ -apiVersion: apps/v1 +apiVersion: apps/v1 kind: StatefulSet metadata: - name: mysql - namespace: bankapp-namespace + name: {{ .Values.db_statefulset.name }} + namespace: {{ default "bankapp-namespace" .Values.namespace }} labels: - app: mysql + app: {{ .Values.db_statefulset.name }} spec: - serviceName: mysql-headless + serviceName: "{{ .Values.db_statefulset.name }}-headless" replicas: 1 selector: matchLabels: - app: mysql + app: {{ .Values.db_statefulset.name }} template: metadata: labels: - app: mysql + app: {{ .Values.db_statefulset.name }} spec: containers: - - name: mysql - image: mysql:latest + - name: {{ .Values.db_statefulset.name }} + image: {{ .Values.image.db }} ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD valueFrom: - secretKeyRef: - name: mysql-secret - key: MYSQL_ROOT_PASSWORD + secretKeyRef: ### CRITICAL + name: mysql-secret ### CRITICAL + key: MYSQL_ROOT_PASSWORD ### CRITICAL - name: MYSQL_DATABASE valueFrom: configMapKeyRef: - name: bankapp-config - key: MYSQL_DATABASE + name: {{ .Values.configmap.name }} + key: MYSQL_DATABASE volumeMounts: - - name: mysql-data + - name: "{{ .Values.db_statefulset.name }}-data" mountPath: /var/lib/mysql livenessProbe: exec: @@ -55,13 +55,13 @@ spec: periodSeconds: 5 volumeClaimTemplates: - metadata: - name: mysql-data + name: "{{ .Values.db_statefulset.name }}-data" labels: - app: mysql + app: {{ .Values.db_statefulset.name }} spec: accessModes: - ReadWriteOnce resources: requests: - storage: 5Gi + storage: {{ .Values.db_statefulset.storage }} diff --git a/helm/bankapp/templates/namespace.yml b/helm/bankapp/templates/namespace.yml new file mode 100644 index 00000000..fb9e98c3 --- /dev/null +++ b/helm/bankapp/templates/namespace.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ default "bankapp-namespace" .Values.namespace }} + labels: + name: {{ default "bankapp-namespace" .Values.namespace }} + + \ No newline at end of file diff --git a/k8s/persistentVolume.yml b/helm/bankapp/templates/persistentVolume.yml similarity index 51% rename from k8s/persistentVolume.yml rename to helm/bankapp/templates/persistentVolume.yml index f147c6b3..6bd04068 100644 --- a/k8s/persistentVolume.yml +++ b/helm/bankapp/templates/persistentVolume.yml @@ -1,17 +1,16 @@ apiVersion: v1 kind: PersistentVolume metadata: - name: bankapp-pv - namespace: bankapp-namespace + name: "{{ .Values.app_deployment.name }}-{{ default "bankapp-namespace" .Values.namespace }}-pv" + namespace: {{ default "bankapp-namespace" .Values.namespace }} labels: - app: bankapp + app: {{ .Values.app_deployment.name }} spec: capacity: - storage: 5Gi + storage: {{ .Values.db_statefulset.storage }} accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: manual hostPath: path: "/tmp/bankapp-mysql" # This will be stored on the host machine running KIND - diff --git a/helm/bankapp/templates/persistentVolumeClaim.yml b/helm/bankapp/templates/persistentVolumeClaim.yml new file mode 100644 index 00000000..758c1e43 --- /dev/null +++ b/helm/bankapp/templates/persistentVolumeClaim.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: "{{ .Values.app_deployment.name }}-pvc" + namespace: {{ default "bankapp-namespace" .Values.namespace }} + labels: + app: {{ .Values.app_deployment.name }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.db_statefulset.storage }} + storageClassName: manual + diff --git a/helm/bankapp/templates/secrets.yml b/helm/bankapp/templates/secrets.yml new file mode 100644 index 00000000..bfec7735 --- /dev/null +++ b/helm/bankapp/templates/secrets.yml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.secret.name }} + namespace: {{ default "bankapp-namespace" .Values.namespace }} +type: Opaque +data: + MYSQL_ROOT_PASSWORD: {{ .Values.secret.data.MYSQL_ROOT_PASSWORD | b64enc | quote }} + SPRING_DATASOURCE_PASSWORD: {{ .Values.secret.data.SPRING_DATASOURCE_PASSWORD | b64enc | quote }} diff --git a/helm/bankapp/templates/service.yml b/helm/bankapp/templates/service.yml new file mode 100644 index 00000000..c1017852 --- /dev/null +++ b/helm/bankapp/templates/service.yml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Values.app_deployment.name }}-service" + namespace: {{ default "bankapp-namespace" .Values.namespace }} + labels: + app: {{ .Values.app_deployment.name }} +spec: + type: NodePort + selector: + app: {{ .Values.app_deployment.name }} + ports: + - protocol: TCP + port: {{ default "8080" .Values.bankapp_svc.port}} + targetPort: {{ default "8080" .Values.bankapp_svc.targetPort}} + nodePort: {{ default "30080" .Values.bankapp_svc.nodePort}} # Exposes the app on this port of the host \ No newline at end of file diff --git a/helm/bankapp/templates/vpa.yaml b/helm/bankapp/templates/vpa.yaml new file mode 100644 index 00000000..e838ba38 --- /dev/null +++ b/helm/bankapp/templates/vpa.yaml @@ -0,0 +1,12 @@ +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: "{{ .Values.app_deployment.name }}-vpa" + namespace: {{ default "bankapp-namespace" .Values.namespace }} +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Values.app_deployment.name }} + updatePolicy: + updateMode: "Auto" # Options: "Off", "Initial", "Auto" \ No newline at end of file diff --git a/helm/bankapp/values.yaml b/helm/bankapp/values.yaml new file mode 100644 index 00000000..58cf8483 --- /dev/null +++ b/helm/bankapp/values.yaml @@ -0,0 +1,54 @@ +# namespace +namespace: bankapp-namespace + +# name of configmap, database and db user. +configmap: + name: bankapp-config + data: + MYSQL_DATABASE: BankDB + SPRING_DATASOURCE_USERNAME: root + +## name, label and storage size for database +db_statefulset: + name: mysql + storage: 5Gi + +## name and label of app deployment +app_deployment: + name: bankapp + cpu_req: 80m + cpu_limit: 800m + mem_req: 150Mi + mem_limit: 700Mi + +## image repository and tag of app and db. +image: + app: trainwithshubham/springboot-bankapp:latest + db: mysql:latest + +# NodePort svc for bankapp +bankapp_svc: + port: 8080 + targetPort: 8080 + nodePort: 30080 + + +# headless svc configuration for db +mysql_svc: + port: 3306 + targetPort: 3306 + +# HPA minimun and maximum pods and average cpu utilization +hpa: + min_replica: 1 + max_replica: 5 + cpu_utilizatoion: 40 + +# Secret for Database connectivity + +secret: + name: mysql-secret + data: + MYSQL_ROOT_PASSWORD: Test@123 # (Base64 encoded 'Test@123') + SPRING_DATASOURCE_PASSWORD: Test@123 # (Base64 encoded 'Test@123') + diff --git a/images/agent.png b/images/agent.png new file mode 100644 index 00000000..fb992a6f Binary files /dev/null and b/images/agent.png differ diff --git a/images/credentials.png b/images/credentials.png new file mode 100644 index 00000000..252f848c Binary files /dev/null and b/images/credentials.png differ diff --git a/images/flow.png b/images/flow.png new file mode 100644 index 00000000..27c06f92 Binary files /dev/null and b/images/flow.png differ diff --git a/images/login_https.png b/images/login_https.png new file mode 100644 index 00000000..c390ab1f Binary files /dev/null and b/images/login_https.png differ diff --git a/images/pipeline.png b/images/pipeline.png new file mode 100644 index 00000000..9a80ab15 Binary files /dev/null and b/images/pipeline.png differ diff --git a/images/shared_library.png b/images/shared_library.png new file mode 100644 index 00000000..5731ced1 Binary files /dev/null and b/images/shared_library.png differ diff --git a/k8s/README.md b/k8s/README.md deleted file mode 100644 index 1005acd5..00000000 --- a/k8s/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# SpringBoot-BankApp Deployment on Kubernetes - -This guide explains how to deploy the SpringBoot-BankApp application on a Kubernetes cluster using the provided manifests and configure the NGINX Ingress Controller for routing. - -### Prerequisites - -- Kubernetes Cluster: Ensure you have a running Kubernetes cluster. KIND, Minikube, or any cloud provider will work. -- kubectl: Installed and configured to interact with your cluster. -- Docker Image: Ensure the SpringBoot-BankApp Docker image is available. - -Update the deployment.yml file to reference the correct image and tag. -Deployment Steps - -## 1. Install and Configure the NGINX Ingress Controller - -Deploy the NGINX Ingress Controller: - -```bash - -kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/deploy-ingress-nginx.yaml -``` -Verify that the Ingress Controller pods are running: - -```bash - -kubectl get pods -n ingress-nginx -``` -Edit the ValidatingWebhookConfiguration to ignore validation errors temporarily: - -```bash - -kubectl edit ValidatingWebhookConfiguration ingress-nginx-admission -``` -Update the failurePolicy to Ignore: - -```yaml - -failurePolicy: Ignore -``` - -## 2. Create a Namespace - -Create a dedicated namespace for the application: - -```bash - -kubectl apply -f namespace.yml -``` -## 3. Create ConfigMap - -Store non-sensitive configuration like database names and other environment variables: - -```bash - -kubectl apply -f configMap.yml -``` - -## 4. Create Secrets -Store sensitive data like database credentials securely: - -```bash - -kubectl apply -f secrets.yml -``` - -## 5. Set Up Persistent Storage -Create a PersistentVolume (PV) for MySQL: - -```bash - -kubectl apply -f persistentVolume.yml -``` -Create a PersistentVolumeClaim (PVC) to bind the PV: - -```bash - -kubectl apply -f persistentVolumeClaim.yml -``` - -## 6. Deploy MySQL - -Deploy MySQL as a StatefulSet for persistent database management: - -```bash - -kubectl apply -f mysqlStatefulSet.yml -``` -Expose MySQL via a Kubernetes Service: - -```bash - -kubectl apply -f mysqlService.yml -``` - -## 7. Deploy SpringBoot-BankApp -Deploy the SpringBoot-BankApp using a Deployment: - -```bash - -kubectl apply -f deployment.yml -``` -Expose the application via a Service: - -```bash - -kubectl apply -f service.yml -``` - -## 8. Configure Ingress -Deploy the Ingress resource to route traffic to the SpringBoot-BankApp: - -```bash - -kubectl apply -f ingress.yml -``` - -Forward port 80 from the Ingress Controller to your localhost: - -```bash - -kubectl port-forward --namespace ingress-nginx service/ingress-nginx-controller 80:80 -``` - -Update your /etc/hosts file to point bankapp.local to your localhost: - -```lua - -127.0.0.1 bankapp.local -``` -Access the application in your browser at: - -```arduino - -http://bankapp.local -``` -Verification -Check the status of all resources: - -```bash - -kubectl get all -n bankapp-namespace -``` -Verify the logs of the MySQL and SpringBoot-BankApp pods: - -```bash - -kubectl logs -n bankapp-namespace -``` -Cleaning Up -To remove all resources related to the SpringBoot-BankApp: - -```bash - -kubectl delete namespace bankapp-namespace -kubectl delete -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml -``` -Notes - -Ingress Tweaks: The failurePolicy: Ignore setting in the ValidatingWebhookConfiguration ensures smooth ingress creation in local environments like KIND. - -Scaling: Scale the BankApp deployment if needed: - -```bash - -kubectl scale deployment bankapp-deployment --replicas=3 -n bankapp-namespace -``` -Monitoring: Use tools like Prometheus or kubectl top to monitor resource usage. diff --git a/k8s/configMap.yml b/k8s/configMap.yml deleted file mode 100644 index 653155ca..00000000 --- a/k8s/configMap.yml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: bankapp-config - namespace: bankapp-namespace -data: - MYSQL_DATABASE: BankDB - SPRING_DATASOURCE_URL: jdbc:mysql://mysql-0.mysql-headless.bankapp-namespace.svc.cluster.local:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - SPRING_DATASOURCE_USERNAME: root - diff --git a/k8s/deployment.yml b/k8s/deployment.yml deleted file mode 100644 index 0e2ab968..00000000 --- a/k8s/deployment.yml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bankapp-deployment - namespace: bankapp-namespace - labels: - app: bankapp -spec: - replicas: 1 - selector: - matchLabels: - app: bankapp - template: - metadata: - labels: - app: bankapp - spec: - initContainers: - - name: wait-for-mysql - image: busybox:1.28 - command: ['sh', '-c', 'until nc -z mysql-0.mysql-headless 3306; do echo waiting for mysql; sleep 5; done;'] - containers: - - name: bankapp - image: trainwithshubham/springboot-bankapp:latest - ports: - - containerPort: 8080 - env: - - name: SPRING_DATASOURCE_URL - valueFrom: - configMapKeyRef: - name: bankapp-config - key: SPRING_DATASOURCE_URL - - name: SPRING_DATASOURCE_USERNAME - valueFrom: - configMapKeyRef: - name: bankapp-config - key: SPRING_DATASOURCE_USERNAME - - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: mysql-secret - key: SPRING_DATASOURCE_PASSWORD - livenessProbe: - httpGet: - path: /actuator/health - port: 8080 - initialDelaySeconds: 30 - periodSeconds: 10 - readinessProbe: - httpGet: - path: /actuator/health - port: 8080 - initialDelaySeconds: 10 - periodSeconds: 5 - diff --git a/k8s/ingress.yml b/k8s/ingress.yml deleted file mode 100644 index ae8dca04..00000000 --- a/k8s/ingress.yml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: bankapp-ingress - namespace: bankapp-namespace - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / -spec: - rules: - - host: bankapp.local - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: bankapp-service - port: - number: 8080 - diff --git a/kubernetes/README.md b/kubernetes/README.md new file mode 100644 index 00000000..4db1d8b8 --- /dev/null +++ b/kubernetes/README.md @@ -0,0 +1,245 @@ +# End-to-End Setup for Deploying Applications with ArgoCD and EKS + +This README provides a complete step-by-step guide with all the commands required to set up ArgoCD on an AWS EKS cluster, deploy your applications, and configure GitOps. + +--- + +## **1. Create an EKS Cluster** + +### **Create the Cluster Without a Node Group** +```bash +eksctl create cluster --name=bankapp \ + --region=ap-south-1 \ + --version=1.31 \ + --without-nodegroup +``` + +### **Associate IAM OIDC Provider** +```bash +eksctl utils associate-iam-oidc-provider \ + --region ap-south-1 \ + --cluster bankapp \ + --approve +``` + +### **Create a Node Group** +```bash +eksctl create nodegroup --cluster=bankapp \ + --region=ap-south-1 \ + --name=bankapp \ + --node-type=t2.medium \ + --nodes=2 \ + --nodes-min=2 \ + --nodes-max=2 \ + --node-volume-size=29 \ + --ssh-access \ + --ssh-public-key=k8s-in-one-shot +``` + +--- + +## **2. Deploy ArgoCD** + +### **Create the ArgoCD Namespace** +```bash +kubectl create namespace argocd +``` + +### **Install ArgoCD Using Official Manifests** +```bash +kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml +``` + +### **Verify ArgoCD Pods** +```bash +watch kubectl get pods -n argocd +``` + +### **Install ArgoCD CLI** +```bash +curl --silent --location -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.4.7/argocd-linux-amd64 +chmod +x /usr/local/bin/argocd +argocd version +``` + +### **Change ArgoCD Server Service Type to NodePort** +```bash +kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}' +``` + +### **Verify the NodePort Service** +```bash +kubectl get svc -n argocd +``` + +### **Expose the Port on Security Groups** +- In the AWS Console, update the security group for your EKS worker nodes to allow inbound traffic on the NodePort assigned to the `argocd-server` service. + +### **Access the ArgoCD Web UI** +- Open your browser and navigate to: + ``` + http://: + ``` + +--- + +## **3. Configure ArgoCD for EKS** + +### **Login to ArgoCD Using CLI** +```bash +argocd login : --username admin +``` + +### **Retrieve the Default Admin Password** +```bash +kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d +``` + +### **Check Available Clusters in ArgoCD** +```bash +argocd cluster list +``` + +### **Get the EKS Cluster Context** +```bash +kubectl config get-contexts +``` + +### **Add EKS Cluster to ArgoCD** +```bash +argocd cluster add --name bankapp-eks-cluster +``` +- Replace `` with your EKS cluster context name (e.g., `Madhup@bankapp.us-west-1.eksctl.io`). + +--- + +## **4. Deploy Applications Using ArgoCD** + +### **Prepare Kubernetes Manifests in a Git Repository** +- Organize your manifests (e.g., `namespace.yaml`, `deployment.yaml`, `service.yaml`) in a Git repository. + +### **Create an Application in ArgoCD** +```bash +argocd app create bankapp \ + --repo \ + --path \ + --dest-server https://kubernetes.default.svc \ + --dest-namespace bankapp-namespace +``` + +### **Sync the Application** +```bash +argocd app sync bankapp +``` + +### **Monitor Application Status** +```bash +argocd app list +``` + +--- + +## **5. Deploy NGINX Ingress Controller** + +### **Install NGINX Ingress Controller Using Helm** +```bash +helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx +helm repo update +helm install ingress-nginx ingress-nginx/ingress-nginx \ + --namespace ingress-nginx --create-namespace +``` + +### **Verify Installation** +Check if the NGINX Ingress Controller pods are running: +```bash +kubectl get pods -n ingress-nginx +``` + +### **Retrieve the Load Balancer IP** +Get the external IP assigned to the NGINX Ingress Controller: +```bash +kubectl get svc -n ingress-nginx +``` + +### **Update DNS** +Point your domain (`junoon.trainwithshubham.com`) to the external IP of the NGINX Load Balancer. + +--- + +## **6. Enable HTTPS for the Application** + +### **Install Cert-Manager** +```bash +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.1/cert-manager.yaml +``` + +### **Create Let's Encrypt ClusterIssuer** +Save the following as `letsencrypt-clusterissuer.yaml`: +```yaml +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: your-email@example.com + privateKeySecretRef: + name: letsencrypt-prod-key + solvers: + - http01: + ingress: + class: nginx +``` +Apply the ClusterIssuer: +```bash +kubectl apply -f letsencrypt-clusterissuer.yaml +``` + +### **Update Ingress with TLS Configuration** +- Modify your Ingress to include TLS and reference the `letsencrypt-prod` ClusterIssuer. +- Apply the updated Ingress: +```bash +kubectl apply -f +``` + +### **Verify Certificate Issuance** +```bash +kubectl get certificate -n bankapp-namespace +``` + +--- + +## **7. Verify Deployment** + +### **Check Deployed Resources** +```bash +kubectl get all -n bankapp-namespace +``` + +### **Access the Application** +- Open your browser and navigate to: + ``` + https://junoon.trainwithshubham.com + ``` + +--- + +## **8. Add Autoscaling** + +### **Install the Metrics Server** +```bash +kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml +``` + +### **Get the Top Nodes and Pods** +```bash + kubectl top nodes + kubectl top pods -n bankapp-namespace +``` +### **Apply HPA** +```bash + kubectl apply -f bankapp-hpa.yml +``` +--- + diff --git a/kubernetes/bankapp-deployment.yml b/kubernetes/bankapp-deployment.yml new file mode 100644 index 00000000..45a35b6f --- /dev/null +++ b/kubernetes/bankapp-deployment.yml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: bankapp-deploy + name: bankapp-deploy + namespace: bankapp-namespace +spec: + replicas: 2 # Keep replicas >= 2 for high availability + selector: + matchLabels: + app: bankapp-deploy + template: + metadata: + labels: + app: bankapp-deploy + spec: + containers: + - name: bankapp + image: trainwithshubham/bankapp-eks:v2 + ports: + - containerPort: 8080 + env: + - name: SPRING_DATASOURCE_URL + valueFrom: + configMapKeyRef: + name: bankapp-config + key: SPRING_DATASOURCE_URL + - name: SPRING_DATASOURCE_USERNAME + valueFrom: + configMapKeyRef: + name: bankapp-config + key: SPRING_DATASOURCE_USERNAME + - name: MYSQL_DATABASE + valueFrom: + configMapKeyRef: + name: bankapp-config + key: MYSQL_DATABASE + - name: SPRING_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: SPRING_DATASOURCE_PASSWORD + # readinessProbe: + # httpGet: + # path: /actuator/health # Update this based on your app's health endpoint + # port: 8080 + # initialDelaySeconds: 10 + # periodSeconds: 5 + # livenessProbe: + # httpGet: + # path: /actuator/health # Update this based on your app's health endpoint + # port: 8080 + # initialDelaySeconds: 30 + # periodSeconds: 10 + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "500m" + diff --git a/kubernetes/bankapp-hpa.yml b/kubernetes/bankapp-hpa.yml new file mode 100644 index 00000000..6c030161 --- /dev/null +++ b/kubernetes/bankapp-hpa.yml @@ -0,0 +1,19 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: bankapp-hpa + namespace: bankapp-namespace +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: bankapp-deploy + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 40 diff --git a/kubernetes/bankapp-ingress.yml b/kubernetes/bankapp-ingress.yml new file mode 100644 index 00000000..e1b8f06e --- /dev/null +++ b/kubernetes/bankapp-ingress.yml @@ -0,0 +1,28 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bankapp-ingress + namespace: bankapp-namespace + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/proxy-body-size: "50m" + nginx.ingress.kubernetes.io/ssl-redirect: "true" # Force HTTPS + cert-manager.io/cluster-issuer: letsencrypt-prod # Use Let's Encrypt +spec: + ingressClassName: nginx + tls: + - hosts: + - megaproject.trainwithshubham.com + secretName: bankapp-tls-secret # Cert-Manager will manage this + rules: + - host: megaproject.trainwithshubham.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: bankapp-service + port: + number: 8080 + diff --git a/k8s/namespace.yml b/kubernetes/bankapp-namespace.yaml similarity index 99% rename from k8s/namespace.yml rename to kubernetes/bankapp-namespace.yaml index a1ebb8f9..3a4a5170 100644 --- a/k8s/namespace.yml +++ b/kubernetes/bankapp-namespace.yaml @@ -4,4 +4,3 @@ metadata: name: bankapp-namespace labels: name: bankapp-namespace - diff --git a/k8s/service.yml b/kubernetes/bankapp-service.yaml similarity index 67% rename from k8s/service.yml rename to kubernetes/bankapp-service.yaml index a46714da..c63175da 100644 --- a/k8s/service.yml +++ b/kubernetes/bankapp-service.yaml @@ -6,12 +6,10 @@ metadata: labels: app: bankapp spec: - type: NodePort selector: - app: bankapp + app: bankapp-deploy ports: - protocol: TCP port: 8080 targetPort: 8080 - nodePort: 30080 # Exposes the app on this port of the host - + diff --git a/kubernetes/configmap.yaml b/kubernetes/configmap.yaml new file mode 100644 index 00000000..f2acc025 --- /dev/null +++ b/kubernetes/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: bankapp-config + namespace: bankapp-namespace +data: + MYSQL_DATABASE: BankDB + SPRING_DATASOURCE_URL: jdbc:mysql://mysql-svc.bankapp-namespace.svc.cluster.local:3306/BankDB?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + SPRING_DATASOURCE_USERNAME: root diff --git a/kubernetes/letsencrypt-clusterissuer.yaml b/kubernetes/letsencrypt-clusterissuer.yaml new file mode 100644 index 00000000..959db1b9 --- /dev/null +++ b/kubernetes/letsencrypt-clusterissuer.yaml @@ -0,0 +1,15 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: trainwithshubham@gmail.com + privateKeySecretRef: + name: letsencrypt-prod-key + solvers: + - http01: + ingress: + class: nginx + diff --git a/kubernetes/mysql-deployment.yml b/kubernetes/mysql-deployment.yml new file mode 100644 index 00000000..c9baa53a --- /dev/null +++ b/kubernetes/mysql-deployment.yml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql + namespace: bankapp-namespace + labels: + app: mysql +spec: + replicas: 1 + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + spec: + containers: + - name: mysql + image: mysql:8.0 # Use a specific, stable version for production + ports: + - containerPort: 3306 + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-secret + key: MYSQL_ROOT_PASSWORD + - name: MYSQL_DATABASE + valueFrom: + configMapKeyRef: + name: bankapp-config + key: MYSQL_DATABASE + volumeMounts: + - name: mysql-pv-storage + mountPath: /var/lib/mysql + subPath: mysql-data # Optional: Ensure a subdirectory is used for better volume organization + volumes: + - name: mysql-pv-storage + persistentVolumeClaim: + claimName: mysql-pvc + diff --git a/k8s/mysqlService.yml b/kubernetes/mysql-service.yaml similarity index 81% rename from k8s/mysqlService.yml rename to kubernetes/mysql-service.yaml index 8acf7b63..607a8ef2 100644 --- a/k8s/mysqlService.yml +++ b/kubernetes/mysql-service.yaml @@ -1,16 +1,14 @@ apiVersion: v1 kind: Service metadata: - name: mysql-headless + name: mysql-svc namespace: bankapp-namespace labels: app: mysql spec: - clusterIP: None selector: app: mysql ports: - protocol: TCP port: 3306 targetPort: 3306 - diff --git a/k8s/persistentVolumeClaim.yml b/kubernetes/persistent-volume-claim.yaml similarity index 61% rename from k8s/persistentVolumeClaim.yml rename to kubernetes/persistent-volume-claim.yaml index 0ac8b0a3..ff23dbd1 100644 --- a/k8s/persistentVolumeClaim.yml +++ b/kubernetes/persistent-volume-claim.yaml @@ -1,15 +1,12 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: bankapp-pvc + name: mysql-pvc namespace: bankapp-namespace - labels: - app: bankapp spec: accessModes: - ReadWriteOnce resources: requests: - storage: 5Gi - storageClassName: manual - + storage: 10Gi + storageClassName: standard diff --git a/kubernetes/persistent-volume.yaml b/kubernetes/persistent-volume.yaml new file mode 100644 index 00000000..efbda4d3 --- /dev/null +++ b/kubernetes/persistent-volume.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: mysql-pv + namespace: bankapp-namespace +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain # Keeps the PV after the PVC is deleted + storageClassName: standard # Make sure this matches your cluster's default storage class + hostPath: + path: /mnt/data/mysql + type: DirectoryOrCreate diff --git a/k8s/secrets.yml b/kubernetes/secrets.yaml similarity index 98% rename from k8s/secrets.yml rename to kubernetes/secrets.yaml index 466f15ad..c6596fdb 100644 --- a/k8s/secrets.yml +++ b/kubernetes/secrets.yaml @@ -7,4 +7,4 @@ type: Opaque data: MYSQL_ROOT_PASSWORD: VGVzdEAxMjM= # Base64 for "Test@123" SPRING_DATASOURCE_PASSWORD: VGVzdEAxMjM= # Base64 for "Test@123" - + diff --git a/nginx.md b/nginx.md new file mode 100644 index 00000000..a1da61de --- /dev/null +++ b/nginx.md @@ -0,0 +1,139 @@ +## Configure nginx as proxy server, Domain Mapping and enable SSL encryption for HTTPS. +--- + + +![Login diagram](images/login_https.png) + +### Configure nginx on your EC2. +- Install nginx + ```bash + sudo apt update + ``` +- Start nginx + ```bash + sudo systemctl start nginx + ``` + +- enable nginx + ```bash + sudo systemctl enable nginx + ``` + +- Create a new Nginx server block configuration file for our bank-app application + ```bash + sudo touch /etc/nginx/sites-available/bank-app + ``` + +- Configure server: add the following code + ```bash + server { + listen 80; + server_name bank.joakim.online; + + # Security headers + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-XSS-Protection "1; mode=block"; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # Buffer size optimizations + client_body_buffer_size 10K; + client_header_buffer_size 1k; + client_max_body_size 8m; + + # Timeouts + client_body_timeout 12; + client_header_timeout 12; + + # Rate limiting + limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; + + location / { + proxy_pass http://localhost:8080; + 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; + + # Apply rate limiting + limit_req zone=one burst=5 nodelay; + + # Error handling + proxy_intercept_errors on; + error_page 500 502 503 504 /50x.html; + } + + location ~ /\. { + deny all; + } + + # Error page + location = /50x.html { + root /usr/share/nginx/html; + internal; + } + } + ``` + +- Create a symbolic link to the configuration file in the sites-enabled directory: + ```bash + sudo ln -s /etc/nginx/sites-available/bank-app /etc/nginx/sites-enabled/ + ``` +- Test Nginx Configuration and restart nginx if test is successful + ```bash + sudo nginx -t + sudo systemctl restart nginx + ``` +- SSL certificate to the Domain. + ```bash + sudo apt install python3-certbot-nginx + ``` + ```bash + certbot --version + ``` + ```bash + certbot --nginx -d bank.joakim.online + ``` +- Verify SSL setup: + 1. Check SSL certificate: + ```bash + curl -vI https://bank.joakim.online + # Success: Look for "SSL certificate verify ok" and "HTTP/2 200" + # If failed: Check certificate path and permissions + ``` + 2. Verify automatic renewal: + ```bash + sudo certbot renew --dry-run + # Success: Look for "Congratulations, all renewals succeeded" + # If failed: Check certbot logs at /var/log/letsencrypt/letsencrypt.log + ``` + + + 3. Test HTTPS redirect: + ```bash + curl -I http://bank.joakim.online + # Success: Look for "301 Moved Permanently" and "Location: https://" + # If failed: Check Nginx configuration for proper redirect rules + ``` + +- Configure SSL parameters + ```bash + # Add to server block + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ``` + +- Backup SSL certificates + ```bash + sudo cp -r /etc/letsencrypt/live/bank.joakim.online /ssl/backup + sudo cp -r /etc/letsencrypt/archive/bank.joakim.online /ssl/backup + ``` + +- Set up automatic certificate renewal + ```bash + # Add to crontab + echo "0 0 1 * * certbot renew --quiet" | sudo tee -a /etc/crontab + ``` diff --git a/vars/buildImage.groovy b/vars/buildImage.groovy new file mode 100644 index 00000000..5cdae742 --- /dev/null +++ b/vars/buildImage.groovy @@ -0,0 +1,12 @@ +def call(String imageName){ + if (!imageName.matches('^[a-zA-Z0-9][a-zA-Z0-9_.-]*$')) { + error('Invalid image name. Must contain only alphanumeric characters, dots, dashes, and underscores') + } + + try { + sh "docker info > /dev/null 2>&1" + sh "docker build -t $imageName ." + } catch (Exception e) { + error "Docker daemon is not accessible. Please ensure Docker is running: ${e.message}" + } +} diff --git a/vars/codeCheckout.groovy b/vars/codeCheckout.groovy new file mode 100644 index 00000000..e7cb58f5 --- /dev/null +++ b/vars/codeCheckout.groovy @@ -0,0 +1,36 @@ +def call(String branch, String url, String credId) { + // Validate branch name format + if (!branch.matches('^[\\w.-]+$')) { + error("Invalid branch name format") + } + + // Validate URL format + if (!url.matches('^https?://[\\w.-]+(/[\\w.-]+)*(\\.git)?$')) { + error("Invalid git URL format") + } + + try { + timeout(time: 5, unit: 'MINUTES') { + def gitConfig = [ + branch: branch, + url: url, + changelog: true, + poll: false + ] + + if (credentialsId) { + gitConfig.credentialsId = credentialsId + } + + git(gitConfig) + } + } catch (Exception e) { + def errorMsg = "Git checkout failed:\n" + + "Branch: ${branch}\n" + + "URL: ${url}\n" + + "Error: ${e.message}" + error(errorMsg) + } + + +} \ No newline at end of file diff --git a/vars/deploy.groovy b/vars/deploy.groovy new file mode 100644 index 00000000..7c176a47 --- /dev/null +++ b/vars/deploy.groovy @@ -0,0 +1,45 @@ +def call() { + try { + // Validate environment + sh 'docker compose config -q' + + // Graceful shutdown + sh 'docker compose down --timeout 30' + + // Verify cleanup + sh ''' + if docker compose ps -q | grep -q .; then + echo "Failed to stop all containers" + exit 1 + fi + ''' + + // Start services + sh 'docker compose up -d' + +// Verify deployment + sh ''' + max_attempts=30 + attempt=1 + while [ $attempt -le $max_attempts ]; do + unhealthy_services=$(docker compose ps --format '{{.Name}}: {{.Status}}' | grep -v "(healthy)") + if [ -z "$unhealthy_services" ]; then + echo "All services are healthy" + exit 0 + else + echo "Unhealthy services detected:" + echo "$unhealthy_services" + fi + echo "Waiting for services to be healthy (attempt $attempt/$max_attempts)..." + sleep 10 + attempt=$((attempt + 1)) + done + echo "Health check timeout after $max_attempts attempts" + docker compose ps + exit 1 + ''' + } catch (Exception e) { + echo "Deployment failed: ${e.message}" + throw e + } +} diff --git a/vars/greet.groovy b/vars/greet.groovy new file mode 100644 index 00000000..b646b396 --- /dev/null +++ b/vars/greet.groovy @@ -0,0 +1,3 @@ +def call(String name){ + echo "hello ${name.replaceAll('[^a-zA-Z0-9\\s-]', '')}" +} diff --git a/vars/pushImage.groovy b/vars/pushImage.groovy new file mode 100644 index 00000000..7b0ab470 --- /dev/null +++ b/vars/pushImage.groovy @@ -0,0 +1,7 @@ +def call(String imageName){ + withCredentials([usernamePassword(credentialsId: "dockerhub", passwordVariable: 'DOCKER_PASSWD', usernameVariable: 'DOCKER_USER')]) { + sh "docker tag ${imageName} ${DOCKER_USER}/springboot-application" + sh "docker login -u${DOCKER_USER} -p${DOCKER_PASSWD}" + sh "docker push ${DOCKER_USER}/${imageName}" + } +}