Fission Serverless Framework on Kubernetes
Fission is a fast, open-source serverless framework for Kubernetes that focuses on minimizing cold start latency through pre-warmed environment pools, making it ideal for latency-sensitive serverless workloads. This guide covers installing Fission, creating language environments, deploying functions with HTTP and timer triggers, composing workflows, and performance tuning.
Prerequisites
- Kubernetes cluster 1.19+ with at least 3 nodes
kubectlconfigured with cluster-admin permissions- Helm 3.x installed
- At least 4GB RAM available for Fission components and environment pools
# Verify cluster readiness
kubectl get nodes
kubectl version --short
# Verify Helm is installed
helm version
Installing Fission
# Add Fission Helm chart repository
helm repo add fission-charts https://fission.github.io/fission-charts/
helm repo update
# Create the fission namespace
kubectl create namespace fission
# Install Fission (includes all core components)
helm install fission fission-charts/fission-all \
--namespace fission \
--set routerServiceType=LoadBalancer
# Watch installation progress
kubectl get pods -n fission -w
# Verify all components are running
kubectl get pods -n fission
# Expected components:
# controller, router, executor, buildermgr, kubewatcher, timer, storagesvc, mqtrigger
Check Fission services:
kubectl get svc -n fission
# Get the router external IP (for HTTP triggers)
export FISSION_ROUTER=$(kubectl get svc router -n fission -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Fission Router: http://$FISSION_ROUTER"
Installing the Fission CLI
# Linux amd64
FISSION_VERSION="1.20.0"
curl -Lo fission https://github.com/fission/fission/releases/download/v${FISSION_VERSION}/fission-v${FISSION_VERSION}-linux-amd64
chmod +x fission
sudo mv fission /usr/local/bin/
# Verify
fission version
# Configure namespace
export FISSION_NAMESPACE=fission
Creating Language Environments
Environments are pre-loaded language runtimes that run in warm pods, eliminating cold start delays:
# Create a Python environment
fission environment create \
--name python \
--image fission/python-env:latest \
--builder fission/python-builder:latest \
--mincpu 40 --maxcpu 200 \
--minmemory 64 --maxmemory 512 \
--poolsize 3 # Keep 3 warm pods ready
# Create a Node.js environment
fission environment create \
--name node \
--image fission/node-env:latest \
--builder fission/node-builder:latest \
--poolsize 2
# Create a Go environment
fission environment create \
--name go \
--image fission/go-env-1.22:latest \
--builder fission/go-builder-1.22:latest \
--poolsize 2
# List environments
fission environment list
Check environment pool status:
# Environment pools run in fission-builder namespace
kubectl get pods -n fission-builder
kubectl get pods -n fission | grep pool
Creating and Deploying Functions
Simple Python function:
# Create function file
cat > /tmp/hello.py << 'EOF'
def main():
return "Hello from Fission!"
EOF
# Create function using source code (auto-builds)
fission function create \
--name hello \
--env python \
--code /tmp/hello.py
# Test immediately
fission function test --name hello
Function with request/response handling:
cat > /tmp/api-handler.py << 'EOF'
import json
from flask import request, current_app
def main():
# Get request data
method = request.method
body = request.get_json(silent=True) or {}
headers = dict(request.headers)
# Process the request
response = {
"method": method,
"received": body,
"message": f"Processed {method} request",
"headers": {
"user-agent": headers.get("User-Agent", "unknown")
}
}
return json.dumps(response), 200, {"Content-Type": "application/json"}
EOF
# Create the function
fission function create \
--name api-handler \
--env python \
--code /tmp/api-handler.py \
--minscale 1 \
--maxscale 10 \
--executortype newdeploy
# Functions with executortype=newdeploy use Kubernetes Deployments
# executortype=poolmgr (default) uses the warm environment pool
Node.js function:
cat > /tmp/node-function.js << 'EOF'
module.exports = async function(context) {
const { request, response } = context;
const body = request.body || {};
const name = body.name || "World";
response.status(200).json({
message: `Hello, ${name}!`,
timestamp: new Date().toISOString(),
pid: process.pid
});
};
EOF
fission function create \
--name hello-node \
--env node \
--code /tmp/node-function.js
fission function test --name hello-node --body '{"name": "Fission"}'
HTTP Triggers
HTTP triggers expose functions as API endpoints:
# Create HTTP trigger (GET request to /hello)
fission httptrigger create \
--name hello-trigger \
--url /hello \
--method GET \
--function hello
# Create trigger with URL parameters
fission httptrigger create \
--name user-trigger \
--url "/users/{userId}" \
--method GET \
--function get-user
# Create trigger for all HTTP methods
fission httptrigger create \
--name api-trigger \
--url "/api/v1/{path:*}" \
--method "" \
--function api-handler
# List triggers
fission httptrigger list
# Test via the router
curl http://$FISSION_ROUTER/hello
curl -X POST http://$FISSION_ROUTER/api/v1/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice"}'
Timer and Schedule Triggers
# Run a function every 5 minutes
fission timetrigger create \
--name cleanup-trigger \
--function cleanup-old-files \
--cron "@every 5m"
# Run daily at midnight
fission timetrigger create \
--name daily-report \
--function generate-daily-report \
--cron "0 0 * * *"
# Run every weekday at 9 AM
fission timetrigger create \
--name morning-digest \
--function send-digest \
--cron "0 9 * * 1-5"
# List time triggers
fission timetrigger list
# Update a trigger's schedule
fission timetrigger update \
--name cleanup-trigger \
--cron "@every 10m"
# Get trigger details
fission timetrigger get --name daily-report
The cleanup function example:
cat > /tmp/cleanup.py << 'EOF'
import os
import time
def main():
target_dir = os.environ.get("CLEANUP_DIR", "/tmp")
max_age_days = int(os.environ.get("MAX_AGE_DAYS", "7"))
now = time.time()
cutoff = now - (max_age_days * 86400)
cleaned = 0
for filename in os.listdir(target_dir):
filepath = os.path.join(target_dir, filename)
if os.path.isfile(filepath) and os.path.getmtime(filepath) < cutoff:
os.remove(filepath)
cleaned += 1
print(f"Removed: {filepath}")
return f"Cleaned {cleaned} files from {target_dir}"
EOF
fission function create \
--name cleanup-old-files \
--env python \
--code /tmp/cleanup.py \
--env-vars "CLEANUP_DIR=/data/uploads,MAX_AGE_DAYS=30"
Message Queue Triggers (NATS)
# NATS is bundled with Fission
# Create a message queue trigger
fission mqtrigger create \
--name order-processor \
--function process-order \
--mqtype nats-streaming \
--topic orders.created \
--resptopic orders.processed \
--errortopic orders.errors \
--maxretries 3 \
--cooldown 30s \
--mqtkind keda
# List MQ triggers
fission mqtrigger list
# Test by publishing to the NATS topic
# Connect to NATS and publish
kubectl run nats-test --image nats-io/nats-box -it --rm -- sh
# Inside the container:
# nats pub orders.created '{"orderId":"123","amount":99.99}'
Process order function:
cat > /tmp/process-order.py << 'EOF'
import json
import os
def main():
# For MQ triggers, the message is in the request body
from flask import request
message = request.get_data(as_text=True)
order = json.loads(message)
print(f"Processing order: {order.get('orderId')}")
# Simulate processing
result = {
"orderId": order.get("orderId"),
"status": "processed",
"processedAt": __import__("datetime").datetime.utcnow().isoformat()
}
return json.dumps(result)
EOF
fission function create \
--name process-order \
--env python \
--code /tmp/process-order.py
Workflow Composition
Chain functions together using Fission workflows:
# Install Fission Workflows (optional)
helm install fission-workflows fission-charts/fission-workflows \
--namespace fission
# Create a workflow YAML
cat > /tmp/order-workflow.yaml << 'EOF'
apiVersion: 1
output: send-confirmation
tasks:
validate-order:
run: validate-order-fn
inputs:
order: "{ $.args.order }"
process-payment:
run: process-payment-fn
depends_on: [validate-order]
inputs:
orderId: "{ $.tasks.validate-order.output.orderId }"
amount: "{ $.args.order.amount }"
update-inventory:
run: update-inventory-fn
depends_on: [process-payment]
inputs:
items: "{ $.args.order.items }"
send-confirmation:
run: send-confirmation-fn
depends_on: [update-inventory, process-payment]
inputs:
orderId: "{ $.tasks.validate-order.output.orderId }"
email: "{ $.args.order.email }"
EOF
Performance Tuning
# Increase environment pool size for high-traffic functions
fission environment update \
--name python \
--poolsize 5 \
--mincpu 100 \
--maxcpu 500 \
--minmemory 128 \
--maxmemory 1024
# Configure function-level scaling
fission function update \
--name api-handler \
--minscale 2 \
--maxscale 20 \
--targetcpu 60 # Scale up when CPU > 60%
# Switch high-traffic functions to newdeploy executor (more stable at high scale)
fission function update \
--name api-handler \
--executortype newdeploy
Monitor performance:
# View function execution logs
fission function logs --name hello --follow
# Check function status and replicas
fission function pods --name api-handler
# View Prometheus metrics (if enabled)
kubectl port-forward -n fission svc/router 8888:80 &
curl http://localhost:8888/fission-function/hello
Troubleshooting
Function creation fails with build error:
# Check build logs
fission function log --name my-function
kubectl logs -n fission-builder -l buildEnvName=python --follow
# List all builder pods
kubectl get pods -n fission-builder
Cold start still occurring despite pool:
# Check pool is warmed (pods should be Running before requests arrive)
kubectl get pods -n fission | grep pool-python
# Increase pool size
fission environment update --name python --poolsize 5
# Check resource limits aren't preventing pod scheduling
kubectl describe pod <pool-pod> -n fission
HTTP trigger returning 404:
# Verify trigger exists
fission httptrigger list
# Check router logs
kubectl logs -n fission -l svc=router
# Test function directly (bypassing trigger)
fission function test --name hello
Timer trigger not firing:
# List timer triggers and their status
fission timetrigger list
# Check timer component logs
kubectl logs -n fission -l svc=timer -f
# Validate cron expression
# Use: https://crontab.guru/ for validation
Conclusion
Fission's core advantage over other Kubernetes serverless frameworks is its warm pool architecture—language runtimes pre-loaded in running pods eliminate the container scheduling delay on cold starts. Deploy latency-sensitive functions with poolmgr executor for sub-100ms cold starts, and switch to newdeploy executor for functions requiring predictable scaling. Timer triggers make Fission a clean replacement for cron jobs, while NATS message queue triggers enable event-driven processing. Increase pool sizes based on your traffic patterns to keep cold start rates near zero.


