docs: add 100 Days of DevOps challenge notes
This commit is contained in:
575
100 - days of devops/devops-51-60.md
Normal file
575
100 - days of devops/devops-51-60.md
Normal file
@@ -0,0 +1,575 @@
|
||||
## Task 51
|
||||
|
||||
An application currently running on the Kubernetes cluster employs the nginx web server. The Nautilus application development team has introduced some recent changes that need deployment. They've crafted an image nginx:1.18 with the latest updates.
|
||||
|
||||
Execute a rolling update for this application, integrating the nginx:1.18 image. The deployment is named nginx-deployment.
|
||||
|
||||
Ensure all pods are operational post-update.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Rolling update nginx-deployment to nginx:1.18
|
||||
|
||||
## Check current state first
|
||||
|
||||
```bash
|
||||
kubectl get deployment nginx-deployment
|
||||
kubectl describe deployment nginx-deployment | grep -i image
|
||||
```
|
||||
|
||||
Note the container name from the describe output (needed for the set image command).
|
||||
|
||||
## Perform the rolling update
|
||||
|
||||
```bash
|
||||
kubectl set image deployment/nginx-deployment nginx-container=nginx:1.18
|
||||
```
|
||||
|
||||
Replace `nginx` (left of `=`) with the actual container name if it differs — check the describe output above.
|
||||
|
||||
## Watch the rollout
|
||||
|
||||
```bash
|
||||
kubectl rollout status deployment/nginx-deployment
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kubectl rollout status deployment/nginx-deployment
|
||||
kubectl get pods
|
||||
kubectl describe deployment nginx-deployment | grep -i image
|
||||
```
|
||||
|
||||
Want: rollout `successfully rolled out`, all pods `Running`, image now `nginx:1.18`.
|
||||
|
||||
## Task 52
|
||||
|
||||
Earlier today, the Nautilus DevOps team deployed a new release for an application. However, a customer has reported a bug related to this recent release. Consequently, the team aims to revert to the previous version.
|
||||
|
||||
There exists a deployment named nginx-deployment; initiate a rollback to the previous revision.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Rollback nginx-deployment to previous revision
|
||||
|
||||
## Check history first (optional but good)
|
||||
|
||||
```bash
|
||||
kubectl rollout history deployment/nginx-deployment
|
||||
```
|
||||
|
||||
Shows the revisions — confirms there's a previous one to roll back to.
|
||||
|
||||
## Perform the rollback
|
||||
|
||||
```bash
|
||||
kubectl rollout undo deployment/nginx-deployment
|
||||
```
|
||||
|
||||
## Watch + verify
|
||||
|
||||
```bash
|
||||
kubectl rollout status deployment/nginx-deployment
|
||||
kubectl get pods
|
||||
kubectl describe deployment nginx-deployment | grep -i image
|
||||
```
|
||||
|
||||
Want: rollout `successfully rolled out`, all pods `Running`, image reverted to the previous version.
|
||||
|
||||
## Task 53
|
||||
|
||||
We encountered an issue with our Nginx and PHP-FPM setup on the Kubernetes cluster this morning, which halted its functionality. Investigate and rectify the issue:
|
||||
|
||||
The pod name is nginx-phpfpm and configmap name is nginx-config. Identify and fix the problem.
|
||||
|
||||
Once resolved, copy /home/thor/index.php file from the jump host to the nginx-container within the nginx document root. After this, you should be able to access the website using Website button on the top bar.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Fix nginx-phpfpm pod
|
||||
|
||||
## Step 1 — recon: inspect the pod and configmap
|
||||
|
||||
```bash
|
||||
# pod state + how it's configured
|
||||
kubectl describe pod nginx-phpfpm
|
||||
kubectl get pod nginx-phpfpm -o yaml
|
||||
|
||||
# the nginx config
|
||||
kubectl describe configmap nginx-config
|
||||
kubectl get configmap nginx-config -o yaml
|
||||
```
|
||||
|
||||
## Step 2 — identify the mismatch
|
||||
|
||||
Compare two things:
|
||||
- The **document root** in the nginx config (from the configmap) — look for `root /some/path;`
|
||||
- The **shared volume mountPath** in the pod spec — where the shared `emptyDir` volume is mounted in *both* the nginx and php-fpm containers
|
||||
|
||||
The bug: these two paths **don't match**. nginx serves from one path, but the shared volume (where files land) is mounted at a different path → nginx can't find the files.
|
||||
|
||||
## Step 3 — fix the mismatch
|
||||
|
||||
The fix is to make them consistent. Usually the **configmap's `root` directive** is edited to match the volume mountPath (or vice versa). Edit the configmap:
|
||||
|
||||
```bash
|
||||
kubectl edit configmap nginx-config
|
||||
```
|
||||
|
||||
Change the `root` line so it matches the shared volume's mountPath in the pod spec. Common correct value: `/var/www/html`.
|
||||
|
||||
## Step 4 — recreate the pod (configmap changes need a pod restart)
|
||||
|
||||
```bash
|
||||
kubectl get pod nginx-phpfpm -o yaml > /tmp/nginx-phpfpm.yaml
|
||||
kubectl delete pod nginx-phpfpm
|
||||
kubectl apply -f /tmp/nginx-phpfpm.yaml
|
||||
```
|
||||
|
||||
## Step 5 — copy index.php into the nginx container's docroot
|
||||
|
||||
```bash
|
||||
kubectl cp /home/thor/index.php nginx-phpfpm:/var/www/html/index.php -c nginx-container
|
||||
```
|
||||
|
||||
(Use the actual docroot path confirmed in step 2/3, and `-c nginx-container` to target the right container.)
|
||||
|
||||
## Step 6 — verify
|
||||
|
||||
```bash
|
||||
kubectl get pod nginx-phpfpm
|
||||
kubectl exec nginx-phpfpm -c nginx-container -- ls -l /var/www/html/
|
||||
```
|
||||
|
||||
Then hit the **Website** button.
|
||||
|
||||
|
||||
## Task 54
|
||||
|
||||
We are working on an application that will be deployed on multiple containers within a pod on Kubernetes cluster. There is a requirement to share a volume among the containers to save some temporary data. The Nautilus DevOps team is developing a similar template to replicate the scenario. Below you can find more details about it.
|
||||
|
||||
Create a pod named volume-share-nautilus.
|
||||
|
||||
For the first container, use image debian with latest tag only and remember to mention the tag i.e debian:latest, container should be named as volume-container-nautilus-1, and run a sleep command for it so that it remains in running state. Volume volume-share should be mounted at path /tmp/blog.
|
||||
|
||||
For the second container, use image debian with the latest tag only and remember to mention the tag i.e debian:latest, container should be named as volume-container-nautilus-2, and again run a sleep command for it so that it remains in running state. Volume volume-share should be mounted at path /tmp/games.
|
||||
|
||||
Volume name should be volume-share of type emptyDir.
|
||||
|
||||
After creating the pod, exec into the first container i.e volume-container-nautilus-1, and just for testing create a file blog.txt with the content Welcome to xFusionCorp Industries under the mounted path of first container i.e /tmp/blog.
|
||||
|
||||
The file blog.txt should be present under the mounted path /tmp/games on the second container volume-container-nautilus-2 as well, since they are using a shared volume.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Create volume-share-nautilus pod
|
||||
|
||||
## Create the pod
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: volume-share-nautilus
|
||||
spec:
|
||||
containers:
|
||||
- name: volume-container-nautilus-1
|
||||
image: debian:latest
|
||||
command: ["sleep", "infinity"]
|
||||
volumeMounts:
|
||||
- name: volume-share
|
||||
mountPath: /tmp/blog
|
||||
- name: volume-container-nautilus-2
|
||||
image: debian:latest
|
||||
command: ["sleep", "infinity"]
|
||||
volumeMounts:
|
||||
- name: volume-share
|
||||
mountPath: /tmp/games
|
||||
volumes:
|
||||
- name: volume-share
|
||||
emptyDir: {}
|
||||
EOF
|
||||
```
|
||||
|
||||
## Wait for it to be Running
|
||||
|
||||
```bash
|
||||
kubectl get pod volume-share-nautilus -w
|
||||
```
|
||||
|
||||
## Write the file in container 1
|
||||
|
||||
```bash
|
||||
kubectl exec volume-share-nautilus -c volume-container-nautilus-1 -- \
|
||||
bash -c 'echo "Welcome to xFusionCorp Industries" > /tmp/blog/blog.txt'
|
||||
```
|
||||
|
||||
## Verify it appears in container 2 (shared volume)
|
||||
|
||||
```bash
|
||||
kubectl exec volume-share-nautilus -c volume-container-nautilus-2 -- \
|
||||
cat /tmp/games/blog.txt
|
||||
```
|
||||
|
||||
Want: `Welcome to xFusionCorp Industries` — proving the emptyDir is shared across both containers at their respective mount paths.
|
||||
|
||||
|
||||
## Task 55
|
||||
|
||||
We have a web server container running the nginx image. The access and error logs generated by the web server are not critical enough to be placed on a persistent volume. However, Nautilus developers need access to the last 24 hours of logs so that they can trace issues and bugs. Therefore, we need to ship the access and error logs for the web server to a log-aggregation service. Following the separation of concerns principle, we implement the Sidecar pattern by deploying a second container that ships the error and access logs from nginx. Nginx does one thing, and it does it well - serving web pages. The second container also specializes in its task - shipping logs. Since containers are running on the same Pod, we can use a shared emptyDir volume to read and write logs.
|
||||
|
||||
Create a pod named webserver.
|
||||
|
||||
Create an emptyDir volume named shared-logs.
|
||||
|
||||
Create a regular container in the webserver pod from the nginx:latest image named nginx-container, and an init container from the ubuntu:latest image named sidecar-container.
|
||||
|
||||
Add the following command to the sidecar-container "sh","-c","while true; do cat /var/log/nginx/access.log /var/log/nginx/error.log; sleep 30; done"
|
||||
|
||||
Mount the shared-logs volume in both containers at /var/log/nginx. Ensure all containers are in a running state.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Create webserver sidecar pod
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: webserver
|
||||
spec:
|
||||
volumes:
|
||||
- name: shared-logs
|
||||
emptyDir: {}
|
||||
initContainers:
|
||||
- name: sidecar-container
|
||||
image: ubuntu:latest
|
||||
restartPolicy: Always
|
||||
command: ["sh", "-c", "while true; do cat /var/log/nginx/access.log /var/log/nginx/error.log; sleep 30; done"]
|
||||
volumeMounts:
|
||||
- name: shared-logs
|
||||
mountPath: /var/log/nginx
|
||||
containers:
|
||||
- name: nginx-container
|
||||
image: nginx:latest
|
||||
volumeMounts:
|
||||
- name: shared-logs
|
||||
mountPath: /var/log/nginx
|
||||
EOF
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kubectl get pod webserver
|
||||
kubectl get pod webserver -o jsonpath='{.status.phase}{"\n"}'
|
||||
kubectl describe pod webserver | grep -A2 -i "state"
|
||||
```
|
||||
|
||||
Want: pod `Running`, both `nginx-container` and `sidecar-container` up (Ready/Running).
|
||||
|
||||
## Task 56
|
||||
|
||||
Some of the Nautilus team developers are developing a static website and they want to deploy it on Kubernetes cluster. They want it to be highly available and scalable. Therefore, based on the requirements, the DevOps team has decided to create a deployment for it with multiple replicas. Below you can find more details about it:
|
||||
|
||||
Create a deployment using nginx image with latest tag only and remember to mention the tag i.e nginx:latest. Name it as nginx-deployment. The container should be named as nginx-container, also make sure replica counts are 3.
|
||||
|
||||
Create a NodePort type service named nginx-service. The nodePort should be 30011.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# nginx deployment + NodePort service
|
||||
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
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-container
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
EOF
|
||||
```
|
||||
|
||||
## NodePort Service
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx-service
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: nginx
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
nodePort: 30011
|
||||
EOF
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kubectl get deployment nginx-deployment
|
||||
kubectl get pods -l app=nginx
|
||||
kubectl get service nginx-service
|
||||
```
|
||||
|
||||
Want: deployment `3/3` ready, three pods Running, service `nginx-service` type NodePort exposing `30011`.
|
||||
|
||||
## Task 57
|
||||
|
||||
The Nautilus DevOps team is working on to setup some pre-requisites for an application that will send the greetings to different users. There is a sample deployment, that needs to be tested. Below is a scenario which needs to be configured on Kubernetes cluster. Please find below more details about it.
|
||||
|
||||
Create a pod named print-envars-greeting.
|
||||
|
||||
Configure spec as, the container name should be print-env-container and use bash image.
|
||||
|
||||
Create three environment variables:
|
||||
a. GREETING and its value should be Welcome to
|
||||
b. COMPANY and its value should be Stratos
|
||||
c. GROUP and its value should be Industries
|
||||
|
||||
Use command ["/bin/sh", "-c", 'echo "$(GREETING) $(COMPANY) $(GROUP)"'] (please use this exact command), also set its restartPolicy policy to Never to avoid crash loop back.
|
||||
|
||||
You can check the output using kubectl logs -f print-envars-greeting command.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Create print-envars-greeting pod
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: print-envars-greeting
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: print-env-container
|
||||
image: bash
|
||||
command: ["/bin/sh", "-c", 'echo "$(GREETING) $(COMPANY) $(GROUP)"']
|
||||
env:
|
||||
- name: GREETING
|
||||
value: "Welcome to"
|
||||
- name: COMPANY
|
||||
value: "Stratos"
|
||||
- name: GROUP
|
||||
value: "Industries"
|
||||
EOF
|
||||
```
|
||||
|
||||
## Check the output
|
||||
|
||||
```bash
|
||||
kubectl logs -f print-envars-greeting
|
||||
```
|
||||
|
||||
Want: `Welcome to Stratos Industries` in the logs, pod in `Completed` state.
|
||||
|
||||
## Task 58
|
||||
|
||||
The Nautilus DevOps teams is planning to set up a Grafana tool to collect and analyze analytics from some applications. They are planning to deploy it on Kubernetes cluster. Below you can find more details.
|
||||
|
||||
1.) Create a deployment named grafana-deployment-xfusion using any grafana image for Grafana app. Set other parameters as per your choice.
|
||||
2.) Create NodePort type service with nodePort 32000 to expose the app.
|
||||
|
||||
You do not need to make any configuration changes inside the Grafana app once deployed; just make sure you can access the Grafana login page.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# Grafana deployment + NodePort service
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: grafana-deployment-xfusion
|
||||
labels:
|
||||
app: grafana-deployment-xfusion
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: grafana-deployment-xfusion
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: grafana-deployment-xfusion
|
||||
spec:
|
||||
containers:
|
||||
- name: grafana
|
||||
image: grafana/grafana:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: grafana-service
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: grafana-deployment-xfusion
|
||||
ports:
|
||||
- port: 32000
|
||||
targetPort: 3000
|
||||
nodePort: 32000
|
||||
EOF
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kubectl get deployment grafana-deployment-xfusion
|
||||
kubectl get pods -l app=grafana
|
||||
kubectl get service grafana-service
|
||||
kubectl rollout status deployment/grafana-deployment-xfusion
|
||||
```
|
||||
|
||||
Want: deployment `1/1` ready, pod Running, service exposing `32000`. Then hit the app — Grafana login page should load.
|
||||
|
||||
## Task 59
|
||||
|
||||
Last week, the Nautilus DevOps team deployed a redis app on Kubernetes cluster, which was working fine so far. This morning one of the team members was making some changes in this existing setup, but he made some mistakes and the app went down. We need to fix this as soon as possible. Please take a look.
|
||||
|
||||
The deployment name is redis-deployment. The pods are not in running state right now, so please look into the issue and fix the same.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
- incorrect config map name
|
||||
- incorrect image on redis
|
||||
|
||||
## Task 60
|
||||
|
||||
The Nautilus DevOps team is working on a Kubernetes template to deploy a web application on the cluster. There are some requirements to create/use persistent volumes to store the application code, and the template needs to be designed accordingly. Please find more details below:
|
||||
|
||||
Create a PersistentVolume named as pv-devops. Configure the spec as storage class should be manual, set capacity to 4Gi, set access mode to ReadWriteOnce, volume type should be hostPath and set path to /mnt/devops (this directory is already created, you might not be able to access it directly, so you need not to worry about it).
|
||||
|
||||
Create a PersistentVolumeClaim named as pvc-devops. Configure the spec as storage class should be manual, request 1Gi of the storage, set access mode to ReadWriteOnce.
|
||||
|
||||
Create a pod named as pod-devops, mount the persistent volume you created with claim name pvc-devops at document root of the web server, the container within the pod should be named as container-devops using image nginx with latest tag only (remember to mention the tag i.e nginx:latest).
|
||||
|
||||
Create a node port type service named web-devops using node port 30008 to expose the web server running within the pod.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
### Solution
|
||||
|
||||
# PV + PVC + Pod + Service (devops)
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: pv-devops
|
||||
spec:
|
||||
storageClassName: manual
|
||||
capacity:
|
||||
storage: 4Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
hostPath:
|
||||
path: /mnt/devops
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: pvc-devops
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: pod-devops
|
||||
labels:
|
||||
app: web-devops
|
||||
spec:
|
||||
containers:
|
||||
- name: container-devops
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- name: web-storage
|
||||
mountPath: /usr/share/nginx/html
|
||||
volumes:
|
||||
- name: web-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: pvc-devops
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: web-devops
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: web-devops
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
nodePort: 30008
|
||||
EOF
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kubectl get pv pv-devops
|
||||
kubectl get pvc pvc-devops
|
||||
kubectl get pod pod-devops
|
||||
kubectl get svc web-devops
|
||||
```
|
||||
|
||||
Want: PV `Bound`, PVC `Bound`, pod `Running`, service exposing `30008`.
|
||||
Reference in New Issue
Block a user