DevOps Exam App - Example
- Launch Ubuntu 24.04, t2.large, 30 GB VM
Open below ports - Type: All TCP, Protocol: TCP, Port range: 0 - 65535* Type: All ICMP - IPv4, Protocol: ICMP, Port range: All Type: SSH, Protocol: TCP, Port range: 22* Type: Custom TCP, Protocol: TCP, Port range: 3000* Type: Custom TCP, Protocol: TCP, Port range: 8081 Type: Custom TCP, Protocol: TCP, Port range: 8080* Type: HTTPS, Protocol: TCP, Port range: 443* Type: Custom TCP, Protocol: TCP, Port range: 6443 Type: HTTP, Protocol: TCP, Port range: 80*
- Connect to VM
sudo su sudo apt update
- Installation of Jenkins
vi jenkins.sh ----> Paste the below commands ----> #!/bin/bash
sudo apt install openjdk-17-jre-headless -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
sudo apt-get install jenkins -y
----> esc ----> :wq ----> sudo chmod +x jenkins.sh ----> ./jenkins.sh ----> jenkins --version ----> Setup the Jenkins Dashboard
- Installation of Docker
vi docker.sh ----> Paste the below commands ----> #!/bin/bash
sudo apt-get update
sudo apt-get install -y ca-certificates curl
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
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
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
----> esc ----> :wq ----> sudo chmod +x docker.sh ----> ./docker.sh ----> docker --version
Try to pull some default image ----> docker pull hello-world ----> You will be able to pull the image. If you are unable to pull the image. Execute the below command to provide necessary permissions ----> sudo chmod 666 /var/run/docker.sock ----> docker pull hello-world ----> You will be able to pull the image
After executing docker installation commands; execute the below commands in VM;
sudo usermod -aG docker jenkins
sudo systemctl restart jenkins
sudo -u jenkins docker ps
sudo apt-get update sudo apt-get install -y python3-venv python3-pip
sudo apt-get update sudo apt-get install -y docker-compose-plugin
- Installation of Trivy
vi trivy.sh ----> Paste the below commands ----> #!/bin/bash sudo apt-get install wget apt-transport-https gnupg wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list sudo apt-get update sudo apt-get install trivy
----> esc ----> :wq ----> sudo chmod +x trivy.sh ----> ./trivy.sh ----> trivy --version
- Installation of Docker Scout
Make sure to Login to DockerHub account in browser
Goto MobaXTerm Terminal ---> Login to DockerHub ---> docker login -u ---> Click Enter ---> Enter the password of DockerHub --->
Installation of Docker Scout ---> curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /usr/local/bin ---> Give the permission to dockerScout to execute the file ---> sudo chmod 777 /var/run/docker.sock
- Installation of SonarQube
docker run -d --name sonar -p 9000:9000 sonarqube:lts-community docker images docker ps
Access SonarQube, after opening port 9000 Default username and Password: admin Set new password
- Jenkins Plugin Installation
Install below plugins; SonarQube scanner, Docker, Docker Commons, Docker Pipeline, Docker API, docker-build-step, Pipeline stage view, Email Extension Template, Kubernetes, Kubernetes CLI, Kubernetes Client API, Kubernetes Credentials, Kubernetes Credentials Provider, Config File Provider, Prometheus metrics ---> install ---> You will see error while installing Prometheus plugin. Read the error message. Here we need to restart the Jenkins ---> 'Check' the box below 'Go back to the top of page' to restart the Jenkins
- Tools Configuration in Jenkins
Goto the Jenkins console (since we restarted, login again to Jenkins) ---> Manage Jenkins ---> System Configuration ---> Tools ---> SonarQube Scanner Installations ---> Add 'SonarQube Scanner' ---> Name: sonar-scanner, 'Check' Install automatically, Version: Select the latest version 7.1.0.4889 ---> Docker Installations ---> Add Docker---> Name: docker, 'Check' Install automatically, Click on 'Add Installer', Select 'Download from docker.com', Version: latest ---> Apply ---> Save
- Docker Hub Credentials Configuration
10.1. Docker hub Credentials Configuration This is being done because, as soon as the docker image is created, it should get pushed to dockerhub. Goto the Jenkins console ---> Manage Jenkins ---> Security ---> Credentials ---> Under 'Stores scoped to Jenkins', Click on 'Global' ---> Add credentials ---> A dia ---> Kind: Username with Password, Scope: Global, Username: , Password: , ID: docker, Description: docker ---> Create ---> You can see the docker credentials got created.
Lets configure the SonarQube server; Goto SonarQube console --- Click on 'Administration' --- Click on 'Security' --- Select 'Users' --- You can see 'Tokens' --- Click on 3 dashes icon --- A New dialogue --- Name: token, Expires in: 90days --- Generate --- You can see token in green colour. Copy it. Token: squ_655a181a2da0ce3bfd088ff588e1e282f7c71a1c
Manage Jenkins --- Security --- Credentials --- Click on 'global' --- Click on 'Add Credentials' --- Kind: Secret text, Scope: Global, Secret: , ID: sonar-token, Description: sonar-token --- Create
Creation of SonarQube webhooks ----> Administration ----> 'Configuration' dropdown ----> Webhooks ----> Click on 'Create' ----> Name: jenkins, URL: :8080/sonarqube-webhook/ ---> Create
Manage Jenkins ---> System Configuration ---> System ---> Scroll down to 'SonarQube servers' ---> Click on 'Add SonarQube' ---> Name: sonar, Server URL: paste the SonarQube url. Paste only upto 9000. Dont keep / at the end, Server Authentication Token: Select the 'sonar-token' from drop down ---> Apply ---> Save
In the Docker Build & Tag Docker Image stage of pipeline, to generate the pipeline syntax, follow as below; Open Jenkins Job --- Pipeline Syntax --- Sample step: withDockerRegistry: Sets up Docker Registry Endpoint, Docker registry URL: (since its a public docker registry, we dont have to provide the docker hub URL) --- Registry credentials: Select 'docker-cred' from dropdown, Docker installation: docker --- Generate pipeline syntax --- Copy the syntax and paste in the pipeline script.
- Accessing the MySQL Database
docker exec -it mysql_db mysql -u root -p
- Common Database Operations Once connected to MySQL: -- Show all databases SHOW DATABASES;
-- Use your application database USE devops_exam;
-- Show all tables SHOW TABLES;
-- View the structure of your results table DESCRIBE results;
-- View all exam results SELECT * FROM results;
-- View results sorted by score (highest first) SELECT * FROM results ORDER BY score DESC;
-- View average score SELECT AVG(score) FROM results;
-- View number of submissions SELECT COUNT(*) FROM results;
pipeline { agent any
environment {
DOCKER_IMAGE = "kastrov/devopsexamapp:latest"
SCANNER_HOME = tool 'sonar-scanner'
}
stages {
stage('Git Checkout') {
steps {
git url: 'https://github.com/KastroVKiran/devops-exam-app.git',
branch: 'master'
}
}
stage('File System Scan') {
steps {
sh "trivy fs --security-checks vuln,config --format table -o trivy-fs-report.html ."
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('sonar') {
sh """
${SCANNER_HOME}/bin/sonar-scanner \
-Dsonar.projectName=devops-exam-app \
-Dsonar.projectKey=devops-exam-app \
-Dsonar.sources=. \
-Dsonar.language=py \
-Dsonar.python.version=3 \
-Dsonar.host.url=http://localhost:9000
"""
}
}
}
stage('Verify Docker Compose') {
steps {
sh '''
docker compose version || { echo "Docker Compose not available"; exit 1; }
'''
}
}
stage('Build Docker Image') {
steps {
dir('backend') {
script {
withDockerRegistry(credentialsId: 'docker', toolName: 'docker') {
sh "docker build -t ${DOCKER_IMAGE} ."
// Push the image to Docker Hub if needed
sh "docker push ${DOCKER_IMAGE}"
}
}
}
}
}
// Added Docker Scout Image Analysis
stage('Docker Scout Image Analysis') {
steps {
script {
withDockerRegistry(credentialsId: 'docker', toolName: 'docker') {
sh "docker-scout quickview ${DOCKER_IMAGE}"
sh "docker-scout cves ${DOCKER_IMAGE}"
sh "docker-scout recommendations ${DOCKER_IMAGE}"
}
}
}
}
stage('Deploy with Docker Compose') {
steps {
sh '''
# Clean up any existing containers
docker compose down --remove-orphans || true
# Start services with build
docker compose up -d --build
# Wait for MySQL to be ready
echo "Waiting for MySQL to be ready..."
timeout 120s bash -c '
while ! docker compose exec -T mysql mysqladmin ping -uroot -prootpass --silent;
do
sleep 5;
docker compose logs mysql --tail=5 || true;
done'
# Additional wait for full initialization
sleep 10
'''
}
}
stage('Verify Deployment') {
steps {
sh '''
echo "=== Container Status ==="
docker compose ps -a
echo "=== Testing Flask Endpoint ==="
curl -I http://localhost:5000 || true
'''
}
}
}
post {
success {
echo '๐ Deployment successful!'
sh 'docker compose ps'
archiveArtifacts artifacts: 'trivy-fs-report.html', allowEmptyArchive: true
}
failure {
echo 'โ Pipeline failed. Check logs above.'
sh '''
echo "=== Error Investigation ==="
docker compose logs --tail=50 || true
'''
}
always {
sh '''
echo "=== Final Logs ==="
docker compose logs --tail=20 || true
'''
archiveArtifacts artifacts: 'trivy-fs-report.html', allowEmptyArchive: true
}
}
}