This project involves the integration of Jenkins, Kubernetes, Docker, Nexus Repository, SonarQube, Prometheus, and Grafana to create a robust CI/CD pipeline for automated application deployment and monitoring. The primary objectives are to automate the build, test, and deployment processes, ensure code quality and security, and provide real-time monitoring of the deployed applications. The project focuses on a full-stack application developed in Java, ensuring comprehensive coverage from backend to frontend in the deployment pipeline.
In this Project we will be Creating 7 EC2 instances. One to run kubernetes master node, two slave nodes. One to run jenkins pipeline for our CI/CD one for nexus repository, sonarqube and for monitoring (Prometheus & grafana)
-
Sign in to the AWS management console:
- Go to the AWS Management Console
- Sign in with your AWS account details
-
Navigate to EC2:
- Search for "EC2" in the search bar
-
Launch Instance:
- Click "instances" in the EC2 dashboard.
- Click the "Launch Instance" button
-
Choose an Amazon Machine Image (AMI)
- Select "Ubuntu" from the list of available AMIs
- Choose "Ubuntu Server 24.04 LTS"
- confirm changes
-
Choose an Instance type:
- Select an instance type (e.g t2 micro for testing)
- Click "Next: Configure Instance Details"
-
Create or Select a Key pair
- Select keypair which will be used to log into the Ec2 instance
-
Create or Select existing security group
-
Configure storage For kubernetes
- increase the root volume to 30 GB to ensure enough space to work on the application.
-
Review and Launch
-
Access the instance Connect to the instance using SSH.
Set up Docker on the EC2 instance:
- Install prerequsite packages:
sudo apt-get update
sudo apt-get install ca-certificates curl
- Download and add Docker's official GPG key:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
- Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
- Update package index
sudo apt-get update
- Install docker packages
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin.
- Update the system
sudo apt-get update
sudo apt-get upgrade -y
- Install java (Jenkins requires Java)
sudo apt install openjdk-17-jre-headless
- Add jenkins repository key
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
- Add Jenkins repository
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
- Update the package index.
sudo apt-get update
- Install jenkins
sudo apt-get install jenkins -y
- Start and enable Jenkins
sudo systemctl start jenkins
sudo systemctl enable jenkins
- Access Jenkins:
Open a web browser and go to
http://your_server_ip:8080
.
- Install prerequisite packages:
sudo apt-get update
sudo apt-get install -y wget apt-transport-https gnupg lsb-release
- Add Trivy GPG key
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
- Add Trivy repository to APT sources
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" \
| sudo tee /etc/apt/sources.list.d/trivy.list > /dev/null
- Update APT package index
sudo apt-get update
- Install Trivy
sudo apt-get install -y trivy
vi k.sh
paste the command below into the file
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
change file permission to be executable
sudo chmod +x k.sh
run and install
./k.sh
- Pull the nexus Docker image
sudo docker pull sonatype/nexus3
- Run the Nexus container
sudo docker run -d --name Nexus -p 8081:8081 sonatype/nexus3
- Access Nexus
- Run PostgreSQL container
docker run -d --name sonar -p 9000:9000 sonarqube:lts-community
-
Create repository on github
-
clone soource code
git clone https://github.com/Tosin-webdev/boardgame.git
- Initialize git repository
git init
- Add remote repository
git remote add origin https://github.com/Tosin-webdev/boardgame.git
- Navigate to the directory containing source code
cd boardgame
- Add files to git
git add .
- commit files:
git commit -m "Initial commit"
- Push to Github
git push -u origin master
Step 1 - Install neccessary plugins in jenkins Go to manage Jenkins --> Plugins --> Avaliable plugins --> Install Below plugins
- Eclipse termurin Installer
- Sonarqube scanner
- Docker
- Docker pippeline
- Email Extension plugin
- maven
- config file provider
- pipeline maven integration
- kubernetes
- kubernetes credentials
- kubernetes client API
- kubernetes CLI
Goto Manage Jenkins → Tools → Install JDK(17), maven(3), docker,SonarQube Scanner → Click on Apply and Save
-
Navigate to Manage Jenkins.
-
Select Global Tool Configuration.
-
Install the following tools:
- JDK (17)
- Maven (3)
- Docker
- SonarQube Scanner Click Apply and Save to save the configurations.
- Navigate to the Jenkins Dashboard.
- Select Manage Jenkins.
- Choose Manage Credentials.
- Add Docker Hub credentials:
- Click on (global) under Stores scoped to Jenkins.
- Click on Add Credentials.
- Choose Username with password as the kind.
- Fill in the Username and Password with your Docker Hub credentials.
- Provide an ID and Description. Click OK to save the credential
Add credentials for git, sonar and kubernetes.
pipeline {
agent any
tools {
jdk 'jdk17'
maven 'maven3'
}
// Define environment variables
environment {
SCANNER_HOME = tool 'sonar-scanner'
}
stages {
stage('Git checkout') {
steps {
// Checkout code from git
git branch: 'main', credentialsId: 'git-cred', url: 'https://github.com/Tosin-webdev/boardgame'
}
}
stage('Compile') {
steps {
sh 'mvn compile'
}
}
stage('File System Scan') {
steps {
sh 'trivy fs --format table -o trivy-fs-report.html .'
}
}
stage('SonarQube Analysis') {
steps {
// Run SonarQube analysis to check code quality
withSonarQubeEnv('sonar') {
sh '''$SCANNER_HOME/bin/sonar-scanner -Dsonar.projectName=BoardGame -Dsonar.projectKey=BoardGame \
-Dsonar.java.binaries=.'''
}
}
}
stage('Build') {
// Use Maven to build the project
steps {
sh 'mvn package'
}
}
stage('Publish to Nexus') {
steps {
withMaven(globalMavenSettingsConfig: 'global-settings', jdk: 'jdk17', maven: 'maven3', mavenSettingsConfig: '', traceability: true) {
sh 'mvn deploy'
}
}
}
stage('Build and Tag Docker Image') {
steps {
withDockerRegistry(credentialsId: 'docker-cred', url: 'https://index.docker.io/v1/') {
// Build a Docker image from the Dockerfile
sh 'docker build -t blackcypher01/boardgame:latest .'
}
}
}
stage('Docker Image Scan') {
steps {
sh 'trivy image --format table -o trivy-image-report.html blackcypher01/boardgame:latest'
}
}
stage('Push Docker Image') {
steps {
withDockerRegistry(credentialsId: 'docker-cred', url: 'https://index.docker.io/v1/') {
// Push the Docker image to Docker Hub
sh 'docker push blackcypher01/boardgame:latest'
}
}
}
stage('Deploy to Kubernetes') {
steps {
withKubeConfig(caCertificate: '', clusterName: 'kubernetes', contextName: '', credentialsId: 'k8-cred', namespace: 'webapps', restrictKubeConfigAccess: false, serverUrl: 'https://172.31.59.153:6443') {
// Apply Kubernetes configurations to deploy the application
sh 'kubectl apply -f deployment-service.yaml'
}
}
}
stage('Verify the Deployment') {
steps {
withKubeConfig(caCertificate: '', clusterName: 'kubernetes', contextName: '', credentialsId: 'k8-cred', namespace: 'webapps', restrictKubeConfigAccess: false, serverUrl: 'https://172.31.59.153:6443') {
sh 'kubectl get pods -n webapps'
sh 'kubectl get svc -n webapps'
}
}
}
}
post {
always {
script {
def jobName = env.JOB_NAME
def buildNumber = env.BUILD_NUMBER
def pipelineStatus = currentBuild.result ?: 'UNKNOWN'
def bannerColor = pipelineStatus.toUpperCase() == 'SUCCESS' ? 'green' : 'red'
def body = """
<html>
<body>
<div style="border: 4px solid ${bannerColor}; padding: 10px;">
<h2>${jobName} - Build ${buildNumber}</h2>
<div style="background-color: ${bannerColor}; padding: 10px;">
<h3 style="color: white;">Pipeline Status: ${pipelineStatus.toUpperCase()}</h3>
</div>
<p>Check the <a href="${BUILD_URL}">console output</a>.</p>
</div>
</body>
</html>
"""
emailext (
subject: "${jobName} - Build ${buildNumber} - ${pipelineStatus.toUpperCase()}",
body: body,
to: '[email protected]',
from: '[email protected]',
replyTo: '[email protected]',
mimeType: 'text/html',
attachmentsPattern: 'trivy-image-report.html'
)
}
}
}
}
- Create a service account YAML file Open your text editor to create a new file named svc.yaml:
vi svc.yaml
- paste the following configuration into the file
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: webapps
- Create a namespace and apply the service account
kubectl create ns webapps
kubectl apply -f svc.yaml
- Create a role YAML file:
Open your text editor to create a new file named
role.yaml
:
vi role.yaml
- paste the following configuration into the file
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
namespace: webapps
rules:
- apiGroups:
- "" # Core API group
- apps
- autoscaling
- batch
- extensions
- policy
- rbac.authorization.k8s.io
resources:
- pods
- componentstatuses
- configmaps
- daemonsets
- deployments
- events
- endpoints
- horizontalpodautoscalers
- ingress
- jobs
- limitranges
- namespaces
- nodes
- pods # Duplicate entry, remove if not necessary
- persistentvolumes
- persistentvolumeclaims
- resourcequotas
- replicasets
- replicationcontrollers
- serviceaccounts
- services
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- Apply the role configuration
kubectl apply -f role.yaml
- Create a role binding YAML file
Open your text editor to create a new file named bind.yaml:
vi bind.yaml
- Paste the following configuration into the file:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-rolebinding
namespace: webapps
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: app-role
subjects:
- namespace: webapps
kind: ServiceAccount
name: jenkins
save and run the command
- apply the role binding configuration
kubectl appply -f bind.yaml
Now the user we created have permision to perform deployment.
- Create a secret YAML file
open your text editor to create a new file name
sec.yaml
vi sec.yaml
- Paste the following configuration into the file:
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: mysecretname
annotations:
kubernetes.io/service-account.name: jenkins
- Apply the secret configuration:
Provide the name of the namespace and apply:
kubectl apply -f sec.yaml -n webapps
- Get the token for jenkins kubernetes authentication
kubectl describe secret mysecretname -n webapps
Copy the token from the output and use it for Jenkins Kubernetes authentication.
- Create a deployment YAML File
open your text editor to create a new file named deployment-service.yaml
vi deployment.yaml
- Paste the following configuration into the file
apiVersion: apps/v1
kind: Deployment # Kubernetes resource kind we are creating
metadata:
name: boardgame-deployment
spec:
selector:
matchLabels:
app: boardgame
replicas: 2 # Number of replicas that will be created for this deployment
template:
metadata:
labels:
app: boardgame
spec:
containers:
- name: boardgame
image: adijaiswal/boardgame:latest # Image that will be used to containers in the cluster
imagePullPolicy: Always
ports:
- containerPort: 8080 # The port that the container is running on in the cluster
---
apiVersion: v1 # Kubernetes API version
kind: Service # Kubernetes resource kind we are creating
metadata: # Metadata of the resource kind we are creating
name: boardgame-ssvc
spec:
selector:
app: boardgame
ports:
- protocol: "TCP"
port: 8080 # The port that the service is running on in the cluster
targetPort: 8080 # The port exposed by the service
type: LoadBalancer # type of the service.
-
Trigger the pipeline:
- Go to the Jenkins Dashboard.
- Select the pipeline job you created.
- Click Build Now.
Access your appliation using slave 1 ip and your kubernetes cluster port
In this set you will set up prometheus, grafana, node-exporter, blackbox-exporter
- Install prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
- Extract prometheus
tar -xzvf prometheus-2.52.0.linux-amd64.tar.gz
- Move to the extracted directory
cd prometheus-2.53.0.linus-amd-64
- Run prometheus
./prometheus &
- Verify prometheus is running
Open a web browser and navigate to
http://your_server_ip::9090
- Download Node exporter:
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
- Extract the Tarball
tar -xzvf node_exporter-1.8.1.linux-amd64.tar.gz
- move to the extracted directory
cd node_exporter-1.8.1.linux-amd64
- Run Node Exporter
./node_exporter
- Verify Node Exporter Open a web browser and navigate to http://your_server_ip:9100/metrics
- Download blackbox exporter
wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.25.0/blackbox_exporter-0.25.0.linux-amd64.tar.gz
- Extract the tarball
tar -xzvf blackbox_exporter-0.25.0.linux-amd64.tar.gz
- Move to the Extracted Directory
cd blackbox_exporter-0.25.0.linux-amd64
- Run Blackbox exporter
./blackbox_exporter &
- Verify Blackbox Exporter is running
Open a web browser and navigate to http://localhost:9115/metrics.
- Install Dependencies
- Update Package list
- sudo apt-get update
- Download nd Install grafana
- Download the grafana engterprise package
wget https://dl.grafana.com/enterprise/release/grafana-
enterprise_11.0.0_amd64.deb
- Install grafana using dpkg
sudo dpkg -i grafana-enterprise_11.0.0_amd64.deb
-
Start and Enable Grafana
- Start the Grafana service: sudo system start grafan-server
- Enable the Grafana service to start on boot: sudo systemctl enable grafana-server
-
Access grafana
- Open web browser and navaigate to http://your_server_ip:3000
- Log into grafana
- The default username is admin
- The default password is admin
- Change the default password Upon first login, you will be prompted to change the default password. Enter a new password and confirm it.
-
Configure grafana
-
Add a data Source
- Navigate to configurations > Data sources
- Click Add data source
- Choose your desires data source type (prometheus)
- Configure the data source with the appropriate URL (e.g Your server URL)
- CLick save &test
-
Create a dashboard
- Navigate to create > dashboard.
- Add panels and configure quesroies to visualize metrics
- save the dashboard
To make it easier to view metrics, you can import a pre configured dashboard. FOllow these steps:
- Clik on the + plus icon in the left sidebar to open the "create" menu
- Select "Dashboard"
- Click on the "Import" dashboard option
- Enter the code you want to import (e.g code 1860))
- click the "load" button
- Select the data source you added (prometheus) from the dropdown
- Click on the import button You should now have grafana dashnoard set up to visualize metrics from prometheus.