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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723899174264/274ab030-543c-4e7c-9762-2c98afa5dab9.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723899204454/6c3f2619-e8aa-41d8-9cef-c6a133496391.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723900225528/6f6ca021-3441-4976-af4e-efd8e2487d71.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723899856360/9b3a6543-3780-449f-a5eb-fc90a861207e.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723900327744/bee1194c-9430-4a4c-9919-7585221e9ab6.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723900526946/4d22621f-7baa-4bf6-b69c-e9af8416cd80.png?auto=compress,format&format=webp)
- 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.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723900745076/9fe7c5ba-eb8e-4567-be1a-95529075e400.png?auto=compress,format&format=webp)
- 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
![](https://trainwithshubham.blog/wp-content/uploads/2024/09/image-2-1024x383.png)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723901044877/f1ccb1c9-0973-4e38-a4a1-55d3e2f95b10.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723904932668/6fe70c16-8cd1-4cf9-8932-932c5a7d67b7.png?auto=compress,format&format=webp)
- Apply file
kubectl apply -f ingress.yml
- Add an domain entry in
/etc/hosts
file
sudo nano /etc/hosts
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723905089998/75ceac7b-ba6b-4a8e-a17c-a1b04a0a23a2.png?auto=compress,format&format=webp)
- Now, try to send query on URL
curl notes-app
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723905140921/e59edb43-d74b-4940-9c53-db9dabd874f4.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723905916535/4c7c9e7f-a31c-4319-8bc1-abb907eeba74.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723906280297/aee4fb19-c612-4c72-8b2f-b523842d31ad.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723906576695/b7da89a2-e49b-4206-ab69-7d0f91601a55.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723906654543/d4f47323-1df8-4712-9ad5-54cb60f3b648.png?auto=compress,format&format=webp)
For HPA setup in minikube, Need to enable addon called metrics-server
minikube addons enable metrics-server
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723911016717/434b4d6f-c4fa-4f3a-a4bf-45c118ca6284.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723911107300/6952c49c-c8f1-4f34-b379-2f84827ae7cf.png?auto=compress,format&format=webp)
- Apply file
kubectl apply -f hpa.yml
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723911087026/2139c0ee-8827-463d-92a1-f1c70c568fdd.png?auto=compress,format&format=webp)
- Currently, there is only one POD is running,
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723910728144/892f9c7e-77e6-4d66-9981-eecfa848bf8c.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723911247915/4e8f041e-11c9-4575-bbd8-5923b877d715.png?auto=compress,format&format=webp)
- 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,
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723912209246/dd8f2851-5277-4982-bfdc-bc08f5b6c80e.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723912428339/16b5770b-e379-48c2-a6e4-0ea227f60225.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723912577402/c30125b3-9404-4918-9f90-35590a25a161.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723912706526/181d3718-781e-4547-9178-14aeab4ba344.png?auto=compress,format&format=webp)
- Create service account
kubectl create serviceaccount k8s-user
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913255410/2b11b3d8-4391-4b1d-b27c-25fc82be0e37.png?auto=compress,format&format=webp)
- 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"]
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913304592/6863f4ac-6356-41ee-a05d-a77db44bf879.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913416732/ecf058a4-c944-4ca2-9dfd-1d9b6ca7d0b1.png?auto=compress,format&format=webp)
- 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,
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913549718/d47b2a6a-5e42-4f79-b1fe-72e8ecb3f29a.png?auto=compress,format&format=webp)
- As k8s-user don’t have create resource permission, hence action is forbidden.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913677435/1e0b208d-c8de-4c04-9b51-a6bb73274038.png?auto=compress,format&format=webp)
- 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
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913856457/4f08d42b-8ded-433d-a4bf-814fd635edbe.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913873038/e5bdd8fc-af47-4ad4-b350-9d386fdaf09b.png?auto=compress,format&format=webp)
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723913905965/70e7b41e-2118-4b7a-b6b0-83cb8177ebbe.png?auto=compress,format&format=webp)
Connect With Me
Thank you for reading. I hope you were able to understand and learn something new from my blog.
Happy Learning!