"Mastering DevOps with a Real-World Netflix Clone: CI/CD, Kubernetes, Docker, Monitoring & DevSecOps in Action"

Hello DevOps enthusiasts! π
In this project, we'll walk through the deployment of a fully functional Netflix Clone using modern DevOps practices. Our CI/CD pipeline will be built using Jenkins, which will automate the build, test, and deployment processes. The application itself will run inside Docker containers, orchestrated by a Kubernetes cluster for high availability and scalability.
To ensure observability and maintain system health, weβll integrate Prometheus, Grafana, and Node Exporter to monitor both Jenkins pipelines and Kubernetes metrics in real time.
This blog is a complete, hands-on guide that combines infrastructure automation, containerization, orchestration, and monitoring β everything you'd expect in a real-world DevOps workflow. I hope you find it insightful and valuable!
β Step 1 β Launch EC2 Instance
π» Deploy a T2 Large Ubuntu 22.04 instance on AWS to serve as the base environment.
π οΈ Step 2 β Install Jenkins, Docker & Trivy
βοΈ Set up Jenkins, Docker, and Trivy; then run SonarQube in a Docker container.
π Step 3 β Create TMDB API Key
π Generate an API key from TMDB to fetch movie data for the application.
π Step 4 β Install Prometheus & Grafana
π Set up Prometheus for monitoring and Grafana for visualizing system metrics.
π Step 5 β Integrate Jenkins with Prometheus
π Install the Prometheus plugin in Jenkins and connect it with the Prometheus server.
π§ Step 6 β Configure Jenkins Email Alerts
βοΈ Set up SMTP email integration in Jenkins for real-time build notifications.
π¦ Step 7 β Install Essential Jenkins Plugins
π§ Add plugins for JDK, Node.js, SonarQube Scanner, and OWASP Dependency Check.
π§© Step 8 β Create Jenkins Declarative Pipeline
π Define a declarative pipeline script in Jenkins for CI/CD automation.
π‘οΈ Step 9 β Set Up OWASP Dependency Check
π Enable OWASP Dependency Check Plugin for vulnerability scanning of dependencies.
π³ Step 10 β Build & Push Docker Image
π€ Build the Docker image of your app and push it to Docker Hub or another registry.
π’ Step 11 β Deploy Docker Container
π¦ Run the Docker container and expose it to make the app accessible.
βΈοΈ Step 12 β Set Up Kubernetes Cluster
π‘ Configure Kubernetes master and worker nodes using Ubuntu 20.04 instances.
π Step 13 β Access the Netflix App
π₯οΈ Open the app in your browser and verify its functionality and UI.
π Step 14 β Terminate AWS Resources
π Shut down all EC2 instances to avoid unnecessary charges.
ποΈ Implementation Steps
Below is the step-by-step process to implement the entire DevOps pipeline:-
STEP 1: Launch an Ubuntu (22.04) T2 Large Instance
Launch an AWS T2 Large Instance. Use Ubuntu 22.04 as the image. You can create a new key pair or use an existing one. Enable HTTP and HTTPS in the Security Group and open all ports (not recommended for production, but okay for learning purposes).

STEP 2A : Install Jenkins, Docker, and Trivy
- Connect to your console, and enter these commands to Install Jenkins
#!/bin/bash
sudo apt update -y
#sudo apt upgrade -y
wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | tee /etc/apt/keyrings/adoptium.asc
echo "deb [signed-by=/etc/apt/keyrings/adoptium.asc] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list
sudo apt update -y
sudo apt install temurin-17-jdk -y
/usr/bin/java --version
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
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 systemctl start jenkins
sudo systemctl status jenkins
vi jenkins.sh #make sure run in Root (or) add at userdata while ec2 launch
sudo chmod 777 jenkins.sh
./jenkins.sh # this will installl jenkins
Once Jenkins is installed, go to your AWS EC2 Security Group and open Inbound Port 8080, since Jenkins runs on that port.
Now, grab your Public IP Address of the EC2 instance.
You can access Jenkins in your browser using:
<EC2 Public IP Address:8080>
sudo cat /var/lib/jenkins/secrets/initialAdminPassword


Jenkins will now get installed and install all the libraries.

Create a user click on save and continue.
Jenkins Getting Started Screen.

STEP 2B : Install Docker
sudo apt-get update
sudo apt-get install docker.io -y
sudo usermod -aG docker $USER #my case is ubuntu
newgrp docker
sudo chmod 777 /var/run/docker.sock
Once Docker is installed, launch a SonarQube container.
Make sure to open port 9000 in the Security Group, as SonarQube runs on that port.
docker run -d --name sonar -p 9000:9000 sonarqube:lts-community

SonarQube is now successfully up and running.

Log in to SonarQube using the default credentials:
Username: admin
Password: admin
Set your new password.
You will now be redirected to the SonarQube Dashboard.

You will now see the SonarQube Dashboard appear below.

STEP 2C : Install Trivy
vi trivy.sh
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
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 $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy -y
STEP 3 : Generate a TMDB API Key
Now, let's create an API key from The Movie Database (TMDB).
Open a new browser tab and search for βTMDBβ to get started.

As soon as you access the TMDB site, youβll see a page similar to the one shown below.

Click on βLoginβ at the top-right corner. Youβll be redirected to the login page.
If you donβt have an account, click on βClick hereβ to sign up.
(Since I already had an account, I simply entered my credentials.)

once you create an account you will see this page.

Letβs create an API key, By clicking on your profile and clicking settings.


Once you navigate to the API section, click on βCreate APIβ.
Fill in the required details, and your API key will be generated β just like shown in the image below.


STEP 4: Install Prometheus and Grafana on a New Server
Begin by creating a dedicated system user for Prometheus.
Using separate users for services improves security and simplifies management.
Run the following command to add the Prometheus user:
sudo useradd \
--system \
--no-create-home \
--shell /bin/false prometheus

--systemβ Creates a system account.--no-create-homeβ Skips creation of a home directory for Prometheus.--shell /bin/falseβ Disables shell access for the Prometheus user.prometheusβ Adds a user and group namedprometheus.
Letβs check the latest version of Prometheus from the download page.
You can use the curl or wget command to download Prometheus.
wget https://github.com/prometheus/prometheus/releases/download/v2.47.1/prometheus-2.47.1.linux-amd64.tar.gz

Next, extract all Prometheus files from the downloaded archive.
tar -xvf prometheus-2.47.1.linux-amd64.tar.gz

In production, the data directory is usually mounted on a separate disk.
But for this tutorial, we'll simply create a /data directory and a separate folder for Prometheus configuration.
sudo mkdir -p /data /etc/prometheus
Now, letβs change the directory to Prometheus and move some files.
cd prometheus-2.47.1.linux-amd64/

First, move the prometheus binary and promtool to /usr/local/bin/.promtool is useful for validating configuration files and Prometheus rules.
sudo mv prometheus promtool /usr/local/bin/
Optionally, move the console libraries to the Prometheus configuration directory.
These templates help create custom dashboards using Go templating, but theyβre not essential if you're just starting out.
sudo mv consoles/ console_libraries/ /etc/prometheus/
Finally, move the example Prometheus configuration file to the designated config directory.
sudo mv prometheus.yml /etc/prometheus/prometheus.yml
To avoid permission issues, you need to set the correct ownership for the /etc/prometheus/ and data directory.
sudo chown -R prometheus:prometheus /etc/prometheus/ /data/
You can delete the archive and a Prometheus folder when you are done.
cd
rm -rf prometheus-2.47.1.linux-amd64.tar.gz

Verify that the Prometheus binary is executable by running the command below:
prometheus --version

For more details and available configuration options, run the Prometheus help command:
prometheus --help
We'll use some of these options while defining the Prometheus service.
To manage Prometheus as a service, weβll create a Systemd unit file, since Systemd is the default service manager on most modern Linux distributions.
sudo vim /etc/systemd/system/prometheus.service

Prometheus.service
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=500
StartLimitBurst=5
[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/data \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle
[Install]
WantedBy=multi-user.target

Letβs review key Systemd and Prometheus options:
Restartβ Defines if the service should restart on failure, timeout, or exit.RestartSecβ Time delay before the service restarts.User&Groupβ Specifies which Linux user/group runs the Prometheus process.--config.file=/etc/prometheus/prometheus.ymlβ Path to Prometheus's main config file.--storage.tsdb.path=/dataβ Directory where Prometheus stores time-series data.--web.listen-address=0.0.0.0:9090β Listens on all network interfaces. Uselocalhostif reverse proxy (e.g., NGINX) is used.--web.enable-lifecycleβ Enables config reload without restarting the Prometheus process.
To ensure Prometheus starts automatically after reboot, run:
Now, simply start the Prometheus service using the command below:
sudo systemctl enable prometheus
sudo systemctl start prometheus
To check the status of Prometheus run the following command:
sudo systemctl status prometheus

If Prometheus fails to start or runs into issues, use the following command to view logs and identify errors:
journalctl -u prometheus -f --no-pager
Now, open your browser and access Prometheus using your serverβs IP address.
Make sure to append port 9090, like this:
<public-ip:9090>

If you navigate to the Targets tab in Prometheus, youβll see a single target β Prometheus itself.
By default, it scrapes its own metrics every 15 seconds.
Install Grafana on Ubuntu 22.04
To visualize system metrics effectively, we can use Grafana a powerful and flexible visualization tool. It supports various data sources, including the widely-used Prometheus.
Before proceeding, let's ensure that all necessary dependencies are installed.
sudo apt-get install -y apt-transport-https software-properties-common
Open your browser and navigate to http://<your-ip>:3000.
Log in to Grafana using the default credentials:
Username: admin
Password: admin

To start visualizing metrics:
Click on βAdd your first data sourceβ
Choose Prometheus as the data source
In the configuration screen:
Set the URL to
http://localhost:9090(or your Prometheus serverβs IP if itβs remote)Click Save & Test to validate the connection
Once the data source is connected:
Go to the Dashboards section
Click on Import to load a pre-built dashboard
Enter dashboard ID 1860 and click Load
Select your Prometheus data source from the dropdown
Click Import to load the dashboard
β Youβll now see a full dashboard with CPU, Memory, Disk, and other system metrics in real time!

Step 5 β Install the Prometheus Plugin and Integrate it with the Prometheus server
π οΈ Letβs Monitor Jenkins System with Prometheus
Ensure Jenkins is up and running on your system.
Go to:
Manage Jenkins β Plugins β Available PluginsIn the search bar, type βPrometheusβ
Look for and install the plugin named:
Prometheus Metrics PluginThis plugin exposes Jenkins metrics at a
/prometheusendpoint, which Prometheus can scrape.

No changes needed in the plugin config just click Apply and Save.
To configure Prometheus for Jenkins, create a static target by adding a
job_namewithstatic_configs.Head over to your Prometheus server to update the config.
sudo vim /etc/prometheus/prometheus.yml
- job_name: 'jenkins'
metrics_path: '/prometheus'
static_configs:
- targets: ['<jenkins-ip>:8080']
Prometheus will scrape metrics from the
/prometheusendpoint of your Jenkins server.Replace
<jenkins-ip>with your Jenkins hostβs IP or DNS name.Make sure port
8080is the correct port Jenkins is running on.

Before restarting Prometheus, make sure the configuration file is valid.
If everything is correct, youβll see:Checking /etc/prometheus/prometheus.yml β SUCCESS
promtool check config /etc/prometheus/prometheus.yml
π Reload Prometheus Configuration Without Restart
Once the configuration is validated, you can reload it without restarting Prometheus by sending a POST request:
curl -X POST http://localhost:9090/-/reload

To ensure Prometheus is scraping Jenkins metrics correctly, check the Targets section:
Open Prometheus in your browser:
http://<your-prometheus-ip>:9090/targetsUnder the βTargetsβ tab, look for the job named
jenkins.If the status shows βUPβ, you're all set! π

π Import Jenkins Dashboard in Grafana
For a better visualization of Jenkins metrics, follow these steps to import a pre-built Grafana dashboard:
Go to Grafana Web UI β Click on the β+β (Plus) icon in the left sidebar β Select Import Dashboard
In the dashboard import page:
Enter the dashboard ID:
9964Click Load
Once loaded:
Select your Prometheus data source from the dropdown
Click Import to load the dashboard
β Youβll now see a detailed and real-time Jenkins Monitoring Dashboard, showing performance, system usage, and health metrics.

Step 6 β Email Integration With Jenkins and Plugin Setup
π© Install Email Extension Plugin in Jenkins
To enable advanced email notifications in Jenkins:
Go to Manage Jenkins β Plugins β Available Plugins
Search for Email Extension Plugin
Select it and click on Install without restart
This plugin allows Jenkins to send customizable email alerts for build status and job events.

π Generate Gmail App Password for Jenkins
Open Gmail β Click on profile β Manage your Google Account
Go to Security tab β Enable 2-Step Verification
Scroll down β Click on App Passwords
Verify your password when prompted
Select Other (Custom name) β Enter
Jenkinsβ Click GenerateCopy the 16-character app password shown (e.g.,
xxxx xxxx xxxx xxxx)Use this password in Jenkins instead of your Gmail password


βοΈ Configure Email Notification in Jenkins
βοΈ Step 1: Configure Email Notification in Jenkins
Go to Manage Jenkins β Configure System
Scroll down to E-mail Notification section
Enter the following details:
SMTP Server:
smtp.gmail.comDefault user e-mail suffix:
@gmail.com(optional)
Click on Advanced to expand more options
Choose one of the following setups (depending on your preference):
Option 1: TLS Setup
β Use SMTP Authentication
User Name: Your Gmail address
Password: Paste the App Password
β Use TLS
SMTP Port:
587
Option 2: SSL Setup
β Use SMTP Authentication
User Name: Your Gmail address
Password: Paste the App Password
β Use SSL
SMTP Port:
465(Optional) Set Reply-To Address if needed
Make sure Charset is set to
UTF-8β Click on βTest configuration by sending test e-mailβ to verify setup
Click Apply and then Save
π Step 2: Add Email Credentials (Alternative Method)
Go to Manage Jenkins β Credentials
Select the appropriate domain (
(global)or your specific folder)Click Add Credentials:
Username: Your Gmail address
Password: Gmail App Password
ID / Description: e.g.
gmail-creds
Click OK
π₯ Advanced Email Configuration:
Expand the Advanced section under E-mail Notification
Set Default Content Type to:
HTML (text/html)
β This ensures formatted emails with HTML structureLeave List ID and Precedence Header empty unless needed
π Email Extension Plugin Advanced Settings:
Go to Manage Jenkins β Configure System
Scroll down to the Email Extension section
Configure the following:
Optional:
β¬ Enable Debug Mode (for troubleshooting)
β¬ Require Administrator for Template Testing
β¬ Enable watching for jobs
β¬ Allow sending to unregistered users (only if you allow public triggers)
Under Default Triggers, you can select when Jenkins should send emails:
Suggested triggers:β Failure - 2nd
β Failure - Any (or as per your use case)
β¬ Always, Fixed, Aborted, etc. (enable as per your need)
πΎ Save the Configuration
- Finally, click on Apply and then Save to persist all changes.
π‘ Note: The following script is a part of a Jenkins Declarative Pipeline and should be placed inside your
Jenkinsfile.
post {
always {
emailext attachLog: true,
subject: "'${currentBuild.result}'",
body: "Project: ${env.JOB_NAME}<br/>" +
"Build Number: ${env.BUILD_NUMBER}<br/>" +
"URL: ${env.BUILD_URL}<br/>",
to: 'postbox.aj99@gmail.com', #change Your mail
attachmentsPattern: 'trivyfs.txt,trivyimage.txt'
}
}
π§± Step 7 β Install Required Plugins for Pipeline Setup
Before configuring the pipeline, we need to install a few essential plugins in Jenkins to support tools like JDK, SonarQube, Node.js, and Dependency Check.
π 7A β Install Required Plugins
Follow these steps to install the necessary plugins:
Go to Manage Jenkins β Plugins β Available Plugins
Search and install the following plugins (β Install without restart):
Eclipse Temurin Installer
β For managing and installing JDK versions in JenkinsSonarQube Scanner
β Required to run code quality analysis with SonarQubeNodeJS Plugin
β Enables managing and installing Node.js versions inside Jenkins builds
β Once installed, these plugins will allow you to integrate code scanning, JS tools, and JDK inside your pipeline.
π§ 7B β Configure Java and Node.js in Global Tool Configuration
Once the required plugins are installed, configure the tools globally so they can be used in your Jenkins pipelines.
Go to Manage Jenkins β Global Tool Configuration
Under the JDK section:
Click on βAdd JDKβ
Uncheck β Install automatically (if not needed manually)
Provide a name like:
jdk17OR enable auto-install and select Temurin JDK 17
Under the NodeJS section:
Click on βAdd NodeJSβ
Provide a name like:
node16Check β Install automatically
Select version: 16.x
Scroll down and click Apply then Save


π§± 7C β Create a Jenkins Pipeline Job
Go to the Jenkins dashboard
Click on βNew Itemβ
Enter the item name as:
NetflixSelect Pipeline as the project type
Click OK to create the job
π οΈ Step 8 β Configure SonarQube Server in Jenkins
To integrate SonarQube with Jenkins, follow these steps:
Grab the Public IP of your EC2 instance where SonarQube is installed
β SonarQube runs on port9000, so openhttp://<your-public-ip>:9000Go to your SonarQube Web UI:
Click on Administration β Security β Users
Click on Tokens next to your username
Enter a token name (e.g.,
jenkins-token)Click Generate
Copy the generated token and save it somewhere safe β you'll need it in Jenkins

In SonarQube, go to Administration β Security β Users β Tokens, enter a name, and click Generate to create your token.

π Add SonarQube Token in Jenkins
Copy the token generated from SonarQube
Go to Jenkins Dashboard β Manage Jenkins β Credentials
Choose the correct domain (usually
(global)), then click Add CredentialsSelect Secret Text as the kind
Paste the token into the Secret field
Add an ID like
sonar-tokenand a description (e.g.,SonarQube Auth Token)Click OK to save

Once you click on Create, you will be redirected to the token details page where your token is displayed.

Go to Manage Jenkins β Configure System, scroll to SonarQube servers, click Add, enter a name, SonarQube URL, select the token (by ID), check the injection box, and click Save.

Click on Apply and Save after setting up SonarQube server details.
π§ Configure System: Used to connect and configure external servers like SonarQube.
π§° Global Tool Configuration: Used to configure tools installed via plugins (like JDK, NodeJS, Sonar Scanner).
Next, weβll install the SonarQube Scanner in Global Tool Configuration.

π― Add Quality Gate and Webhook in SonarQube
In the SonarQube dashboard, go to Administration β Configuration β Quality Gates
β Create or select a Quality Gate to enforce code standards.Then navigate to Administration β Configuration β Webhooks
β Add a new Webhook to notify Jenkins after analysis is complete.

Click on Create to add the new webhook in SonarQube.

Add a name (e.g., jenkins) and paste the Jenkins webhook URL in the URL field, then click Create.
Go to your Jenkins pipeline job and paste the script inside the Pipeline Script section.
pipeline {
agent any
tools {
jdk 'jdk17'
nodejs 'node16'
}
environment {
SCANNER_HOME = tool 'sonar-scanner'
}
stages {
stage('clean workspace') {
steps {
cleanWs()
}
}
stage('Checkout from Git') {
steps {
git branch: 'main', url: 'https://github.com/ApurvGujjar07/Netflix-clone.git'
}
}
stage("Sonarqube Analysis") {
steps {
withSonarQubeEnv('sonar-server') {
sh ''' $SCANNER_HOME/bin/sonar-scanner -Dsonar.projectName=Netflix \
-Dsonar.projectKey=Netflix '''
}
}
}
stage("quality gate") {
steps {
script {
waitForQualityGate abortPipeline: false, credentialsId: 'Sonar-token'
}
}
}
stage('Install Dependencies') {
steps {
sh "npm install"
}
}
}
post {
always {
emailext attachLog: true,
subject: "'${currentBuild.result}'",
body: "Project: ${env.JOB_NAME}<br/>" +
"Build Number: ${env.BUILD_NUMBER}<br/>" +
"URL: ${env.BUILD_URL}<br/>",
to: 'gujjarapurv181@gmail.com',
attachmentsPattern: 'trivyfs.txt,trivyimage.txt'
}
}
}

To view the analysis report, go to your SonarQube Server β Projects, and select your project.

The report is now generated with status "Passed", showing that around 3.2k lines were scanned.
For detailed insights, go to the Issues section in SonarQube.

First, we installed the required plugins. Next, go to Dashboard β Manage Jenkins β Global Tool Configuration to configure the tools like JDK, NodeJS, and Sonar Scanner.

Click on Apply and Save to store the tool configuration.
Now go to your job β Configure β Pipeline, add the updated script, and click Build Now to run it.
stage('OWASP FS SCAN') {
steps {
dependencyCheck additionalArguments: '--scan ./ --disableYarnAudit --disableNodeAudit', odcInstallation: 'DP-Check'
dependencyCheckPublisher pattern: '**/dependency-check-report.xml'
}
}
stage('TRIVY FS SCAN') {
steps {
sh "trivy fs . > trivyfs.txt"
}
}
The stage view would look like this

Once the build completes, youβll see a status graph along with any detected vulnerabilities in the SonarQube dashboard.

π³ Step 8 β Docker Image Build and Push
To build and push Docker images using Jenkins, you need to install a few essential Docker-related plugins.
π Install Required Docker Plugins:
Go to Dashboard β Manage Jenkins β Plugin Manager β Available Plugins
Search and install the following (β Install without restart):
Docker
Docker Commons
Docker Pipeline
Docker API
docker-build-step
Now, go to Dashboard β Manage Jenkins β Tools β

π Add DockerHub Credentials in Jenkins
Go to Dashboard β Manage Jenkins β Credentials
Click on the appropriate domain (usually
(global)), then click Add CredentialsChoose Username with password as the kind
Fill in:
Username: Your DockerHub username
Password: Your DockerHub password
ID: e.g.
dockerhub-creds(youβll use this in the pipeline)
Click OK to save

stage("Docker Build & Push") {
steps {
script {
withDockerRegistry(credentialsId: 'docker', toolName: 'docker') {
sh "docker build --build-arg TMDB_V3_API_KEY=Aj7ay86fe14eca3e76869b92 -t netflix ."
sh "docker tag netflix adgujjar/netflix:latest"
sh "docker push adgujjar/netflix:latest"
}
}
}
}
stage("TRIVY") {
steps {
sh "trivy image adgujjar/netflix:latest > trivyimage.txt"
}
}
After the build, you'll see the output along with a Dependency-Check trend graph showing vulnerability stats over time.

When you log in to DockerHub, you'll see that a new image has been successfully created and pushed to your repository.

Now, add the following stage to your pipeline to run the container and check if the application is working:
stage("Run Container") {
steps {
sh "docker run -d -p 3000:3000 --name netflix-container adgujjar/netflix:latest"
}
}

Open http://<your-jenkins-public-ip>:8081 in your browser you should see the application running successfully.
βΈοΈ Step 9 β Kubernetes Setup
π Note:
1).Kubernetes cluster setup and pod creation can vary based on your environment, cloud provider, and specific project needs.
You can follow the steps as shown above, or adjust them according to your infrastructure.
2).Below, Iβm sharing a reference GitHub repo with ready-to-use Kubernetes YAMLs and setup scripts β feel free to use the commands from there as well to complete your setup.https://github.com/LondheShubham153/kubernetes-in-one-shot(itβs not a promotion link just for your reference .
To deploy your application on Kubernetes, letβs set up a basic 2-node cluster and prepare Jenkins to interact with it.
π₯οΈ Provision 2 Ubuntu EC2 Instances
Launch two Ubuntu 20.04 EC2 instances:
Master Node β Name it:
masterWorker Node β Name it:
worker
Connect to both instances using PuTTY or MobaXterm ,CMD
βοΈ Install kubectl on Jenkins Server
- Jenkins also needs
kubectlto apply Kubernetes manifests
π₯ Run the following commands on your Jenkins EC2 machin
sudo apt update
sudo apt install curl
curl -LO https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client
π₯οΈ Part 1 β Master Node (master)
πΉ Set Hostname
sudo hostnamectl set-hostname K8s-Master
πΉ Install Docker and Setup Permissions
sudo apt-get update
sudo apt-get install -y docker.io
sudo usermod -aG docker ubuntu
newgrp docker
sudo chmod 777 /var/run/docker.sock
πΉ Install Kubernetes Components
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
πΉ Initialize the Cluster
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
πΉ Configure kubectl for Current User
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
πΉ Apply Flannel CNI
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
π Copy the kubeconfig file (/home/ubuntu/.kube/config) to your Jenkins machine, so Jenkins can connect to the cluster.
π₯οΈ Part 2 β Worker Node (worker)
πΉ Set Hostname
sudo hostnamectl set-hostname K8s-Worker
πΉ Install Kubernetes Components
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key \
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
πΉ Join Worker Node to the Cluster
After you run kubeadm init on the master, it will show you a command like:
kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
π Copy that full command and run it on the worker node to join the cluster.
Copy the config file to Jenkins master or the local file manager and save it

π Configure Kubeconfig in Jenkins
Copy the contents of the kubeconfig file (usually located at:
/home/ubuntu/.kube/configon the K8s Master Node)Open File Explorer on your Jenkins machine and:
Create a new text file named:
secret-file.txtPaste the copied kubeconfig content into it
Save the file in a known location (e.g., Documents folder)
π Note:
This file will be used to configure Kubernetes access in Jenkins using the Kubernetes plugin.

π Add Kubernetes Credentials in Jenkins
Go to Manage Jenkins β Manage Credentials
Click on (global) under Jenkins
Click on Add Credentials
In the Kind dropdown, select: Kubeconfig
Upload the
secret-file.txtyou saved earlierGive it an ID like
k8s-configand a descriptionClick OK to save

π Install Node Exporter on Kubernetes Master & Worker
To monitor system-level metrics like CPU, memory, and disk, we'll install Node Exporter on both the master and worker nodes.
π§ Step 1 β Create a System User for Node Exporter
Run the following command on both Master (master) and Worker (worker) nodes:
sudo useradd \
--system \
--no-create-home \
--shell /bin/false node_exporter
π₯ Step 2 β Download Node Exporter Binary
Run the following command on both Master and Worker nodes to download Node Exporter:
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
π¦ This will download the latest stable version (
v1.8.1) of Node Exporter.
πΉ Extract the Archive
tar -xvf node_exporter-1.8.1.linux-amd64.tar.gz
πΉ Move the Binary to /usr/local/bin
sudo mv node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/
πΉ Clean Up the Archive and Folder
rm -rf node_exporter*
πΉ Verify the Binary Runs
node_exporter --version
β You should see the Node Exporter version output in the terminal.
Node Exporter supports many plugins (called collectors). You can list all available options using:
node_exporter --help
π§ For demo purposes, weβll enable the
logindcollector using a systemd unit file.
π Create a Systemd Service File
Run this on both Master and Worker nodes:
sudo vim /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=500
StartLimitBurst=5
[Service]
User=node_exporter
Group=node_exporter
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/node_exporter \
--collector.logind
[Install]
WantedBy=multi-user.target

Start and Enable Node Exporter Service
After updating the systemd unit file with:
User=node_exporterGroup=node_exporterExecStart=/usr/local/bin/node_exporter --collector.logind
Now run the following commands on both Master and Worker nodes:
β Enable Node Exporter to Start on Boot
sudo systemctl enable node_exporter
βΆοΈ Start the Node Exporter Service
sudo systemctl start node_exporter
π Check Status of the Service
sudo systemctl status node_exporter
πͺ΅ View Logs (if needed for debugging)
journalctl -u node_exporter -f --no-pager
π Tip: Use this log command if Node Exporter fails to start or shows inactive.

π‘ Configure Static Targets in Prometheus
At this stage, Prometheus is scraping only a single default target.
Although Prometheus supports dynamic service discovery for platforms like AWS, GCP, and Kubernetes, weβll keep it simple for now.
π§ In future tutorials, weβll explore Prometheus deployments in cloud-native environments and inside Kubernetes clusters.
π οΈ For Now: Add Static Targets Manually
To add a static target (like your Node Exporters), follow these steps:
Go to your Prometheus server
Open the config file:
sudo vim /etc/prometheus/prometheus.yml
- job_name: node_export_masterk8s
static_configs:
- targets: ["<master-ip>:9100"]
- job_name: node_export_workerk8s
static_configs:
- targets: ["<worker-ip>:9100"]
By default, Node Exporter will be exposed on port 9100.
Whenever it's not clearly mentioned where to run a command, assume it should be executed on the main instance β i.e., the first EC2 or server where the service (like Prometheus, Jenkins, or Kubernetes Master) was initially set up.
π Reload Prometheus Config Without Restart
Since lifecycle management is enabled, you can reload Prometheus config via API β no need to restart the service or cause downtime.
β Validate the Config First
π Reminder: Run this on the main Prometheus instance only.
promtool check config /etc/prometheus/prometheus.yml
π Reload Prometheus Configuration via API
Once the config is valid, reload Prometheus without downtime using:
curl -X POST http://localhost:9090/-/reload
β This tells Prometheus to re-read the updated config file instantly.
π Verify Targets in Prometheus
To confirm that your new targets are being scraped, open:
plaintextCopyEdithttp://<your-prometheus-ip>:9090/targets
β If the status shows UP, your Node Exporters are working correctly.

π Final Step β Deploy to Kubernetes from Jenkins
Add the following stage at the end of your Jenkinsfile to automatically deploy the application to your Kubernetes cluster:
stage('Deploy to kubernets'){
steps{
script{
dir('Kubernetes') {
withKubeConfig(caCertificate: '', clusterName: '', contextName: '', credentialsId: 'k8s', namespace: '', restrictKubeConfigAccess: false, serverUrl: '') {
sh 'kubectl apply -f deployment.yml'
sh 'kubectl apply -f service.yml'
}
}
}
}
}
π Notes:
Make sure you have a
Kubernetesfolder in your repo containingdeployment.ymlandservice.ymlThe
credentialsId: 'k8s'should match the Kubernetes secret you created in Jenkins earlierYou can verify deployment with:
β Once this stage runs, your app will be live on the Kubernetes cluster! π

π Access Your Application
Open the following URL in your browser to view the deployed app:
http://<public-ip-of-slave>:<service-port>
β Output: You should see your Netflix Clone application running in the browser β served directly from your Kubernetes cluster!

Access the Netflix


β Complete Jenkins Declarative Pipeline
pipeline {
agent any
tools {
jdk 'jdk17'
nodejs 'node16'
}
environment {
SCANNER_HOME = tool 'sonar-scanner'
}
stages {
stage('Clean Workspace') {
steps {
cleanWs()
}
}
stage('Checkout from Git') {
steps {
git branch: 'main', url: 'https://github.com/ApurvGujjar07/Netflix-clone.git'
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('sonar-server') {
sh '''$SCANNER_HOME/bin/sonar-scanner \
-Dsonar.projectName=Netflix \
-Dsonar.projectKey=Netflix'''
}
}
}
stage('Quality Gate') {
steps {
script {
waitForQualityGate abortPipeline: false, credentialsId: 'Sonar-token'
}
}
}
stage('Install Dependencies') {
steps {
sh "npm install"
}
}
stage('OWASP FS Scan') {
steps {
dependencyCheck additionalArguments: '--scan ./ --disableYarnAudit --disableNodeAudit', odcInstallation: 'DP-Check'
dependencyCheckPublisher pattern: '**/dependency-check-report.xml'
}
}
stage('Trivy FS Scan') {
steps {
sh "trivy fs . > trivyfs.txt"
}
}
stage('Docker Build & Push') {
steps {
script {
withDockerRegistry(credentialsId: 'docker', toolName: 'docker') {
sh "docker build --build-arg TMDB_V3_API_KEY=AJ7AYe14eca3e76864yah319b92 -t netflix ."
sh "docker tag netflix adgujjar/netflix:latest"
sh "docker push adgujjar/netflix:latest"
}
}
}
}
stage('Trivy Image Scan') {
steps {
sh "trivy image adgujjar/netflix:latest > trivyimage.txt"
}
}
stage('Deploy to Container') {
steps {
sh "docker run -d --name netflix -p 8081:80 adgujjar/netflix:latest"
}
}
stage('Deploy to Kubernetes') {
steps {
script {
dir('Kubernetes') {
withKubeConfig(
credentialsId: 'k8s',
caCertificate: '',
clusterName: '',
contextName: '',
namespace: '',
serverUrl: '',
restrictKubeConfigAccess: false
) {
sh 'kubectl apply -f deployment.yml'
sh 'kubectl apply -f service.yml'
}
}
}
}
}
}
post {
always {
emailext attachLog: true,
subject: "'${currentBuild.result}'",
body: "Project: ${env.JOB_NAME}<br/>" +
"Build Number: ${env.BUILD_NUMBER}<br/>" +
"URL: ${env.BUILD_URL}<br/>",
to: 'gujjarapurv181@gmail.com',
attachmentsPattern: 'trivyfs.txt,trivyimage.txt'
}
}
}
Once you're done testing and deploying, make sure to terminate all unused EC2 instances (Jenkins, Kubernetes Master, Worker, SonarQube, etc.) to avoid unnecessary charges.
π Final Note
If you feel Iβve made any mistake in this project or something wasnβt clear, please feel free to leave a comment.
Iβll make sure to reply to your message as soon as possible.
Thank you so much for reading! π
π¨βπ» About the Author

Hi, I'm Apurv Gujjar, a passionate and aspiring DevOps Engineer.
This project represents the beginning of my professional journey into the world of DevOps, cloud-native technologies, and CI/CD automation.
From writing pipelines and configuring SonarQube to deploying Dockerized applications on Kubernetes β this was more than a technical challenge, it was a learning milestone.
If you're reading this β thank you for being a part of my journey. π
On the right, youβll see a small glimpse of who's behind the terminal. π (Photo goes here)
π¬ Let's Stay Connected
π§ Email: gujjarapurv181@gmail.com
π GitHub: github.com/ApurvGujjar07
πΌ LinkedIn: linkedin.com/in/apurv-gujjar
π‘ If you found this project useful, or have any suggestions or feedback, feel free to reach out or drop a comment Iβd love to connect and improve.
This is just the beginning many more builds, deployments, and learnings ahead.






