Pod and Deployment Solutions
SummaryStep-by-step solutions for Exercises 1 and 2: creating...
Step-by-step solutions for Exercises 1 and 2: creating...
Step-by-step solutions for Exercises 1 and 2: creating a multi-container Pod with a sidecar log reader, and performing a rolling update Deployment with rollback verification.
Pod and Deployment Solutions
Solution: Exercise 1 — Sidecar Logging Pod
This exercise requires a Pod with two containers sharing a volume: an application container that writes log lines, and a sidecar container that reads them.
Step 1: Write the Pod Manifest
Create the manifest file:
cat > sidecar-logging.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: sidecar-logging
labels:
app: sidecar-demo
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c"]
args:
- |
i=0
while true; do
echo "$(date '+%Y-%m-%d %H:%M:%S') log-line-$i" >> /var/log/app/output.log
i=$((i+1))
sleep 2
done
volumeMounts:
- name: log-volume
mountPath: /var/log/app
- name: log-reader
image: busybox:1.36
command: ["sh", "-c"]
args:
- tail -f /var/log/app/output.log
volumeMounts:
- name: log-volume
mountPath: /var/log/app
volumes:
- name: log-volume
emptyDir: {}
EOF
The key structural decisions in this manifest:
-
emptyDirvolume: Created when the Pod is assigned to a node. Both containers mount it at/var/log/app, giving them shared filesystem access. The volume lives as long as the Pod runs on that node — it survives container restarts but not Pod rescheduling. -
appcontainer: Uses a shell loop to write timestamped log lines to/var/log/app/output.logevery 2 seconds. The>>append operator ensures log lines accumulate rather than overwriting. -
log-readercontainer: Runstail -fto stream new lines from the same file. In production, this sidecar would forward logs to a centralized system (Fluentd, Loki, CloudWatch). For this exercise, it demonstrates the shared volume pattern.
Step 2: Apply and Verify
kubectl apply -f sidecar-logging.yaml
Wait for the Pod to reach Running status:
kubectl get pod sidecar-logging -w
Expected output after a few seconds:
NAME READY STATUS RESTARTS AGE
sidecar-logging 2/2 Running 0 8s
The 2/2 confirms both containers are running. If you see 1/2, one container has not started yet — wait a few more seconds.
Step 3: Verify Log Output
Read the sidecar’s stdout to confirm it is receiving log lines:
kubectl logs sidecar-logging -c log-reader
Expected output (timestamps will differ):
2026-03-01 10:15:00 log-line-0
2026-03-01 10:15:02 log-line-1
2026-03-01 10:15:04 log-line-2
2026-03-01 10:15:06 log-line-3
You can also verify the app container’s log file directly:
kubectl exec sidecar-logging -c app -- cat /var/log/app/output.log
This should produce the same lines. Both containers see the same file because they share the log-volume mount.
Step 4: Stream Live Logs
To watch the sidecar stream in real time:
kubectl logs sidecar-logging -c log-reader -f
Press Ctrl+C to stop following. New lines should appear every 2 seconds, confirming the sidecar continuously tails the application log.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
0/2 containers ready | Image pull failure | Check image name: busybox:1.36 |
log-reader shows no output | Volume mount path mismatch | Verify both containers mount to /var/log/app |
CrashLoopBackOff on app | Shell script syntax error | Check the args block uses literal block scalar (|) |
Pod stays Pending | No node available or resource pressure | Run kubectl describe pod sidecar-logging and check Events |
Cleanup
kubectl delete pod sidecar-logging
Solution: Exercise 2 — Rolling Update Deployment
This exercise requires creating a Deployment, performing a rolling update to a new image version, verifying the rollout, and then rolling back.
Step 1: Create the Initial Deployment
cat > rolling-deploy.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
EOF
Key fields:
strategy.rollingUpdate.maxSurge: 1: During an update, Kubernetes can create at most 1 Pod beyond the desired replica count (so up to 4 Pods temporarily exist).strategy.rollingUpdate.maxUnavailable: 1: At most 1 Pod can be unavailable during the update. Combined withmaxSurge: 1, this means the update proceeds one Pod at a time — creating a new Pod, verifying it is ready, then terminating an old one.
Apply the Deployment:
kubectl apply -f rolling-deploy.yaml
Verify all 3 replicas are running:
kubectl get deployment web-app
Expected output:
NAME READY UP-TO-DATE AVAILABLE AGE
web-app 3/3 3 3 12s
Step 2: Record the Initial Revision
Check the rollout history:
kubectl rollout history deployment/web-app
Expected output:
deployment.apps/web-app
REVISION CHANGE-CAUSE
1 <none>
Step 3: Perform the Rolling Update
Update the container image from nginx:1.24 to nginx:1.25:
kubectl set image deployment/web-app nginx=nginx:1.25
Watch the rollout progress:
kubectl rollout status deployment/web-app
Expected output:
Waiting for deployment "web-app" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "web-app" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "web-app" rollout to finish: 2 of 3 updated replicas are available...
deployment "web-app" successfully rolled out
Step 4: Verify the Update
Confirm the new image is running across all Pods:
kubectl get pods -l app=web-app -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
Expected output:
web-app-6d9f8b7c5-abc12 nginx:1.25
web-app-6d9f8b7c5-def34 nginx:1.25
web-app-6d9f8b7c5-ghi56 nginx:1.25
All three Pods should show nginx:1.25. The Pod names will differ — what matters is the image version.
Check rollout history now shows two revisions:
kubectl rollout history deployment/web-app
deployment.apps/web-app
REVISION CHANGE-CAUSE
1 <none>
2 <none>
Step 5: Roll Back to the Previous Version
kubectl rollout undo deployment/web-app
Expected output:
deployment.apps/web-app rolled back
Verify the rollback completed:
kubectl rollout status deployment/web-app
Confirm the image reverted to nginx:1.24:
kubectl get deployment web-app -o jsonpath='{.spec.template.spec.containers[0].image}'
Expected output:
nginx:1.24
Check rollout history — the revision number advances, it does not go backwards:
kubectl rollout history deployment/web-app
deployment.apps/web-app
REVISION CHANGE-CAUSE
2 <none>
3 <none>
Revision 1 disappears because undo promoted revision 1 to become the new revision 3. The Deployment always moves forward in revision numbering.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Rollout stuck at “1 out of 3 updated” | New image fails readiness | Check kubectl describe pod for image pull errors or crash loops |
kubectl rollout undo reports “no last revision” | Only one revision exists | You need at least 2 revisions before undo works |
| Old Pods not terminating | maxUnavailable: 0 with maxSurge: 0 | At least one must be > 0 or the update deadlocks |
| Pods show old image after update | Cached jsonpath output | Re-run the get command; old Pods terminate asynchronously |
Cleanup
kubectl delete deployment web-app