# "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!

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><a target="_self" rel="noopener noreferrer nofollow" href="https://github.com/ApurvGujjar07/Netflix-clone" style="pointer-events: none"><strong>CLICK HERE FOR GITHUB REPOSITORY</strong></a></div>
</div>

### ✅ **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).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751642071972/11844f41-e10b-40d8-88ba-d47837dcf608.png align="center")

### **STEP 2A : Install Jenkins, Docker, and Trivy**

* Connect to your console, and enter these commands to Install Jenkins
    

```yaml
#!/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
```

```powershell
vi jenkins.sh #make sure run in Root (or) add at userdata while ec2 launch
```

```powershell
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:

```powershell
<EC2 Public IP Address:8080>
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751642587099/5b19a4a9-521c-479f-a3ee-4440c9c3a57d.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751642536006/c11dad09-1616-48f2-8f46-ae2685d55e91.png align="center")

Jenkins will now get installed and install all the libraries.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751642731196/d3387d30-2d00-4b86-89b7-3f688a1f5f75.png align="center")

Create a user click on save and continue.

Jenkins Getting Started Screen.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751642820451/6bea1c24-e2ef-4bed-b9d6-9265c0d0587d.png align="center")

### **STEP 2B : Install Docker**

```powershell
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.

```powershell
docker run -d --name sonar -p 9000:9000 sonarqube:lts-community
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643128394/a573f09f-6cbe-4702-b4c0-89f6d47568fe.png align="center")

**SonarQube is now successfully up and running.**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643239300/a18c7438-1696-41ca-b698-4dd6bf69aac7.png align="center")

Log in to SonarQube using the default credentials:

```plaintext
Username: admin

Password: admin
```

Set your new password.  
You will now be redirected to the **SonarQube Dashboard**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643381564/9f2cdfc9-4c2f-4e37-a608-3724a56ec64e.png align="center")

You will now see the **SonarQube Dashboard** appear below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643464937/302714e9-6fd0-4c42-a505-22c78e4b54c2.png align="center")

### **STEP 2C : Install Trivy**

```powershell
vi trivy.sh
```

```yaml
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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643686090/0ff9d4d7-3983-43ec-a15a-8b9f87cc939f.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643822452/6df0b2f5-1d18-4b5c-a022-30eca28ef508.png align="center")

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.)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643896733/8618a956-4b0c-47a7-aa6b-3b9561816672.png align="center")

once you create an account you will see this page.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643912792/908691fa-7e2b-48ff-9cff-57903d584113.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751643966004/271c4a84-9b7c-43f2-88ad-6a91431a964c.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644043628/b1933b1f-7d3e-4385-852c-547b8185e71c.png align="center")

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644367757/7da5b7f0-eb33-4b81-8620-379a5c5f2529.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644204586/20833778-08b9-4001-b2a0-280a5b801818.png align="center")

### **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:

```powershell
sudo useradd \
    --system \
    --no-create-home \
    --shell /bin/false prometheus
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644483386/c88dacdf-0a03-4d86-a0b4-dce288848848.png align="center")

* `--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** named `prometheus`.
    

Let’s check the latest version of Prometheus from the [**download page**](https://prometheus.io/download/).

You can use the curl or wget command to download Prometheus.

```powershell
wget https://github.com/prometheus/prometheus/releases/download/v2.47.1/prometheus-2.47.1.linux-amd64.tar.gz
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644667326/4719a290-bb33-4324-bb39-7f209e4465a6.png align="center")

Next, extract all Prometheus files from the downloaded archive.

```powershell
tar -xvf prometheus-2.47.1.linux-amd64.tar.gz
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644738672/f4f2437b-e9e6-48e2-a45c-ab7748ecc6c4.png align="center")

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.

```powershell
sudo mkdir -p /data /etc/prometheus
```

Now, let’s change the directory to Prometheus and move some files.

```powershell
cd prometheus-2.47.1.linux-amd64/
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751644967833/b0c66351-3f2b-4d7d-b37f-c831c3b54959.png align="center")

First, move the `prometheus` binary and `promtool` to `/usr/local/bin/`.  
`promtool` is useful for validating configuration files and Prometheus rules.

```powershell
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.

```powershell
sudo mv consoles/ console_libraries/ /etc/prometheus/
```

Finally, move the **example Prometheus configuration file** to the designated config directory.

```powershell
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.

```powershell
sudo chown -R prometheus:prometheus /etc/prometheus/ /data/
```

You can delete the archive and a Prometheus folder when you are done.

```powershell
cd
rm -rf prometheus-2.47.1.linux-amd64.tar.gz
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751645209163/83d2e5cd-6ab2-4e08-abe2-6b9da6efd40b.png align="center")

Verify that the **Prometheus binary** is executable by running the command below:

```powershell
prometheus --version
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751645309334/16a1a18e-9984-4b4f-80b2-4155e90d7af4.png align="center")

For more details and available configuration options, run the Prometheus help command:

```powershell
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.

```powershell
sudo vim /etc/systemd/system/prometheus.service
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751645471474/12015419-95c6-4376-87d7-0912bcc58e1a.png align="center")

**Prometheus.service**

```yaml
[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
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751645573519/4ba045e1-2f37-425d-ad4c-80f495267ad5.png align="center")

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. Use [`localhost`](http://localhost) if 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:

```powershell
sudo systemctl enable prometheus
sudo systemctl start prometheus
```

To check the status of Prometheus run the following command:

```powershell
sudo systemctl status prometheus
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751645708933/10cdbe34-7af4-44e0-9207-7fcc6eed5b34.png align="center")

If Prometheus fails to start or runs into issues, use the following command to view logs and identify errors:

```powershell
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:

```plaintext
<public-ip:9090>
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751645885469/09e937b3-5ae2-4547-ab69-3a497efb4d45.png align="center")

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.

```powershell
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:

```plaintext
Username: admin
Password: admin
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751789516982/d3734368-1c26-473c-8f77-6d312c246d75.png align="center")

* 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`](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!
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751789676857/c4211f31-de7f-4160-8806-b90149aee9e8.png align="center")

### **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 Plugins**
    
* In the search bar, type **“Prometheus”**
    
* Look for and install the plugin named:  
    **Prometheus Metrics Plugin**
    
* This plugin exposes Jenkins metrics at a `/prometheus` endpoint, which Prometheus can scrape.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751789850373/db213e66-56d6-4e7e-ad62-675b2abefd35.png align="center")

* 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_name` with `static_configs`.
    
* Head over to your **Prometheus server** to update the config.
    

```powershell
sudo vim /etc/prometheus/prometheus.yml
```

```yaml
- job_name: 'jenkins'
    metrics_path: '/prometheus'
    static_configs:
      - targets: ['<jenkins-ip>:8080']
```

* Prometheus will **scrape metrics** from the `/prometheus` endpoint of your Jenkins server.
    
* Replace `<jenkins-ip>` with your Jenkins host’s IP or DNS name.
    
* Make sure port `8080` is the correct port Jenkins is running on.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790073200/d9586cc6-fe9c-44f4-8fef-8bea4175a29d.png align="center")

Before restarting Prometheus, make sure the configuration file is valid.

If everything is correct, you’ll see:  
`Checking /etc/prometheus/prometheus.yml` → `SUCCESS`

```powershell
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:

```powershell
curl -X POST http://localhost:9090/-/reload
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790355339/3c8bea65-bd2c-4a7f-aa33-4aab9c8a6ea6.png align="center")

To ensure Prometheus is scraping Jenkins metrics correctly, check the **Targets** section:

1. Open Prometheus in your browser:  
    `http://<your-prometheus-ip>:9090/targets`
    
2. Under the **“Targets”** tab, look for the job named `jenkins`.
    
3. If the status shows **“UP”**, you're all set! 🎉
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790449769/a2c03a2c-43dc-4b4a-ae20-7d790ebc25de.png align="center")

### 📈 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: `9964`
        
    * Click **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.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790542639/6607f203-7946-4afa-a3c1-107e6d1d7add.png align="center")

### **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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790648904/05a892a8-fd60-4d6b-b714-dd5f751797db.png align="center")

### 🔐 Generate Gmail App Password for Jenkins

1. Open Gmail → Click on profile → **Manage your Google Account**
    
2. Go to **Security** tab → Enable **2-Step Verification**
    
3. Scroll down → Click on **App Passwords**
    
4. Verify your password when prompted
    
5. Select **Other (Custom name)** → Enter `Jenkins` → Click **Generate**
    
6. Copy the **16-character app password** shown (e.g., `xxxx xxxx xxxx xxxx`)
    
7. Use this password in Jenkins instead of your Gmail password
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790796823/fcf53874-a13c-4809-b4f2-c1fa77c14b10.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751790808323/d1d25642-bee5-44e8-a33a-27492a1de574.png align="center")

### ✉️ 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.com`](http://smtp.gmail.com)
        
    * **Default user e-mail suffix**: `@`[`gmail.com`](http://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 structure
    
* Leave **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`.

```typescript
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):
    
    1. **Eclipse Temurin Installer**  
        → For managing and installing JDK versions in Jenkins
        
    2. **SonarQube Scanner**  
        → Required to run code quality analysis with SonarQube
        
    3. **NodeJS 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: `jdk17`
        
    * OR enable auto-install and select **Temurin JDK 17**
        
* Under the **NodeJS** section:
    
    * Click on **“Add NodeJS”**
        
    * Provide a name like: `node16`
        
    * Check ✅ **Install automatically**
        
    * Select version: **16.x**
        
* Scroll down and click **Apply** then **Save**
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751791686110/bcb92dc7-ac19-4913-8b60-d86c6ad1facc.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751791699533/9ae93c12-550c-4cc2-b10a-2c0b15b2f062.png align="center")

## 🧱 7C — Create a Jenkins Pipeline Job

* Go to the Jenkins dashboard
    
* Click on **“New Item”**
    
* Enter the item name as: `Netflix`
    
* Select **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 port `9000`, so open `http://<your-public-ip>:9000`
    
* Go 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
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751791747090/40ab301a-fe6d-4bc2-9264-9188d1b86f5d.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751791802077/12b37419-d9b2-4211-b9f8-7551641a258c.png align="center")

### 🔐 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 Credentials**
    
* Select **Secret Text** as the kind
    
* Paste the token into the **Secret** field
    
* Add an **ID** like `sonar-token` and a description (e.g., `SonarQube Auth Token`)
    
* Click **OK** to save
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751791838289/f05cd505-6f5d-4b80-8012-50a70778015c.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751791869791/6d252c29-f414-48af-a042-5badecdbdaba.png align="center")

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**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792096559/6ffe557e-f0d3-4790-b2f5-d9bff9ea09ad.png align="center")

* 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.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792164450/31ff7695-342c-498e-aedd-f6deb904ef9e.png align="center")

### 🎯 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.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792209011/f9a16b7b-fc58-40b3-8548-8e3d6c7c7618.png align="center")

Click on **Create** to add the new webhook in SonarQube.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792244895/deabaa5b-53b4-4f10-a839-ca1bcc0bf17b.png align="center")

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.

```typescript
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'
        }
    }
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792651238/13792421-3963-4aab-a63a-67b4cde6bf12.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792729517/14d556ad-3169-4898-80f7-15bf8893894a.png align="center")

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792831141/c284bf86-c719-4a71-8697-cb76279f0acc.png align="center")

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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751792861904/1af849e8-5165-4f3a-8dd5-a80365ac7938.png align="center")

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.

```typescript
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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793008676/5a0bff38-0578-444d-a318-cded80bcbc57.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793046643/d49ff91c-5a59-4ebb-95c7-92154d7acfbb.png align="center")

## 🐳 **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):
    
    1. **Docker**
        
    2. **Docker Commons**
        
    3. **Docker Pipeline**
        
    4. **Docker API**
        
    5. **docker-build-step**
        
* Now, go to Dashboard → Manage Jenkins → Tools →
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793160131/5b0088e5-6b54-4481-922a-857c58c1e4a8.webp align="center")

### 🔐 Add DockerHub Credentials in Jenkins

* Go to **Dashboard → Manage Jenkins → Credentials**
    
* Click on the appropriate domain (usually `(global)`), then click **Add Credentials**
    
* Choose **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
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793267397/dfa9a159-f245-4e57-a8f4-327db2d3d832.png align="center")

```typescript
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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793403117/2add9126-f160-4b89-b36c-b8b8b458389f.png align="center")

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793507127/696e16c0-86d9-4027-aee0-8ae93e3ad98b.png align="center")

Now, add the following stage to your pipeline to run the container and check if the application is working:

```typescript
stage("Run Container") {
    steps {
        sh "docker run -d -p 3000:3000 --name netflix-container adgujjar/netflix:latest"
    }
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751793604121/5c89fc2b-c288-4e4e-b902-036fc8cd1157.png align="center")

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](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: `master`
        
    * **Worker Node** → Name it: `worker`
        
* Connect to both instances using **PuTTY** or **MobaXterm ,CMD**
    

---

### ⚙️ Install `kubectl` on Jenkins Server

* Jenkins also needs `kubectl` to apply Kubernetes manifests
    

#### 📥 Run the following commands on your Jenkins EC2 machin

```powershell
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

```powershell
sudo hostnamectl set-hostname K8s-Master
```

🔹 Install Docker and Setup Permissions

```powershell
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

```powershell
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

```powershell
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
```

🔹 Configure kubectl for Current User

```powershell
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

```powershell
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

```powershell
sudo hostnamectl set-hostname K8s-Worker
```

🔹 Install Kubernetes Components

```powershell
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:

```powershell
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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751794406556/4c036872-b84f-4206-a532-19177bd2bb7a.png align="center")

### 🔐 Configure Kubeconfig in Jenkins

* Copy the contents of the kubeconfig file (usually located at:  
    `/home/ubuntu/.kube/config` on the **K8s Master Node**)
    
* Open **File Explorer** on your Jenkins machine and:
    
    * Create a new text file named: `secret-file.txt`
        
    * Paste 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.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751794804314/6a2c0fc4-1dd9-4d06-ae4f-1b3a586bc643.png align="center")

### 🔐 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.txt` you saved earlier
    
* Give it an **ID** like `k8s-config` and a **description**
    
* Click **OK** to save
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751794839765/3e5bbaf4-f257-4c0c-b171-75a008d78b3d.webp align="center")

## 📊 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:

```powershell
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:

```powershell
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

```powershell
tar -xvf node_exporter-1.8.1.linux-amd64.tar.gz
```

#### 🔹 Move the Binary to `/usr/local/bin`

```powershell
sudo mv node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/
```

#### 🔹 Clean Up the Archive and Folder

```powershell
rm -rf node_exporter*
```

#### 🔹 Verify the Binary Runs

```powershell
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:

```powershell
node_exporter --help
```

> 🧠 For demo purposes, we’ll enable the `logind` collector using a systemd unit file.

---

### 📝 Create a Systemd Service File

Run this on **both Master and Worker nodes**:

```powershell
sudo vim /etc/systemd/system/node_exporter.service
```

```yaml
[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
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751795334304/a6e67cc1-0270-4c06-9170-2c1efb4da007.webp align="center")

### Start and Enable Node Exporter Service

After updating the systemd unit file with:

* `User=node_exporter`
    
* `Group=node_exporter`
    
* `ExecStart=/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

```powershell
sudo systemctl enable node_exporter
```

#### ▶️ Start the Node Exporter Service

```powershell
sudo systemctl start node_exporter
```

#### 📊 Check Status of the Service

```powershell
sudo systemctl status node_exporter
```

#### 🪵 View Logs (if needed for debugging)

```powershell
journalctl -u node_exporter -f --no-pager
```

> 📝 **Tip:** Use this log command if Node Exporter fails to start or shows inactive.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751795567221/bf04f747-851d-4313-a6bd-bcfc37bfaec4.png align="center")

## 📡 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:
    

```powershell
sudo vim /etc/prometheus/prometheus.yml
```

```yaml
- 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.

---

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">📝 <strong>Note:</strong></div>
</div>

  
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.

```powershell
promtool check config /etc/prometheus/prometheus.yml
```

### 🔄 Reload Prometheus Configuration via API

Once the config is valid, reload Prometheus without downtime using:

```powershell
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:

```powershell
plaintextCopyEdithttp://<your-prometheus-ip>:9090/targets
```

> ✅ If the status shows **UP**, your Node Exporters are working correctly.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751796160017/17f037bd-d16f-406a-8dfc-19db9cf6a2ec.png align="center")

### 🚀 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:

```typescript
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 `Kubernetes` folder in your repo containing `deployment.yml` and `service.yml`
    
* The `credentialsId: 'k8s'` should match the Kubernetes secret you created in Jenkins earlier
    
* You can verify deployment with:
    

> ✅ Once this stage runs, your app will be live on the Kubernetes cluster! 🚀

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751796288297/21170d78-d553-4f89-86de-b0899e9a58e4.png align="center")

### 🌐 Access Your Application

Open the following URL in your browser to view the deployed app:

```plaintext
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!

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751796394624/55abfc18-8a0a-483b-bc60-0dcc14fc0d18.png align="center")

> ### **Access the Netflix**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751796469618/95171a33-547c-408b-b670-c0a28c5ca06e.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751796492247/f6525486-49f5-4259-bc99-b70ca87e8faf.png align="center")

## ✅ **Complete Jenkins Declarative Pipeline**

```typescript
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'
        }
    }
}
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">🧹 Final Cleanup</div>
</div>

> 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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1751797710818/123a7231-3dca-4273-ad68-7bd026f69b95.png align="center")

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](https://github.com/ApurvGujjar07)
    
* 💼 **LinkedIn**: [linkedin.com/in/apurv-gujjar](https://www.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.**
