Mock Exam 2
Mock Exam 2
-
Question 1
-
Create a StorageClass named local-sc with the following specifications and set it as the default storage class:
The provisioner should be kubernetes.io/no-provisioner The volume binding mode should be WaitForFirstConsumer Volume expansion should be enabled
-
ssh into the cluster.
-
Check the documentation and pick a
storageclassexample configuration. -
https://kubernetes.io/docs/concepts/storage/storage-classes/
-
Use this example:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: low-latency
annotations:
storageclass.kubernetes.io/is-default-class: "false"
provisioner: csi-driver.example-vendor.example
reclaimPolicy: Retain # default value is Delete
allowVolumeExpansion: true
mountOptions:
- discard # this might enable UNMAP / TRIM at the block storage layer
volumeBindingMode: WaitForFirstConsumer
parameters:
guaranteedReadWriteLatency: "true" # provider-specific
- Edit the file so it looks like this:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-sc
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/no-provisioner
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
-
Apply it with
kubectl apply -f <file.yaml> -
Question 2
-
Create a deployment named logging-deployment in the namespace logging-ns with 1 replica, with the following specifications:
The main container should be named app-container, use the image busybox, and should run the following command to simulate writing logs:
sh -c “while true; do echo ‘Log entry’ » /var/log/app/app.log; sleep 5; done”
Add a sidecar container named log-agent that also uses the busybox image and runs the command:
tail -f /var/log/app/app.log
log-agent logs should display the entries logged by the main app-container
- Check the deployment documentation on the Kubernetes website.
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Use this example deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
- Edit the file like so:
apiVersion: apps/v1
kind: Deployment
metadata:
name: logging-deployment
namespace: logging-ns
spec:
replicas: 1
selector:
matchLabels:
app: logger
template:
metadata:
labels:
app: logger
spec:
volumes:
- name: log-volume
emptyDir: {}
containers:
- name: app-container
image: busy-box
volumeMounts:
- name: log-volume
mount: /var/log/app
command:
- sh
- c
- "while true; do echo 'Log entry' >> /var/log/app/app.log; sleep 5; done"
- name: log-agent
image: busybox
volumeMounts:
- name: log-volume
mount: /var/log/app
command:
- tail
- -f
- /var/log/app/app.log
/var/log/app is the same directory in both containers.
- Then we apply the configuration:
kubectl apply -f <file.yaml>
- Check if it is logging or not:
kubectl logs logging-deployment-<container-name> -c log-agent -n logging-ns
- To follow the logs, use the
-fflag:
kubectl logs logging-deployment-<container-name> -c log-agent -n logging-ns -f
-
Question 3
-
A Deployment named webapp-deploy is running in the ingress-ns namespace and is exposed via a Service named webapp-svc.
Create an Ingress resource called webapp-ingress in the same namespace that will route traffic to the service. The Ingress must:
Use pathType: Prefix
Route requests sent to path / to the backend service
Forward traffic to port 80 of the service
Be configured for the host kodekloud-ingress.app
Test app availablility using the following command:
curl -s http://kodekloud-ingress.app/
- Check the deployment with the following:
kubectl get deploy -n ingress-nss
- Check the service that is in use:
kubectl get svc -n ingress-nss
- Check the documentation and look for Ingress:
https://kubernetes.io/docs/concepts/services-networking/ingress/
- We create an Ingress Resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx-example
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
- As this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
namespace: ingress-ns
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
rules:
- host: kodekloud-ingress.app
spec:
ingressClassName: nginx
rules:
- host: kodekloud-ingress.app
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-svc
port:
number: 80
- Apply the file:
kubectl apply -f <file.yaml>
-
Run
kubectl get ingressclass -
Run a
curlcommand to make sure it can connect to the app:
curl -s http://kodekloud-ingress.app
-
Question 4
-
Create a new deployment called nginx-deploy, with image nginx:1.16 and 1 replica. Next, upgrade the deployment to version 1.17 using rolling update.
-
kubectl create deployment nginx-deploy --image=nginx:1.16 --dry-run=client -o yaml > <file.yaml> -
This would create a deployment file like so:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deploy
name: nginx-deploy
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deploy
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.16
name: nginx
resources: {}
status: {}
- Change the file to the following:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx-deploy
name: nginx-deploy
spec:
strategy:
type: RollingUpdate
replicas: 1
selector:
matchLabels:
app: nginx-deploy
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.16
name: nginx
resources: {}
status: {}
- Technically
RollingUpdateis the default, so you don’t need the following:
strategy:
type: RollingUpdate
- Then apply the file with:
kubectl apply -f <file.yaml>
- Check for the Deployment with:
kubectl get deployment
- Check out the rollout history with:
kubectl rollout history deployment nginx-deploy
- To show more information about the
rollout, run the following:
kubectl rollout history deployment nginx-deploy --revision=1
- Now to change the version of
nginxto1.17, run:
kubectl set image deployment/nginx-deploy nginx=nginx:1.17
- If you again run
rollout history, there are two versions shown:
kubectl rollout history deployment nginx-deploy
- Checking the latest version should show
1.17:
kubectl rollout history deployment nginx-deploy --revision=1
-
Question 5
-
Create a new user called john. Grant him access to the cluster using a csr named john-developer. Create a role developer which should grant John the permission to create, list, get, update and delete pods in the development namespace . The private key exists in the location: /root/CKA/john.key and csr at /root/CKA/john.csr.
Important Note: As of kubernetes 1.19, the CertificateSigningRequest object expects a signerName.
Please refer to the documentation to see an example. The documentation tab is available at the top right of the terminal.
-
A
csris a Certificate Signing Request. -
However, we need to create a Kubernetes object, for John to join the Kubernetes cluster.
-
Go to the documentation and search for
Issue a Certificate for a Kubernetes API Client Using a CertificateSigningRequest -
We create the CertificateSigningRequest object from this file:
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: myuser # example
spec:
# This is an encoded CSR. Change this to the base64-encoded contents of myuser.csr
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client auth
EOF
- Change the above to the following:
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
john-developer
spec:
signerName: kubernetes.io/kube-apiserver-client
request: <base64-encoding-output-from-the-below-cat-command>
usages:
- digital signature
- key encipherment
- client auth
-
To get the Certificate Signing Request, however the
requestproperty needs to be base64 encoded. -
cat /root/CKA/john.csr
cat /root/CKAjohn.csr | base64 | tr -d '\n'
-
Once all done we apply the object with
kubectl apply -f <file.yaml>. -
Check the Certificate Signing Request with the following:
kubectl get csr
-
You can see that the certificate signing request is waiting for approval.
-
To approve or reject it:
kubectl certificate approve john-developer
-
The nrun
kubectl get csragain to see it approved. -
Further checks:
kubectl get csr john-developer -o yaml
-
Under
Status, that is the certificate that the user uses to access the cluster. -
To allow John to
create,list,get,updateanddeletepods, we need an RBAC role. We create a new file:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: development
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "list", "get", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: john-developer-role-binding
namespace: development
subjects:
- kind: User
name: john
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: role
name: developer
apiGroup: rbac.authorization.k8s.io
-
You can create multiple Kubernetes objects in one file with the
---syntax. -
Apply the above role binding:
kubectl apply -f <role-binding>
- To test access that a user (current user) can do:
kubectl auth can-i create pods
- We need to test with user john:
kubectl auth can-i create pods --as=john -n development
-
The answer will be
yes. -
If this is done in a namespace where John doesn’t have permissions:
kubectl auth can-i create pods --as=john -n default
-
The answer will be
no. -
Regarding
apiGroups, this is empty like[""], we’re giving permissions for pods as part of thecoregroup. When using thecoregroup, it is left empty like so[""]. -
You can then see the certificate available.
-
Take the long line it outputs and place that in the
requestline. -
Question 6
-
Create an nginx pod called nginx-resolver using the image nginx and expose it internally with a service called nginx-resolver-service. Test that you are able to look up the service and pod names from within the cluster. Use the image: busybox:1.28 for dns lookup. Record results in /root/CKA/nginx.svc and /root/CKA/nginx.pod
-
Create the
nginxpod with the following command:
kubectl run nginx-resolver --image=nginx
-
Expose it internallyfrom the question above basically meansClusterIP. -
If you want access outside of the cluster, use
NodePortorLoadBalancer. -
Need to expose the pod:
kubectl expose pod nginx-resolver --name=nginx-resolver --port=80 --target-port=80 --type=ClusterIP
- Verify the service was created:
kubectl get svc
kubectl describe svc nginx-resolver-service
-
The above will show one endpoint, which is the pod.
-
Check the IP address of the
nginx-resolver:
kubectl get pod -o wide
-
Now we know the service is working as intended.
-
We need to bring up an ephemeral container that runs one command.
kubectl run test-nslookup --image=busybox:1.28 --rm -it --restart=Never -- nslookup nginx-resolver-service
-
From the above command, that should resolve the IP address of the service.
-
The
--rmmeans once we detach from the pod, it will be destroyed. -
Now will run the same command as above, but output the file into
/root/CKA/nginx.svcand/root/CKA/nginx.pod.
kubectl run test-nslookup --image=busybox:1.28 --rm -it --restart=Never -- nslookup nginx-resolver-service > /root/CKA/nginx.svc
- Then to create a DNS entry for the pod IP like so:
kubectl run test-nslookup --image=busybox:1.28 --rm -it --restart=Never -- nslookup 172-17-1-18.default.pod
- Then we save the above output to a file:
kubectl run test-nslookup --image=busybox:1.28 --rm -it --restart=Never -- nslookup 172-17-1-18.default.pod > /root/CKA/nginx.pod
-
Question 7
-
Create a static pod on node01 called nginx-critical with the image nginx. Make sure that it is recreated/restarted automatically in case of a failure.
For example, use /etc/kubernetes/manifests as the static Pod path.
-
Have to create a manifest / file on Node1.
-
Run the
kubectl runcommand:
kubectl run nginx-critical --image=nginx --dry-run=client -o yaml > static.yaml
- If you
catthe above file, you’ll observe this:
apiVersion: v1
kind: Pod
metadata:
creationTimeStamp: null
labels:
run: nginx-critical
name: nginx-critical
spec:
containers:
- image: nginx
name: nginx-critical
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
-
sshinto Node1. -
Navigate towards
/etc/kubernetes/manifests -
Create a file called
static.yaml. -
Then in the
/etc/kubernetes/manifestsdirectory, we create a manifest for a pod that we want to create statically. -
Check the pods with:
kubectl get pod -o wide
-
When a pod is created statically, it is assigned to the node name.
-
That’s how you create a static pod in Kubernetes.
-
Question 8
-
Create a Horizontal Pod Autoscaler with name backend-hpa for the deployment named backend-deployment in the backend namespace with the webapp-hpa.yaml file located under the root folder. Ensure that the HPA scales the deployment based on memory utilisation, maintaining an average memory usage of 65% across all pods. Configure the HPA with a minimum of 3 replicas and a maximum of 15.
-
Open up
web-app-hpa.yaml:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: webapp-hpa
namespace: backend
spec:
scaleTargetRef:
apiVersion: app/v1
kind: Deployment
name: kkapp-deploy
minReplicas: 3
maxReplicas: 15
- We change the above file to the following:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
namespace: backend
spec:
scaleTargetRef:
apiVersion: app/v1
kind: Deployment
name: backend-deployment
minReplicas: 3
maxReplicas: 15
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 65
- Apply the file with:
kubectl apply -f webapp-hpa.yaml
- Do a describe to see what it shows:
kubectl describe hpa -n backend
-
From the above command, you see the minimum and maximum replicas and the metrics that were previously set.
-
Question 9
-
Modify the existing web-gateway on cka5673 namespace to handle HTTPS traffic on port 443 for kodekloud.com, using a TLS certificate stored in a secret named kodekloud-tls.
-
sshintocluster1-controlplane. -
Check for the existing gateway:
kubectl get gateway -n cka5673
-
You should be a ble to see some form of gateway created.
-
Output the above gateway file to yaml:
kubectl get gateway -n cka5673 -o yaml > <file.yaml>
- Check the secrets:
kubectl get secret -n cka-5673
-
This will show the TLS certificates.
-
Open
file.yamland it will be a very large file. Items changed are:
port: 80 --> port: 443
protocol: HTTP --> protocol: HTTPS
hostname: kodekloud.com
tls:
certificateRefs:
- name: kodekloud-tls
-
The
kodekloud-tlspart points to the secret that we saw earlier. -
kubectl apply -f <file.yaml> -
Question 10
-
On the cluster, the team has installed multiple helm charts on a different namespace. By mistake, those deployed resources include one of the vulnerable images called kodekloud/webapp-colour:v1. Find out the release name and uninstall it.
-
Need to find out what
helmcharts are installed, therefore:
helm list -A
-
The
-Ais for all namespaces. -
Need to find the release that has an image that matches the name.
-
Show the manifest generated by a Helm release:
helm get manifest <helm_chart> -n <namespace> | grep -i webapp-color:v1
- In this example, this shows the following:
image: "kodekloud/webapp-color:v1"
- Then we uninstall the chart with:
helm uninstall <release-name> -n <namespace>
-
Question 11
-
You are requested to create a NetworkPolicy to allow traffic from frontend apps located in the frontend namespace, to backend apps located in the backend namespace, but not from the databases in the databases namespace. There are three policies available in the /root folder. Apply the most restrictive policy from the provided YAML files to achieve the desired result. Do not delete any existing policies.
-
Good command for namespaces:
kubectl get ns --show-labels
- Example NetworkPolicy that works for the above question:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: net-policy-3
namespace: backend
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
ports:
- protocol: TCP
port: 80
-
An ingress policy will only apply the above configuration.
-
Apply the above file:
kubectl apply -f <file.yaml>