Author: Ojas Jawale
Table of Contents
- Project Overview
- Installation of Minikube Cluster
- Step 1 : Namespace Creation
- Step 2 : Create Deployment
- Step 3 : Create Service
- Step 4 : Persistent Volumes and Claims
- Step 5 : Ingress Controller
- Step 6 : Network Policies and CNI
- Step 7 : Job and CronJob
- Step 8 : Horizontal Pod Auto-scaling
- Step 9 : Role Base Access Control (RBAC)
- Step 10 : Testing application on browser
- Project Overview
In this Kubernetes project, the goal is to deploy and manage an application using the ojasjawale/notes-app:latest
image within a dedicated namespace, notes-app
on minikube cluster. This deployment will incorporate a wide range of Kubernetes concepts, each contributing to a robust and secure application environment.
This project is an extension of previous project deployed -> Django Notes App
Where, deployed an Django Notes application using Docker and pushed image on DockerHub. Now as an add-on of kubernetes, using same image deployed on DockerHub.
For detailed steps of installation of minikube cluster visit -> Minikube Installation
In Next steps we will directly going to setup k8s cluster for project.
- Create a namespace to organize all Kubernetes resources for this project.
- Create
namespace.yml
file, - This YAML file creates a namespace named
notes-app
to isolate resources and manage them more easily.
apiVersion: v1
kind: Namespace
metadata:
name: notes-app
- Apply file
kubectl apply -f namespace.yml


- Step 2 : Create Deployment
- Deploy the
notes-app
using a Deployment resource to manage replicas and updates. - Create
deployment.yml
file, - This Deployment ensures three replicas of the
notes-app
container are running and manages updates seamlessly.
apiVersion: apps/v1
kind: Deployment
metadata:
name: notes-app-deployment
namespace: notes-app
spec:
replicas: 3
selector:
matchLabels:
app: notes-app
template:
metadata:
labels:
app: notes-app
spec:
containers:
- name: notes-app
image: ojasjawale/notes-app:latest
ports:
- containerPort: 8000
- Apply file
kubectl apply -f deployment.yml



- Step 3 : Create Service
- Expose the
notes-app
deployment using a Service. - Create
service.yml
file,
apiVersion: v1
kind: Service
metadata:
name: notes-app-service
namespace: notes-app
spec:
selector:
app: notes-app
ports:
- protocol: TCP
port: 80
targetPort: 8000
- Apply file
kubectl apply -f service.yml

- For testing, port forwarding of traffic.
kubectl port-forward service/notes-app-service 8000:80 --address=0.0.0.0 -n notes-app
- Copy Public IP of instance with port 8000 and access application on browser.

- Set up Persistent Volumes (PV) and Persistent Volume Claims (PVC) for stateful applications.
- Create
pv.yml
file,
apiVersion: v1
kind: PersistentVolume
metadata:
name: notes-app-pv
namespace: notes-app
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /mnt/data
- Apply file
kubectl apply -f pv.yml

- Till now persistentVolume is not claimed.
- PV defines the storage resource, while PVC requests storage for a pod.
- Create
pvc.yml
file
Claiming PV storage for POD’s.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: notes-app-pvc
namespace: notes-app
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
- Apply file
kubectl apply -f pvc.yml
- Attach storage to deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: notes-app-deployment
namespace: notes-app
spec:
replicas: 3
selector:
matchLabels:
app: notes-app
template:
metadata:
labels:
app: notes-app
spec:
containers:
- name: notes-app
image: ojasjawale/notes-app:latest
ports:
- containerPort: 8000
volumeMounts:
- name: notes-app-storage
mountPath: /data # Mount path inside the container
volumes:
- name: notes-app-storage
persistentVolumeClaim:
claimName: notes-app-pvc # Reference to the PVC
To setup Ingress in minikube, need to enable addon called ingress
minikube addon enable ingress

- Set up an Ingress for path-based routing to the application.
- Create
ingress.yml
file, - The Ingress routes traffic based on the URL path to the
notes-app-service
, which listens on port 80 and forwards it to port 8000 in the pods.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: notes-app-ingress
namespace: notes-app
spec:
rules:
- host: notes-app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: notes-app-service
port:
number: 80
- path: /app
pathType: Prefix
backend:
service:
name: notes-app-service
port:
number: 80

- Apply file
kubectl apply -f ingress.yml
- Add an domain entry in
/etc/hosts
file
sudo nano /etc/hosts

- Now, try to send query on URL
curl notes-app

- This is an we called it as path based routing using Ingress controller.
Step 6 : Network Policies and CNI
- Define Network Policies to control traffic and configure CNI for network management.
- Create
networkPolicy.yml
file, - Network Policies control the communication between pods based on labels. CNI (Container Network Interface) is typically configured at the cluster level.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: notes-app-network-policy
namespace: notes-app
spec:
podSelector:
matchLabels:
app: notes-app
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: notes-app
egress:
- to:
- podSelector:
matchLabels:
app: notes-app
- Apply file
kubectl apply -f networkPolicy.yml

- Define a Job for one-time tasks and a CronJob for scheduled tasks.
- Create
job.yml
file
apiVersion: batch/v1
kind: Job
metadata:
name: notes-app-job
namespace: notes-app
spec:
template:
spec:
containers:
- name: notes-app-job
image: ojasjawale/notes-app:latest
ports:
- containerPort: 8000
restartPolicy: OnFailure


- Create
cron.yml
file
apiVersion: batch/v1
kind: CronJob
metadata:
name: notes-app-cronjob
namespace: notes-app
spec:
schedule: "0 1 * * *" # Daily at 1 AM
jobTemplate:
spec:
template:
spec:
containers:
- name: notes-app-cronjob
image: ojasjawale/notes-app:latest
ports:
- containerPort: 8000
restartPolicy: OnFailure

For HPA setup in minikube, Need to enable addon called metrics-server
minikube addons enable metrics-server

- Modify deployment for resource limiting
apiVersion: apps/v1
kind: Deployment
metadata:
name: notes-app-deployment
namespace: notes-app
spec:
replicas: 1
selector:
matchLabels:
app: notes-app
template:
metadata:
labels:
app: notes-app
spec:
containers:
- name: notes-app
image: ojasjawale/notes-app:latest
ports:
- containerPort: 8000
resources:
requests:
cpu: "100m" # Minimum CPU required
limits:
cpu: "200m" # Maximum CPU allowed
- Implement HPA to scale pods based on CPU utilization.
- Create
hpa.yml
file
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: notes-app-hpa
namespace: notes-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: notes-app-deployment
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 15

- Apply file
kubectl apply -f hpa.yml

- Currently, there is only one POD is running,

- Create two screens and in one screen try port-forwarding
kubectl port-forward service/notes-app-service 8000:80 --address=0.0.0.0 -n notes-app

- Second screen watch for real-time CPU utilization and auto-scaling of POD’s
watch kubectl get hpa -n notes-app
- POD’s are scaling up automatically,




- Create service account
kubectl create serviceaccount k8s-user

- Implement RBAC for fine-grained access control.
- Create
role.yml
file
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: notes-app-role
namespace: notes-app
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]

- Create
roleBinding.yml
file
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: notes-app-rolebinding
namespace: notes-app
subjects:
- kind: User
name: k8s-user # Replace with your Kubernetes user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: notes-app-role
apiGroup: rbac.authorization.k8s.io

- Role defines permissions, and RoleBinding assigns those permissions to a user or set of users.
- Testing of RBAC configurations,
- Run commands using –as=user flag (Where
user
is the name of the user you wish to impersonate.) - As
k8s-user
has get permissions,

- As k8s-user don’t have create resource permission, hence action is forbidden.

- Forward port on containerPort from local port and try to access application
kubectl port-forward service/notes-app-service 8000:80 --address=0.0.0.0 -n notes-app



Connect With Me
Thank you for reading. I hope you were able to understand and learn something new from my blog.
Happy Learning!