Spaces:
Paused
Paused
Commit
Β·
f870b34
1
Parent(s):
2d2ce73
feat(deploy): add kubernetes manifest
Browse files- .pre-commit-config.yaml +1 -0
- Makefile +5 -1
- deploy/kubernetes.yaml +153 -0
- scripts/deploy-k8s.sh +134 -0
.pre-commit-config.yaml
CHANGED
@@ -3,6 +3,7 @@ repos:
|
|
3 |
rev: v2.3.0
|
4 |
hooks:
|
5 |
- id: check-yaml
|
|
|
6 |
- id: end-of-file-fixer
|
7 |
- id: trailing-whitespace
|
8 |
|
|
|
3 |
rev: v2.3.0
|
4 |
hooks:
|
5 |
- id: check-yaml
|
6 |
+
args: ['--allow-multiple-documents']
|
7 |
- id: end-of-file-fixer
|
8 |
- id: trailing-whitespace
|
9 |
|
Makefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
.PHONY: help venv install run test lint format clean setup-secrets
|
2 |
|
3 |
PYTHON=python
|
4 |
PIP=pip
|
@@ -15,6 +15,7 @@ help:
|
|
15 |
@echo " lint Run pre-commit hooks (includes black, yaml, gitleaks)"
|
16 |
@echo " format Format code with black"
|
17 |
@echo " setup-secrets Copy and edit secrets template for local dev"
|
|
|
18 |
@echo " clean Remove Python cache and virtual environment"
|
19 |
|
20 |
venv:
|
@@ -41,6 +42,9 @@ setup-secrets:
|
|
41 |
cp -n tests/secrets/nebius_secrets.py.template tests/secrets/cred.py; \
|
42 |
echo "Edit tests/secrets/cred.py to add your own API credentials."
|
43 |
|
|
|
|
|
|
|
44 |
clean:
|
45 |
rm -rf $(VENV) __pycache__ */__pycache__ .pytest_cache .mypy_cache .coverage .hypothesis
|
46 |
find . -type f -name '*.pyc' -delete
|
|
|
1 |
+
.PHONY: help venv install run test lint format clean setup-secrets deploy-k8s
|
2 |
|
3 |
PYTHON=python
|
4 |
PIP=pip
|
|
|
15 |
@echo " lint Run pre-commit hooks (includes black, yaml, gitleaks)"
|
16 |
@echo " format Format code with black"
|
17 |
@echo " setup-secrets Copy and edit secrets template for local dev"
|
18 |
+
@echo " deploy-k8s Deploy application to Kubernetes"
|
19 |
@echo " clean Remove Python cache and virtual environment"
|
20 |
|
21 |
venv:
|
|
|
42 |
cp -n tests/secrets/nebius_secrets.py.template tests/secrets/cred.py; \
|
43 |
echo "Edit tests/secrets/cred.py to add your own API credentials."
|
44 |
|
45 |
+
deploy-k8s:
|
46 |
+
./scripts/deploy-k8s.sh
|
47 |
+
|
48 |
clean:
|
49 |
rm -rf $(VENV) __pycache__ */__pycache__ .pytest_cache .mypy_cache .coverage .hypothesis
|
50 |
find . -type f -name '*.pyc' -delete
|
deploy/kubernetes.yaml
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Kubernetes manifest for Yuga Planner
|
2 |
+
# Note: This file contains environment variable placeholders that need to be substituted before deployment
|
3 |
+
# Use the provided deploy script or substitute manually: envsubst < kubernetes.yaml | kubectl apply -f -
|
4 |
+
---
|
5 |
+
apiVersion: v1
|
6 |
+
kind: Secret
|
7 |
+
metadata:
|
8 |
+
name: yuga-planner-secrets
|
9 |
+
labels:
|
10 |
+
app: yuga-planner
|
11 |
+
type: Opaque
|
12 |
+
stringData:
|
13 |
+
# These values will be populated from environment variables during deployment
|
14 |
+
NEBIUS_API_KEY: "${NEBIUS_API_KEY}"
|
15 |
+
NEBIUS_MODEL: "${NEBIUS_MODEL}"
|
16 |
+
MODAL_TOKEN_ID: "${MODAL_TOKEN_ID}"
|
17 |
+
MODAL_TOKEN_SECRET: "${MODAL_TOKEN_SECRET}"
|
18 |
+
HF_MODEL: "${HF_MODEL}"
|
19 |
+
HF_TOKEN: "${HF_TOKEN}"
|
20 |
+
|
21 |
+
---
|
22 |
+
apiVersion: v1
|
23 |
+
kind: ConfigMap
|
24 |
+
metadata:
|
25 |
+
name: yuga-planner-config
|
26 |
+
labels:
|
27 |
+
app: yuga-planner
|
28 |
+
data:
|
29 |
+
JAVA_HOME: "/usr/lib/jvm/temurin-21-jdk-amd64"
|
30 |
+
PATH: "/usr/lib/jvm/temurin-21-jdk-amd64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
31 |
+
|
32 |
+
---
|
33 |
+
apiVersion: apps/v1
|
34 |
+
kind: Deployment
|
35 |
+
metadata:
|
36 |
+
name: yuga-planner
|
37 |
+
labels:
|
38 |
+
app: yuga-planner
|
39 |
+
spec:
|
40 |
+
replicas: 1
|
41 |
+
selector:
|
42 |
+
matchLabels:
|
43 |
+
app: yuga-planner
|
44 |
+
template:
|
45 |
+
metadata:
|
46 |
+
labels:
|
47 |
+
app: yuga-planner
|
48 |
+
spec:
|
49 |
+
containers:
|
50 |
+
- name: yuga-planner
|
51 |
+
image: ghcr.io/blackopsrepl/yuga-planner-test:latest
|
52 |
+
imagePullPolicy: Always
|
53 |
+
ports:
|
54 |
+
- containerPort: 7860
|
55 |
+
name: http
|
56 |
+
protocol: TCP
|
57 |
+
env:
|
58 |
+
- name: JAVA_HOME
|
59 |
+
valueFrom:
|
60 |
+
configMapKeyRef:
|
61 |
+
name: yuga-planner-config
|
62 |
+
key: JAVA_HOME
|
63 |
+
- name: PATH
|
64 |
+
valueFrom:
|
65 |
+
configMapKeyRef:
|
66 |
+
name: yuga-planner-config
|
67 |
+
key: PATH
|
68 |
+
- name: NEBIUS_API_KEY
|
69 |
+
valueFrom:
|
70 |
+
secretKeyRef:
|
71 |
+
name: yuga-planner-secrets
|
72 |
+
key: NEBIUS_API_KEY
|
73 |
+
- name: NEBIUS_MODEL
|
74 |
+
valueFrom:
|
75 |
+
secretKeyRef:
|
76 |
+
name: yuga-planner-secrets
|
77 |
+
key: NEBIUS_MODEL
|
78 |
+
- name: MODAL_TOKEN_ID
|
79 |
+
valueFrom:
|
80 |
+
secretKeyRef:
|
81 |
+
name: yuga-planner-secrets
|
82 |
+
key: MODAL_TOKEN_ID
|
83 |
+
- name: MODAL_TOKEN_SECRET
|
84 |
+
valueFrom:
|
85 |
+
secretKeyRef:
|
86 |
+
name: yuga-planner-secrets
|
87 |
+
key: MODAL_TOKEN_SECRET
|
88 |
+
- name: HF_MODEL
|
89 |
+
valueFrom:
|
90 |
+
secretKeyRef:
|
91 |
+
name: yuga-planner-secrets
|
92 |
+
key: HF_MODEL
|
93 |
+
- name: HF_TOKEN
|
94 |
+
valueFrom:
|
95 |
+
secretKeyRef:
|
96 |
+
name: yuga-planner-secrets
|
97 |
+
key: HF_TOKEN
|
98 |
+
command: ["python", "src/app.py"]
|
99 |
+
args:
|
100 |
+
- "--server-name"
|
101 |
+
- "0.0.0.0"
|
102 |
+
- "--server-port"
|
103 |
+
- "7860"
|
104 |
+
resources:
|
105 |
+
requests:
|
106 |
+
memory: "512Mi"
|
107 |
+
cpu: "250m"
|
108 |
+
limits:
|
109 |
+
memory: "2Gi"
|
110 |
+
cpu: "1000m"
|
111 |
+
livenessProbe:
|
112 |
+
httpGet:
|
113 |
+
path: /
|
114 |
+
port: 7860
|
115 |
+
initialDelaySeconds: 30
|
116 |
+
periodSeconds: 10
|
117 |
+
timeoutSeconds: 5
|
118 |
+
failureThreshold: 3
|
119 |
+
readinessProbe:
|
120 |
+
httpGet:
|
121 |
+
path: /
|
122 |
+
port: 7860
|
123 |
+
initialDelaySeconds: 10
|
124 |
+
periodSeconds: 5
|
125 |
+
timeoutSeconds: 3
|
126 |
+
failureThreshold: 3
|
127 |
+
securityContext:
|
128 |
+
runAsNonRoot: true
|
129 |
+
runAsUser: 1000
|
130 |
+
runAsGroup: 1000
|
131 |
+
allowPrivilegeEscalation: false
|
132 |
+
readOnlyRootFilesystem: false
|
133 |
+
capabilities:
|
134 |
+
drop:
|
135 |
+
- ALL
|
136 |
+
|
137 |
+
---
|
138 |
+
apiVersion: v1
|
139 |
+
kind: Service
|
140 |
+
metadata:
|
141 |
+
name: yuga-planner-service
|
142 |
+
labels:
|
143 |
+
app: yuga-planner
|
144 |
+
spec:
|
145 |
+
type: NodePort
|
146 |
+
ports:
|
147 |
+
- port: 80
|
148 |
+
targetPort: 7860
|
149 |
+
nodePort: 30860
|
150 |
+
protocol: TCP
|
151 |
+
name: http
|
152 |
+
selector:
|
153 |
+
app: yuga-planner
|
scripts/deploy-k8s.sh
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
set -e
|
3 |
+
|
4 |
+
# Yuga Planner Kubernetes Deployment Script
|
5 |
+
# This script loads credentials from environment variables or creds.py and deploys to Kubernetes
|
6 |
+
|
7 |
+
echo "π Deploying Yuga Planner to Kubernetes..."
|
8 |
+
|
9 |
+
# Check if we're in the correct directory (project root)
|
10 |
+
if [ ! -f "deploy/kubernetes.yaml" ]; then
|
11 |
+
echo "β Error: kubernetes.yaml not found. Please run this script from the project root."
|
12 |
+
exit 1
|
13 |
+
fi
|
14 |
+
|
15 |
+
# Function to load credentials from creds.py if environment variables are not set
|
16 |
+
load_credentials() {
|
17 |
+
local creds_file="tests/secrets/creds.py"
|
18 |
+
|
19 |
+
if [ -f "$creds_file" ]; then
|
20 |
+
echo "π Loading credentials from $creds_file..."
|
21 |
+
|
22 |
+
# Extract credentials from creds.py if environment variables are not set
|
23 |
+
if [ -z "$NEBIUS_API_KEY" ]; then
|
24 |
+
export NEBIUS_API_KEY=$(python3 -c "
|
25 |
+
import sys
|
26 |
+
sys.path.append('tests/secrets')
|
27 |
+
import creds
|
28 |
+
print(creds.NEBIUS_API_KEY)
|
29 |
+
" 2>/dev/null || echo "")
|
30 |
+
fi
|
31 |
+
|
32 |
+
if [ -z "$NEBIUS_MODEL" ]; then
|
33 |
+
export NEBIUS_MODEL=$(python3 -c "
|
34 |
+
import sys
|
35 |
+
sys.path.append('tests/secrets')
|
36 |
+
import creds
|
37 |
+
print(creds.NEBIUS_MODEL)
|
38 |
+
" 2>/dev/null || echo "")
|
39 |
+
fi
|
40 |
+
|
41 |
+
if [ -z "$MODAL_TOKEN_ID" ]; then
|
42 |
+
export MODAL_TOKEN_ID=$(python3 -c "
|
43 |
+
import sys
|
44 |
+
sys.path.append('tests/secrets')
|
45 |
+
import creds
|
46 |
+
print(creds.MODAL_TOKEN_ID)
|
47 |
+
" 2>/dev/null || echo "")
|
48 |
+
fi
|
49 |
+
|
50 |
+
if [ -z "$MODAL_TOKEN_SECRET" ]; then
|
51 |
+
export MODAL_TOKEN_SECRET=$(python3 -c "
|
52 |
+
import sys
|
53 |
+
sys.path.append('tests/secrets')
|
54 |
+
import creds
|
55 |
+
print(creds.MODAL_TOKEN_SECRET)
|
56 |
+
" 2>/dev/null || echo "")
|
57 |
+
fi
|
58 |
+
|
59 |
+
if [ -z "$HF_MODEL" ]; then
|
60 |
+
export HF_MODEL=$(python3 -c "
|
61 |
+
import sys
|
62 |
+
sys.path.append('tests/secrets')
|
63 |
+
import creds
|
64 |
+
print(creds.HF_MODEL)
|
65 |
+
" 2>/dev/null || echo "")
|
66 |
+
fi
|
67 |
+
|
68 |
+
if [ -z "$HF_TOKEN" ]; then
|
69 |
+
export HF_TOKEN=$(python3 -c "
|
70 |
+
import sys
|
71 |
+
sys.path.append('tests/secrets')
|
72 |
+
import creds
|
73 |
+
print(creds.HF_TOKEN)
|
74 |
+
" 2>/dev/null || echo "")
|
75 |
+
fi
|
76 |
+
else
|
77 |
+
echo "β οΈ Warning: $creds_file not found"
|
78 |
+
fi
|
79 |
+
}
|
80 |
+
|
81 |
+
# Check if credentials are available in environment variables
|
82 |
+
echo "π Checking for credentials..."
|
83 |
+
|
84 |
+
missing_vars=()
|
85 |
+
required_vars=("NEBIUS_API_KEY" "NEBIUS_MODEL" "MODAL_TOKEN_ID" "MODAL_TOKEN_SECRET" "HF_MODEL" "HF_TOKEN")
|
86 |
+
|
87 |
+
for var in "${required_vars[@]}"; do
|
88 |
+
if [ -z "${!var}" ]; then
|
89 |
+
missing_vars+=("$var")
|
90 |
+
fi
|
91 |
+
done
|
92 |
+
|
93 |
+
if [ ${#missing_vars[@]} -gt 0 ]; then
|
94 |
+
echo "π Missing environment variables: ${missing_vars[*]}"
|
95 |
+
echo "π Attempting to load from creds.py..."
|
96 |
+
load_credentials
|
97 |
+
|
98 |
+
# Check again after loading from creds.py
|
99 |
+
missing_vars=()
|
100 |
+
for var in "${required_vars[@]}"; do
|
101 |
+
if [ -z "${!var}" ]; then
|
102 |
+
missing_vars+=("$var")
|
103 |
+
fi
|
104 |
+
done
|
105 |
+
|
106 |
+
if [ ${#missing_vars[@]} -gt 0 ]; then
|
107 |
+
echo "β Error: The following required environment variables are not set: ${missing_vars[*]}"
|
108 |
+
echo "π‘ Please set them in your environment or ensure tests/secrets/creds.py exists with the required values."
|
109 |
+
exit 1
|
110 |
+
fi
|
111 |
+
fi
|
112 |
+
|
113 |
+
echo "β
All credentials found"
|
114 |
+
|
115 |
+
# Check if envsubst is available
|
116 |
+
if ! command -v envsubst &> /dev/null; then
|
117 |
+
echo "β Error: envsubst is required but not installed. Please install gettext-base package."
|
118 |
+
exit 1
|
119 |
+
fi
|
120 |
+
|
121 |
+
# Check if kubectl is available
|
122 |
+
if ! command -v kubectl &> /dev/null; then
|
123 |
+
echo "β Error: kubectl is required but not installed."
|
124 |
+
exit 1
|
125 |
+
fi
|
126 |
+
|
127 |
+
# Substitute environment variables and apply to Kubernetes
|
128 |
+
echo "π§ Substituting environment variables and deploying..."
|
129 |
+
envsubst < deploy/kubernetes.yaml | kubectl apply -f -
|
130 |
+
|
131 |
+
echo "β
Deployment complete!"
|
132 |
+
echo "π Access the application at: http://<node-ip>:30860"
|
133 |
+
echo "π Check deployment status: kubectl get pods -l app=yuga-planner"
|
134 |
+
echo "π View logs: kubectl logs -l app=yuga-planner -f"
|