Skip to main content

Command Palette

Search for a command to run...

DevSecOps CICD Pipelines with EKS deployment using ArgoCD

Published
19 min read

1. Application Layer

  • Frontend → Built with React.js

  • Backend → Built with Node.js

  • Database → Uses MongoDB

  • Repository → Code is stored and version-controlled in GitHub

This is the actual application stack that the DevSecOps pipeline will deploy.


2. Master Machine (Provisioning & Infrastructure as Code)

  • Uses Terraform to set up cloud resources.

  • IAM, Key Pairs, Security Groups → Handle authentication, authorization, and secure access.

  • Master Machine (EC2 t2.large) → The main control node for provisioning infrastructure.


3. Kubernetes Cluster (EKS on AWS)

  • Terraform provisions an EKS (Elastic Kubernetes Service) cluster.

  • Takes ~20 minutes to set up.

  • Node 1 & Node 2 → Worker nodes where the application containers will actually run.

  • Kubernetes (K8s) manages scaling, deployments, and networking.


4. DevSecOps Pipeline

  • Jenkins → CI/CD pipeline automation.

  • Trivy → Container vulnerability scanning.

  • OWASP Dependency-Check → Scans code dependencies for security issues.

  • SonarQube → Code quality and bug detection.

  • Docker → Builds application images.

  • Mail Notification → Alerts developers about pipeline results.

This ensures secure, automated builds and deployments.


5. GitOps Workflow

  • Developers push code to GitHub Repo.

  • ArgoCD continuously syncs GitHub with the Kubernetes cluster (GitOps model).

  • This ensures deployments are automated and version-controlled.


6. Monitoring & Observability

  • Prometheus → Metrics collection (CPU, memory, latency, etc.)

  • Grafana → Dashboards and visualizations.

  • Helm → Package manager for Kubernetes, used to install Prometheus/Grafana.

This ensures the system is observable, reliable, and secure.


🔑 Abstract Summary

This architecture represents a DevSecOps-driven CI/CD pipeline for deploying a cloud-native application on AWS EKS:

  • Infrastructure automated by Terraform.

  • Security integrated with Trivy, OWASP, SonarQube.

  • Delivery automated using Jenkins + GitOps (ArgoCD).

  • Monitoring enabled with Prometheus & Grafana.

It combines DevOps + Security (Sec) + Cloud (AWS + K8s) + GitOps into a mega project pipeline.

step-01:- start with terraform

step- a:- install aws CLI

for this fist create a new user

Then attach the policies and grant administrative access.

click on user

Go to the Security Credentials section

then go to the access keys

create new branch in github

then go on vs code

create a new folder

now go to the terraform

Now, go there and create one.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs

here use provider

Now, create a variables.tf file to specify the region.

We are now using this variable, so we can apply it for this purpose.

Now we want a public key in the Terraform folder because it is used in EC2.tf.

so, we use ssh-keygen

If you want to make any changes, such as volume or tags, you can change them yourself.

If your Terraform version is old, go to the link below and download the latest version.

After downloading, extract it. To do this, double-click on the folder where you saved Terraform.

Then, you will see another folder. Go inside that folder

copy terraform

and paste it on your folder where you want to use terraform

Then write correct path of you terraform where you store it

then terraform init

then write terrraform plan

now create output.tf

inside this

now do terraform apply

step-02:- start with Docker

install Docker Extension

now find an image in DockerHub

now create a docker file

✅ What is Maven?

Maven is a build automation tool used primarily for Java projects.

🔧 Its Main Purposes:

  1. ✅ Dependency Management:
    Automatically downloads and manages the libraries (JAR files) your project depends on.

  2. ✅ Build Automation:
    Compile code, run tests, package applications, generate reports, and deploy artifacts.

  3. ✅ Project Structure Standardization:
    Encourages a standard project directory layout (like src/main/java, src/test/java, etc.).

✅ What is a JAR file?

🔹 JAR = Java ARchive

👉 The JAR file is the final product of the Maven build process.

It contains:

  • Your compiled code

  • All resources needed at runtime

Here, for the OS image, search on Google and download it

To run it, get the installation command from Google or the Maven installation site.

but here test cases are empty

so we have to write below

also give name of this stage

in this asked maven stored compiled java classes into “target” folder

We should copy only the generated JAR file from the target directory into the Docker image, so it can be run by the container.

now lets buid a docker file

first give correct path

before run please open Docker Desktop . if you do not open Docker desktop then it is not working

Here first we login Docker

now go on Docker Hub for login

go on account setting

inside this create a personal access token

HERE we also show this

now here we add terraform private key,lock file,terraform tfstate,terraform provider,licence in .gitignore

for this go into source code

double click on file

Now, to work on your EC2 instanc

open a gitbash

i found some error so i recreate the keys

successfully logined

now we do a docker ps

but it shows error

now it is successfully run

this code commit above where write mega-project has recent pushes. clicked on this compare & pull request

clone code

here i did a mistake i have to write Dockerfile instead of DockerFile

step-03:- start with EKS

Step:- 1 Create a Cluster

step a:- for this first install a CLIv2

Link:- https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html

download for Liniux

step b:- for this first install a EKSctl

Link:- https://eksctl.io/installation/

copy this and create below for pate

Now open aws and search EKS

step c:- create a controler manager

before it note down that if you stop EC2 instance than take a new IPv4 . old ipv4 not worked

for checkout EKS latest version

so we take 1.33 version

it shows an error because we have not install kubectl. so we install kubectl

what is kubectl

kubectl is the command-line tool used to interact with a Kubernetes cluster. Think of it as the "remote control" for managing Kubernetes resources (pods, deployments, services, etc.).

link:- https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/

now working

now go on

here shows we had not add any node. so we add node but before add node we add IAM OIDC provider

🔑 What is an IAM OIDC Provider?

  • OIDC = OpenID Connect, an identity layer built on top of OAuth 2.0.

  • In AWS, an IAM OIDC identity provider allows you to federate identities from an OIDC-compatible IdP (like Kubernetes, Okta, Google, GitHub, etc.) to AWS.

  • Instead of managing IAM users/keys, you let external identities authenticate and assume IAM roles.


🚀 Why is it used?

  1. EKS (Kubernetes on AWS)

    • In EKS, workloads (pods) need to access AWS services (like S3, DynamoDB, Secrets Manager).

    • Instead of storing AWS credentials inside pods, you configure an IAM OIDC provider for your cluster.

    • Then you create IAM roles for service accounts (IRSA) → Pods can assume those roles securely.

  2. Federated Login

    • You can allow users from an external IdP (Okta, Azure AD, Google, etc.) to assume AWS roles via OIDC.

here you show identity providers

now we create it

now we create a node group

it is not working again try

successfull

here we will not show control plan because in EKS it is managed by AWS

click on this and checkout

can you see two cluster

click on eksctl-bankapp-cluster-cluster

click on control panel security group id

click on this id

here you manage inbound rule and outbound rule

When you create a Kubernetes cluster through EKS, a personal VPC is also created automatically.

click on this id

ou have not created this template. For this, you can use tools such as the Serverless Framework.

if you want to create infrastructure on AWS lambda then use serverless

if you wan to create infrastructure on EKS then use eksctl

Step:- 2 Create a namespace,pod,deployment,service,ingress

Here, the BankApp also uses a database in the backend, so we created mysql-deployment.yml and mysql-service.yml

We also need to create secrets.yml, persistent-volume.yml, persistent-volume-claim.yml, configmap.yml, vpa.yml, and hpa.yml

now for this first install extension for kubernetes

let’s first create a backapp-namespace.yml

kind: Namespace
apiVersion: v1
metadata:
  name: bankapp-namespace
  labels:
    app: bankapp-namespace

Now, let's create bankapp-deployment.yml

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: bhagyapatel123/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"

but before we have not publish docker images so, now we have publish a docker images

Here, we need to publish the Docker image, which means we have to push it to Docker Hub. However, it cannot be pushed directly.

now push it in docker hub

now bakapp-service.yml

apiVersion: v1      
kind: Service
metadata:
  name: bankapp-service
  namespace: bankapp-namespace
  labels:
    app: bankapp
spec:
  selector:
    app: bankapp-deploy
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

now bankapp-ingress.yml

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

now mysql-deployment.yml

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

now mysql-service.yml

apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
  namespace: bankapp-namespace
  labels:
    app: mysql
spec:
  selector:
    app: mysql
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306

now secrets.yml

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: bankapp-namespace
type: Opaque
data:
  MYSQL_ROOT_PASSWORD: VGVzdEAxMjM=  # Base64 for "Test@123"
  SPRING_DATASOURCE_PASSWORD: VGVzdEAxMjM= # Base64 for "Test@123"

now persistent-volume.yml

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

now persistent-volume-claim.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: bankapp-namespace
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: standard

now configmap.yml

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

now hpa.yml

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

now do git commit

step-04:- start with ArgoCD

start it in cluster

now we have to download official arogocd manifest file

but please try below command

step -01:- now Download ArgoCDCLI

Link:- https://argo-cd.readthedocs.io/en/stable/cli_installation/

here we show argocd server is running on port 80

now we give address of argocd-server

which service type is which allows you to expose a port number ?

ans: NodePort (Here N and P both are capital letter)

so,

now you can see it becomes a NodePort

also you show new port number 30571. in this port your argocd server is running

Now, you have to edit the inbound rules for one worker node to allow port 30571. Since all nodes are connected to each other, any change made on one should also be applied to the others.

go in second one

now take a this worker node public IPV4 address

now we take is as http

also you see this

now go in advanced

now click on proceed

now it is working correctly

now for username and password

use username as “admin”

and password shows after below command

now it is successfully open

now in this go on Accounts

now go on user info

click on update password

now login

but in this it has a default cluster. i want to add my EKS cluster

for this first find a URL

this is my cluster URL. i want add this

now check it on GUI

successfully i created

now go to the repository

connect repo

now connect it

now create new application

click on new app

SYNS means automatically deploy when we change on github , prune resources means when new code comes old is deleted, self heal ,Auto-create namespace means if i forget to create namespace then it will automatically create it

revision means branch

path means where are kubernetes menifest file.

now this source manifest file in which cluster deploy for these we used a destination

now create it

click on these

it shows error. now check logs

i understand my problem here i take v2 and in docker image i take v1

successful

now in security group also add 32418 port

in this if you want than also add a range like 30000-32767

check this our bankapp correctly working

step-01:- register for domain

register domain

after that it will be created.

i don’t want so i don’t create this

but if you use domain then also change in ingress

in host we take a domain

step -2: kubernetes service.yml manifest file

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.bhagyapatel.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: bankapp-service
            port:
              number: 8080

but we have not domain then start manually

But to run these, you also need an Ingress controller. Here, we are using NGINX as the Ingress controller.

But before this, we need to add the controller. So first, install the NGINX controller.

now install nginx controler through helm

first helm install

helm is package manager. through helm you deploy in cluster

now add it for this search command

now install ingress-nginx

successful

these is the ip of these

here you completely show nginx. it is not error. it shows nginx

now we will apply ingress

here we have not domain so we take svc URL. because it is free

so take these

so change inside these

successful

but here we show mot secure

now we convert it to https

means we do here SSL

step -03:- now we do cert manager

Cert-Manager is an open-source Kubernetes add-on that automates the management and issuance of TLS/SSL certificates.

🔑 What it does:

  • Automatically requests certificates from certificate authorities (CAs) like Let’s Encrypt, HashiCorp Vault, or custom CAs.

  • Renews certificates before they expire (so no downtime due to expired certs).

  • Stores certificates securely in Kubernetes secrets.

  • Makes it easy to enable HTTPS for your applications in Kubernetes.

LInk:- https://github.com/cert-manager/cert-manager

for downloads

now i have to create cert-issuer

in github you shows name inside metadata

acme server means which server help issue these certificate

means server gives you certificate

inside these

we add these

it takes some time . it shows certificate detail

in this it shows these

now i check it

please copy all two file code ingress and certificate code

and change in github

but here i have not any Domain so TLB not working.

for TLB Domain name required

👉 Reason: Let’s Encrypt only issues certificates for valid domain names you control.
It will not issue for AWS ELB hostnames (they belong to Amazon, not you). That’s why your cert is stuck in False.

here i requested but it is not issued

now it shows these error so go back

now correctly working

step-05:- start with Jenkins

first inatallation java

then take these

Jenkins by default running on 8080 port number.

and also our bank app is running on same port numer.

so ,

change these port number 8080 to 8081

here also shows admin password

here we install jenkins into t2.large server

so add inside rule in t2.large

take public ip

using these jenkins server you build a Docker

through Argocd upload manifest

now create job

click on pipeline

before writing full pipeline add credential for docker hub . it is help when we try to push

now go on setting

then go to the credential

now click on global

add credential

click bankapp-ci

and go in configure

pipeline {
    agent any

    stages {
        stage("Code Clone") {
            steps {
                git url: 'https://github.com/bhagya-patel/DevOps-SPRINGBOOT-BANKAPP.git', branch: 'mega-project'
            }
        }

        stage("Build") {
            steps {
                sh 'docker build -t bankapp-eks:v1 .'
            }
        }

        stage("Push") {
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'dockerHub',
                    usernameVariable: 'dockerHubUser',
                    passwordVariable: 'dockerHubPassword'
                )]) {
                    sh 'docker login -u $dockerHubUser -p $dockerHubPassword'
                    sh 'docker image tag bankapp-eks:v1 $dockerHubUser/bankapp-eks:v1'
                    sh 'docker push $dockerHubUser/bankapp-eks:v1'
                }
            }
        }
    }
}

save and apply

click on run button

it is failed checked in console output

but i take dockerfile code in main branch so i used main branch then it shows correct

pipeline {
    agent any

    stages {
        stage("Code Clone") {
            steps {
                git url: 'https://github.com/bhagya-patel/DevOps-SPRINGBOOT-BANKAPP.git', branch: 'main'
            }
        }

        stage("Build") {
            steps {
                sh 'docker build -t bankapp-eks:v1 .'
            }
        }

        stage("Push") {
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'dockerHub',
                    usernameVariable: 'dockerHubUser',
                    passwordVariable: 'dockerHubPassword'
                )]) {
                    sh 'docker login -u $dockerHubUser -p $dockerHubPassword'
                    sh 'docker image tag bankapp-eks:v1 $dockerHubUser/bankapp-eks:v1'
                    sh 'docker push $dockerHubUser/bankapp-eks:v1'
                }
            }
        }
    }
}

done

step-06:- start with SonarQube

now we add sonarqube in t2.large inbound rules

now it is working

in this initially password is admin and user is also admin

go in administration

i want to sonar qube communate with jenkins. for these

click on user

now update tokens for communate with jenkins

write name and click on generate. then it is generate

now go in jenkins credential

clicked on global of Stores scoped to Jenkins

add credentials

first install sonar plugging

install it

now integret with jenkins for these

click on system

here add sonar qube server

take like these sonar URL

save then

Now we have to install sonarqube version

now go into the tools

step-06:- start with trivy

add this into jenkins pipeline

save it

when jenkins pipeline running then also sonarqube running . for these webHook requiered

click on webHooks

click on create

take jenkins URL. bul last add sonarqube-webhook.

secret is not required

sonar qube is not working correctly so i take only Trive

step-07:- start with observability

and now open it in t2.medium which is used before please open these

using these command you show password

and username is admin

successfully logined

here you show prometheus

go to your dashboard

if i want to monitor my pods then click on these

choose namespace as a bankapp-namespace

now delete cluster

successfully created these project

Note: - iam not able to add security tools like SonarQube or Mail in these. i just add a Trivy