|
| 1 | +# Lab09: Minikube |
| 2 | + |
| 3 | +## Task 1-3 |
| 4 | + |
| 5 | +- [deployment.yaml](./deployment.yaml) (replicas 3) |
| 6 | +- [service.yaml](./service.yaml) |
| 7 | + |
| 8 | +Usage: |
| 9 | + |
| 10 | +```sh |
| 11 | +kubectl apply -f labs/k8s/deployment.yaml |
| 12 | +kubectl get deployment python-info-service |
| 13 | +kubectl describe deployment python-info-service |
| 14 | +kubectl get pods -l app=python-info-service |
| 15 | +``` |
| 16 | + |
| 17 | +```sh |
| 18 | +kubectl get deployment python-info-service |
| 19 | +NAME READY UP-TO-DATE AVAILABLE AGE |
| 20 | +python-info-service 3/3 3 3 11m |
| 21 | + |
| 22 | +kubectl describe deployment python-info-service |
| 23 | +Name: python-info-service |
| 24 | +Namespace: default |
| 25 | +CreationTimestamp: Thu, 26 Mar 2026 21:33:30 +0300 |
| 26 | +Labels: app=python-info-service |
| 27 | +Annotations: deployment.kubernetes.io/revision: 1 |
| 28 | +Selector: app=python-info-service |
| 29 | +Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable |
| 30 | +StrategyType: RollingUpdate |
| 31 | +MinReadySeconds: 0 |
| 32 | +RollingUpdateStrategy: 0 max unavailable, 1 max surge |
| 33 | +Pod Template: |
| 34 | + Labels: app=python-info-service |
| 35 | + Containers: |
| 36 | + python-info-service: |
| 37 | + Image: projacktor/python-info-service:latest |
| 38 | + Port: 8080/TCP |
| 39 | + Host Port: 0/TCP |
| 40 | + Limits: |
| 41 | + cpu: 200m |
| 42 | + memory: 256Mi |
| 43 | + Requests: |
| 44 | + cpu: 100m |
| 45 | + memory: 128Mi |
| 46 | + Liveness: tcp-socket :8080 delay=15s timeout=2s period=10s #success=1 #failure=3 |
| 47 | + Readiness: tcp-socket :8080 delay=5s timeout=2s period=5s #success=1 #failure=3 |
| 48 | + Environment: <none> |
| 49 | + Mounts: <none> |
| 50 | + Volumes: <none> |
| 51 | + Node-Selectors: <none> |
| 52 | + Tolerations: <none> |
| 53 | +Conditions: |
| 54 | + Type Status Reason |
| 55 | + ---- ------ ------ |
| 56 | + Available True MinimumReplicasAvailable |
| 57 | + Progressing True NewReplicaSetAvailable |
| 58 | +OldReplicaSets: <none> |
| 59 | +NewReplicaSet: python-info-service-85d87fc579 (3/3 replicas created) |
| 60 | +Events: |
| 61 | + Type Reason Age From Message |
| 62 | + ---- ------ ---- ---- ------- |
| 63 | + Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set python-info-service-85d87fc579 from 0 to 3 |
| 64 | + |
| 65 | +kubectl get pods -l app=python-info-service |
| 66 | +NAME READY STATUS RESTARTS AGE |
| 67 | +python-info-service-85d87fc579-rjbx8 1/1 Running 0 11m |
| 68 | +python-info-service-85d87fc579-sxbp5 1/1 Running 0 11m |
| 69 | +python-info-service-85d87fc579-zq7gd 1/1 Running 0 11m |
| 70 | +``` |
| 71 | + |
| 72 | +```sh |
| 73 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> kubectl apply -f labs/k8s/service.yaml |
| 74 | +service/python-info-service created |
| 75 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> kubectl get svc -n default |
| 76 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 77 | +kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h |
| 78 | +python-info-service NodePort 10.104.130.60 <none> 8080:30080/TCP 6s |
| 79 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> kubectl get svc python-info-service -n default |
| 80 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 81 | +python-info-service NodePort 10.104.130.60 <none> 8080:30080/TCP 16s |
| 82 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> minikube service python-info-service --url |
| 83 | +http://192.168.49.2:30080 |
| 84 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> kubectl get services |
| 85 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 86 | +kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h |
| 87 | +python-info-service NodePort 10.104.130.60 <none> 8080:30080/TCP 68s |
| 88 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> kubectl get services python-info-service |
| 89 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 90 | +python-info-service NodePort 10.104.130.60 <none> 8080:30080/TCP 79s |
| 91 | +projacktor@projacktorLaptop ~/P/e/DevOps-Core-Course (lab9)> kubectl get endpoints |
| 92 | +Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice |
| 93 | +NAME ENDPOINTS AGE |
| 94 | +kubernetes 192.168.49.2:8443 23h |
| 95 | +python-info-service 10.244.0.4:8080,10.244.0.5:8080,10.244.0.6:8080 85s |
| 96 | +``` |
| 97 | + |
| 98 | +## Task 4 |
| 99 | + |
| 100 | +Increase replicas: |
| 101 | + |
| 102 | +```sh |
| 103 | +kubectl scale deployment/python-info-service --replicas=5 |
| 104 | + |
| 105 | +deployment.apps/python-info-service scaled |
| 106 | + |
| 107 | +kubectl get pods -w |
| 108 | +NAME READY STATUS RESTARTS AGE |
| 109 | +python-info-service-85d87fc579-c8z74 1/1 Running 0 33s |
| 110 | +python-info-service-85d87fc579-nqxrh 1/1 Running 0 33s |
| 111 | +python-info-service-85d87fc579-rjbx8 1/1 Running 0 16m |
| 112 | +python-info-service-85d87fc579-sxbp5 1/1 Running 0 16m |
| 113 | +python-info-service-85d87fc579-zq7gd 1/1 Running 0 16m |
| 114 | + |
| 115 | + |
| 116 | +^C⏎ |
| 117 | + |
| 118 | +kubectl rollout status deployment/python-info-service |
| 119 | +deployment "python-info-service" successfully rolled out |
| 120 | +``` |
| 121 | + |
| 122 | +## Task 5 |
| 123 | + |
| 124 | +### Architecture Overview |
| 125 | + |
| 126 | +- Cluster: minikube (single-node local Kubernetes) |
| 127 | +- Workload: Deployment/python-info-service |
| 128 | +- Replicas: 3 (scaled to 5 in Task 4) |
| 129 | +- Networking: Service/python-info-service type NodePort (8080 -> 30080) |
| 130 | +- Traffic flow: Client -> NodeIP:30080 -> Service -> Pod:8080 |
| 131 | +- Resources per Pod: |
| 132 | + - requests: 100m CPU, 128Mi RAM |
| 133 | + - limits: 200m CPU, 256Mi RAM |
| 134 | + |
| 135 | +### Manifest Files |
| 136 | + |
| 137 | +- deployment.yaml |
| 138 | + - replicas: 3 |
| 139 | + - RollingUpdate strategy (maxSurge: 1, maxUnavailable: 0) |
| 140 | + - livenessProbe/readinessProbe via TCP 8080 |
| 141 | + - resources.requests/limits set for predictable scheduling |
| 142 | +- service.yaml |
| 143 | + - type: NodePort |
| 144 | + - selector app: python-info-service |
| 145 | + - port: 8080, targetPort: 8080, nodePort: 30080 |
| 146 | + |
| 147 | +### Deployment Evidence |
| 148 | +```sh |
| 149 | +kubectl get all |
| 150 | +kubectl get all |
| 151 | +NAME READY STATUS RESTARTS AGE |
| 152 | +pod/python-info-service-85d87fc579-c8z74 1/1 Running 0 5m34s |
| 153 | +pod/python-info-service-85d87fc579-nqxrh 1/1 Running 0 5m34s |
| 154 | +pod/python-info-service-85d87fc579-rjbx8 1/1 Running 0 21m |
| 155 | +pod/python-info-service-85d87fc579-sxbp5 1/1 Running 0 21m |
| 156 | +pod/python-info-service-85d87fc579-zq7gd 1/1 Running 0 21m |
| 157 | + |
| 158 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 159 | +service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h |
| 160 | +service/python-info-service NodePort 10.104.130.60 <none> 8080:30080/TCP 14m |
| 161 | + |
| 162 | +NAME READY UP-TO-DATE AVAILABLE AGE |
| 163 | +deployment.apps/python-info-service 5/5 5 5 21m |
| 164 | + |
| 165 | +NAME DESIRED CURRENT READY AGE |
| 166 | +replicaset.apps/python-info-service-85d87fc579 5 5 5 21m |
| 167 | +``` |
| 168 | + |
| 169 | +```sh |
| 170 | +kubectl get pods,svc -o wide |
| 171 | +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES |
| 172 | +pod/python-info-service-85d87fc579-c8z74 1/1 Running 0 5m56s 10.244.0.8 minikube <none> <none> |
| 173 | +pod/python-info-service-85d87fc579-nqxrh 1/1 Running 0 5m56s 10.244.0.7 minikube <none> <none> |
| 174 | +pod/python-info-service-85d87fc579-rjbx8 1/1 Running 0 22m 10.244.0.4 minikube <none> <none> |
| 175 | +pod/python-info-service-85d87fc579-sxbp5 1/1 Running 0 22m 10.244.0.6 minikube <none> <none> |
| 176 | +pod/python-info-service-85d87fc579-zq7gd 1/1 Running 0 22m 10.244.0.5 minikube <none> <none> |
| 177 | + |
| 178 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR |
| 179 | +service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23h <none> |
| 180 | +service/python-info-service NodePort 10.104.130.60 <none> 8080:30080/TCP 14m app=python-info-service |
| 181 | +``` |
| 182 | +```sh |
| 183 | +kubectl describe deployment python-info-service |
| 184 | +Name: python-info-service |
| 185 | +Namespace: default |
| 186 | +CreationTimestamp: Thu, 26 Mar 2026 21:33:30 +0300 |
| 187 | +Labels: app=python-info-service |
| 188 | +Annotations: deployment.kubernetes.io/revision: 1 |
| 189 | +Selector: app=python-info-service |
| 190 | +Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable |
| 191 | +StrategyType: RollingUpdate |
| 192 | +MinReadySeconds: 0 |
| 193 | +RollingUpdateStrategy: 0 max unavailable, 1 max surge |
| 194 | +Pod Template: |
| 195 | + Labels: app=python-info-service |
| 196 | + Containers: |
| 197 | + python-info-service: |
| 198 | + Image: projacktor/python-info-service:latest |
| 199 | + Port: 8080/TCP |
| 200 | + Host Port: 0/TCP |
| 201 | + Limits: |
| 202 | + cpu: 200m |
| 203 | + memory: 256Mi |
| 204 | + Requests: |
| 205 | + cpu: 100m |
| 206 | + memory: 128Mi |
| 207 | + Liveness: tcp-socket :8080 delay=15s timeout=2s period=10s #success=1 #failure=3 |
| 208 | + Readiness: tcp-socket :8080 delay=5s timeout=2s period=5s #success=1 #failure=3 |
| 209 | + Environment: <none> |
| 210 | + Mounts: <none> |
| 211 | + Volumes: <none> |
| 212 | + Node-Selectors: <none> |
| 213 | + Tolerations: <none> |
| 214 | +Conditions: |
| 215 | + Type Status Reason |
| 216 | + ---- ------ ------ |
| 217 | + Progressing True NewReplicaSetAvailable |
| 218 | + Available True MinimumReplicasAvailable |
| 219 | +OldReplicaSets: <none> |
| 220 | +NewReplicaSet: python-info-service-85d87fc579 (5/5 replicas created) |
| 221 | +Events: |
| 222 | + Type Reason Age From Message |
| 223 | + ---- ------ ---- ---- ------- |
| 224 | + Normal ScalingReplicaSet 22m deployment-controller Scaled up replica set python-info-service-85d87fc579 from 0 to 3 |
| 225 | + Normal ScalingReplicaSet 6m26s deployment-controller Scaled up replica set python-info-service-85d87fc579 from 3 to 5 |
| 226 | +``` |
| 227 | + |
| 228 | +#### App accessibility check |
| 229 | +```sh |
| 230 | +curl http://192.168.49.2:30080/ |
| 231 | +{"service":{"name":"devops-info-service","version":"1.0.0","description":"DevOps course info service","framework":"FastAPI"},"system":{"hostname":"python-info-service-85d87fc579-nqxrh","platform":"Linux","platform_version":"#37~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Nov 20 10:25:38 UTC 2","architecture":"x86_64","cpu_count":16,"python_version":"3.12.13"},"runtime":{"uptime_seconds":428,"uptime_human":"0 hours, 7 minutes","current_time":"2026-03-26T18:56:57.746777","timezone":"UTC"},"request":{"client_ip":"10.244.0.1","user_agent":"curl/8.5.0","method":"GET","path":"/"},"endpoints":[{"path":"/","method":"GET","description":"Service information"},{"path":"/health","method":"GET","description":"Health check"}]}⏎ |
| 232 | +``` |
| 233 | + |
| 234 | + |
| 235 | +### Operations Performed |
| 236 | + |
| 237 | +#### Deploy |
| 238 | +- ```kubectl apply -f labs/k8s/deployment.yaml``` |
| 239 | +- ```kubectl apply -f labs/k8s/service.yaml``` |
| 240 | + |
| 241 | +#### Scale |
| 242 | +- ```kubectl scale deployment/python-info-service --replicas=5``` |
| 243 | +- ```kubectl rollout status deployment/python-info-service``` |
| 244 | + |
| 245 | +#### Rolling update |
| 246 | +- Performed by changing runtime config: |
| 247 | + - ```kubectl set env deployment/python-info-service RELEASE=lab09-update``` |
| 248 | +- Verified: |
| 249 | + - ```kubectl rollout status deployment/python-info-service``` |
| 250 | + - ```kubectl rollout history deployment/python-info-service``` |
| 251 | + |
| 252 | +#### Rollback |
| 253 | +- ```kubectl rollout undo deployment/python-info-service``` |
| 254 | +- Verified: |
| 255 | + - ```kubectl rollout status deployment/python-info-service``` |
| 256 | + - ```kubectl rollout history deployment/python-info-service``` |
| 257 | + |
| 258 | +### Production Considerations |
| 259 | + |
| 260 | +- Health checks: |
| 261 | + - readiness probe prevents routing traffic to not-ready Pods |
| 262 | + - liveness probe restarts hung container |
| 263 | +- Resource limits: |
| 264 | + - protect node from noisy-neighbor effect |
| 265 | + - guarantee minimum CPU/memory via requests |
| 266 | +- Production improvements: |
| 267 | + - use fixed image tags (not latest) |
| 268 | + - add startupProbe for slow starts |
| 269 | + - add HPA + metrics-server |
| 270 | + - central logging/monitoring (Prometheus + Grafana, Loki/ELK) |
| 271 | + |
| 272 | +### Challenges & Solutions |
| 273 | + |
| 274 | +- Issue: Service not found in minikube |
| 275 | + - Cause: wrong kubectl context/namespace |
| 276 | + - Fix: kubectl config use-context minikube, then re-apply manifests |
| 277 | +- Issue: Deployment initially showed 0/3 available |
| 278 | + - Cause: probes and startup delay |
| 279 | + - Fix: waited for readiness and checked with kubectl rollout status |
| 280 | +- Learning: |
| 281 | + - Kubernetes is declarative; actual state converges asynchronously |
| 282 | + - Labels/selectors are critical for Service-to-Pod routing |
0 commit comments