aissemble-inference-deploy 1.5.0rc3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aissemble_inference_deploy/__init__.py +38 -0
- aissemble_inference_deploy/cli.py +278 -0
- aissemble_inference_deploy/config.py +182 -0
- aissemble_inference_deploy/generators/__init__.py +36 -0
- aissemble_inference_deploy/generators/base.py +239 -0
- aissemble_inference_deploy/generators/docker.py +307 -0
- aissemble_inference_deploy/generators/kserve.py +89 -0
- aissemble_inference_deploy/generators/kubernetes.py +119 -0
- aissemble_inference_deploy/generators/local.py +162 -0
- aissemble_inference_deploy/registry.py +158 -0
- aissemble_inference_deploy/templates/docker/.dockerignore.j2 +47 -0
- aissemble_inference_deploy/templates/docker/Dockerfile.j2 +59 -0
- aissemble_inference_deploy/templates/docker/README.md.j2 +163 -0
- aissemble_inference_deploy/templates/docker/docker-compose.yml.j2 +22 -0
- aissemble_inference_deploy/templates/kserve/README.md.j2 +278 -0
- aissemble_inference_deploy/templates/kserve/inference-service.yaml.j2 +14 -0
- aissemble_inference_deploy/templates/kserve/serving-runtime.yaml.j2 +35 -0
- aissemble_inference_deploy/templates/kubernetes/README.md.j2 +164 -0
- aissemble_inference_deploy/templates/kubernetes/deployment.yaml.j2 +50 -0
- aissemble_inference_deploy/templates/kubernetes/kustomization.yaml.j2 +11 -0
- aissemble_inference_deploy/templates/kubernetes/overlays/dev/kustomization.yaml.j2 +52 -0
- aissemble_inference_deploy/templates/kubernetes/overlays/prod/kustomization.yaml.j2 +36 -0
- aissemble_inference_deploy/templates/kubernetes/service.yaml.j2 +19 -0
- aissemble_inference_deploy/templates/local/run-mlserver.sh.j2 +47 -0
- aissemble_inference_deploy-1.5.0rc3.dist-info/METADATA +248 -0
- aissemble_inference_deploy-1.5.0rc3.dist-info/RECORD +29 -0
- aissemble_inference_deploy-1.5.0rc3.dist-info/WHEEL +4 -0
- aissemble_inference_deploy-1.5.0rc3.dist-info/entry_points.txt +8 -0
- aissemble_inference_deploy-1.5.0rc3.dist-info/licenses/LICENSE.txt +201 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by aissemble-inference-deploy
|
|
2
|
+
# Docker Compose configuration for local MLServer deployment
|
|
3
|
+
|
|
4
|
+
services:
|
|
5
|
+
mlserver:
|
|
6
|
+
image: {{ image_name }}:latest
|
|
7
|
+
build:
|
|
8
|
+
context: ../.. # Project root (where models/ and pyproject.toml are)
|
|
9
|
+
dockerfile: deploy/docker/Dockerfile
|
|
10
|
+
ports:
|
|
11
|
+
- "{{ http_port }}:8080" # HTTP
|
|
12
|
+
- "{{ grpc_port }}:8081" # gRPC
|
|
13
|
+
environment:
|
|
14
|
+
- MLSERVER_HOST=0.0.0.0 # Bind to all interfaces (required for Docker)
|
|
15
|
+
- MLSERVER_HTTP_PORT=8080
|
|
16
|
+
- MLSERVER_GRPC_PORT=8081
|
|
17
|
+
{% if models %}
|
|
18
|
+
# Models served:
|
|
19
|
+
{% for model in models %}
|
|
20
|
+
# - {{ model.name }}
|
|
21
|
+
{% endfor %}
|
|
22
|
+
{% endif %}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# KServe Deployment
|
|
2
|
+
|
|
3
|
+
This directory contains KServe manifests for deploying MLServer models using the
|
|
4
|
+
ServingRuntime + InferenceService pattern for DRY configuration.
|
|
5
|
+
|
|
6
|
+
## Prerequisites
|
|
7
|
+
|
|
8
|
+
### 1. Kubernetes Cluster
|
|
9
|
+
|
|
10
|
+
A Kubernetes cluster (Rancher Desktop, kind, minikube, EKS, GKE, etc.)
|
|
11
|
+
|
|
12
|
+
### 2. cert-manager
|
|
13
|
+
|
|
14
|
+
KServe requires cert-manager for webhook certificates:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Install cert-manager
|
|
18
|
+
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
|
|
19
|
+
|
|
20
|
+
# Wait for cert-manager to be ready
|
|
21
|
+
kubectl wait --for=condition=Available deployment --all -n cert-manager --timeout=300s
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 3. Knative Serving (for serverless/scale-to-zero)
|
|
25
|
+
|
|
26
|
+
KServe's serverless mode requires Knative Serving:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Install Knative Serving CRDs and core
|
|
30
|
+
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.12.0/serving-crds.yaml
|
|
31
|
+
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.12.0/serving-core.yaml
|
|
32
|
+
|
|
33
|
+
# Install networking layer (Kourier - lighter than Istio)
|
|
34
|
+
kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.12.0/kourier.yaml
|
|
35
|
+
|
|
36
|
+
# Configure Knative to use Kourier
|
|
37
|
+
kubectl patch configmap/config-network -n knative-serving \
|
|
38
|
+
--type merge -p '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}'
|
|
39
|
+
|
|
40
|
+
# Wait for Knative to be ready
|
|
41
|
+
kubectl wait --for=condition=Available deployment --all -n knative-serving --timeout=300s
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Note:** If your cluster already has Istio, you can skip Kourier and configure Knative to use Istio instead.
|
|
45
|
+
|
|
46
|
+
### 4. KServe
|
|
47
|
+
|
|
48
|
+
Install KServe (includes ServingRuntime CRD):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Install KServe
|
|
52
|
+
kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.11.2/kserve.yaml
|
|
53
|
+
|
|
54
|
+
# Wait for KServe to be ready
|
|
55
|
+
kubectl wait --for=condition=Available deployment --all -n kserve --timeout=300s
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 5. Docker Image
|
|
59
|
+
|
|
60
|
+
Build and push the Docker image (see `../docker/`).
|
|
61
|
+
|
|
62
|
+
## Structure
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
kserve/
|
|
66
|
+
serving-runtime.yaml # ServingRuntime (shared runtime configuration)
|
|
67
|
+
inference-service.yaml # InferenceService (model deployment)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Why two files?** This follows the DRY principle:
|
|
71
|
+
- **ServingRuntime** defines the runtime configuration once (image, ports, resources)
|
|
72
|
+
- **InferenceService** references the runtime and adds scaling configuration
|
|
73
|
+
- If you later add more services, they can share the same ServingRuntime
|
|
74
|
+
|
|
75
|
+
## Models Included
|
|
76
|
+
|
|
77
|
+
{% for model in models %}
|
|
78
|
+
- **{{ model.name }}**{% if model.runtime %} ({{ model.runtime }}){% endif %}
|
|
79
|
+
|
|
80
|
+
{% endfor %}
|
|
81
|
+
|
|
82
|
+
## Namespace Configuration
|
|
83
|
+
|
|
84
|
+
By default, these manifests deploy to the `default` namespace. For production deployments,
|
|
85
|
+
create a dedicated namespace:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Create namespace
|
|
89
|
+
kubectl create namespace ml-serving
|
|
90
|
+
|
|
91
|
+
# Deploy to the namespace
|
|
92
|
+
kubectl apply -f serving-runtime.yaml -n ml-serving
|
|
93
|
+
kubectl apply -f inference-service.yaml -n ml-serving
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Alternatively, uncomment and set the `namespace` field in both YAML files.
|
|
97
|
+
|
|
98
|
+
## Deployment
|
|
99
|
+
|
|
100
|
+
### 1. Build and Push Docker Image
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cd ../docker
|
|
104
|
+
docker-compose build
|
|
105
|
+
|
|
106
|
+
# Tag and push to your registry
|
|
107
|
+
docker tag {{ image_name }}:latest your-registry/{{ image_name }}:v1.0.0
|
|
108
|
+
docker push your-registry/{{ image_name }}:v1.0.0
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 2. Update Image Reference
|
|
112
|
+
|
|
113
|
+
Edit `serving-runtime.yaml` to use your registry:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
containers:
|
|
117
|
+
- name: kserve-container
|
|
118
|
+
image: your-registry/{{ image_name }}:v1.0.0 # Update this line
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Deploy to KServe
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Apply the ServingRuntime first (defines the runtime)
|
|
125
|
+
kubectl apply -f serving-runtime.yaml
|
|
126
|
+
|
|
127
|
+
# Verify ServingRuntime is created
|
|
128
|
+
kubectl get servingruntime {{ app_name }}-runtime
|
|
129
|
+
|
|
130
|
+
# Apply the InferenceService (deploys the model)
|
|
131
|
+
kubectl apply -f inference-service.yaml
|
|
132
|
+
|
|
133
|
+
# Watch for the InferenceService to become ready
|
|
134
|
+
kubectl get inferenceservice {{ app_name }} -w
|
|
135
|
+
|
|
136
|
+
# Wait for ready status
|
|
137
|
+
kubectl wait --for=condition=Ready inferenceservice/{{ app_name }} --timeout=300s
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Testing the Deployment
|
|
141
|
+
|
|
142
|
+
### Get the Ingress URL
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Get the InferenceService URL
|
|
146
|
+
SERVICE_URL=$(kubectl get inferenceservice {{ app_name }} -o jsonpath='{.status.url}')
|
|
147
|
+
echo $SERVICE_URL
|
|
148
|
+
|
|
149
|
+
# For local clusters without ingress, use port-forward:
|
|
150
|
+
kubectl port-forward svc/{{ app_name }}-predictor 8080:80
|
|
151
|
+
SERVICE_URL="http://localhost:8080"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Test Health Endpoint
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
curl ${SERVICE_URL}/v2/health/ready
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Test Inference
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Example inference request (adjust for your model)
|
|
164
|
+
curl -X POST ${SERVICE_URL}/v2/models/{{ models[0].name if models else 'your-model' }}/infer \
|
|
165
|
+
-H "Content-Type: application/json" \
|
|
166
|
+
-d '{
|
|
167
|
+
"inputs": [
|
|
168
|
+
{
|
|
169
|
+
"name": "input",
|
|
170
|
+
"shape": [1],
|
|
171
|
+
"datatype": "BYTES",
|
|
172
|
+
"data": ["your input data"]
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}'
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Scale-to-Zero Verification
|
|
179
|
+
|
|
180
|
+
KServe supports scale-to-zero when there's no traffic:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Check current pods
|
|
184
|
+
kubectl get pods -l serving.kserve.io/inferenceservice={{ app_name }}
|
|
185
|
+
|
|
186
|
+
# Wait 5+ minutes with no traffic, then check again
|
|
187
|
+
kubectl get pods -l serving.kserve.io/inferenceservice={{ app_name }}
|
|
188
|
+
# Should show 0 pods
|
|
189
|
+
|
|
190
|
+
# Send a request - pods should spin up
|
|
191
|
+
curl ${SERVICE_URL}/v2/health/ready
|
|
192
|
+
kubectl get pods -l serving.kserve.io/inferenceservice={{ app_name }}
|
|
193
|
+
# Should show 1+ pods starting
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Configuration Options
|
|
197
|
+
|
|
198
|
+
### Scaling Configuration
|
|
199
|
+
|
|
200
|
+
Edit `inference-service.yaml`:
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
spec:
|
|
204
|
+
predictor:
|
|
205
|
+
minReplicas: 1 # Set to 1 to disable scale-to-zero
|
|
206
|
+
maxReplicas: 10 # Maximum replicas for high traffic
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Resource Limits
|
|
210
|
+
|
|
211
|
+
Edit `serving-runtime.yaml`:
|
|
212
|
+
|
|
213
|
+
```yaml
|
|
214
|
+
resources:
|
|
215
|
+
requests:
|
|
216
|
+
memory: "1Gi"
|
|
217
|
+
cpu: "500m"
|
|
218
|
+
limits:
|
|
219
|
+
memory: "4Gi"
|
|
220
|
+
cpu: "2000m"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### GPU Support
|
|
224
|
+
|
|
225
|
+
Add to `serving-runtime.yaml`:
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
resources:
|
|
229
|
+
limits:
|
|
230
|
+
nvidia.com/gpu: 1
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Monitoring
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# View logs
|
|
237
|
+
kubectl logs -l serving.kserve.io/inferenceservice={{ app_name }} -c kserve-container
|
|
238
|
+
|
|
239
|
+
# View events
|
|
240
|
+
kubectl describe inferenceservice {{ app_name }}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Cleanup
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# Remove InferenceService
|
|
247
|
+
kubectl delete inferenceservice {{ app_name }}
|
|
248
|
+
|
|
249
|
+
# Remove ServingRuntime
|
|
250
|
+
kubectl delete servingruntime {{ app_name }}-runtime
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Troubleshooting
|
|
254
|
+
|
|
255
|
+
### "no matches for kind ServingRuntime"
|
|
256
|
+
|
|
257
|
+
KServe is not installed or missing the ServingRuntime CRD. Follow the Prerequisites section above.
|
|
258
|
+
|
|
259
|
+
### InferenceService stuck in "Unknown"
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
kubectl get servingruntime {{ app_name }}-runtime
|
|
263
|
+
kubectl describe inferenceservice {{ app_name }}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Pod fails to start
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
kubectl describe pod -l serving.kserve.io/inferenceservice={{ app_name }}
|
|
270
|
+
kubectl logs -l serving.kserve.io/inferenceservice={{ app_name }} -c kserve-container
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Image pull errors
|
|
274
|
+
|
|
275
|
+
For local images on Rancher Desktop with containerd:
|
|
276
|
+
```bash
|
|
277
|
+
docker save {{ image_name }}:latest | nerdctl --namespace k8s.io load
|
|
278
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
apiVersion: serving.kserve.io/v1beta1
|
|
2
|
+
kind: InferenceService
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ app_name }}
|
|
5
|
+
# namespace: your-namespace # Uncomment and set for non-default namespace
|
|
6
|
+
spec:
|
|
7
|
+
predictor:
|
|
8
|
+
minReplicas: 0
|
|
9
|
+
maxReplicas: 5
|
|
10
|
+
model:
|
|
11
|
+
modelFormat:
|
|
12
|
+
name: mlserver
|
|
13
|
+
runtime: {{ app_name }}-runtime
|
|
14
|
+
protocolVersion: v2
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: serving.kserve.io/v1alpha1
|
|
2
|
+
kind: ServingRuntime
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ app_name }}-runtime
|
|
5
|
+
# namespace: your-namespace # Uncomment and set for non-default namespace
|
|
6
|
+
spec:
|
|
7
|
+
supportedModelFormats:
|
|
8
|
+
- name: mlserver
|
|
9
|
+
version: "1"
|
|
10
|
+
autoSelect: true
|
|
11
|
+
protocolVersions:
|
|
12
|
+
- v2
|
|
13
|
+
containers:
|
|
14
|
+
- name: kserve-container
|
|
15
|
+
image: {{ image_name }}:latest
|
|
16
|
+
ports:
|
|
17
|
+
- name: h2c
|
|
18
|
+
containerPort: {{ http_port }}
|
|
19
|
+
protocol: TCP
|
|
20
|
+
- name: grpc
|
|
21
|
+
containerPort: {{ grpc_port }}
|
|
22
|
+
protocol: TCP
|
|
23
|
+
env:
|
|
24
|
+
- name: MLSERVER_HTTP_PORT
|
|
25
|
+
value: "{{ http_port }}"
|
|
26
|
+
- name: MLSERVER_GRPC_PORT
|
|
27
|
+
value: "{{ grpc_port }}"
|
|
28
|
+
# Adjust resources based on model size - larger models may need 4Gi+ memory
|
|
29
|
+
resources:
|
|
30
|
+
requests:
|
|
31
|
+
memory: "512Mi"
|
|
32
|
+
cpu: "250m"
|
|
33
|
+
limits:
|
|
34
|
+
memory: "2Gi"
|
|
35
|
+
cpu: "1000m"
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Kubernetes Deployment
|
|
2
|
+
|
|
3
|
+
This directory contains Kubernetes manifests for deploying MLServer using Kustomize.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- kubectl configured with cluster access
|
|
8
|
+
- Docker image built and pushed to a registry (see `../docker/`)
|
|
9
|
+
- Kustomize (built into kubectl 1.14+)
|
|
10
|
+
|
|
11
|
+
## Structure
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
kubernetes/
|
|
15
|
+
base/ # Base manifests
|
|
16
|
+
deployment.yaml # MLServer Deployment
|
|
17
|
+
service.yaml # ClusterIP Service
|
|
18
|
+
kustomization.yaml # Kustomize base config
|
|
19
|
+
overlays/
|
|
20
|
+
dev/ # Development overlay (1 replica, lower resources)
|
|
21
|
+
prod/ # Production overlay (3 replicas, higher resources)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Models Included
|
|
25
|
+
|
|
26
|
+
{% for model in models %}
|
|
27
|
+
- **{{ model.name }}**{% if model.runtime %} ({{ model.runtime }}){% endif %}
|
|
28
|
+
|
|
29
|
+
{% endfor %}
|
|
30
|
+
|
|
31
|
+
## Deployment
|
|
32
|
+
|
|
33
|
+
### Development Environment
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Preview the manifests
|
|
37
|
+
kubectl kustomize overlays/dev
|
|
38
|
+
|
|
39
|
+
# Apply to cluster
|
|
40
|
+
kubectl apply -k overlays/dev
|
|
41
|
+
|
|
42
|
+
# Check rollout status
|
|
43
|
+
kubectl rollout status deployment/dev-{{ app_name }}
|
|
44
|
+
|
|
45
|
+
# Check pods
|
|
46
|
+
kubectl get pods -l app={{ app_name }},environment=dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Production Environment
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Preview the manifests
|
|
53
|
+
kubectl kustomize overlays/prod
|
|
54
|
+
|
|
55
|
+
# Apply to cluster
|
|
56
|
+
kubectl apply -k overlays/prod
|
|
57
|
+
|
|
58
|
+
# Check rollout status
|
|
59
|
+
kubectl rollout status deployment/prod-{{ app_name }}
|
|
60
|
+
|
|
61
|
+
# Check pods
|
|
62
|
+
kubectl get pods -l app={{ app_name }},environment=prod
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Image Configuration
|
|
66
|
+
|
|
67
|
+
The deployment uses the image `{{ image_name }}:latest` which should be built using the Docker
|
|
68
|
+
generator (`inference deploy init --target docker`) and then `docker-compose build`.
|
|
69
|
+
|
|
70
|
+
### Local Development (Rancher Desktop)
|
|
71
|
+
|
|
72
|
+
The dev overlay uses `imagePullPolicy: Never` so the image must be available locally.
|
|
73
|
+
With Rancher Desktop, load the image into the cluster:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Build the image
|
|
77
|
+
cd ../docker && docker-compose build
|
|
78
|
+
|
|
79
|
+
# For Rancher Desktop with dockerd (moby):
|
|
80
|
+
# Images are automatically available - just deploy
|
|
81
|
+
|
|
82
|
+
# For Rancher Desktop with containerd:
|
|
83
|
+
# Export and import the image
|
|
84
|
+
docker save {{ image_name }}:latest | nerdctl --namespace k8s.io load
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Remote Clusters
|
|
88
|
+
|
|
89
|
+
For remote clusters, push the image to a registry and update the image reference:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Tag and push to your registry
|
|
93
|
+
docker tag {{ image_name }}:latest your-registry/{{ image_name }}:v1.0.0
|
|
94
|
+
docker push your-registry/{{ image_name }}:v1.0.0
|
|
95
|
+
|
|
96
|
+
# Update image using kustomize
|
|
97
|
+
cd overlays/prod
|
|
98
|
+
kustomize edit set image {{ image_name }}=your-registry/{{ image_name }}:v1.0.0
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Accessing the Service
|
|
102
|
+
|
|
103
|
+
### Development (NodePort)
|
|
104
|
+
|
|
105
|
+
The dev overlay uses NodePort for direct access without port-forwarding:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Test health endpoint (HTTP on port {{ node_port_http }}, gRPC on port {{ node_port_grpc }})
|
|
109
|
+
curl http://localhost:{{ node_port_http }}/v2/health/ready
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If ports {{ node_port_http }}/{{ node_port_grpc }} conflict with other services, edit `overlays/dev/kustomization.yaml`
|
|
113
|
+
to change the `nodePort` values (valid range: 30000-32767).
|
|
114
|
+
|
|
115
|
+
### Production (Port Forward)
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
kubectl port-forward svc/prod-{{ app_name }} {{ http_port }}:{{ http_port }}
|
|
119
|
+
|
|
120
|
+
# Test health endpoint
|
|
121
|
+
curl http://localhost:{{ http_port }}/v2/health/ready
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### LoadBalancer (Production)
|
|
125
|
+
|
|
126
|
+
To expose externally, modify the service type in your overlay:
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
# overlays/prod/service-patch.yaml
|
|
130
|
+
apiVersion: v1
|
|
131
|
+
kind: Service
|
|
132
|
+
metadata:
|
|
133
|
+
name: {{ app_name }}
|
|
134
|
+
spec:
|
|
135
|
+
type: LoadBalancer
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Health Checks
|
|
139
|
+
|
|
140
|
+
The deployment includes:
|
|
141
|
+
- **Startup probe**: `/v2/health/ready` - Allows up to 5 minutes for model loading (30 retries × 10s)
|
|
142
|
+
- **Readiness probe**: `/v2/health/ready` - Pod ready to receive traffic
|
|
143
|
+
- **Liveness probe**: `/v2/health/live` - Pod is healthy
|
|
144
|
+
|
|
145
|
+
For larger models that take longer to load, increase `failureThreshold` in the startup probe.
|
|
146
|
+
|
|
147
|
+
## Resource Limits
|
|
148
|
+
|
|
149
|
+
| Environment | CPU Request | CPU Limit | Memory Request | Memory Limit | Replicas |
|
|
150
|
+
|-------------|-------------|-----------|----------------|--------------|----------|
|
|
151
|
+
| dev | 100m | 500m | 256Mi | 1Gi | 1 |
|
|
152
|
+
| prod | 500m | 2000m | 1Gi | 4Gi | 3 |
|
|
153
|
+
|
|
154
|
+
Adjust these values in the overlay kustomization files based on your model requirements.
|
|
155
|
+
|
|
156
|
+
## Cleanup
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Remove dev deployment
|
|
160
|
+
kubectl delete -k overlays/dev
|
|
161
|
+
|
|
162
|
+
# Remove prod deployment
|
|
163
|
+
kubectl delete -k overlays/prod
|
|
164
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
apiVersion: apps/v1
|
|
2
|
+
kind: Deployment
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ app_name }}
|
|
5
|
+
labels:
|
|
6
|
+
app: {{ app_name }}
|
|
7
|
+
spec:
|
|
8
|
+
replicas: 1
|
|
9
|
+
selector:
|
|
10
|
+
matchLabels:
|
|
11
|
+
app: {{ app_name }}
|
|
12
|
+
template:
|
|
13
|
+
metadata:
|
|
14
|
+
labels:
|
|
15
|
+
app: {{ app_name }}
|
|
16
|
+
spec:
|
|
17
|
+
containers:
|
|
18
|
+
- name: {{ app_name }}
|
|
19
|
+
image: {{ image_name }}:latest
|
|
20
|
+
imagePullPolicy: IfNotPresent
|
|
21
|
+
ports:
|
|
22
|
+
- name: http
|
|
23
|
+
containerPort: {{ http_port }}
|
|
24
|
+
protocol: TCP
|
|
25
|
+
- name: grpc
|
|
26
|
+
containerPort: {{ grpc_port }}
|
|
27
|
+
protocol: TCP
|
|
28
|
+
resources:
|
|
29
|
+
requests:
|
|
30
|
+
memory: "512Mi"
|
|
31
|
+
cpu: "250m"
|
|
32
|
+
limits:
|
|
33
|
+
memory: "2Gi"
|
|
34
|
+
cpu: "1000m"
|
|
35
|
+
startupProbe:
|
|
36
|
+
httpGet:
|
|
37
|
+
path: /v2/health/ready
|
|
38
|
+
port: http
|
|
39
|
+
failureThreshold: 30
|
|
40
|
+
periodSeconds: 10
|
|
41
|
+
readinessProbe:
|
|
42
|
+
httpGet:
|
|
43
|
+
path: /v2/health/ready
|
|
44
|
+
port: http
|
|
45
|
+
periodSeconds: 5
|
|
46
|
+
livenessProbe:
|
|
47
|
+
httpGet:
|
|
48
|
+
path: /v2/health/live
|
|
49
|
+
port: http
|
|
50
|
+
periodSeconds: 10
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
2
|
+
kind: Kustomization
|
|
3
|
+
|
|
4
|
+
resources:
|
|
5
|
+
- ../../base
|
|
6
|
+
|
|
7
|
+
namePrefix: dev-
|
|
8
|
+
|
|
9
|
+
labels:
|
|
10
|
+
- pairs:
|
|
11
|
+
environment: dev
|
|
12
|
+
|
|
13
|
+
patches:
|
|
14
|
+
- patch: |-
|
|
15
|
+
- op: replace
|
|
16
|
+
path: /spec/replicas
|
|
17
|
+
value: 1
|
|
18
|
+
- op: replace
|
|
19
|
+
path: /spec/template/spec/containers/0/imagePullPolicy
|
|
20
|
+
value: Never
|
|
21
|
+
target:
|
|
22
|
+
kind: Deployment
|
|
23
|
+
name: {{ app_name }}
|
|
24
|
+
- patch: |-
|
|
25
|
+
- op: replace
|
|
26
|
+
path: /spec/template/spec/containers/0/resources/requests/memory
|
|
27
|
+
value: "256Mi"
|
|
28
|
+
- op: replace
|
|
29
|
+
path: /spec/template/spec/containers/0/resources/requests/cpu
|
|
30
|
+
value: "100m"
|
|
31
|
+
- op: replace
|
|
32
|
+
path: /spec/template/spec/containers/0/resources/limits/memory
|
|
33
|
+
value: "1Gi"
|
|
34
|
+
- op: replace
|
|
35
|
+
path: /spec/template/spec/containers/0/resources/limits/cpu
|
|
36
|
+
value: "500m"
|
|
37
|
+
target:
|
|
38
|
+
kind: Deployment
|
|
39
|
+
name: {{ app_name }}
|
|
40
|
+
- patch: |-
|
|
41
|
+
- op: replace
|
|
42
|
+
path: /spec/type
|
|
43
|
+
value: NodePort
|
|
44
|
+
- op: add
|
|
45
|
+
path: /spec/ports/0/nodePort
|
|
46
|
+
value: {{ node_port_http }}
|
|
47
|
+
- op: add
|
|
48
|
+
path: /spec/ports/1/nodePort
|
|
49
|
+
value: {{ node_port_grpc }}
|
|
50
|
+
target:
|
|
51
|
+
kind: Service
|
|
52
|
+
name: {{ app_name }}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
2
|
+
kind: Kustomization
|
|
3
|
+
|
|
4
|
+
resources:
|
|
5
|
+
- ../../base
|
|
6
|
+
|
|
7
|
+
namePrefix: prod-
|
|
8
|
+
|
|
9
|
+
labels:
|
|
10
|
+
- pairs:
|
|
11
|
+
environment: prod
|
|
12
|
+
|
|
13
|
+
patches:
|
|
14
|
+
- patch: |-
|
|
15
|
+
- op: replace
|
|
16
|
+
path: /spec/replicas
|
|
17
|
+
value: 3
|
|
18
|
+
target:
|
|
19
|
+
kind: Deployment
|
|
20
|
+
name: {{ app_name }}
|
|
21
|
+
- patch: |-
|
|
22
|
+
- op: replace
|
|
23
|
+
path: /spec/template/spec/containers/0/resources/requests/memory
|
|
24
|
+
value: "1Gi"
|
|
25
|
+
- op: replace
|
|
26
|
+
path: /spec/template/spec/containers/0/resources/requests/cpu
|
|
27
|
+
value: "500m"
|
|
28
|
+
- op: replace
|
|
29
|
+
path: /spec/template/spec/containers/0/resources/limits/memory
|
|
30
|
+
value: "4Gi"
|
|
31
|
+
- op: replace
|
|
32
|
+
path: /spec/template/spec/containers/0/resources/limits/cpu
|
|
33
|
+
value: "2000m"
|
|
34
|
+
target:
|
|
35
|
+
kind: Deployment
|
|
36
|
+
name: {{ app_name }}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
apiVersion: v1
|
|
2
|
+
kind: Service
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ app_name }}
|
|
5
|
+
labels:
|
|
6
|
+
app: {{ app_name }}
|
|
7
|
+
spec:
|
|
8
|
+
type: ClusterIP
|
|
9
|
+
ports:
|
|
10
|
+
- name: http
|
|
11
|
+
port: {{ http_port }}
|
|
12
|
+
targetPort: http
|
|
13
|
+
protocol: TCP
|
|
14
|
+
- name: grpc
|
|
15
|
+
port: {{ grpc_port }}
|
|
16
|
+
targetPort: grpc
|
|
17
|
+
protocol: TCP
|
|
18
|
+
selector:
|
|
19
|
+
app: {{ app_name }}
|