Lab 23 - Application end to end
Lab 23 - Application end to end
Infodiscovery optional / if time permits
Goal: build, operate, break and fix a complete application using everything from the three days.
This lab gives you what, not how. Every command is in the
cheat sheets, in
kubectl explain, or behind --help.
Each stage ends with an answer key box. Try the stage first; open the box if you get stuck or if you want to check your solution against one that works. Each box is self-contained, so you can rejoin the lab at the start of any stage without having done the previous one your own way. If you are completely lost, jump to Catch up in one paste at the bottom.
Build it
- Create a namespace
shopand make it your default. - Create a ConfigMap
web-contentholding anindex.htmlthat saysShop v1. - Create a Deployment
shop-web, imagenginx:1.27, 3 replicas, with:- CPU request
50m, memory request64Mi, memory limit128Mi - the ConfigMap mounted at
/usr/share/nginx/html - a readiness probe on
/
- CPU request
- Expose it with a ClusterIP Service.
- Publish it through a Gateway with an HTTPRoute for
shop.k8s.lab. (Remember the data plane Service lives in the Gateway’s namespace.) - Verify from support01 -
curl -H 'Host: shop.k8s.lab' http://worker01:<gateway-nodeport>returnsShop v1.
Operate it
- Scale to 5 replicas and confirm they are spread across the workers.
- Change the content to
Shop v2and make it visible without deleting any Pod by hand. - Roll the image forward to
nginx:1.28with zero downtime. Prove it by running a request loop during the rollout. - Roll back to the previous revision and show the history.
Add state
- Give the application a PersistentVolumeClaim mounted at
/datain every Pod. It must be shared by all replicas. - Write a file into
/datafrom one Pod and read it from another.
Break it and fix it
- Set the image to
nginx:nosuchtag. Answer fromkubectloutput alone: is the site still up, and why? Which ReplicaSet is stuck, and what does its event say? - Recover.
- Change the Service selector so it matches nothing. Prove the breakage using endpoints, then fix it.
- Cordon the node running most of the Pods, drain it, and show the application stayed available throughout.
Package it
- Turn the whole thing into a Helm chart with
replicaCount, the content message, and the hostname as values. - Install it twice, under two release names, on two hostnames.
Clean up
- Remove both releases, the namespace, the PVC, and release the PV.
Catch up in one paste
Lost the thread completely, or want to skip ahead to a later stage? This rebuilds everything up to the end of Operate it (steps 1-10) in one go. Paste it, wait, then continue from Add state.
cd ~
kubectl create namespace shop --dry-run=client -o yaml | kubectl apply -f -
kubectl config set-context --current --namespace=shop
echo '<h1>Shop v2</h1>' > index.html
kubectl create configmap web-content --from-file=index.html \
--dry-run=client -o yaml | kubectl apply -f -
kubectl apply -f - <<'YAML'
apiVersion: apps/v1
kind: Deployment
metadata:
name: shop-web
labels: { app: shop-web }
spec:
replicas: 5
selector:
matchLabels: { app: shop-web }
template:
metadata:
labels: { app: shop-web }
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests: { cpu: "50m", memory: "64Mi" }
limits: { memory: "128Mi" }
readinessProbe:
httpGet: { path: /, port: 80 }
initialDelaySeconds: 3
periodSeconds: 5
volumeMounts:
- name: content
mountPath: /usr/share/nginx/html
volumes:
- name: content
configMap: { name: web-content }
---
apiVersion: v1
kind: Service
metadata:
name: shop-svc
spec:
selector: { app: shop-web }
ports:
- port: 80
targetPort: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shop-gw
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces: { from: All }
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop
spec:
parentRefs:
- name: shop-gw
hostnames: ["shop.k8s.lab"]
rules:
- matches:
- path: { type: PathPrefix, value: / }
backendRefs:
- name: shop-svc
port: 80
YAML
kubectl rollout status deploy/shop-web
PORT=$(kubectl get svc -n shop -l gateway.networking.k8s.io/gateway-name=shop-gw \
-o jsonpath='{.items[0].spec.ports[?(@.port==80)].nodePort}')
echo "gateway node port: $PORT"
curl -s -H 'Host: shop.k8s.lab' http://worker01:$PORT
If you get stuck anywhere, the answer is almost always: kubectl describe the
object and read the Events.