Deployment Guide¶
Deploy your IVCAP lambda service to production.
Docker Containerization¶
Create a minimal Dockerfile:
FROM python:3.11-slim-bookworm
WORKDIR /app
COPY pyproject.toml ./
RUN pip install poetry \
&& poetry config virtualenvs.create false \
&& poetry install --no-root \
&& pip uninstall -y poetry
COPY my_service.py ./
ARG VERSION=dev
ENV VERSION=$VERSION
ENV PORT=80
ENTRYPOINT ["python", "/app/my_service.py"]
Build and run:
docker build --build-arg VERSION=1.2.3 -t my-lambda-service:1.2.3 .
docker run -p 8090:80 my-lambda-service:1.2.3
Environment Configuration¶
Local Development¶
# Port (can also be set with --port)
export PORT=8095
# Optional: OpenObserve integration
export OPENOBSERVE_URL="http://localhost:5080"
export OPENOBSERVE_ORG="myorg"
export OPENOBSERVE_USERNAME="admin@example.com"
export OPENOBSERVE_TOKEN="<token>"
# Run the service
python my_service.py
Production Environment¶
# Service version
export VERSION="1.2.3"
# Server binding
export HOST="0.0.0.0"
export PORT="80"
# Observability
export OPENOBSERVE_URL="https://observe.example.com"
export OPENOBSERVE_ORG="production"
export OPENOBSERVE_USERNAME="service@example.com"
export OPENOBSERVE_TOKEN="<production-token>"
# Distributed tracing
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
Service Registration¶
Print the service description (for IVCAP registration):
Register with IVCAP:
CLI Flags¶
start_lambda_server provides these built-in CLI flags:
--host HOST Bind address (default: 0.0.0.0 / $HOST)
--port PORT Port to listen on (default: 8090 / $PORT)
--with-telemetry Initialise OpenTelemetry tracing
--with-mcp Expose an MCP endpoint at /mcp
--list-services List the names of all registered services/tools and exit
--print-tool-description Print the tool description JSON and exit
--print-service-description Print the full service description JSON and exit
--service-name NAME Override the service name used in --print-service-description
(defaults to "<service.name>-<tool-name-with-dashes>")
Custom CLI Flags¶
Add your own command-line flags via custom_args:
import argparse
import os
def custom_args(parser: argparse.ArgumentParser) -> argparse.Namespace:
parser.add_argument("--model-path", type=str, help="Path to the model file")
parser.add_argument("--batch-size", type=int, default=32, help="Inference batch size")
args = parser.parse_args()
if args.model_path:
os.environ["MODEL_PATH"] = args.model_path
if args.batch_size:
os.environ["BATCH_SIZE"] = str(args.batch_size)
return args
if __name__ == "__main__":
start_lambda_server(service, custom_args=custom_args)
Kubernetes Deployment¶
Create a deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-lambda-service
spec:
replicas: 2
selector:
matchLabels:
app: my-lambda-service
template:
metadata:
labels:
app: my-lambda-service
spec:
containers:
- name: my-lambda-service
image: my-lambda-service:1.2.3
ports:
- containerPort: 80
env:
- name: VERSION
value: "1.2.3"
- name: OPENOBSERVE_URL
value: "https://observe.example.com"
- name: OPENOBSERVE_TOKEN
valueFrom:
secretKeyRef:
name: observability
key: token
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /_healtz
port: 80
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /_healtz
port: 80
initialDelaySeconds: 5
periodSeconds: 10
Deploy:
Scalability Patterns¶
Lambda services are stateless by design — each tool invocation is independent. The IVCAP platform can route requests to any instance.
Thread Pool Sizing¶
Configure the thread pool for CPU-intensive tools:
from ivcap_lambda import ExecutionContext
from ivcap_lambda.executor import ExecutorOpts
@ivcap_lambda(
"/analyse",
opts=ToolOptions(
tags=["ML"],
executor_opts=ExecutorOpts(
max_workers=4, # Fixed thread pool of 4
job_cache_size=1000, # Cache up to 1000 job results
job_cache_ttl=3600, # Cache results for 1 hour
)
)
)
def analyse(req: AnalyseRequest) -> AnalyseResult:
...
Resource Requirements¶
Set resource requirements in your service definition (IVCAP platform uses this for scheduling):
from ivcap_service import Service, ResourceRequirements
service = Service(
name="GPU Inference Service",
resources=ResourceRequirements(cpu=2, memory="4Gi", gpu=1),
...
)
Troubleshooting¶
Container Won't Start¶
Check logs:
Print service description to verify configuration:
Jobs Timing Out¶
Increase max_wait_time in ToolOptions:
@ivcap_lambda("/slow-tool", opts=ToolOptions(max_wait_time=30.0))
def slow_tool(req: SlowRequest) -> SlowResult:
...
Or encourage clients to use the async pattern:
High Memory Usage¶
Check job_cache_size and job_cache_ttl in ExecutorOpts. The job result cache holds completed job results in memory; reduce its size if needed.
See Also¶
- Best Practices — Production patterns
- Observability — Monitoring setup
- Error Handling — Robust error handling
- Environment Variables Reference