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
  • kubectl configured 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.