# Deployment Guide This guide covers deploying Fission Python functions to Kubernetes, including configuration tuning, troubleshooting, and best practices. ## Table of Contents 1. [Prerequisites](#prerequisites) 2. [Quick Start](#quick-start) 3. [Deployment Configuration](#deployment-configuration) 4. [Executors](#executors) 5. [Resource Tuning](#resource-tuning) 6. [Environments](#environments) 7. [Secrets Management](#secrets-management) 8. [Rolling Updates](#rolling-updates) 9. [Monitoring & Logging](#monitoring--logging) 10. [Troubleshooting](#troubleshooting) ## Prerequisites - Kubernetes cluster (v1.19+) - Fission installed (`kubectl apply -f https://github.com/fission/fission/releases/latest/download/fission-all.yaml`) - `fission` CLI installed and configured - `kubectl` configured to access cluster - Docker registry access (for custom images if needed) ## Quick Start Assuming you have a project set up: ```bash # 1. Build the package (creates specs/ directory) cd /path/to/project ./src/build.sh # 2. Verify deployment configuration fission spec verify --file=.fission/deployment.json # 3. Deploy to Fission fission deploy # 4. Test deployed function curl http://$FISSION_ROUTER/api/items ``` **That's it!** Fission will: - Build package.zip from src/ - Create environment (if not exists) - Create package - Create functions from docstring metadata - Set up HTTP triggers ## Deployment Configuration ### deployment.json vs fission.yaml This template uses `deployment.json`, **not** `fission.yaml` or `fission.json`. The Fission Python builder extracts function metadata from Python docstrings directly. ### Key Sections #### environments Define build environment: ```json { "environments": { "myproject-py": { "image": "ghcr.io/fission/python-env", "builder": "ghcr.io/fission/python-builder", "mincpu": 50, "maxcpu": 100, "minmemory": 50, "maxmemory": 500, "poolsize": 1 } } } ``` - `image` - Runtime image (Python + libraries) - `builder` - Builder image (compiles dependencies) - Resource limits in millicores (50 = 0.05 CPU) and MB #### packages Define how to build your code: ```json { "packages": { "myproject": { "buildcmd": "./build.sh", "sourcearchive": "package.zip", "env": "myproject-py" } } } ``` - `buildcmd` - Build script inside builder container - `sourcearchive` - Generated by builder from `sourcepath` - `env` - Links to environment definition #### function_common Default configuration for all functions: ```json { "function_common": { "pkg": "myproject", "secrets": ["fission-myproject-env"], "configmaps": ["fission-myproject-config"], "executor": { ... }, "mincpu": 50, "maxcpu": 100, "minmemory": 50, "maxmemory": 500 } } ``` - `pkg` - Package name to use - `secrets` / `configmaps` - K8s resources to mount into functions - `executor` - Execution strategy (poolmgr or newdeploy) #### secrets / configmaps **Placeholder definitions only**. These inform Fission what secret names to expect, but the actual values go in real K8s secrets: ```json { "secrets": { "fission-myproject-env": { "literals": [ "PG_HOST=localhost", "PG_PORT=5432" ] } } } ``` Create the actual secret: ```bash kubectl create secret generic fission-myproject-env \ --from-literal=PG_HOST=prod-db.example.com \ --from-literal=PG_PORT=5432 \ --from-literal=PG_USER=myuser \ --from-literal=PG_PASS=mypassword ``` ## Executors Fission supports two executor types: ### poolmgr (default) Good for: - High-concurrency HTTP functions - Functions that should scale to zero - Stateless request/response patterns Configuration: ```json "executor": { "select": "poolmgr", "poolmgr": { "concurrency": 1, // Requests per pod "requestsperpod": 1, "onceonly": false } } ``` - `concurrency` - How many concurrent requests each pod handles (usually 1 for Python due to GIL) - `poolsize` from environment controls number of pods in pool ### newdeploy Good for: - Dedicated function instances - Long-running or background jobs - Functions needing stable network identity Configuration: ```json "executor": { "select": "newdeploy", "newdeploy": { "minscale": 1, // Minimum pods (set to 0 for scale-to-zero) "maxscale": 5, // Maximum pods "targetcpu": 80 // Scale up when CPU > 80% } } ``` - `minscale` - Keep at least N pods running (0 = scale to zero) - `maxscale` - Maximum pods for auto-scaling - `targetcpu` - CPU threshold for scaling ## Resource Tuning Resources are defined in millicores (m) and MB: - `mincpu` / `maxcpu`: 1000 = 1 CPU core - `minmemory` / `maxmemory`: in MB **Example settings**: | Function Type | mincpu | maxcpu | minmemory | maxmemory | |--------------|--------|--------|-----------|-----------| | Simple API | 50 | 100 | 128 | 256 | | DB-intensive | 200 | 500 | 256 | 512 | | ML inference | 1000 | 2000 | 1024 | 2048 | **Tips**: - Start conservatively, monitor, then adjust - Function pods are killed if they exceed `maxmemory` - CPU limits are enforced by Kubernetes scheduler - Use `minmemory` >= 128 to avoid OOM kills ### Checking Current Usage ```bash # Get function pods kubectl get pods -n fission # Describe pod for resource usage kubectl describe pod -n fission # See metrics (if metrics-server installed) kubectl top pod -n fission ``` ## Environments You can have multiple deployment environments (dev, staging, prod): ### Using deployment.json variants - `deployment.json` - Production (default) - `dev-deployment.json` - Development (used with `fission deploy --dev`) Example `dev-deployment.json`: ```json { "namespace": "fission-dev", "function_common": { "secrets": ["fission-myproject-dev-env"], "configmaps": ["fission-myproject-dev-config"] } } ``` ### Switching Environments ```bash # Deploy to dev fission deploy --dev # Deploy to prod (default) fission deploy # Specify namespace fission deploy --namespace fission-staging ``` ## Secrets Management ### Creating Secrets ```bash # Basic secret from literals kubectl create secret generic fission-myproject-env \ --from-literal=PG_HOST=localhost \ --from-literal=PG_PORT=5432 # From file kubectl create secret generic fission-myproject-env \ --from-file=secrets.properties # With multiple namespaces kubectl create secret generic fission-myproject-env \ --namespace fission-dev \ --from-literal=PG_HOST=dev-db.example.com ``` ### Encrypted Secrets (Vault) To encrypt sensitive values: ```python # On your local machine (with PyNaCl installed) from vault import encrypt_vault key = "your-32-byte-hex-key-here..." # 64 hex chars encrypted = encrypt_vault("super-secret-password", key) print(encrypted) # vault:v1:base64... ``` Store the encrypted string in K8s secret: ```bash kubectl create secret generic fission-myproject-env \ --from-literal=PG_PASS='vault:v1:base64...' ``` Set `CRYPTO_KEY` in `helpers.py` to the hex key: ```python CRYPTO_KEY = "e24ad6ceed96115520f6e6dc8a0da506ae9a706823d54f30a5b75447ecf477b6" ``` **Important**: Rotate keys periodically. When changing key, re-encrypt all secrets. ### Updating Secrets ```bash # Edit secret kubectl edit secret fission-myproject-env # Update single key kubectl set secret secret fission-myproject-env \ --from-literal=PG_PASS='new-password' # Roll function to pick up new secret fission function update --name my-function ``` ## Rolling Updates ### Deploy Changes ```bash # Build and deploy ./src/build.sh fission deploy # Or deploy single function fission function update --name my-function ``` ### Zero-Downtime Deployments Fission handles rolling updates automatically: 1. New package is built 2. New function pods are created with new code 3. Old pods continue serving traffic until new pods are ready 4. Old pods are terminated **No downtime** by default for HTTP triggers. ### Canary Deployments For canary deployments: 1. Deploy new version with different function name: `my-function-v2` 2. Route some traffic using ingress annotations or service mesh 3. Gradually shift traffic 4. Delete old function ## Monitoring & Logging ### Viewing Logs ```bash # All function logs in namespace kubectl logs -n fission -l fission-function=true --tail=100 # Specific function kubectl logs -n fission -l fission-function/name=my-function --tail=100 # Follow logs kubectl logs -n fission -l fission-function/name=my-function -f # Container logs (if multiple containers) kubectl logs -n fission -l fission-function/name=my-function -c builder ``` ### Structured Logging Use `logger` from `helpers.py` (already configured): ```python logger.info("Processing request", extra={"user_id": user_id}) logger.error("Database error", exc_info=True, extra={"query": sql}) ``` Logs are collected by the container runtime and available via `kubectl logs`. ### Metrics Fission exposes Prometheus metrics: ```bash # Get metrics endpoint kubectl port-forward -n fission svc/fission-prometheus-server 9090:9090 # Or query via kubectl kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/fission/pods/*" | jq . ``` Metrics include: - Request rate - Error rate - Response latency - Pod counts ## Troubleshooting ### Deployment Fails **Error**: `Error building package` Check: - `build.sh` is executable: `chmod +x src/build.sh` - All dependencies in `requirements.txt` are valid - Python syntax is correct: `python -m py_compile src/*.py` **Error**: `Function not found after deploy` Check: - Fission docstring block is properly formatted (must be ````fission` with backticks) - No YAML/JSON syntax errors in docstring - Function file is in `src/` directory ### Function Not Responding **Check pod status**: ```bash kubectl get pods -n fission -l fission-function/name=my-function ``` **Pod stuck in Pending** - Insufficient resources or image pull error **Pod stuck in ContainerCreating** - Volume mount issue or image pull **Pod CrashLoopBackOff** - Application error. Check logs: ```bash kubectl logs -n fission --previous ``` ### Configuration Not Loading **Secrets not available**: ```bash # Check secret exists in correct namespace kubectl get secret fission-myproject-env -n fission # Verify secret is mounted kubectl exec -it -n fission -- ls /secrets/default/ ``` **ConfigMaps not available**: ```bash kubectl get configmap fission-myproject-config -n fission ``` **Profusion parms not reading**: - Ensure `SECRET_NAME` in helpers.py matches created secret name - Path format: `/secrets/{namespace}/{secret-name}/{key}` ### Slow Performance 1. **Increase resources**: Raise `maxmemory` and `maxcpu` 2. **Connection pooling**: Use connection pooler like PgBouncer for heavy DB load 3. **Database queries**: Check slow queries, add indexes 4. **Cold starts**: Set `minscale: 1` with newdeploy executor to keep warm ### Database Connection Errors **Error**: `could not connect to server: Connection refused` - Verify database is reachable from cluster - Check security groups/network policies - Test connectivity from pod: ```bash kubectl exec -it -n fission -- nc -zv $PG_HOST $PG_PORT ``` **Error**: `password authentication failed` - Verify credentials in secret - Check PG_USER format (with `plaintext:` prefix for vault) ## Advanced Topics ### Custom Runtime Image If you need system packages: ```dockerfile FROM ghcr.io/fission/python-env:latest RUN apk add --no-cache gcc libffi-dev ``` Build and push: ```bash docker build -t myregistry/python-custom:latest . docker push myregistry/python-custom:latest ``` Update `deployment.json`: ```json "environments": { "myproject-py": { "image": "myregistry/python-custom:latest", ... } } ``` ### Environment Variables from ConfigMap ```json "configmaps": { "fission-myproject-config": { "literals": [ "LOG_LEVEL=DEBUG", "FEATURE_FLAG_X=true" ] } } ``` Access in code: ```python import os log_level = os.getenv("LOG_LEVEL", "INFO") ``` ### Lifecycle Hooks Use `function_pre_remove` and `function_post_remove` in deployment hooks: ```json "hooks": { "function_pre_remove": [ { "type": "http", "url": "http://cleanup-service/cleanup", "timeout": 30000 } ] } ``` ## Common Commands Reference ```bash # List functions fission function list # Test function manually fission function test --name my-function # Update single function fission function update --name my-function # Delete function fission function delete --name my-function # View function pods kubectl get pods -n fission -l fission-function/name=my-function # View logs kubectl logs -n fission -l fission-function/name=my-function -f # Exec into pod kubectl exec -it -n fission -- /bin/sh # Describe function fission function describe --name my-function # Get function YAML fission function get --name my-function -o yaml # Check Fission version fission version # Check Fission status kubectl get pods -n fission ``` ## Further Reading - [Fission Deployment Documentation](https://fission.io/docs/usage/deploy/) - [Fission Executors](https://fission.io/docs/architecture/executor/) - [Kubernetes Resource Management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) - [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)