Deploying a Netflix Clone on EKS Using a DevSecOps Pipeline

Muhammad Mustafa
9 min readJul 25, 2024

--

Introduction

In today’s fast-paced digital landscape, deploying applications securely and efficiently is paramount. As a DevOps Engineer passionate about streamlining deployment processes while maintaining robust security, I recently embarked on an exciting project: deploying a Netflix clone application on Amazon EKS (Elastic Kubernetes Service) using a comprehensive DevSecOps pipeline.

This project aimed to accomplish several key objectives:

  1. Implement a CI/CD pipeline while integrating security best practices
  2. Leverage containerization and orchestration technologies for scalable deployment
  3. Establish comprehensive monitoring and observability
  4. Gain hands-on experience with cloud-native technologies

In this blog post, I’ll walk you through the entire process, from development to production deployment, highlighting key decisions, challenges faced, and lessons learned along the way.

Phase 1: Development Process

Setting Up the Environment

The project kicked off with the creation of an EC2 instance (Ubuntu 22.04, t2.large) to serve as my development environment. Here, I installed essential tools, with Docker being a cornerstone of my setup. Containerizing my Netflix clone application using Docker ensured consistent environments across all stages of my pipeline, from development to production.

Creating a TMDB API Key

My Netflix clone relies on the TMDB (The Movie Database) API for fetching movie data. To get started:

  1. Sign up on the TMDB website
  2. Navigate to the API section under your profile
  3. Create a new API key

This key is crucial for populating my application with real movie data.

Building and Pushing the Application Image

With my environment set up, I proceeded to build my application image:

docker build --build-arg TMDB_V3_API_KEY=<your-api-key> -t netflix .

After thorough local testing to verify functionality, I pushed the image to DockerHub, making it reliable for deployment of the pipeline.

Phase 2: Security Integration

Security is not an afterthought in DevSecOps; it’s an integral part of the entire process. Here’s how I baked security into my pipeline:

Static Code Analysis with SonarQube

I integrated SonarQube to perform static code analysis, helping me identify code smells, bugs, and vulnerabilities early in the development process. This proactive approach allowed me to address issues before they made their way into production.

Docker Image Scanning with Trivy

Trivy was employed to scan my Docker images for known vulnerabilities:

trivy image <imageid>

This step ensured that my containerized application and its dependencies were free from known security issues.

Dependency Checks with OWASP

I used OWASP Dependency-Check to identify vulnerabilities in my project dependencies, ensuring that all libraries and frameworks used in my application were secure and up-to-date.

Phase 3: CI/CD Setup and Deployment

Orchestrating the Pipeline with Jenkins

Jenkins served as the backbone of my CI/CD pipeline, automating my build, security scans, and deployment processes. Here’s a simplified version of my Jenkins 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/Aj7Ay/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=<your-api-key> -t netflix ."
sh "docker tag netflix mmustafa1/netflix:latest "
sh "docker push mmustafa1/netflix:latest "
}
}
}
}
stage("TRIVY"){
steps{
sh "trivy image mmustafa1/netflix:latest > trivyimage.txt"
}
}
stage('Deploy to container'){
steps{
sh 'docker run -d -p 8081:80 mmustafa1/netflix:latest'
}
}
}
}

This pipeline ensures that every code change goes through rigorous testing and security checks before deployment.

Phase 4: Kubernetes Setup on Amazon EKS

Creating the EKS Cluster

To set up my Kubernetes environment, I chose to use Amazon EKS (Elastic Kubernetes Service). Instead of using CLI tools, I opted for the AWS Management Console to create my EKS cluster and node group. This approach gave me a more visual and intuitive way to configure my cluster settings.

After creating the cluster through the console, I connected to it using the AWS CLI:

aws eks update-kubeconfig --region <my-region> --name <my-cluster-name>

This command updated my kubeconfig file, allowing me to interact with my EKS cluster using kubectl.

Phase 5: Deploy Application with ArgoCD

Install ArgoCD

You can install ArgoCD on your Kubernetes cluster by following the instructions provided in the EKS Workshop documentation.

Set Your GitHub Repository as a Source

After installing ArgoCD, you need to set up your GitHub repository as a source for your application deployment. This typically involves configuring the connection to your repository and defining the source for your ArgoCD application. The specific steps will depend on your setup and requirements.

Create an ArgoCD Application:

  • name: Set the name for your application.
  • destination: Define the destination where your application should be deployed.
  • project: Specify the project the application belongs to.
  • source: Set the source of your application, including the GitHub repository URL, revision, and the path to the application within the repository.
  • syncPolicy: Configure the sync policy, including automatic syncing, pruning, and self-healing.

Access your Application

To Access the app make sure port 30007 is open in your security group and then open a new tab and paste your <NodeIP>:30007, your app should be running.

Phase 6: Monitoring and Observability

After successfully deploying my application, the next crucial step was to establish robust monitoring and observability. This phase was critical to ensure the health, performance, and security of my Netflix clone in the production environment.

Setting Up Prometheus and Grafana on a New Server

I set up Prometheus and Grafana on a new EC2 Ubuntu 22.04 instance for monitoring. Prometheus was configured to collect metrics from Jenkins and Kubernetes, while Grafana provided visualization through customizable dashboards.

Installing Prometheus and Node Exporter

Create a system user and download Prometheus and Node Exporter.

sudo useradd --system --no-create-home --shell /bin/false prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.47.1/prometheus-2.47.1.linux-amd64.tar.gz
tar -xvf prometheus-2.47.1.linux-amd64.tar.gz
sudo mv prometheus-2.47.1.linux-amd64/prometheus /usr/local/bin/
sudo mkdir -p /etc/prometheus /data
sudo mv prometheus-2.47.1.linux-amd64/prometheus.yml /etc/prometheus/

Create systemd service file for Prometheus:

sudo nano /etc/systemd/system/prometheus.service

Prometheus service configuration:

[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
ExecStart=/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/data
Restart=always
[Install]
WantedBy=multi-user.target

Enable and start Prometheus:

sudo systemctl enable prometheus
sudo systemctl start prometheus

Install and Configure Grafana

Install Grafana and configure it to use Prometheus as a data source:

sudo apt-get update
sudo apt-get install -y grafana
sudo systemctl enable grafana-server
sudo systemctl start grafana-server

Access Grafana at http://<your-server-ip>:3000 and configure it to connect to Prometheus.

Monitor Kubernetes Cluster

Prometheus is a powerful monitoring and alerting toolkit, and I used it to monitor my Kubernetes cluster. Additionally, I installed the Node Exporter using Helm to collect metrics from my cluster nodes.

Install Node Exporter using Helm

To begin monitoring my Kubernetes cluster, I installed the Prometheus Node Exporter. This component allows me to collect system-level metrics from my cluster nodes. Here are the steps I followed to install the Node Exporter using Helm:

Add the Prometheus Community Helm repository:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

Create a Kubernetes namespace for the Node Exporter:

kubectl create namespace prometheus-node-exporter

Install the Node Exporter using Helm:

helm install prometheus-node-exporter prometheus-community/prometheus-node-exporter --namespace prometheus-node-exporter

Update your Prometheus configuration (prometheus.yml) to add a new job for scraping metrics from Node Exporter. You can do this by adding the following configuration:

- job_name: 'node-exporter'
metrics_path: '/metrics'
static_configs:
- targets: ['<nodeip>:9100']

Replace <nodeip> with the IP addresses of your nodes where Node Exporter is running.

Reload or restart Prometheus to apply these changes to your configuration.

This setup allowed Prometheus to collect metrics from my Kubernetes nodes using Node Exporter, providing valuable insights into the health and performance of my cluster.

With this monitoring solution in place, I now had comprehensive, real-time insights into the performance and health of both my application and the underlying infrastructure. This visibility proved invaluable for proactive issue detection and capacity planning.

Challenges and Solutions

Throughout this project, I encountered several challenges:

AWS IAM Integration with Kubernetes:

One of the main challenges I faced was configuring the correct permissions for accessing the Kubernetes cluster. By default, only the IAM user who created the cluster has access to it.

  • Solution: I had to carefully study and implement the AWS IAM Authenticator for Kubernetes. This involved editing the aws-auth ConfigMap in the kube-system namespace to grant access to additional IAM users or roles. Here’s an example of how I modified the ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapUsers: |
- userarn: arn:aws:iam::ACCOUNT-ID:user/NewUser
username: NewUser
groups:
- system:masters

This process required a deep dive into AWS IAM and Kubernetes RBAC (Role-Based Access Control) to ensure secure yet appropriate access to the cluster.

EKS Networking Complexities:

Setting up proper networking for the EKS cluster, especially regarding security groups and VPC configuration, proved challenging.

  • Solution: I thoroughly studied AWS networking concepts and used a combination of the AWS Management Console and CloudFormation templates to manage my network infrastructure. This allowed me to have both visual control and infrastructure-as-code benefits.

Future Improvements

While my current setup is robust, there’s always room for improvement:

  1. Enhance Security with Service Mesh: Implement a service mesh like Istio to provide additional security features such as mutual TLS and fine-grained traffic management.
  2. Implement Cost Optimization: Utilize tools like Kubecost to monitor and optimize my cloud spending, ensuring I’m using my resources efficiently.
  3. Infrastructure as Code with Terraform: Implement Terraform to manage and version control my entire infrastructure. This would allow for more consistent and reproducible deployments across different environments, easier collaboration among team members, and the ability to quickly spin up or tear down entire environments. Terraform can be used to manage AWS resources, Kubernetes deployments, and even application configurations, providing a single source of truth for the entire infrastructure.

Conclusion

Deploying my Netflix clone on EKS using a DevSecOps pipeline was a challenging yet rewarding experience. It allowed me to implement best practices in continuous integration, continuous deployment, and security while leveraging the power of Kubernetes for scalable and resilient applications.

This project has not only resulted in a robust, secure deployment of my application but has also significantly enhanced my skills in cloud-native technologies and DevSecOps practices.

Remember, the journey doesn’t end here. As technologies evolve and new best practices emerge, continual learning and improvement are key to staying at the forefront of DevSecOps.

For a detailed, step-by-step guide and all the code used in this project, check out my GitHub repository.

--

--