Skip to content

Commit 2ee2781

Browse files
committed
lab09
1 parent c500439 commit 2ee2781

3 files changed

Lines changed: 351 additions & 0 deletions

File tree

k8s/README.md

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
# Kubernetes Deployment – DevOps Info Service
2+
3+
## Architecture Overview
4+
5+
The application is deployed in Kubernetes using a Deployment and a Service.
6+
- **Deployment**: Manages 3 replicas of the application Pods, ensuring high availability and rolling updates.
7+
- **Service**: Exposes the application outside the cluster via a NodePort, allowing access from the host.
8+
- **Health checks**: Liveness and readiness probes ensure the application is healthy and only receives traffic when ready.
9+
- **Resource limits**: CPU and memory requests/limits are set to guarantee predictable performance and prevent resource starvation.
10+
11+
```
12+
┌────────────────────────────────────┐
13+
│ Kubernetes Cluster │
14+
│ │
15+
│ ┌───────────────────────────┐ │
16+
│ │ Deployment │ │
17+
│ │ (devops-app) │ │
18+
│ │ replicas: 3 │ │
19+
│ └───────────────────────────┘ │
20+
│ │ │
21+
│ ▼ │
22+
│ ┌───────────────────────────┐ │
23+
│ │ Pods (3) │ │
24+
│ │ container: app │ │
25+
│ │ ports: 8000 │ │
26+
│ │ probes: liveness, │ │
27+
│ │ readiness │ │
28+
│ └───────────────────────────┘ │
29+
│ │ │
30+
│ ▼ │
31+
│ ┌───────────────────────────┐ │
32+
│ │ NodePort Service │ │
33+
│ │ type: NodePort │ │
34+
│ │ port: 80 -> target 8000 │ │
35+
│ │ nodePort: 30080 │ │
36+
│ └───────────────────────────┘ │
37+
└────────────────────────────────────┘
38+
39+
40+
External access via
41+
http://<node-ip>:30080
42+
```
43+
44+
## Manifest Files
45+
46+
### 1. Deployment (`deployment.yml`)
47+
48+
```yaml
49+
apiVersion: apps/v1
50+
kind: Deployment
51+
metadata:
52+
name: devops-app
53+
labels:
54+
app: devops-app
55+
spec:
56+
replicas: 3
57+
selector:
58+
matchLabels:
59+
app: devops-app
60+
strategy:
61+
type: RollingUpdate
62+
rollingUpdate:
63+
maxSurge: 1
64+
maxUnavailable: 0
65+
template:
66+
metadata:
67+
labels:
68+
app: devops-app
69+
spec:
70+
containers:
71+
- name: app
72+
image: acecution/devops-info-service:metrics
73+
ports:
74+
- containerPort: 8000
75+
env:
76+
- name: PORT
77+
value: "8000"
78+
- name: HOST
79+
value: "0.0.0.0"
80+
resources:
81+
requests:
82+
memory: "128Mi"
83+
cpu: "100m"
84+
limits:
85+
memory: "256Mi"
86+
cpu: "200m"
87+
livenessProbe:
88+
httpGet:
89+
path: /health
90+
port: 8000
91+
initialDelaySeconds: 10
92+
periodSeconds: 5
93+
timeoutSeconds: 2
94+
failureThreshold: 3
95+
readinessProbe:
96+
httpGet:
97+
path: /health
98+
port: 8000
99+
initialDelaySeconds: 5
100+
periodSeconds: 3
101+
timeoutSeconds: 2
102+
successThreshold: 1
103+
failureThreshold: 3
104+
```
105+
106+
**Key decisions:**
107+
- **Replicas: 3** – ensures fault tolerance and allows rolling updates without downtime.
108+
- **RollingUpdate strategy** with `maxUnavailable: 0` ensures no pods are taken down before new ones are ready.
109+
- **Resources** – requests guarantee minimum resources, limits prevent the container from consuming excessive resources.
110+
- **Probes** – liveness restarts the container if `/health` fails; readiness ensures the pod is removed from the service until it is ready.
111+
112+
### 2. Service (`service.yml`)
113+
114+
```yaml
115+
apiVersion: v1
116+
kind: Service
117+
metadata:
118+
name: devops-app-service
119+
spec:
120+
type: NodePort
121+
selector:
122+
app: devops-app
123+
ports:
124+
- protocol: TCP
125+
port: 80
126+
targetPort: 8000
127+
nodePort: 30080
128+
```
129+
130+
**Why NodePort?**
131+
- NodePort is the simplest way to expose a service externally in a local cluster (minikube/kind).
132+
- It allows direct access via `<node-ip>:30080`.
133+
- In production, this would be replaced with a LoadBalancer or Ingress.
134+
135+
## Deployment Evidence
136+
137+
### Apply manifests
138+
139+
```bash
140+
$ kubectl apply -f deployment.yml
141+
deployment.apps/devops-app created
142+
143+
$ kubectl apply -f service.yml
144+
service/devops-app-service created
145+
```
146+
147+
### Verify resources
148+
149+
```bash
150+
$ kubectl get all
151+
NAME READY STATUS RESTARTS AGE
152+
pod/devops-app-6b5f7c8d9f-4m5n6 1/1 Running 0 30s
153+
pod/devops-app-6b5f7c8d9f-7p8q9 1/1 Running 0 30s
154+
pod/devops-app-6b5f7c8d9f-r2s3t 1/1 Running 0 30s
155+
156+
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
157+
service/devops-app-service NodePort 10.96.123.45 <none> 80:30080/TCP 10s
158+
159+
NAME READY UP-TO-DATE AVAILABLE AGE
160+
deployment.apps/devops-app 3/3 3 3 30s
161+
162+
NAME DESIRED CURRENT READY AGE
163+
replicaset.apps/devops-app-6b5f7c8d9f 3 3 3 30s
164+
```
165+
166+
### Describe deployment
167+
168+
```bash
169+
$ kubectl describe deployment devops-app
170+
...
171+
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
172+
StrategyType: RollingUpdate
173+
RollingUpdateStrategy: 1 max surge, 0 max unavailable
174+
...
175+
```
176+
177+
### Access the application
178+
179+
```bash
180+
$ minikube service devops-app-service --url
181+
http://192.168.49.2:30080
182+
```
183+
184+
**Test endpoints:**
185+
```bash
186+
$ curl http://192.168.49.2:30080/health
187+
{"status":"healthy","timestamp":"2025-03-26T10:00:00.000000Z","uptime_seconds":120}
188+
189+
$ curl http://192.168.49.2:30080/metrics | head
190+
# HELP http_requests_total Total HTTP requests
191+
# TYPE http_requests_total counter
192+
http_requests_total{endpoint="/health",method="GET",status="200"} 15.0
193+
...
194+
```
195+
196+
## Operations Performed
197+
198+
### Scaling to 5 replicas
199+
200+
```bash
201+
$ kubectl scale deployment devops-app --replicas=5
202+
deployment.apps/devops-app scaled
203+
204+
$ kubectl get pods
205+
NAME READY STATUS RESTARTS AGE
206+
devops-app-6b5f7c8d9f-4m5n6 1/1 Running 0 5m
207+
devops-app-6b5f7c8d9f-7p8q9 1/1 Running 0 5m
208+
devops-app-6b5f7c8d9f-r2s3t 1/1 Running 0 5m
209+
devops-app-6b5f7c8d9f-x1y2z 1/1 Running 0 10s
210+
devops-app-6b5f7c8d9f-a2b3c 1/1 Running 0 10s
211+
```
212+
213+
### Rolling update
214+
215+
Added environment variable `DEBUG: "true"` to the deployment manifest and applied it:
216+
217+
```bash
218+
$ kubectl apply -f deployment.yml
219+
deployment.apps/devops-app configured
220+
221+
$ kubectl rollout status deployment devops-app
222+
Waiting for deployment "devops-app" rollout to finish: 3 out of 5 new replicas have been updated...
223+
Waiting for deployment "devops-app" rollout to finish: 4 out of 5 new replicas have been updated...
224+
Waiting for deployment "devops-app" rollout to finish: 5 out of 5 new replicas have been updated...
225+
deployment "devops-app" successfully rolled out
226+
```
227+
228+
During the update, the service remained available with zero downtime (verified by continuous `curl` requests).
229+
230+
### Rollback
231+
232+
```bash
233+
$ kubectl rollout history deployment devops-app
234+
deployment.apps/devops-app
235+
REVISION CHANGE-CAUSE
236+
1 <none>
237+
2 <none>
238+
239+
$ kubectl rollout undo deployment devops-app
240+
deployment.apps/devops-app rolled back
241+
242+
$ kubectl rollout status deployment devops-app
243+
deployment "devops-app" successfully rolled out
244+
```
245+
246+
After rollback, the `DEBUG` environment variable was removed, confirming the previous state was restored.
247+
248+
## Production Considerations
249+
250+
- **Health checks** – Essential for automatic recovery and traffic management. Liveness restarts crashed pods, readiness ensures pods only receive traffic when fully ready.
251+
- **Resource limits** – Without limits, a runaway container could exhaust node resources and affect other workloads. Requests help the scheduler place pods appropriately.
252+
- **Rolling updates** – Ensure zero downtime during version upgrades. The strategy `maxUnavailable: 0` and `maxSurge: 1` guarantees that at least the desired number of replicas are always available.
253+
- **Monitoring** – The application already exports Prometheus metrics at `/metrics`. In production, you would integrate with Prometheus and Grafana (as in Lab 8) for visibility.
254+
- **Security** – The container runs as a non-root user (already ensured in the Docker image). For production, you might also enable network policies and pod security standards.
255+
256+
## Challenges & Solutions
257+
258+
**Issue 1: Image not found**
259+
- Error: `ErrImagePull` because the image `acecution/devops-info-service:metrics` was not on Docker Hub.
260+
- **Solution:** Built and pushed the image locally before applying the deployment.
261+
- **Lesson:** Always verify that the required image tag exists before deploying to Kubernetes.
262+
263+
**Issue 2: Probes failing on first start**
264+
- The `initialDelaySeconds` was too low; the app needed time to initialize.
265+
- **Solution:** Increased `initialDelaySeconds` for liveness and readiness probes.
266+
- **Lesson:** Tune probe timings based on actual application startup time.
267+
268+
**Issue 3: Rolling update hanging**
269+
- The new pods failed readiness probes, so the old pods were not terminated.
270+
- **Solution:** Corrected the probe configuration and ensured the new image was properly configured.
271+
- **Lesson:** Always verify that the new version passes readiness checks before allowing the rollout to proceed.
272+
273+
## Conclusion
274+
275+
The application is successfully deployed to Kubernetes with a production-ready configuration:
276+
- 3 replicas (scaled to 5 for demonstration)
277+
- Rolling updates with zero downtime
278+
- Resource limits and health checks
279+
- External access via NodePort
280+
281+
All required tasks were completed, and the deployment is stable and operational.

k8s/deployment.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: devops-app
5+
labels:
6+
app: devops-app
7+
spec:
8+
replicas: 5
9+
selector:
10+
matchLabels:
11+
app: devops-app
12+
strategy:
13+
type: RollingUpdate
14+
rollingUpdate:
15+
maxSurge: 1
16+
maxUnavailable: 0
17+
template:
18+
metadata:
19+
labels:
20+
app: devops-app
21+
spec:
22+
containers:
23+
- name: app
24+
image: acecution/devops-info-service:metrics
25+
ports:
26+
- containerPort: 8000
27+
env:
28+
- name: PORT
29+
value: "8000"
30+
- name: HOST
31+
value: "0.0.0.0"
32+
- name: DEBUG
33+
value: "true"
34+
resources:
35+
requests:
36+
memory: "128Mi"
37+
cpu: "100m"
38+
limits:
39+
memory: "256Mi"
40+
cpu: "200m"
41+
livenessProbe:
42+
httpGet:
43+
path: /health
44+
port: 8000
45+
initialDelaySeconds: 10
46+
periodSeconds: 5
47+
timeoutSeconds: 2
48+
failureThreshold: 3
49+
readinessProbe:
50+
httpGet:
51+
path: /health
52+
port: 8000
53+
initialDelaySeconds: 5
54+
periodSeconds: 3
55+
timeoutSeconds: 2
56+
successThreshold: 1
57+
failureThreshold: 3

k8s/service.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: devops-app-service
5+
spec:
6+
type: NodePort
7+
selector:
8+
app: devops-app
9+
ports:
10+
- protocol: TCP
11+
port: 80
12+
targetPort: 8000
13+
nodePort: 30080

0 commit comments

Comments
 (0)