Skip to content

Commit a437ffb

Browse files
committed
Enhance Kubernetes deployment with Istio integration, add DNS and TLS configurations, and update Dockerfile for Gunicorn support
1 parent b804034 commit a437ffb

File tree

16 files changed

+199
-34
lines changed

16 files changed

+199
-34
lines changed

Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ RUN apt-get update \
1616
# Install Python dependencies
1717
COPY pyproject.toml poetry.lock* requirements.txt* ./
1818
RUN pip install --upgrade pip \
19-
&& pip install -r requirements.txt
19+
&& pip install -r requirements.txt \
20+
&& pip install gunicorn
2021

2122
# Copy project
2223
COPY . .
2324

2425
# Expose port for Flask app
2526
EXPOSE 5000
2627

27-
# Default command to run Flask app
28-
CMD ["python", "-m", "flask_app.app"]
28+
# Default command to run Flask app with Gunicorn
29+
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "flask_app.app:app"]

flask_app/app.py

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -250,39 +250,41 @@ def get_categories() -> dict[str, list[dict]]:
250250
def utility_processor():
251251
def get_card_type(category, demo):
252252
# Add a check for the existence of 'id' and its type
253-
demo_id = demo.get('id')
254-
if category == 'visualizations' or (isinstance(demo_id, str) and demo_id.startswith('viz.')):
255-
return 'visualization-card'
256-
if 'leetcode' in category:
257-
return 'leetcode-card'
258-
return 'algorithm-card'
253+
demo_id = demo.get("id")
254+
if category == "visualizations" or (
255+
isinstance(demo_id, str) and demo_id.startswith("viz.")
256+
):
257+
return "visualization-card"
258+
if "leetcode" in category:
259+
return "leetcode-card"
260+
return "algorithm-card"
259261

260262
def get_demo_status(demo):
261263
# Placeholder logic for demo status
262-
if 'TODO' in demo.get('title', '').upper():
263-
return 'todo'
264-
if demo.get('id') and hash(demo['id']) % 5 == 0:
265-
return 'partial'
266-
return 'complete'
264+
if "TODO" in demo.get("title", "").upper():
265+
return "todo"
266+
if demo.get("id") and hash(demo["id"]) % 5 == 0:
267+
return "partial"
268+
return "complete"
267269

268270
def get_progress_percentage(demo):
269271
status = get_demo_status(demo)
270-
if status == 'complete':
272+
if status == "complete":
271273
return 100
272-
if status == 'partial':
274+
if status == "partial":
273275
return 50
274276
return 0
275277

276278
def get_progress_text(demo):
277279
status = get_demo_status(demo)
278-
if status == 'complete':
280+
if status == "complete":
279281
return "Completed"
280-
if status == 'partial':
282+
if status == "partial":
281283
return "In Progress"
282284
return "Not Started"
283-
285+
284286
def get_category_progress(category, demos):
285-
completed = sum(1 for d in demos if get_demo_status(d) == 'complete')
287+
completed = sum(1 for d in demos if get_demo_status(d) == "complete")
286288
return int((completed / len(demos)) * 100) if demos else 0
287289

288290
return dict(
@@ -298,11 +300,10 @@ def get_category_progress(category, demos):
298300
def index():
299301
# Build categories with additional top-level visualization entries for the dashboard
300302
categories = {k: v[:] for k, v in get_categories().items()}
301-
303+
302304
# Add LeetCode problems to categories
303305
from src.interview_workbook.leetcode._registry import get_all as get_all_leetcode
304-
from src.interview_workbook.leetcode._types import Category
305-
306+
306307
leetcode_problems = get_all_leetcode()
307308
for problem in leetcode_problems:
308309
category_key = f"leetcode/{problem['category'].value}"
@@ -311,13 +312,55 @@ def index():
311312
# Add visualizations
312313
categories.setdefault("visualizations", [])
313314
visualizations = [
314-
{"id": "viz.sorting", "title": "Sorting Visualizations", "category": "visualizations", "module": "viz.sorting", "path": "flask_app/visualizations/sorting_viz.py"},
315-
{"id": "viz.graph", "title": "Graph Traversal (BFS/DFS)", "category": "visualizations", "module": "viz.graph", "path": "flask_app/visualizations/graph_viz.py"},
316-
{"id": "viz.path", "title": "Pathfinding (A*/Dijkstra/BFS/GBFS)", "category": "visualizations", "module": "viz.path", "path": "flask_app/visualizations/path_viz.py"},
317-
{"id": "viz.arrays", "title": "Array Techniques", "category": "visualizations", "module": "viz.arrays", "path": "flask_app/visualizations/array_viz.py"},
318-
{"id": "viz.mst", "title": "Minimum Spanning Tree (Kruskal/Prim)", "category": "visualizations", "module": "viz.mst", "path": "flask_app/visualizations/mst_viz.py"},
319-
{"id": "viz.topo", "title": "Topological Sort (Kahn)", "category": "visualizations", "module": "viz.topo", "path": "flask_app/visualizations/topo_viz.py"},
320-
{"id": "viz.nn", "title": "Neural Network (MLP Classifier)", "category": "visualizations", "module": "viz.nn", "path": "flask_app/visualizations/nn_viz.py"},
315+
{
316+
"id": "viz.sorting",
317+
"title": "Sorting Visualizations",
318+
"category": "visualizations",
319+
"module": "viz.sorting",
320+
"path": "flask_app/visualizations/sorting_viz.py",
321+
},
322+
{
323+
"id": "viz.graph",
324+
"title": "Graph Traversal (BFS/DFS)",
325+
"category": "visualizations",
326+
"module": "viz.graph",
327+
"path": "flask_app/visualizations/graph_viz.py",
328+
},
329+
{
330+
"id": "viz.path",
331+
"title": "Pathfinding (A*/Dijkstra/BFS/GBFS)",
332+
"category": "visualizations",
333+
"module": "viz.path",
334+
"path": "flask_app/visualizations/path_viz.py",
335+
},
336+
{
337+
"id": "viz.arrays",
338+
"title": "Array Techniques",
339+
"category": "visualizations",
340+
"module": "viz.arrays",
341+
"path": "flask_app/visualizations/array_viz.py",
342+
},
343+
{
344+
"id": "viz.mst",
345+
"title": "Minimum Spanning Tree (Kruskal/Prim)",
346+
"category": "visualizations",
347+
"module": "viz.mst",
348+
"path": "flask_app/visualizations/mst_viz.py",
349+
},
350+
{
351+
"id": "viz.topo",
352+
"title": "Topological Sort (Kahn)",
353+
"category": "visualizations",
354+
"module": "viz.topo",
355+
"path": "flask_app/visualizations/topo_viz.py",
356+
},
357+
{
358+
"id": "viz.nn",
359+
"title": "Neural Network (MLP Classifier)",
360+
"category": "visualizations",
361+
"module": "viz.nn",
362+
"path": "flask_app/visualizations/nn_viz.py",
363+
},
321364
]
322365
categories["visualizations"].extend(visualizations)
323366

k8s/base/auth.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: security.istio.io/v1beta1
2+
kind: AuthorizationPolicy
3+
metadata:
4+
name: python-dsa-policy
5+
namespace: prod
6+
spec:
7+
action: ALLOW
8+
rules:
9+
- to:
10+
- operation:
11+
methods: ["*"]

k8s/base/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ spec:
1313
metadata:
1414
labels:
1515
app: python-dsa
16+
istio-injection: enabled
17+
annotations:
18+
sidecar.istio.io/inject: "true"
1619
spec:
1720
containers:
1821
- name: python-dsa

k8s/base/dns.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: dns.cnrm.cloud.google.com/v1beta1
2+
kind: DNSRecordSet
3+
metadata:
4+
name: hugecat-net-dsa-a
5+
namespace: config-control
6+
annotations:
7+
cnrm.cloud.google.com/management-conflict-prevention-policy: none
8+
cnrm.cloud.google.com/project-id: kame-457417
9+
cnrm.cloud.google.com/state-into-spec: absent
10+
spec:
11+
name: "dsa.hugecat.net."
12+
type: "A"
13+
ttl: 300
14+
managedZoneRef:
15+
name: hugecat-net
16+
rrdatas:
17+
- "34.31.128.59"

k8s/base/istio-certificate.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: cert-manager.io/v1
2+
kind: Certificate
3+
metadata:
4+
name: python-dsa-tls-cert
5+
labels:
6+
app: python-dsa
7+
spec:
8+
secretName: python-dsa-tls-cert
9+
issuerRef:
10+
name: letsencrypt-prod
11+
kind: ClusterIssuer
12+
dnsNames:
13+
- dsa.hugecat.net

k8s/base/istio-gateway.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: networking.istio.io/v1beta1
2+
kind: Gateway
3+
metadata:
4+
name: python-dsa-gateway
5+
namespace: prod
6+
spec:
7+
selector:
8+
istio: ingressgateway
9+
servers:
10+
- port:
11+
number: 443
12+
name: https
13+
protocol: HTTPS
14+
hosts:
15+
- "dsa.hugecat.net"
16+
tls:
17+
mode: SIMPLE
18+
credentialName: dsa-tls-cert
19+
- port:
20+
number: 80
21+
name: http
22+
protocol: HTTP
23+
hosts:
24+
- "dsa.hugecat.net"

k8s/base/istio-virtualservice.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: networking.istio.io/v1beta1
2+
kind: VirtualService
3+
metadata:
4+
name: python-dsa-virtualservice
5+
namespace: prod
6+
spec:
7+
hosts:
8+
- "dsa.hugecat.net"
9+
gateways:
10+
- python-dsa-gateway
11+
http:
12+
- match:
13+
- uri:
14+
prefix: /
15+
route:
16+
- destination:
17+
host: python-dsa
18+
port:
19+
number: 80

k8s/base/kustomization.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,11 @@ kind: Kustomization
33

44
resources:
55
- deployment.yaml
6+
- dns.yaml
67
- service.yaml
8+
- istio-gateway.yaml
9+
- istio-virtualservice.yaml
10+
- istio-certificate.yaml
11+
- auth.yaml
12+
- serviceaccount.yaml
13+

k8s/base/service.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ spec:
1111
- protocol: TCP
1212
port: 80
1313
targetPort: 5000
14+
15+
type: ClusterIP
16+

0 commit comments

Comments
 (0)