Restaurant Company: Deploy, Configure, Scale & Troubleshoot
Goal
You are the DevOps Engineer responsible for deploying the Restaurant Company application into Kubernetes.
By the end of this lab, you should be able to explain and demonstrate:
EKS Cluster
↓
Worker Node
↓
Deployment
↓
ReplicaSet
↓
Pods
↓
Service
↓
Application
ConfigMap + Secret
↓
Pods
Resources
CPU + Memory
↓
Pods
Metrics Server
↓
HPA
↓
Deployment replicas
Do not simply copy commands. After every section, understand what Kubernetes created and why.
Part 1 — Verify Your Kubernetes Environment
Before creating anything:
kubectl get nodes
Your Worker Node should show:
STATUS
Ready
Run:
kubectl get nodes -o wide
Then:
kubectl describe node <NODE-NAME>
Find:
Capacity:
cpu:
memory:
pods:
Allocatable:
cpu:
memory:
pods:
Questions
Students must answer:
- What is a Worker Node?
- What is
Capacity? - What is
Allocatable? - Why can Allocatable be smaller than Capacity?
- How many Pods can your Node run?
- Is Pod capacity the same thing as CPU capacity?
- What does
1930mCPU mean if you see it?
Remember:
1000m = 1 CPU core
500m = 0.5 CPU
100m = 0.1 CPU
Part 2 — Create Your Working Directory
mkdir -p ~/weekend-k8s-lab
cd ~/weekend-k8s-lab
Verify:
pwd
You will create:
weekend-k8s-lab/
├── configmap.yaml
├── secret.yaml
├── deployment.yaml
├── service.yaml
└── hpa.yaml
Part 3 — ConfigMap
Create:
nano configmap.yaml
Add:
apiVersion: v1
kind: ConfigMap
metadata:
name: restaurant-config
data:
APP_ENV: "production"
APP_NAME: "restaurant-company"
Apply:
kubectl apply -f configmap.yaml
Verify:
kubectl get configmap
kubectl describe configmap restaurant-config
Understand
A ConfigMap stores non-sensitive configuration separately from the application image.
Examples:
APP_ENV
APP_NAME
LOG_LEVEL
API_URL
Interview Question
Why shouldn't configuration always be hard-coded into the Docker image?
Part 4 — Secret
Create:
nano secret.yaml
For this classroom lab only:
apiVersion: v1
kind: Secret
metadata:
name: restaurant-secret
type: Opaque
stringData:
DB_PASSWORD: "JumpToTech123"
Apply:
kubectl apply -f secret.yaml
Check:
kubectl get secret
kubectl describe secret restaurant-secret
You may see:
Data
====
DB_PASSWORD: 13 bytes
Important
Do not commit real production passwords to GitHub.
Also remember:
Kubernetes Secret is not automatically "safe because it is a Secret." Base64 encoding is not encryption.
Part 5 — Deployment
Create:
nano deployment.yaml
Use:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: restaurant-config
key: APP_ENV
- name: APP_NAME
valueFrom:
configMapKeyRef:
name: restaurant-config
key: APP_NAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: restaurant-secret
key: DB_PASSWORD
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 20
Apply:
kubectl apply -f deployment.yaml
Check:
kubectl get deployment
kubectl get pods
kubectl get rs
Students should understand:
Deployment
↓
ReplicaSet
↓
Pods
Part 6 — Prove Self-Healing
Get Pods:
kubectl get pods
Delete ONE Deployment-managed Pod:
kubectl delete pod <POD-NAME>
Immediately:
kubectl get pods -w
Observe
You deleted one Pod.
But the desired state says:
replicas: 2
Therefore:
Desired = 2
Actual = 1
ReplicaSet
↓
creates replacement
↓
Actual = 2
Interview Question
Why did Kubernetes recreate the Pod?
Do not answer:
"Because Kubernetes always recreates Pods."
Correct idea:
The Pod is managed by a ReplicaSet created by the Deployment, and the controller reconciles actual state with desired state.
Part 7 — Verify ConfigMap and Secret Injection
Find a Pod:
kubectl get pods
Check ConfigMap values:
kubectl exec -it <POD-NAME> -- printenv APP_ENV
Expected:
production
Then:
kubectl exec -it <POD-NAME> -- printenv APP_NAME
Expected:
restaurant-company
For this classroom lab only, verify that the Secret variable exists:
kubectl exec -it <POD-NAME> -- printenv DB_PASSWORD
Do not expose production secrets this way.
Part 8 — Understand Resources
Your Deployment contains:
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
Requests
Requests are especially important to scheduling.
New Pod
↓
CPU request = 100m
Memory request = 128Mi
↓
Scheduler
↓
Find suitable Node
Limits
Limits constrain resource usage.
CPU limit exceeded
→ CPU may be throttled
Memory limit exceeded
→ Container may be terminated / OOMKilled
Verify:
kubectl describe pod <POD-NAME>
Find:
Requests:
cpu: 100m
memory: 128Mi
Limits:
cpu: 500m
memory: 256Mi
Calculation
If there are 6 Pods:
6 × 100m CPU = 600m requested CPU
6 × 128Mi = 768Mi requested Memory
Part 9 — Readiness Probe
Your Deployment contains:
readinessProbe:
httpGet:
path: /
port: 80
Readiness asks:
Should Kubernetes send normal Service traffic to this Pod?
Now intentionally break it.
Change:
path: /
to:
path: /wrong-page
Apply:
kubectl apply -f deployment.yaml
Watch:
kubectl get pods -w
You may see:
READY
0/1
But:
STATUS
Running
Important Interview Question
Can a Pod be Running but not Ready?
YES.
Investigate:
kubectl describe pod <POD-NAME>
Look at:
Events:
Now fix:
path: /
Apply again:
kubectl apply -f deployment.yaml
Watch:
kubectl get pods -w
Expected eventually:
1/1 Running
Part 10 — Liveness Probe
Your Deployment contains:
livenessProbe:
httpGet:
path: /
port: 80
Remember:
Readiness
→ Should this workload receive traffic?
Liveness
→ Is this workload healthy enough to keep running?
Repeated liveness failures can cause kubelet to restart the Container.
Interview Question
Explain the difference between:
Readiness Probe
vs
Liveness Probe
in your own words.
Part 11 — Create a Service
Create:
nano service.yaml
Add:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
Apply:
kubectl apply -f service.yaml
Check:
kubectl get svc
Then:
kubectl get endpoints nginx-service
You should see Pod IP addresses.
Architecture:
Client
↓
nginx-service
↓
selector:
app: nginx
↓
matching Pods
Important
The Service does not randomly discover your application.
It uses:
selector:
app: nginx
and finds Pods with:
labels:
app: nginx
Part 12 — Break the Service
Now create a real incident.
Change:
selector:
app: nginx
to:
selector:
app: wrong-label
Apply:
kubectl apply -f service.yaml
Check:
kubectl get endpoints nginx-service
You may see no endpoints.
Now troubleshoot:
kubectl get pods --show-labels
Compare:
Service selector
vs
Pod labels
Fix:
selector:
app: nginx
Apply:
kubectl apply -f service.yaml
Check again:
kubectl get endpoints nginx-service
Interview Scenario
Pods are Running, but the Service has no endpoints. What do you check?
Answer:
Pod labels and Service selector.
Part 13 — Metrics Server
Now check resource usage:
kubectl top nodes
Then:
kubectl top pods
Understand the difference:
REQUEST
100m CPU
≠
ACTUAL USAGE
for example 5m CPU
≠
LIMIT
500m CPU
Three different concepts.
Architecture:
Pod / Container
↓
kubelet
↓
Metrics Server
↓
Kubernetes Metrics API
↓
HPA
Part 14 — Create HPA
Create:
nano hpa.yaml
Add:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
minReplicas: 2
maxReplicas: 8
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
Apply:
kubectl apply -f hpa.yaml
Check:
kubectl get hpa
You may see:
TARGETS
cpu: 0%/50%
Interpret:
0% = current CPU utilization
50% = target
Also:
kubectl describe hpa nginx-hpa
Part 15 — Understand HPA Before Testing It
HPA does not simply mean:
CPU reaches exactly 50%
→ create exactly 1 Pod
Instead, HPA evaluates the metric and calculates a desired replica count.
Also:
HPA
↓
changes desired replicas
↓
Deployment / ReplicaSet
↓
Pods are created/removed
For this CPU-utilization HPA, your CPU request matters:
requests:
cpu: "100m"
Very simplified example:
CPU request = 100m
actual usage 10m
≈ 10%
actual usage 50m
≈ 50%
actual usage 80m
≈ 80%
Part 16 — Generate Traffic
Make sure:
kubectl get svc nginx-service
Then create a load generator:
kubectl run load-generator \
--image=busybox:1.36 \
--restart=Never \
-- /bin/sh -c \
'for i in 1 2 3 4 5 6 7 8 9 10; do while true; do wget -q -O- http://nginx-service > /dev/null; done & done; wait'
Now use multiple terminals.
Terminal 1
kubectl get hpa -w
Terminal 2
kubectl get pods -w
Terminal 3
kubectl top pods
Observe:
Load Generator
↓
HTTP requests
↓
Service
↓
Nginx Pods
↓
CPU utilization ↑
↓
Metrics Server
↓
HPA
↓
Desired replicas ↑
↓
Deployment / ReplicaSet
↓
More Pods
Do not expect exact CPU percentages or exact scaling timing to be identical on every student's cluster.
Part 17 — Stop Traffic
Delete:
kubectl delete pod load-generator
Watch:
kubectl get hpa -w
CPU usage should decrease.
Eventually HPA can reduce replicas toward:
minReplicas = 2
Scale-down may not happen immediately.
Part 18 — Production Incident: Pending Pods
This is based on a real incident from class.
Suppose:
Node Pod Capacity = 29
Current Pods = 29
HPA wants additional replicas.
What happens?
HPA
↓
Desired replicas ↑
↓
ReplicaSet creates new Pod objects
↓
Scheduler tries to place them
↓
Node = 29/29 Pods
↓
No available Pod slot
↓
Pending
Investigate:
kubectl get pods
Then:
kubectl describe pod <PENDING-POD>
Look at:
Events:
You might find:
FailedScheduling
Too many pods
Important
This is different from:
Insufficient cpu
or:
Insufficient memory
Do not guess the root cause.
Read the Events.
Part 19 — Kubernetes Troubleshooting Challenge
For each scenario, write:
1. Symptom
2. Command used
3. Root cause
4. Fix
5. Verification
Incident A
Pod = Pending
Start:
kubectl describe pod <POD>
Check Events.
Incident B
Pod = Running
READY = 0/1
Think:
Readiness Probe
Incident C
Pods Running
Service exists
Endpoints = none
Think:
Service selector
vs
Pod labels
Incident D
Container keeps restarting
Start:
kubectl describe pod <POD>
kubectl logs <POD>
Consider liveness failures, application errors, OOMKilled, etc.
Incident E
HPA shows unknown CPU metric
Check:
kubectl top pods
kubectl describe hpa nginx-hpa
Also verify the workload has appropriate CPU requests for utilization-based CPU HPA.
Part 20 — Commands You Must Know
By Monday, students should be comfortable with:
kubectl get nodes
kubectl describe node <NODE>
kubectl get pods
kubectl get pods -o wide
kubectl get pods -w
kubectl describe pod <POD>
kubectl logs <POD>
kubectl get deployment
kubectl describe deployment nginx-deployment
kubectl get rs
kubectl get svc
kubectl describe svc nginx-service
kubectl get endpoints nginx-service
kubectl get configmap
kubectl get secret
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl top nodes
kubectl top pods
kubectl get hpa
kubectl get hpa -w
kubectl describe hpa nginx-hpa
Final Architecture — Draw This Yourself
Every student must be able to draw and explain this without notes:
USERS
↓
Load Balancer
↓
Service
↓
┌───────────┼───────────┐
↓ ↓ ↓
Pod 1 Pod 2 Pod 3
│ │ │
└──── Deployment ───────┘
↓
ReplicaSet
ConfigMap ─────────→ Pods
Secret ────────────→ Pods
Worker Node
├── CPU
├── Memory
├── Storage
├── Networking
└── Pod Capacity
Pods
↓
CPU / Memory usage
↓
kubelet
↓
Metrics Server
↓
HPA
↓
Deployment desired replicas
↓
ReplicaSet
↓
More / Fewer Pods
Weekend Interview Questions
Students should prepare answers to these without reading from notes:
- What is Kubernetes?
- What is Amazon EKS?
- What is the Control Plane?
- What is a Worker Node?
- What is a Pod?
- What is a Container?
- What does
kubectldo? - What does the Scheduler do?
- What is a Deployment?
- What is a ReplicaSet?
- What does
replicas: 3mean? - What is desired state?
- What is reconciliation?
- What happens when you delete a Deployment-managed Pod?
- Why can Pod IP addresses change?
- What problem does a Service solve?
- What is ClusterIP?
- What is LoadBalancer?
- How does a Service find Pods?
- What are labels?
- What is a selector?
- What are endpoints?
- What happens when Service selector does not match Pod labels?
- What is a ConfigMap?
- What is a Secret?
- ConfigMap vs Secret?
- What are resource requests?
- What are resource limits?
- Who uses requests during scheduling?
- What is
100mCPU? - What is
1000mCPU? - What can happen when CPU reaches its limit?
- What can happen when Memory exceeds its limit?
- What does
OOMKilledmean? - What is a Readiness Probe?
- What is a Liveness Probe?
- Can a Pod be
Runningbut0/1 Ready? - What is Metrics Server?
- What does
kubectl top podsshow? - What is HPA?
- What does Horizontal scaling mean?
- What is
minReplicas? - What is
maxReplicas? - What does
averageUtilization: 50mean? - Why are CPU requests important for CPU-utilization HPA?
- Does HPA directly create Pods?
- Does HPA create Worker Nodes?
- What happens if HPA wants more Pods but the Node is full?
- What does
Pendingmean? - How do you find why a Pod is Pending?
- What does
FailedSchedulingmean? - What does
Too many podsmean? - What's the difference between CPU capacity and Pod capacity?
- What do you check when Pods are Running but Service has no endpoints?
- What commands would you use if an application is down?
Required Submission
Each student should submit screenshots showing:
1. kubectl get nodes
2. kubectl get pods
3. kubectl get deployment
4. kubectl get rs
5. kubectl get svc
6. kubectl get endpoints nginx-service
7. kubectl get configmap
8. kubectl get secret
9. kubectl describe pod showing Requests/Limits
10. kubectl top nodes
11. kubectl top pods
12. kubectl get hpa
13. HPA before load
14. Load generator Running
15. HPA during CPU load
16. Additional Nginx Pods created by scaling
17. HPA after load is removed
18. One troubleshooting example and its Events
Top comments (0)