Monday, August 25, 2025

Kubernetes part11

Kubernetes part11

Class 96 Kubernetes Part8 August 24th


Helm :
Helm is a Kubernetes package manager in which the multiple numbers of YAML files such as the backend, and frontend come under one roof(helm) and deploy using helm.

Helm =front end +backend +database

Package installation:
Monitoring the application (we need write, daemonsets, svc,cm & sec,volumes) these are we need to write ,helm package has all these manifest file , we just install helm Similar way argocd has so many resource instead of that simple ,install helm
Deployment:
If you are deploy the application , you need to these manifest file (deploy,svc,cm & sec,ns,volumes,statefulset), one service has multiple manifest files , all are maintained by helm
in future if you want change anything on  service, simple change on helm file


Practical:

Step1: Create instance C7 larger,2 cpu,4 memory
 kops installation 
[root@ip-10-0-0-29 subbu]# curl -Lo kops https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  274M  100  274M    0     0  73.5M      0  0:00:03  0:00:03 --:--:-- 80.8M
[root@ip-10-0-0-29 subbu]# chmod +x kops
[root@ip-10-0-0-29 subbu]# sudo mv kops /usr/local/bin/kops
[root@ip-10-0-0-29 subbu]# kops version
Client version: 1.33.0 (git-v1.33.0)

[root@ip-10-0-0-29 ~]# aws s3 ls
2025-08-16 16:58:08 ccitpublicbucket16
[root@ip-10-0-0-29 ~]# export KOPS_STATE_STORE=s3://ccitpublicbucket16

Step2: Kops Cluster creation 
Worker node ,we can able taken any, but master node should be odd numbers need to take

[root@ip-10-0-0-29 ~]#kops create cluster --name kopsclstr.k8s.local --zones eu-west-2b,eu-west-2a --master-count 1 --master-size m7i-flex.large --master-volume-size 25 --node-count 2 --node-size c7i-flex.large --node-volume-size=20 --image=ami-044415bb13eee2391
[root@ip-10-0-0-29 ~]#kops update cluster --name kopsclstr.k8s.local --yes --admin

[root@ip-10-0-0-29 ~]# kops validate cluster --wait 10m
[root@ip-10-0-0-29 ~]# kubectl get nodes
NAME                  STATUS   ROLES           AGE    VERSION
i-024f0dd4fa62e367b   Ready    node            92s    v1.32.4
i-06146bd534402f3e7   Ready    control-plane   3m5s   v1.32.4
i-0fcbb7cfc223712de   Ready    node            51s    v1.32.4

Step3: Helm Installation 

https://helm.sh/docs/intro/install/
[root@ip-10-0-0-29 ~]# curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
[root@ip-10-0-0-29 ~]# chmod 700 get_helm.sh
[root@ip-10-0-0-29 ~]# ./get_helm.sh
Downloading https://get.helm.sh/helm-v3.18.6-linux-amd64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
helm installed into /usr/local/bin/helm

[root@ip-10-0-0-29 ~]# helm version
version.BuildInfo{Version:"v3.18.6", GitCommit:"b76a950f6835474e0906b96c9ec68a2eff3a6430", GitTreeState:"clean", GoVersion:"go1.24.6"}


Step4: Click on Helm chart ,type Jenkins ,it was deployed helm repos , you just add , and install the jenkins

https://artifacthub.io

[root@ip-10-0-0-29 ~]# helm repo add jenkins https://charts.jenkins.io
"jenkins" has been added to your repositories
[root@ip-10-0-0-29 ~]# helm install cicd jenkins/jenkins
NAME: cicd
LAST DEPLOYED: Thu Aug 28 10:30:12 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get your 'admin' user password by running:
  kubectl exec --namespace default -it svc/cicd-jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo
2. Get the Jenkins URL to visit by running these commands in the same shell:
  echo http://127.0.0.1:8080
  kubectl --namespace default port-forward svc/cicd-jenkins 8080:8080

3. Login with the password from step 1 and the username: admin
4. Configure security realm and authorization strategy
5. Use Jenkins Configuration as Code by specifying configScripts in your values.yaml file, see documentation: http://127.0.0.1:8080/configuration-as-code and examples: https://github.com/jenkinsci/configuration-as-code-plugin/tree/master/demos

For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine

For more information about Jenkins Configuration as Code, visit:
https://jenkins.io/projects/jcasc/

Jenkins deployed successfully.

[root@ip-10-0-0-29 ~]# helm list
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
cicd    default         1               2025-08-28 10:30:12.90224605 +0000 UTC  deployed        jenkins-5.8.83  2.516.2

Step5:See automatically all pod and service deployed,if you are expose the service we can able to use jenkins 

[root@ip-10-0-0-29 ~]# kubectl get all
NAME                 READY   STATUS    RESTARTS   AGE
pod/cicd-jenkins-0   2/2     Running   0          94s

NAME                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
service/cicd-jenkins         ClusterIP   100.69.238.40   <none>        8080/TCP    94s
service/cicd-jenkins-agent   ClusterIP   100.68.56.47    <none>        50000/TCP   94s
service/kubernetes           ClusterIP   100.64.0.1      <none>        443/TCP     15m

NAME                            READY   AGE
statefulset.apps/cicd-jenkins   1/1     94s

Step6: Jenkin login access key token
[root@ip-10-0-0-29 ~]#  kubectl exec --namespace default -it svc/cicd-jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo
enaF8FPbxnGo81wfmwoBj7

Step7: Expose the port ClusterIP to nodeport

[root@ip-10-0-0-29 ~]# kubectl get service cicd-jenkins
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
cicd-jenkins   ClusterIP   100.69.238.40   <none>        8080/TCP   21m

--Changed to Nodeport from clusterport

[root@ip-10-0-0-29 ~]# kubectl patch service cicd-jenkins -p '{"spec":{"type":"NodePort"}}'
service/cicd-jenkins patched
[root@ip-10-0-0-29 ~]# kubectl get service cicd-jenkins
NAME           TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
cicd-jenkins   NodePort   100.69.238.40   <none>        8080:32589/TCP   22m

--This command will give you ,all External-ip node is public for nodes , you able to access using 
[root@ip-10-0-0-29 ~]# kubectl get nodes -o wide
NAME                  STATUS   ROLES           AGE   VERSION   INTERNAL-IP      EXTERNAL-IP      OS-IMAGE             KERNEL-VERSION   CONTAINER-RUNTIME
i-024f0dd4fa62e367b   Ready    node            39m   v1.32.4   172.20.55.209    35.177.119.234   Ubuntu 24.04.2 LTS   6.8.0-1029-aws   containerd://1.7.28
i-06146bd534402f3e7   Ready    control-plane   40m   v1.32.4   172.20.209.124   18.130.219.218   Ubuntu 24.04.2 LTS   6.8.0-1029-aws   containerd://1.7.28
i-0fcbb7cfc223712de   Ready    node            38m   v1.32.4   172.20.186.174   13.42.35.13      Ubuntu 24.04.2 LTS   6.8.0-1029-aws   containerd://1.7.28

--Before you need open the security ports to node server.


Step8:uninstall the deployment 
root@ip-10-0-0-29 ~]# helm delete cicd
release "cicd" uninstalled
[root@ip-10-0-0-29 ~]# helm list
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP V

Above one package management for Helm 
  Now are planning create manifest files using helm for deployment
Step1:

[root@ip-10-0-0-29 ~]# helm create ccit
Creating ccit

--By default some file are create in the ccit directory 

[root@ip-10-0-0-29 ~]# cd ccit
[root@ip-10-0-0-29 ccit]# ls
Chart.yaml  charts  templates  values.yaml

--Values.yaml has ,deployment stuff how many replicas you need  

Step2: Change below thing and save  Values.yaml

 replicaCount: 2
 image:
  repository: vakatisubbu/train
 type: LoadBalancer

Step3: Characte.yaml 

appVersion: "latest"

Step4: Successfully deployed 
[root@ip-10-0-0-29 ccit]# helm install release-1 .
NAME: release-1
LAST DEPLOYED: Thu Aug 28 11:27:06 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch its status by running 'kubectl get --namespace default svc -w release-1-ccit'
  export SERVICE_IP=$(kubectl get svc --namespace default release-1-ccit --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
  echo http://$SERVICE_IP:80

Step5: with the deployment, below pods and service created 

[root@ip-10-0-0-29 ccit]# kubectl get all
NAME                                  READY   STATUS    RESTARTS   AGE
pod/release-1-ccit-67c74cd674-hd4xm   1/1     Running   0          6m15s
pod/release-1-ccit-67c74cd674-zg694   1/1     Running   0          6m15s

NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP                                                               PORT(S)        AGE
service/kubernetes       ClusterIP      100.64.0.1       <none>                                                                    443/TCP        76m
service/release-1-ccit   LoadBalancer   100.67.212.244   a4b72e79b052941108ae11c17eee7397-1886167053.eu-west-2.elb.amazonaws.com   80:30163/TCP   6m15s

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/release-1-ccit   2/2     2            2           6m15s

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/release-1-ccit-67c74cd674   2         2         2       6m15s

With load balancer url ,iam able to access the application


With node ip also working fine
Step6: If you want to change anything replicas need to reduce value.yaml update 

 replicaCount: 4

[root@ip-10-0-0-29 ccit]# helm upgrade release-1 .
Release "release-1" has been upgraded. Happy Helming!
NAME: release-1
LAST DEPLOYED: Thu Aug 28 11:43:52 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch its status by running 'kubectl get --namespace default svc -w release-1-ccit'
  export SERVICE_IP=$(kubectl get svc --namespace default release-1-ccit --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
  echo http://$SERVICE_IP:80
Step7: See here replicas 4 created 
[root@ip-10-0-0-29 ccit]# kubectl get all
NAME                                  READY   STATUS    RESTARTS   AGE
pod/release-1-ccit-67c74cd674-hd4xm   1/1     Running   0          17m
pod/release-1-ccit-67c74cd674-pqt2r   1/1     Running   0          44s
pod/release-1-ccit-67c74cd674-rdv6l   1/1     Running   0          44s
pod/release-1-ccit-67c74cd674-zg694   1/1     Running   0          17m

NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP                                                               PORT(S)        AGE
service/kubernetes       ClusterIP      100.64.0.1       <none>                                                                    443/TCP        87m
service/release-1-ccit   LoadBalancer   100.67.212.244   a4b72e79b052941108ae11c17eee7397-1886167053.eu-west-2.elb.amazonaws.com   80:30163/TCP   17m

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/release-1-ccit   4/4     4            4           17m

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/release-1-ccit-67c74cd674   4         4         4       17m

Step7: Update the image now ,  value.yaml file 
image:
  repository: vakatisubbu/movies


Step8: Now change the image to vakatisubbu/recharge
[root@ip-10-0-0-29 ccit]# helm upgrade release-1 .
Release "release-1" has been upgraded. Happy Helming!
NAME: release-1
LAST DEPLOYED: Thu Aug 28 12:14:09 2025
NAMESPACE: default
STATUS: deployed
REVISION: 4
NOTES:
1. Get the application URL by running these commands:
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch its status by running 'kubectl get --namespace default svc -w release-1-ccit'
  export SERVICE_IP=$(kubectl get svc --namespace default release-1-ccit --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
  echo http://$SERVICE_IP:80

Step8: History for the release-1
[root@ip-10-0-0-29 ccit]# helm history release-1
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Thu Aug 28 11:27:06 2025        superseded      ccit-0.1.0      latest          Install complete
2               Thu Aug 28 11:43:52 2025        superseded      ccit-0.1.0      latest          Upgrade complete
3               Thu Aug 28 11:48:21 2025        superseded      ccit-0.1.0      latest          Upgrade complete
4               Thu Aug 28 12:14:09 2025        deployed        ccit-0.1.0      latest          Upgrade complete

Step9: See above all are revision version,you can rollback one version to another version 

[root@ip-10-0-0-29 ccit]# helm rollback release-1 2
Rollback was a success! Happy Helming!
[root@ip-10-0-0-29 ccit]# helm history release-1
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Thu Aug 28 11:27:06 2025        superseded      ccit-0.1.0      latest          Install  complete (Train)
2               Thu Aug 28 11:43:52 2025        superseded      ccit-0.1.0      latest          Upgrade complete(Train) replica 4
3               Thu Aug 28 11:48:21 2025        superseded      ccit-0.1.0      latest          Upgrade complete(Movies)
4               Thu Aug 28 12:14:09 2025        superseded      ccit-0.1.0      latest          Upgrade complete(Recharge)
5               Thu Aug 28 12:18:28 2025        deployed        ccit-0.1.0      latest          Rollback to 2

Rollback to version 2 train with replica 4 
Rollback to version to 4 now movies 

[root@ip-10-0-0-29 ccit]# helm history release-1
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Thu Aug 28 11:27:06 2025        superseded      ccit-0.1.0      latest          Install complete
2               Thu Aug 28 11:43:52 2025        superseded      ccit-0.1.0      latest          Upgrade complete
3               Thu Aug 28 11:48:21 2025        superseded      ccit-0.1.0      latest          Upgrade complete
4               Thu Aug 28 12:14:09 2025        superseded      ccit-0.1.0      latest          Upgrade complete
5               Thu Aug 28 12:18:28 2025        superseded      ccit-0.1.0      latest          Rollback to 2
6               Thu Aug 28 12:25:15 2025        deployed        ccit-0.1.0      latest          Rollback to 4

Uninstall 
[root@ip-10-0-0-29 ccit]# helm uninstall release-1
release "release-1" uninstalled
remove ccit folder 

If you are difficult to manage your own manifestfiles also the helm ,delete template folder all existing manifest files instead of them ,created you own manifest files,svc files
Step1:
[root@ip-10-0-0-29 ~]#  helm create devops
Creating devops
[root@ip-10-0-0-29 ~]# cd devops
[root@ip-10-0-0-29 devops]# ls
Chart.yaml  charts  templates  values.yaml
[root@ip-10-0-0-29 devops]# rm -rf  templates charts values.yaml

[root@ip-10-0-0-29 devops]# ls
Chart.yaml
[root@ip-10-0-0-29 devops]# vi manifest.yaml
[root@ip-10-0-0-29 devops]# vi svc.yaml
[root@ip-10-0-0-29 devops]# vi Chart.yaml
[root@ip-10-0-0-29 devops]# helm install subbu-1 .
NAME: subbu-1
LAST DEPLOYED: Thu Aug 28 12:41:18 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

[root@ip-10-0-0-29 devops]# kubectl get all
NAME        READY   STATUS    RESTARTS     AGE
pod/pod-1   1/1     Running   1 (6s ago)   13m

NAME                 TYPE           CLUSTER-IP       EXTERNAL-IP                                                              PORT(S)        AGE
service/kubernetes   ClusterIP      100.64.0.1       <none>                                                                   443/TCP        3h3m
service/myservice    LoadBalancer   100.71.148.165   a41d28df204c5426783ca08cf7c1a06e-188168759.eu-west-2.elb.amazonaws.com   80:30629/TCP   13m
Real time we are using values.yaml only 

Argocd
https://github.com/devops0014/all-setups/blob/master/argocd.sh

Git :we can called sem tool
mvn:Build tool
Jenkins: ci/cd tool
argocd:git ops tool 

GitOps is a way of managing software infrastructure and deployments using
Git as the source of truth.
Git as the Source of Truth: In GitOps, all our configurations like (deployments,
services, secrets etc..) are stored in git repository.
Automated Processes: Whenever we make any changes in those YAML files
gitops tools like (Argo CD/ Flux) will detects and apply those changes on
kubernetes cluster. It ensures that the live infrastructure matches the
configurations in the Git repository.
Here, we can clearly observe that continuous deployment. Whenever we
make any changes in git, it will automatically reflects in kubernetes cluster.


Step1:

[root@ip-10-0-0-29 devops]# kubectl create ns argocd
namespace/argocd created

[root@ip-10-0-0-29 ]#kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl get all -n argocd

See these are service created 

[root@ip-10-0-0-29 ~]# kubectl get all -n argocd
NAME                                                    READY   STATUS    RESTARTS   AGE
pod/argocd-application-controller-0                     1/1     Running   0          4m28s
pod/argocd-applicationset-controller-64b8948d8b-wwpcp   1/1     Running   0          4m29s
pod/argocd-dex-server-6f48b6c5c7-qr9h8                  1/1     Running   0          4m29s
pod/argocd-notifications-controller-6c4547fb9c-mxl4l    1/1     Running   0          4m29s
pod/argocd-redis-78b9ff5487-kkp9r                       1/1     Running   0          4m28s
pod/argocd-repo-server-67d8c6bbf6-x77gd                 1/1     Running   0          4m28s
pod/argocd-server-577756d78b-x26gx                      1/1     Running   0          4m28s

NAME                                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/argocd-applicationset-controller          ClusterIP   100.65.179.160   <none>        7000/TCP,8080/TCP            4m29s
service/argocd-dex-server                         ClusterIP   100.67.105.248   <none>        5556/TCP,5557/TCP,5558/TCP   4m29s
service/argocd-metrics                            ClusterIP   100.65.16.224    <none>        8082/TCP                     4m29s
service/argocd-notifications-controller-metrics   ClusterIP   100.67.55.85     <none>        9001/TCP                     4m29s
service/argocd-redis                              ClusterIP   100.64.151.140   <none>        6379/TCP                     4m29s
service/argocd-repo-server                        ClusterIP   100.69.214.207   <none>        8081/TCP,8084/TCP            4m29s
service/argocd-server                             ClusterIP   100.66.122.126   <none>        80/TCP,443/TCP               4m29s
service/argocd-server-metrics                     ClusterIP   100.68.60.26     <none>        8083/TCP                     4m29s

NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/argocd-applicationset-controller   1/1     1            1           4m29s
deployment.apps/argocd-dex-server                  1/1     1            1           4m29s
deployment.apps/argocd-notifications-controller    1/1     1            1           4m29s
deployment.apps/argocd-redis                       1/1     1            1           4m29s
deployment.apps/argocd-repo-server                 1/1     1            1           4m28s
deployment.apps/argocd-server                      1/1     1            1           4m28s

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/argocd-applicationset-controller-64b8948d8b   1         1         1       4m29s
replicaset.apps/argocd-dex-server-6f48b6c5c7                  1         1         1       4m29s
replicaset.apps/argocd-notifications-controller-6c4547fb9c    1         1         1       4m29s
replicaset.apps/argocd-redis-78b9ff5487                       1         1         1       4m29s
replicaset.apps/argocd-repo-server-67d8c6bbf6                 1         1         1       4m28s
replicaset.apps/argocd-server-577756d78b                      1         1         1       4m28s

NAME                                             READY   AGE
statefulset.apps/argocd-application-controller   1/1     4m28s

Step2: To access these service we have argocd dashboad, execute this command 

[root@ip-10-0-0-29 ~]# kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
yum install jq -y
export ARGOCD_SERVER='kubectl get svc argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname''
echo $ARGOCD_SERVER
kubectl get svc argocd-server -n argocd -o json | jq --raw-output .status.loadBalancer.ingress[0].hostname
service/argocd-server patched
Amazon Linux 2023 repository                                                                                              69 kB/s | 3.6 kB     00:00
Amazon Linux 2023 Kernel Livepatch repository                                                                             58 kB/s | 2.9 kB     00:00
Package jq-1.7.1-50.amzn2023.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
kubectl get svc argocd-server -n argocd -o json | jq --raw-output .status.loadBalancer.ingress[0].hostname
null

[root@ip-10-0-0-29 ~]# kubectl get svc argocd-server -n argocd -o json | jq --raw-output .status.loadBalancer.ingress[0].hostname
a0c3024346c62444f9d55b6055cf9f15-880560546.eu-west-2.elb.amazonaws.com

Step3:password ,we need get using command ,password yellow color


[root@ip-10-0-0-29 ~]# export ARGO_PWD='kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d'
echo $ARGO_PWD
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
ijU6rjPrCcyul5tv
Step4: After login click +New app


[root@ip-10-0-0-29 ~]# kubectl create  ns dev
namespace/dev created


Step5: cluster url will come automatically ,namespace dev created given click create

Step6: it is synchrize to git repo healthy


As see here deployment and services,replica set three pods created

Using command

[root@ip-10-0-0-29 ~]# kubectl get po -n dev
NAME                      READY   STATUS    RESTARTS   AGE
my-app-5fb94777b5-9m7gs   1/1     Running   0          5m45s
my-app-5fb94777b5-c5tm4   1/1     Running   0          5m45s
my-app-5fb94777b5-pbps6   1/1     Running   0          5m45s

See here application opened successfully.


Step7: now planning to change image in git hub , need to check automaticly gitrepo 
argocd deployed or not 

Step8: deployment.yml
 from image: shaikmustafa/paytm:bus to image: shaikmustafa/cycle

See here synchroized automatically ,new replica set was created , from there new pod created.

Step9: See here automatically new application 


 kops delete cluster --name kopsclstr.k8s.local --yes

--Thanks 


Saturday, August 23, 2025

Kubernetes part10

Kubernetes part10

Class 95 Kubernetes Part8 August 23rd

Kubernetes cluster usually different people has access (developer/tester/deployment user..etc)
for them how to give the access is call Rollback access concept.

Kubernetes admin need to decided give the permissions which person to give which permission

Rbac(Rollback access):  Iam a developer I want to see the pods, another developer he need delete the pods ,one more Devops guy he need create, delete the pod

Role-Based Access Control (RBAC) is a critical security feature in Kubernetes that allows you to define and manage access to resources based on roles and permissions. RBAC ensures that only authorized users, processes, or services can interact with specific resources within a Kubernetes cluster
For ex:-
Role( Dev ,Tester,Devops(PODS view watch,create,delete, deploy: create,delete, Svc: all)
First we need create the Role create -->then permission--> then attached to developer

Functionality How it will work:

Kubernetes resources(PODS,Deploy,RS,SVC,VOL,CM,SEC) permisson(view,watch,create,delete)
here we attached to user.
IAM (EC2,S3,RDS,VPC) permission(Read,write,delete) for all them we create one policy attached to user attached.

In Kubernetes, there are two types of accounts
1.User Account
2.Service Account
User account: User accounts are used to log into a Kubernetes cluster and manipulate resources therein. Each user account is associated with a unique set of credentials, which are used to authenticate the service’s requests.
Service Account: Kubernetes Service Accounts are specialized accounts used by applications and services running on Kubernetes to interact with the Kubernetes API.

Practical : 
in Kubernetes we can not directly create the user , below multiple way to create the user 
  • client certificates 
  • bearer tokens 
  • authenticating proxy 
  • HTTP basic auth.
I will choose client certificate to create a user which is very easy to create. This certificates are used to create users. When a user perform any command like kubectl get po then K8's API will authenticate and authorize the request.

Step1: Generate the certificate, key just like sshkeygen type of the key 

lets create a folder: subbu
Generate a key using openssl : openssl genrsa -out subbu.key 2048
Generate a Client Sign Request (CSR) : openssl req -new -key subbu.key -out
subbu.csr -subj "/CN=subbu/O=group1"

Generate the certificate (CRT): openssl x509 -req -in subbu.csr -CA
~/.minikube/ca.crt -CAkey ~/.minikube/ca.key -CAcreateserial -out subbu.crt -days
500

steps to create user.
lets create a user: kubectl config set-credentials subbu --client-certificate=subbu.crt --client-key=subbu.key

[root@ip-10-0-0-29 subbu]# openssl genrsa -out subbu.key 2048
[root@ip-10-0-0-29 subbu]# ls
subbu.key

[root@ip-10-0-0-29 subbu]# openssl req -new -key subbu.key -out subbu.csr -subj "/CN=subbu/O=group1"
[root@ip-10-0-0-29 subbu]# ls -lrt
total 8
-rw-------. 1 root root 1704 Aug 26 14:36 subbu.key
-rw-r--r--. 1 root root  907 Aug 26 14:38 subbu.csr

[root@ip-10-0-0-29 subbu]# openssl x509 -req -in subbu.csr -CA ~/.minikube/ca.crt -CAkey ~/.minikube/ca.key -CAcreateserial -out subbu.crt -days 500
Certificate request self-signature ok
subject=CN=subbu, O=group1

[root@ip-10-0-0-29 subbu]# kubectl config set-credentials subbu --client-certificate=subbu.crt --client-key=subbu.key
User "subbu" set.

Step2: user create successfully, one user to another user to switch we are using context 
--Below we get know which user your in current-context minikube and list of users 
[root@ip-10-0-0-29 subbu]# kubectl config view
current-context: minikube

users:
- name: minikube
  user:
    client-certificate: /root/.minikube/profiles/minikube/client.crt
    client-key: /root/.minikube/profiles/minikube/client.key
- name: subbu
  user:
    client-certificate: /root/subbu/subbu.crt
    client-key: /root/subbu/subbu.key

Step3: one user to another user to switch required context , As you see above minikube ,has context, subbu user no context ,we need create context for our user

Create context with name my-context
Set a context entry in kubeconfig: kubectl config set-context my-context --cluster=minikube --user=subbu

[root@ip-10-0-0-29 subbu]# kubectl config set-context my-context --cluster=minikube --user=subbu
Context "my-context" created.
[root@ip-10-0-0-29 subbu]# kubectl config view
contexts:

- context:

    cluster: minikube

     name: context_info

   user: minikube

  name: minikube

- context:

    cluster: minikube

    user: subbu

  name: my-context

Step4: Switch the context 
Switch to devops user: kubectl config use-context my-context 
[root@ip-10-0-0-29 subbu]# kubectl config use-context my-context
Switched to context "my-context".
--Now you see we are in my-context 
[root@ip-10-0-0-29 subbu]# kubectl config view
current-context: my-context
--we are not give permission just create the user 
[root@ip-10-0-0-29 subbu]# kubectl get po
Error from server (Forbidden): pods is forbidden: User "subbu" cannot list resource "pods" in API group "" in the namespace "default"

There are four components to RBAC in Kubernetes: 
1.roles 2.Cluster roles 3.role bindings 4.ClusterRolesBinding

We have roles (pods,svc,deploy,create,delete,watch) ,these role attached to user called as rolebinding
Cluster also same roles(pods,svc,deploy,create,delete,watch) ,attached to  user called as cluster role binding

If you are giving specific namespace is called role binding .
If you are giving all namespace to give permission is called cluster binding 

Permission to give role need to create:

Create specific namespace 
Step1:
[root@ip-10-0-0-29 subbu]# kubectl create ns dev
namespace/dev created

You will get the different version of the resource

[root@ip-10-0-0-29 subbu]# kubectl api-resources

Create the role
[root@ip-10-0-0-29 subbu]# vi role.yaml
[root@ip-10-0-0-29 subbu]# cat role.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dev-role
  namespace: dev
rules:
  - apiGroups: ["*"]
    resources: ["pods","service"]
    verbs: ["get","list","create"]
[root@ip-10-0-0-29 subbu]# kubectl create -f role.yaml
role.rbac.authorization.k8s.io/dev-role created

Step2: Need to check dev namespace roles create or not 
[root@ip-10-0-0-29 subbu]# kubectl get roles -n dev
NAME       CREATED AT
dev-role   2025-08-26T15:23:56Z
Step3: Role binding need attached the above role to the user subbu
[root@ip-10-0-0-29 subbu]# cat binding.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-role-binding
  namespace: dev
subjects:
  - kind: User
    name: subbu
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-role
  apiGroup: rbac.authorization.k8s.io

[root@ip-10-0-0-29 subbu]# kubectl create -f binding.yaml
rolebinding.rbac.authorization.k8s.io/dev-role-binding created

Step3: Attached role to user that is called rolebase, now the subbu user has ,able create the pod 
let switch user using context 
[root@ip-10-0-0-29 subbu]# kubectl config use-context my-context
Switched to context "my-context".
[root@ip-10-0-0-29 subbu]# kubect config view
current-context: my-context
Get error we have give permission to dev tablespace not default tablespace 
[root@ip-10-0-0-29 subbu]# kubectl get po
Error from server (Forbidden): pods is forbidden: User "subbu" cannot list resource "pods" in API group "" in the namespace "default"
--See here permission exists 
[root@ip-10-0-0-29 subbu]# kubectl get po -n dev
No resources found in dev namespace.
Step4: Lets create the pod ,Successfully create the pod ,able list also 
[root@ip-10-0-0-29 subbu]# kubectl run pod-1 --image=nginx -n dev
pod/pod-1 created
[root@ip-10-0-0-29 subbu]# kubectl get pod -n dev
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          14s

Step5: We have not given delete permission to subbu lets try once .
[root@ip-10-0-0-29 subbu]# kubectl delete pod pod-1 -n dev
Error from server (Forbidden): pods "pod-1" is forbidden: User "subbu" cannot delete resource "pods" in API group "" in the namespace "dev"

Getting error subbu use not having permssion ,let us give permission to subbu, switch minikube 
and update the role 

Step6:
[root@ip-10-0-0-29 subbu]# kubectl config use-context minikube
Switched to context "minikube".
current-context: minikube
[root@ip-10-0-0-29 subbu]# cat role.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dev-role
  namespace: dev
rules:
  - apiGroups: ["*"]
    resources: ["pods","service"]
    verbs: ["get","list","create","delete","watch"]

Step7: apply the role
After applied below command 
[root@ip-10-0-0-29 subbu]# kubectl apply -f role.yaml
Warning: resource roles/dev-role is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
role.rbac.authorization.k8s.io/dev-role configured
[root@ip-10-0-0-29 subbu]# kubectl get pod -n dev
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          61s
[root@ip-10-0-0-29 subbu]# kubectl delete po pod-1 -n dev
pod "pod-1" deleted
 
Cluster role and Cluster binding 
Step1: Delete the role first dev
[root@ip-10-0-0-29 subbu]# kubectl delete role --all -n dev
role.rbac.authorization.k8s.io "dev-role" deleted
Step2:Delete the rolebinding 
[root@ip-10-0-0-29 subbu]# kubectl delete rolebinding --all -n dev
rolebinding.rbac.authorization.k8s.io "dev-role-binding" deleted

Step3: now attach the cluster role and cluster binding attach to subbu user 
[root@ip-10-0-0-29 subbu]# cat clusterrole.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: devops-role
rules:
  - apiGroups: ["*"]
    resources: ["pods","service"]
    verbs: ["get","list","create","delete","watch"]

[root@ip-10-0-0-29 subbu]# kubectl create -f clusterrole.yaml
clusterrole.rbac.authorization.k8s.io/devops-role created

[root@ip-10-0-0-29 subbu]# cat clusterbinding.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: devops-role-binding
subjects:
  - kind: User
    name: subbu
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: devops-role
  apiGroup: rbac.authorization.k8s.io

[root@ip-10-0-0-29 subbu]# kubectl create -f clusterbinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/devops-role-binding created

Now the user has permission to all namespace 
Step4: switched to my-context subbu user 
[root@ip-10-0-0-29 subbu]# kubectl config use-context my-context
Switched to context "my-context".

-- See here even default namespace pod also coming 
[root@ip-10-0-0-29 subbu]# kubectl get po
NAME        READY   STATUS                       RESTARTS       AGE
pod-1       0/1     CreateContainerConfigError   0              5d
pod-2       0/1     CreateContainerConfigError   0              5d
pod-3       1/1     Running                      7 (4h9m ago)   4d23h
pod-4       1/1     Running                      6 (4h9m ago)   4d9h
test-curl   0/1     ImagePullBackOff             0              4d6h

-- See here we can delete the pod's also coming 

[root@ip-10-0-0-29 subbu]# kubectl delete pod pod-1
pod "pod-1" deleted
[root@ip-10-0-0-29 subbu]# kubectl delete pod pod-2
pod "pod-2" deleted

-- See here we can create the pod also coming 

[root@ip-10-0-0-29 subbu]# kubectl run pod-1 --image=nginx
pod/pod-1 created

[root@ip-10-0-0-29 subbu]# kubectl get po
NAME        READY   STATUS             RESTARTS        AGE
pod-1       1/1     Running            0               10s
pod-3       1/1     Running            7 (4h11m ago)   4d23h
pod-4       1/1     Running            6 (4h11m ago)   4d9h
test-curl   0/1     ImagePullBackOff   0               4d6h

Step5: Created one dev namespace one pod , let create one namespace 

[root@ip-10-0-0-29 subbu]# kubectl run pod-1 --image=nginx -n dev
pod/pod-1 created

Step6:
[root@ip-10-0-0-29 subbu]# kubectl config use-context minikube
Switched to context "minikube".
--Created one namespace prod
[root@ip-10-0-0-29 subbu]# kubectl create ns prod
namespace/prod created

--Created one pod new namespace prod

[root@ip-10-0-0-29 subbu]# kubectl run pod-2 --image=ubuntu -n prod
pod/pod-2 created

--See here all namespace able to access pod, able create,delete all tablespace

[root@ip-10-0-0-29 subbu]# kubectl get po -n prod
NAME    READY   STATUS             RESTARTS      AGE
pod-2   0/1     CrashLoopBackOff   4 (17s ago)   119s
[root@ip-10-0-0-29 subbu]# kubectl get po -n dev
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          9m23s



--Thanks 


Friday, August 22, 2025

Kubernetes part9

Kubernetes part9

Class 94 Kubernetes Part8 August 22nd

Resource Quota: Resource quota is on of the rich features of Kubernetes that helps to manage and distribute resources according to the requirements.

Just assume situation We have 2 teams( team-A,team-B) which are working on single Kubernetes cluster
Team -A need more CPUS & memory because of heavy workload tasks. Team-B pod are not created with resource quota,
whenever team-A application resource high usage trying create one more pod, if space is less delete the team-B pod and occupied the space, because team-B  space not allocated to resource quota.for the reason every pod must resource quota is important

There are tow type of restrictions that need to be mentioned while using resource quota

Limit: Represent the maximum amount of CPUS or memory the pod can use 

(limit: 4 cpus & 4 gb ram)

Request: Represent the minimum amount of CPU or memory that the pod is guaranteed to have

(Pod creation minimum requirement 1cpu & 1 gb ram)

Practical:

Step1: minikube already setup done ec2-instance amazon Linux 

[root@ip-10-0-0-29 ~]# systemctl start docker

[root@ip-10-0-0-29 ~]# minikube start --driver=docker --force

[root@ip-10-0-0-29 ~]# minikube status

minikube

type: Control Plane

host: Running

kubelet: Running

apiserver: Running

kubeconfig: Configured

Step2:Create namespace and going to inside the namespace 

[root@ip-10-0-0-29 ~]# kubectl create ns dev

namespace/dev created

[root@ip-10-0-0-29 ~]# kubectl config  set-context --current --namespace=dev

Context "minikube" modified.

Step3: As you see here  Create resource 

[root@ip-10-0-0-29 ~]# vi resourcequote.yaml

[root@ip-10-0-0-29 ~]# cat resourcequote.yaml

apiVersion: v1

kind: Pod

metadata:

  name: team-a

spec:

  containers:

    - name: container1

      image: nginx

      ports:

        - containerPort: 80

      resources:

        requests:

          memory: "10Mi"

          cpu: "100m"

        limits:

          memory: "20Mi"

          cpu: "200m"

[root@ip-10-0-0-29 ~]# kubectl create -f resourcequote.yaml

pod/team-a created

Step3: As see below namespace is dev and for the pod  created with 100mi memory 10 mi

[root@ip-10-0-0-29 ~]# kubectl describe po team-a
Name:             team-a
Namespace:        dev
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2
Start Time:       Mon, 25 Aug 2025 15:22:56 +0000
Labels:           <none>
Annotations:      <none>
Status:           Running
IP:               10.244.0.38

 Ready:          True
    Restart Count:  0
    Limits:
      cpu:     200m
      memory:  20Mi
    Requests:
      cpu:        100m
      memory:     10Mi
    Environment:  <none>

Step4: Now trying to create new pod without request options ,give limit  observer what limit you have given automatically it was taken request also same size.
 
[root@ip-10-0-0-29 ~]# cat resourcequote.yaml
apiVersion: v1
kind: Pod
metadata:
  name: team-b
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      resources:
        limits:
          memory: "20Mi"
          cpu: "200m"
[root@ip-10-0-0-29 ~]# kubectl create -f resourcequote.yaml
pod/team-b created
[root@ip-10-0-0-29 ~]# kubectl describe po team-b
Name:             team-b
Namespace:        dev
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2

    Limits:
      cpu:     200m
      memory:  20Mi
    Requests:
      cpu:        200m
      memory:     20Mi

Step5: Now we plan to putting request and removed limits 
[root@ip-10-0-0-29 ~]# cat resourcequote.yaml

apiVersion: v1

kind: Pod

metadata:

  name: team-c

spec:

  containers:

    - name: container1

      image: nginx

      ports:

        - containerPort: 80

      resources:

         requests:

          memory: "10Mi"

          cpu: "100m"

[root@ip-10-0-0-29 ~]# kubectl create -f resourcequote.yaml

pod/team-c created

As see below request given it will take request only , no limit that mean it is unlimited , it is not good practice 

[root@ip-10-0-0-29 ~]# kubectl describe po team-c

Name:             team-c

Namespace:        dev

Priority:         0

Service Account:  default

Node:             minikube/192.168.49.2


 Requests:

      cpu:        100m

      memory:     10Mi

    Environment:  <none>

    Mounts:

Note: Three case above 
1. Both request and limit --it as follow limit
2. Limit  limit=request
3. Request request=unlimited
[root@ip-10-0-0-29 ~]# kubectl delete po --all
pod "team-a" deleted
pod "team-b" deleted
pod "team-c" deleted

Realtime 

Step1:
[root@ip-10-0-0-29 ~]# cat realtime.yaml
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myreq
spec:
  hard:
    requests.cpu: "258m"
    requests.memory: "500Mi"
    limits.cpu: "1000m"
    limits.memory: "1500Mi"

[root@ip-10-0-0-29 ~]# kubectl create -f realtime.yaml
resourcequota/myreq created

We have added the resource to dev tablespace 

[root@ip-10-0-0-29 ~]# kubectl get ns

NAME              STATUS   AGE

default           Active   4d

dev               Active   3h58m

As see below showing how many cpu 1, you able create memory 

[root@ip-10-0-0-29 ~]# kubectl describe ns dev

Name:         dev

Labels:       kubernetes.io/metadata.name=dev

Annotations:  <none>

Status:       Active

Resource Quotas

  Name:            myreq

  Resource         Used  Hard

  --------         ---   ---

  limits.cpu       0     1

  limits.memory    0     1500Mi

  requests.cpu     0     258m

  requests.memory  0     500Mi

No LimitRange resource.


Step6:Lets create the pod in dev namspace , you must specified the limit other wise pod will not create 

[root@ip-10-0-0-29 ~]# cat pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: team-a
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      resources:
        requests:
          memory: "10Mi"
          cpu: "100m"
        limits:
          memory: "20Mi"
          cpu: "200m"

--Now namespace Resource quota used dev namespace

Resource Quotas
  Name:            myreq
  Resource         Used  Hard
  --------         ---   ---
  limits.cpu       200m  1
  limits.memory    20Mi  1500Mi
  requests.cpu     100m  258m
  requests.memory  10Mi  500Mi

Step7:now trying to create without resource, see getting must be specified request and limit need to give
[root@ip-10-0-0-29 ~]# kubectl create -f pod.yml
Error from server (Forbidden): error when creating "pod.yml": pods "team-b" is forbidden: failed quota: myreq: must specify limits.cpu for: container1; limits.memory for: container1; requests.cpu for: container1; requests.memory for: container1
[root@ip-10-0-0-29 ~]#

Step8: Created one more pod  team-b CPU 58m left , let us create one more pod 
[root@ip-10-0-0-29 ~]# vi pod.yml
[root@ip-10-0-0-29 ~]# kubectl create -f pod.yml
pod/team-b created
[root@ip-10-0-0-29 ~]# kubectl get pod
NAME     READY   STATUS    RESTARTS   AGE
team-a   1/1     Running   0          7m52s
team-b   1/1     Running   0          15s
[root@ip-10-0-0-29 ~]# kubectl describe ns dev
Name:         dev
Labels:       kubernetes.io/metadata.name=dev
Annotations:  <none>
Status:       Active
Resource Quotas
  Name:            myreq
  Resource         Used  Hard
  --------         ---   ---
  limits.cpu       400m  1
  limits.memory    40Mi  1500Mi
  requests.cpu     200m  258m
  requests.memory  20Mi  500Mi

Step9: Creating more pod ,getting quora exceeded, now increase the request quota

[root@ip-10-0-0-29 ~]# vi pod.yml
[root@ip-10-0-0-29 ~]# kubectl create -f pod.yml
Error from server (Forbidden): error when creating "pod.yml": pods "team-c" is forbidden: exceeded quota: myreq, requested: requests.cpu=100m, used: requests.cpu=200m, limited: requests.cpu=258m
[root@ip-10-0-0-29 ~]#

                                                    Increase the request quota
Step1:increasing cpu 258 to 400m
[root@ip-10-0-0-29 ~]# cat realtime.yaml
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myreq
spec:
  hard:
    requests.cpu: "400m"
    requests.memory: "500Mi"
    limits.cpu: "1000m"
    limits.memory: "1500Mi"

[root@ip-10-0-0-29 ~]# kubectl apply -f realtime.yaml

Warning: resource resourcequotas/myreq is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.

resourcequota/myreq configured

--See below resource quota increased

[root@ip-10-0-0-29 ~]# kubectl describe ns dev
Name:         dev
Labels:       kubernetes.io/metadata.name=dev
Annotations:  <none>
Status:       Active

Resource Quotas
  Name:            myreq
  Resource         Used  Hard
  --------         ---   ---
  limits.cpu       400m  1
  limits.memory    40Mi  1500Mi
  requests.cpu     200m  400m
  requests.memory  20Mi  500Mi

[root@ip-10-0-0-29 ~]# kubectl create -f pod.yml
pod/team-c created
[root@ip-10-0-0-29 ~]# kubectl get po
NAME     READY   STATUS    RESTARTS   AGE
team-a   1/1     Running   0          19m
team-b   1/1     Running   0          11m
team-c   1/1     Running   0          18s

--Deleted all pod Resourcequota name dev quota released 
[root@ip-10-0-0-29 ~]# kubectl delete pod --all
pod "team-a" deleted
pod "team-b" deleted
pod "team-c" deleted
[root@ip-10-0-0-29 ~]# kubectl describe ns dev
Name:         dev
Labels:       kubernetes.io/metadata.name=dev
Annotations:  <none>
Status:       Active

Resource Quotas
  Name:            myreq
  Resource         Used  Hard
  --------         ---   ---
  limits.cpu       0     1
  limits.memory    0     1500Mi
  requests.cpu     0     400m
  requests.memory  0     500Mi

--This is my resource quota 
[root@ip-10-0-0-29 ~]# kubectl get ResourceQuota
NAME    REQUEST                                          LIMIT                                      AGE
myreq   requests.cpu: 0/400m, requests.memory: 0/500Mi   limits.cpu: 0/1, limits.memory: 0/1500Mi   30m

PROBES 
Container and container health checks purpose we are using probs 

PROBES: used to determine the health and readiness of containers running within pods. Probes
are 3 types:
1.Readiness probes are used to indicate when a container is ready to receive traffic.
2.Liveness probes are used to determine whether a container is still running and responding to
requests.
3.Startup Probe are used to determines whether the application within the container has
started successfully. It's used to delay the liveness and readiness probes until the application
is ready to handle traffic

WHY PROBES?
  • In K8s, its common to scale up and scale down the pods. But when the pod is created newly it
  • will take some time to start the container and run the applications.
  • If a pod is not ready to receive traffic, it may receive requests that it cannot handle, that
  • causes downtime for our application.
  • Similarly, if a container is not running correctly, it may not be able to respond to requests,
  • resulting in the pod being terminated and replaced with a new one.
  • To overcome this issues, we are using Probes.
TYPES OF PROBES:    
There are several types of probes that can be used in Kubernetes which includes HTTP, TCP, and
command probes

Practical:
Real time need to check application running or not using curl  5 sec wait for 30 sec, it application still not responding, container will recreate.
Step1:

[root@ip-10-0-0-29 ~]# cat pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: team-a
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      args:
        - /bin/bash
        - -c
        - touch /tmp/ccit; sleep 10000
      livenessProbe:
        exec:
          command:
            - cat
            - /tmp/ccit
        initialDelaySeconds: 5
        periodSeconds: 5
        timeoutSeconds: 30
      resources:
        requests:
          memory: "10Mi"
          cpu: "100m"
        limits:
          memory: "20Mi"
          cpu: "200m"
[root@ip-10-0-0-29 ~]# kubectl create -f pod.yml
pod/team-a created

--See here Livness probe failed after 31 second create new container 
[root@ip-10-0-0-29 ~]# kubectl describe pod team-a
Name:             team-a
Namespace:        dev
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2
 bytes.
  Warning  Unhealthy  76s (x3 over 86s)    kubelet            Liveness probe failed: cat: /tmp/ccit: No such file or directory
  Normal   Killing    76s                  kubelet            Container container1 failed liveness probe, will be restarted
  Normal   Pulling    46s (x2 over 3m56s)  kubelet            Pulling image "nginx"
  Normal   Created    45s (x2 over 3m55s)  kubelet            Created container: container1
  Normal   Started    45s (x2 over 3m55s)  kubelet            Started container container1
  Normal   Pulled     45s                  kubelet            Successfully pulled image "nginx" in 795ms (795ms inc

Step2: Delete ccit file one more time ,1 second pull the image 0 second created one more container
every 5 second it will send the request if 30 seconds not respond ,create new container.

 Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  9m41s                default-scheduler  Successfully assigned dev/team-a to minikube
  Normal   Pulled     9m40s                kubelet            Successfully pulled image "nginx" in 786ms (786ms including waiting). Image size: 192385800 bytes.
  Normal   Pulled     6m30s                kubelet            Successfully pulled image "nginx" in 795ms (795ms including waiting). Image size: 192385800 bytes.
  Warning  Unhealthy  31s (x6 over 7m11s)  kubelet            Liveness probe failed: cat: /tmp/ccit: No such file or directory
  Normal   Killing    31s (x2 over 7m1s)   kubelet            Container container1 failed liveness probe, will be restarted
  Normal   Pulling    1s (x3 over 9m41s)   kubelet            Pulling image "nginx"
  Normal   Created    0s (x3 over 9m40s)   kubelet            Created container: container1
  Normal   Started    0s (x3 over 9m40s)   kubelet            Started container container1
  Normal   Pulled     0s                   kubelet            Successfully pulled image "nginx" in 798ms (798ms including waiting). Image size: 192385800 bytes.

So far deployment these are completed.
Deploy
   pods 
     containers 
   name,images.ports
   resources,volume,cm & sec & probes


--Thanks 

Wednesday, August 20, 2025

Kubernetes part8

Kubernetes part8    

Class 93 Kubernetes Part8 August 21st

Topic: Config maps ,Secrete

Config maps : non-sensitive information  pod (container):   

We will create config map file like this{port:300 ,  url:myql.com } attached to pod using those key pair value container will use them.

Secrets: sensitive information user and password ,  Secrets(encrypt)-->pod(container) 

How many ways to CM will create

1.Literal(through CLI)

2.env-file

3.folder(not using)

 (above two imperative)

4. manifest file (Declarative )

Practical:

Step1: Create one Ec2 machine amazon linux C7i-flex-large  25 Gb

Minikube installation

[root@ip-10-0-0-29 ~]# curl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64

sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64

[root@ip-10-0-0-29 bin]# chmod 777  minikube

[root@ip-10-0-0-29 bin]# minikube version

minikube version: v1.36.0

commit: f8f52f5de11fc6ad8244afac475e1d0f96841df1-dirty

[root@ip-10-0-0-29 bin]#

Docker Installation

[root@ip-10-0-0-29 bin]# yum install docker -y

[root@ip-10-0-0-29 bin]# systemctl start docker

[root@ip-10-0-0-29 bin]# minikube start --driver=docker --force

[root@ip-10-0-0-29 bin]# minikube status

minikube

type: Control Plane

host: Running

kubelet: Running

apiserver: Running

kubeconfig: Configured

Kubectl Installation

[root@ip-10-0-0-29 bin]# curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100   138  100   138    0     0   1240      0 --:--:-- --:--:-- --:--:--  1243

100 57.3M  100 57.3M    0     0   114M      0 --:--:-- --:--:-- --:--:--  126M

-rwxrwxrwx. 1 root root 132766301 Aug 21 18:09 minikube

-rw-r--r--. 1 root root  60129464 Aug 21 18:18 kubectl

[root@ip-10-0-0-29 bin]# chmod +x kubectl

[root@ip-10-0-0-29 bin]# kubectl version

Client Version: v1.33.4

Kustomize Version: v5.6.0

Server Version: v1.33.1

Step2: Below one is by default config map file

[root@ip-10-0-0-29 bin]# kubectl get cm

NAME               DATA   AGE

kube-root-ca.crt   1      16m

If you want see this config map file ,it has some certificate when do kubernete setup it will come default
[root@ip-10-0-0-29 bin]# kubectl describe cm kube-root-ca.crt
Name:         kube-root-ca.crt
Namespace:    default
-----BEGIN CERTIFICATE-----

Step3: using literal create one configmap file 

[root@ip-10-0-0-29 bin]# kubectl create cm mycm1 --from-literal name=subbu --from-literal course=Devops --from-literal cloud=aws

configmap/mycm1 created

[root@ip-10-0-0-29 bin]# kubectl get cm

NAME               DATA   AGE

kube-root-ca.crt   1      22m

mycm1              3      10s

[root@ip-10-0-0-29 bin]# kubectl describe cm mycm1
Name:         mycm1
Namespace:    default
Labels:       <none>
Annotations:  <none>
Data
====
cloud:
----
aws
course:
----
Devops
name:
----
subbu

Step4:Create manifest file for pod creation
Here Environment --name:person is variable Key is name value assigned to the person variable
--Created one more config map file 

[root@ip-10-0-0-29 bin]# kubectl create cm mycm2 --from-literal company=tcs  --from-literal project=swiggy

configmap/mycm2 created

[root@ip-10-0-0-29 bin]# cat manifest.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      env:
        - name: person
          valueFrom:
            configMapKeyRef:
              key: name
              name: mycm1
        - name: secondvalue
          valueFrom:
            configMapKeyRef:
              key: cloud
              name: mycm1
        - name: client
          valueFrom:
            configMapKeyRef:
              key: project
              name: mycm2
Step5: Create the pod

[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml

pod/pod-1 created

[root@ip-10-0-0-29 ~]# kubectl get pod

NAME    READY   STATUS    RESTARTS   AGE

pod-1   1/1     Running   0          9s

-- Go to inside the pod

[root@ip-10-0-0-29 ~]# kubectl exec -it pod-1 -- bash
root@pod-1:/#
-- printenv command shows the all environment variables for the system
   all key value pair from coming from mycm1 and mycm2

root@pod-1:/# printenv

KUBERNETES_SERVICE_PORT_HTTPS=443

KUBERNETES_SERVICE_PORT=443

HOSTNAME=pod-1

PWD=/

person=subbu

PKG_RELEASE=1~bookworm

secondvalue=aws

HOME=/root

KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443

client=swiggy

DYNPKG_RELEASE=1~bookworm

NJS_VERSION=0.9.1

TERM=xterm

SHLVL=1

KUBERNETES_PORT_443_TCP_PROTO=tcp

KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1

KUBERNETES_SERVICE_HOST=10.96.0.1

KUBERNETES_PORT=tcp://10.96.0.1:443

KUBERNETES_PORT_443_TCP_PORT=443

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

NGINX_VERSION=1.29.1

NJS_RELEASE=1~bookworm

_=/usr/bin/printenv

 Now Planning to complete config map file attach the pod (mycm2)
  it has two key value pair company=tcs project=swiggy

Step1:

[root@ip-10-0-0-29 ~]# cat manifest.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-1
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      envFrom:
        - configMapRef:
              name: mycm2
Step2: Deleting existing po
[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
pod/pod-1 created
[root@ip-10-0-0-29 ~]# kubectl get po
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          7s

[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
pod/pod-1 created
[root@ip-10-0-0-29 ~]# kubectl get po
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          7s

--Go to inside the pod ,see here complete configmap file loaded into environment file
[root@ip-10-0-0-29 ~]# kubectl exec -it pod-1 -- bash
root@pod-1:/# printenv
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
project=swiggy
HOSTNAME=pod-1
PWD=/
PKG_RELEASE=1~bookworm
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
DYNPKG_RELEASE=1~bookworm
NJS_VERSION=0.9.1
TERM=xterm
company=tcs
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=1.29.1
NJS_RELEASE=1~bookworm
_=/usr/bin/printenv

2.env-file

Step1: Create one env file 

[root@ip-10-0-0-29 ~]# vi one.env

[root@ip-10-0-0-29 ~]# cat one.env

app=swiggy

env=dev

team=devops

api=http://www.amazon.com

port:3000

Step2:Create configmap one config file we have place maximum size 1 MB for one config map file,

if required more then that kubernete volume we can use.

[root@ip-10-0-0-29 ~]# kubectl create cm amazon  --from-env-file=one.env

configmap/amazon created

[root@ip-10-0-0-29 ~]# kubectl get cm
NAME               DATA   AGE
amazon             5      27s
kube-root-ca.crt   1      69m
mycm1              3      47m
mycm2              2      32m
Step3: attach the config map to pod ,just change the name of configmap name
[root@ip-10-0-0-29 ~]# cat manifest.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-2
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      envFrom:
        - configMapRef:
              name: amazon

[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
pod/pod-2 created
[root@ip-10-0-0-29 ~]# kubectl get po
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          14m
pod-2   1/1     Running   0          9s
Step4: See below compelet confimap file loaded into envirornment file, general it is used application and database connect we are using this config map envfile
[root@ip-10-0-0-29 ~]# kubectl exec -it pod-2 -- bash
root@pod-2:/# printenv
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
env=dev
HOSTNAME=pod-2
PWD=/
app=swiggy
PKG_RELEASE=1~bookworm
api=http://www.amazon.com
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
port=3000
DYNPKG_RELEASE=1~bookworm
team=devops
NJS_VERSION=0.9.1
TERM=xterm
SHLVL=1
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=1.29.1
NJS_RELEASE=1~bookworm
_=/usr/bin/printenv

Delete the config map 
[root@ip-10-0-0-29 ~]# kubectl get cm
NAME               DATA   AGE
amazon             5      12m
kube-root-ca.crt   1      81m
mycm1              3      59m
mycm2              2      44m
[root@ip-10-0-0-29 ~]# kubectl delete cm mycm1
configmap "mycm1" deleted
[root@ip-10-0-0-29 ~]# kubectl delete cm mycm2
configmap "mycm2" deleted
[root@ip-10-0-0-29 ~]# kubectl delete cm amazon
configmap "amazon" deleted

4. manifest file (Declarative )
Step1: Create manifest file  we will give key value format, create the configmap,number should double quotes , other wise getting error unmarshal number 

[root@ip-10-0-0-29 ~]# vi configmapdec.yaml
[root@ip-10-0-0-29 ~]# cat configmapdec.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: finalcm
data:
  DB_URL: http://www.mysql.com
  PORT: "3306"
Step2:create the configmap
[root@ip-10-0-0-29 ~]# kubectl create -f configmapdec.yaml
configmap/finalcm created
[root@ip-10-0-0-29 ~]# kubectl get cm
NAME               DATA   AGE
finalcm            2      10s
kube-root-ca.crt   1      92m

                                                      Secrets
Literal
Step1: Create secrets
[root@ip-10-0-0-29 ~]# kubectl get secret
No resources found in default namespace.

[root@ip-10-0-0-29 ~]# kubectl create secret generic mysec1  --from-literal username=subbu --from-literal password=admin123
secret/mysec1 created
[root@ip-10-0-0-29 ~]# kubectl get secret
NAME     TYPE     DATA   AGE
mysec1   Opaque   2      47s

--See here values are encrypted ,only showing bytes
[root@ip-10-0-0-29 ~]# kubectl describe secret mysec1
Name:         mysec1
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  8 bytes
username:  5 bytes
--As you need below user and password encrypted 
[root@ip-10-0-0-29 ~]# kubectl describe secret mysec1 yaml

[root@ip-10-0-0-29 ~]# kubectl get secret mysec1 -o yaml

apiVersion: v1

data:

  password: YWRtaW4xMjM=

  username: c3ViYnU=

kind: Secret

metadata:

  creationTimestamp: "2025-08-21T19:52:34Z"

  name: mysec1

  namespace: default

  resourceVersion: "4999"

  uid: d0dcb7ed-897d-4e12-bc79-21d9c171950e

type: Opaque

Env file :Encrpt

[root@ip-10-0-0-29 ~]# kubectl create secret generic envcmfile --from-env-file=one.env
secret/envcmfile created
[root@ip-10-0-0-29 ~]# kubectl get secret
NAME        TYPE     DATA   AGE
envcmfile   Opaque   5      11s
mysec1      Opaque   2      7m24s
[root@ip-10-0-0-29 ~]#
--See here envfile also encrypted 
[root@ip-10-0-0-29 ~]# kubectl get secret envcmfile -o yaml
apiVersion: v1
data:
  api: aHR0cDovL3d3dy5hbWF6b24uY29t
  app: c3dpZ2d5
  env: ZGV2
  port: MzAwMA==
  team: ZGV2b3Bz
kind: Secret
metadata:
  creationTimestamp: "2025-08-21T19:59:47Z"
  name: envcmfile
  namespace: default
  resourceVersion: "5345"
  uid: 04a0cd0c-d124-4035-9c3b-ec0649bd1bca

Manifest file

Step1:

[root@ip-10-0-0-29 ~]# cat manifest1.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: finalsecret
data:
  key: apivalues
  pass: admin@123

Step2:here we have given direct value in the above manifest1 file it should be encrypted data
[root@ip-10-0-0-29 ~]# kubectl create -f manifest1.yaml
Error from server (BadRequest): error when creating "manifest1.yaml": Secret in version "v1" cannot be handled as a Secret: illegal base64 data at input byte 8
--See apivalues key we encrupted the data ,now we need give encrypted value to manifest1 file
[root@ip-10-0-0-29 ~]# echo -n "apivalues" | base64
YXBpdmFsdWVz
[root@ip-10-0-0-29 ~]# echo -n "admin@123" | base64
YWRtaW5AMTIz

data:
  key: YXBpdmFsdWVz
  pass: YWRtaW5AMTIz

Step3:
[root@ip-10-0-0-29 ~]# vi manifest1.yaml
[root@ip-10-0-0-29 ~]# kubectl create -f manifest1.yaml
secret/finalsecret created
[root@ip-10-0-0-29 ~]# kubectl get secret
NAME          TYPE     DATA   AGE
envcmfile     Opaque   5      13m
finalsecret   Opaque   2      35s
mysec1        Opaque   2      20m

Step4: now create the pod
[root@ip-10-0-0-29 ~]# vi manifest.yaml
[root@ip-10-0-0-29 ~]# cat manifest.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
spec:
  containers:
    - name: container1
      image: nginx
      ports:
        - containerPort: 80
      envFrom:
        - secretRef:
              name: finalsecret

[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
Error from server (BadRequest): error when creating "manifest.yaml": Pod in version "v1" cannot be handled as a Pod: strict decoding error: unknown field "spec.containers[0].envFrom[0].SecretRef"
[root@ip-10-0-0-29 ~]#
-- pod3 created 
[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
pod/pod-3 created
[root@ip-10-0-0-29 ~]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
pod-1   1/1     Running   0          63m
pod-2   1/1     Running   0          48m
pod-3   1/1     Running   0          12s

Step5: Go to inside the pod ,as you out side configuremap file encrypted the data,but pod it will showing data

[root@ip-10-0-0-29 ~]# kubectl exec -id pod-3  -- bash
error: unknown shorthand flag: 'd' in -d
See 'kubectl exec --help' for usage.
[root@ip-10-0-0-29 ~]# kubectl exec -it pod-3  -- bash
root@pod-3:/# printenv
KUBERNETES_SERVICE_PORT_HTTPS=443
pass=admin@123
KUBERNETES_SERVICE_PORT=443
HOSTNAME=pod-3
PWD=/
PKG_RELEASE=1~bookworm
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
DYNPKG_RELEASE=1~bookworm
NJS_VERSION=0.9.1
TERM=xterm
key=apivalues
 
                                                                   Task 
 Docker hub repository create one private repository push the one image 
 Private repository ,trying to create pod getting error 

Step1: See here getting error 

[root@ip-10-0-0-29 ~]# vi manifest.yaml
[root@ip-10-0-0-29 ~]# cat manifest.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-4
spec:
  containers:
    - name: container1
      image: vakatisubbu/movie1:latest

[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
pod/pod-4 created
[root@ip-10-0-0-29 ~]# kubectl get pod
NAME    READY   STATUS         RESTARTS   AGE
pod-1   1/1     Running        0          79m
pod-2   1/1     Running        0          65m
pod-3   1/1     Running        0          16m
pod-4   0/1     ErrImagePull   0          9s

Step2: Describer the pod , as you see below credential issue, we need choose secrete
1.need create one secrete --in that docker username password 
2.For secrete need to give in pod and create the pod

Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  65s                default-scheduler  Successfully assigned default/pod-4 to minikube
  Normal   Pulling    22s (x3 over 64s)  kubelet            Pulling image "shaikmustafa77/myprivaterepo:latest"
  Warning  Failed     21s (x3 over 63s)  kubelet            Failed to pull image "shaikmustafa77/myprivaterepo:latest": Error response from daemon: pull access denied for shaikmustafa77/myprivaterepo, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
  Warning  Failed     21s (x3 over 63s)  kubelet            Error: ErrImagePull
  Normal   BackOff    7s (x3 over 62s)   kubelet            Back-off pulling image "shaikmustafa77/myprivaterepo:latest"
  Warning  Failed     7s (x3 over 62s)   kubelet            Error: ImagePullBackOff

 Step3: literal ,secret creation 
[root@ip-10-0-0-29 ~]# kubectl create secret docker-registry dockersecret --docker-server=docker.io --docker-username=vakatisubbu --docker-password=Jan20@2015 --docker-email=vakati.subbu@gmail.com
secret/dockersecret created

--New secret created successfully

[root@ip-10-0-0-29 ~]# kubectl get secret
NAME           TYPE                             DATA   AGE
dockersecret   kubernetes.io/dockerconfigjson   1      21s
envcmfile      Opaque                           5      13h
finalsecret    Opaque                           2      13h
mysec1         Opaque                           2      13h
--See here Secret encrypted 
[root@ip-10-0-0-29 ~]# kubectl get  secret dockersecret -o yaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJkb2NrZXIuaW8iOnsidXNlcm5hbWUiOiJ2YWthdGlzdWJidSIsInBhc3N3b3JkIjoiSmFuMjBAMjAxNSIsImVtYWlsIjoidmFrYXRpLnN1YmJ1QGdtYWlsLmNvbSIsImF1dGgiOiJkbUZyWVhScGMzVmlZblU2U21GdU1qQkFNakF4TlE9PSJ9fX0=
kind: Secret
metadata:
  creationTimestamp: "2025-08-22T09:47:36Z"
  name: dockersecret
  namespace: default
  resourceVersion: "12738"
  uid: 4c6776da-794f-45bc-9526-ffdf678970d5
type: kubernetes.io/dockerconfigjson

Step4:

[root@ip-10-0-0-29 ~]# cat manifest.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-4
spec:
  containers:
    - name: container1
      image: vakatisubbu/movie1:latest
  imagePullSecrets:
    - name: dockersecret
[root@ip-10-0-0-29 ~]# kubectl create -f manifest.yaml
pod/pod-4 created
[root@ip-10-0-0-29 ~]# kubectl get pod
NAME    READY   STATUS                       RESTARTS      AGE
pod-1   0/1     CreateContainerConfigError   0             14h
pod-2   0/1     CreateContainerConfigError   0             14h
pod-3   1/1     Running                      1 (13h ago)   13h
pod-4   1/1     Running                      0             7s

--Describe for pod-4
[root@ip-10-0-0-29 ~]# kubectl describe pod pod-4
Name:             pod-4
Namespace:        default

Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  3m     default-scheduler  Successfully assigned default/pod-4 to minikube
  Normal  Pulling    3m     kubelet            Pulling image "vakatisubbu/movie1:latest"
  Normal  Pulled     2m54s  kubelet            Successfully pulled image "vakatisubbu/movie1:latest" in 5.409s (5.41s including waiting). Image size: 244571564 bytes.
  Normal  Created    2m54s  kubelet            Created container: container1
  Normal  Started    2m54s  kubelet            Started container container1


[root@ip-10-0-0-29 ~]# kubectl get pods -o wide
NAME    READY   STATUS                       RESTARTS      AGE     IP            NODE       NOMINATED NODE   READINESS GATES
pod-3   1/1     Running                      1 (13h ago)   13h     10.244.0.9    minikube   <none>           <none>
pod-4   1/1     Running                      0             7m59s   10.244.0.14   minikube   <none>           <none>

--Create  the service 

[root@ip-10-0-0-29 ~]# cat movie-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: movie-service
spec:
  selector:
    app: movie-app  # This must match your pod's label
  ports:
    - port: 80        # Service port
      targetPort: 80  # Container port (where Apache runs)
  type: NodePort      # Makes it accessible from outside

[root@ip-10-0-0-29 ~]# kubectl get svc
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP        19h
movie-service   NodePort    10.109.52.96   <none>        80:30361/TCP   66m

--See here url is responding 

[root@ip-10-0-0-29 ~]# kubectl get service movie-service
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
movie-service   NodePort   10.109.52.96   <none>        80:30361/TCP   12m
[root@ip-10-0-0-29 ~]# minikube service movie-service --url
http://192.168.49.2:30361
[root@ip-10-0-0-29 ~]# curl http://192.168.49.2:30361
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {font-family: Arial, Helvetica, sans-serif;}

/* Full-width input fields */

--Thanks