Nuclio Serverless Platform Installation

Nuclio is a high-performance serverless platform designed for real-time data processing and AI/ML workloads, featuring native GPU support, ultra-low latency function execution, and integrations with data platforms like Kafka, Kinesis, and Iguazio. This guide covers deploying Nuclio on Docker and Kubernetes, configuring functions, enabling GPU support, and using the dashboard.

Prerequisites

  • Ubuntu 20.04+ or CentOS/Rocky 8+ with root access
  • Docker installed (for standalone mode) or Kubernetes cluster
  • At least 4GB RAM, 2 CPUs
  • Optional: NVIDIA GPU with CUDA drivers for GPU functions
  • Optional: Kafka or Kinesis for streaming triggers

Installing Nuclio with Docker

The simplest way to run Nuclio is with Docker:

# Create a Docker network for Nuclio
docker network create nuclio

# Start the Nuclio dashboard and controller
docker run -d \
  --name nuclio-dashboard \
  --network nuclio \
  -p 8070:8070 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /tmp/nuclio-local:/opt/nuclio \
  -e NUCLIO_CHECK_FUNCTION_CONTAINERS_EXISTENCE=true \
  nuclio/dashboard:stable

# Verify it's running
docker logs nuclio-dashboard --tail 20
curl http://localhost:8070/ready

Access the dashboard:

# Open in browser
echo "Dashboard: http://YOUR_SERVER_IP:8070"

# Create a namespace in the dashboard or via CLI

Installing Nuclio on Kubernetes

# Add Nuclio Helm chart repository
helm repo add nuclio https://nuclio.github.io/nuclio/charts
helm repo update

# Create namespace
kubectl create namespace nuclio

# Create an image pull secret if using a private registry
kubectl create secret docker-registry registry-credentials \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass \
  -n nuclio

# Install Nuclio
helm install nuclio nuclio/nuclio \
  --namespace nuclio \
  --set dashboard.enabled=true \
  --set dashboard.serviceType=LoadBalancer \
  --set registry.pushPullUrl=registry.example.com/myorg \
  --set registry.defaultBaseRegistryURL=docker.io

# Check installation
kubectl get pods -n nuclio

# Get dashboard URL
kubectl get svc nuclio-dashboard -n nuclio

Using the Nuclio Dashboard

# Access dashboard
DASHBOARD_IP=$(kubectl get svc nuclio-dashboard -n nuclio -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Dashboard: http://$DASHBOARD_IP:8070"

Install the nuctl CLI:

# Download nuctl
NUCLIO_VERSION="1.13.0"
wget https://github.com/nuclio/nuclio/releases/download/${NUCLIO_VERSION}/nuctl-${NUCLIO_VERSION}-linux-amd64
chmod +x nuctl-${NUCLIO_VERSION}-linux-amd64
sudo mv nuctl-${NUCLIO_VERSION}-linux-amd64 /usr/local/bin/nuctl

# Configure nuctl to connect to the dashboard
export NUCLIO_PLATFORM=kube
export NUCLIO_NAMESPACE=nuclio

# Or for Docker mode:
export NUCLIO_PLATFORM=local

nuctl version
nuctl get functions --namespace nuclio

Creating and Deploying Functions

Python function example:

cat > /tmp/hello_nuclio.py << 'EOF'
import nuclio

def handler(context, event):
    """
    Nuclio function handler.
    context: function execution context (logger, user_data)
    event: incoming event (body, headers, method, path, etc.)
    """
    # Log using the provided logger
    context.logger.info(f"Received request: {event.method} {event.path}")
    
    # Parse request body
    body = event.body
    if isinstance(body, bytes):
        body = body.decode('utf-8')
    
    # Return response
    return nuclio.Response(
        headers={"Content-Type": "application/json"},
        body=f'{{"message": "Hello from Nuclio!", "received": "{body}"}}',
        status_code=200
    )
EOF

Deploy with nuctl:

# Deploy to Docker (local mode)
nuctl deploy hello \
  --path /tmp/hello_nuclio.py \
  --runtime python:3.9 \
  --handler hello_nuclio:handler \
  --platform local \
  --namespace nuclio

# Deploy to Kubernetes
nuctl deploy hello \
  --path /tmp/hello_nuclio.py \
  --runtime python:3.9 \
  --handler hello_nuclio:handler \
  --namespace nuclio \
  --registry registry.example.com/myorg \
  --replicas 2

# Test the function
nuctl invoke hello \
  --method POST \
  --body '{"test": "data"}' \
  --content-type "application/json" \
  --platform local

# For Kubernetes:
nuctl invoke hello \
  --method GET \
  --namespace nuclio

Function with dependencies:

mkdir -p /tmp/my-function

cat > /tmp/my-function/function.py << 'EOF'
import requests
import nuclio
import json

def handler(context, event):
    url = event.body.decode('utf-8') if event.body else "https://api.github.com"
    
    try:
        resp = requests.get(url, timeout=10)
        return nuclio.Response(
            headers={"Content-Type": "application/json"},
            body=json.dumps({
                "url": url,
                "status": resp.status_code,
                "content_length": len(resp.content)
            }),
            status_code=200
        )
    except Exception as e:
        return nuclio.Response(
            body=str(e),
            status_code=500
        )
EOF

cat > /tmp/my-function/requirements.txt << 'EOF'
requests==2.31.0
nuclio-sdk==0.3.0
EOF

# Deploy with requirements
nuctl deploy http-checker \
  --path /tmp/my-function \
  --runtime python:3.9 \
  --handler function:handler \
  --platform local \
  --namespace nuclio

Function Configuration and Triggers

Nuclio function YAML specification:

cat > /tmp/my-function/function.yaml << 'EOF'
apiVersion: nuclio.io/v1beta1
kind: NuclioFunction
metadata:
  name: data-processor
  namespace: nuclio
spec:
  description: "Real-time data processing function"
  runtime: python:3.9
  handler: handler:main
  
  # Resources
  resources:
    requests:
      cpu: "100m"
      memory: "128Mi"
    limits:
      cpu: "1"
      memory: "512Mi"
  
  # Scaling
  minReplicas: 1
  maxReplicas: 20
  targetCPU: 70
  
  # Environment variables
  env:
  - name: DB_HOST
    value: postgres.default.svc.cluster.local
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-secret
        key: password
  
  # Triggers
  triggers:
    http:
      kind: http
      attributes:
        port: 8080
    kafka-input:
      kind: kafka-cluster
      attributes:
        brokers:
        - kafka:9092
        topics:
        - name: input-events
        consumerGroup: nuclio-processor
        initialOffset: latest
  
  # Build configuration
  build:
    commands:
    - pip install -r requirements.txt
    image: nuclio/handler-builder-python-onbuild:latest
EOF

Apply the function configuration:

kubectl apply -f /tmp/my-function/function.yaml
kubectl get nucliofunctions -n nuclio

GPU Support for AI/ML Functions

# Verify NVIDIA GPU is available
nvidia-smi
kubectl describe node | grep -i gpu

# Enable NVIDIA device plugin for Kubernetes
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.0/nvidia-device-plugin.yml

# Verify GPU is allocatable
kubectl get nodes -o json | jq '.items[].status.allocatable | {"nvidia.gpu": .["nvidia.com/gpu"]}'

Deploy a GPU-enabled function:

cat > /tmp/gpu-function/function.yaml << 'EOF'
apiVersion: nuclio.io/v1beta1
kind: NuclioFunction
metadata:
  name: ml-inference
  namespace: nuclio
spec:
  runtime: python:3.9
  handler: inference:handler
  
  # Request GPU resources
  resources:
    requests:
      nvidia.com/gpu: "1"
    limits:
      nvidia.com/gpu: "1"
      memory: "8Gi"
      cpu: "4"
  
  # Use CUDA-enabled base image
  build:
    baseImage: "nvidia/cuda:11.8-runtime-ubuntu20.04"
    commands:
    - apt-get update && apt-get install -y python3 python3-pip
    - pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

  env:
  - name: CUDA_VISIBLE_DEVICES
    value: "0"
EOF
cat > /tmp/gpu-function/inference.py << 'EOF'
import torch
import nuclio
import json
import base64
from io import BytesIO

# Load model at startup (not in handler to avoid cold start on every request)
_model = None

def init_context(context):
    global _model
    context.logger.info("Loading ML model...")
    # Load your model here
    # _model = torch.load('/opt/models/my_model.pt')
    context.logger.info(f"GPU available: {torch.cuda.is_available()}")
    context.logger.info("Model loaded successfully")

def handler(context, event):
    global _model
    
    if _model is None:
        return nuclio.Response(body="Model not loaded", status_code=503)
    
    # Process inference request
    try:
        data = json.loads(event.body)
        # Run inference on GPU
        with torch.no_grad():
            # result = _model(torch.tensor(data['input']).cuda())
            result = {"prediction": [0.85, 0.15], "device": str(torch.device("cuda" if torch.cuda.is_available() else "cpu"))}
        
        return nuclio.Response(
            headers={"Content-Type": "application/json"},
            body=json.dumps(result),
            status_code=200
        )
    except Exception as e:
        context.logger.error(f"Inference error: {e}")
        return nuclio.Response(body=str(e), status_code=500)
EOF

Real-Time Data Processing

Kafka-triggered function for stream processing:

cat > /tmp/stream-processor.py << 'EOF'
import json
import nuclio

def handler(context, event):
    """Process Kafka messages in real time."""
    
    # Kafka event metadata
    partition = event.trigger.annotation.get("nuclio.io/kafka-partition", "unknown")
    offset = event.trigger.annotation.get("nuclio.io/kafka-offset", "unknown")
    
    context.logger.debug(f"Processing message from partition={partition} offset={offset}")
    
    try:
        message = json.loads(event.body)
        
        # Process the message
        processed = {
            "original": message,
            "processed_at": __import__("datetime").datetime.utcnow().isoformat(),
            "processed": True
        }
        
        # Return processed data (sent to output topic if configured)
        return nuclio.Response(
            headers={"Content-Type": "application/json"},
            body=json.dumps(processed),
            status_code=200
        )
    except Exception as e:
        context.logger.error(f"Processing error: {e}")
        # Returning non-200 causes message to be retried
        return nuclio.Response(body=str(e), status_code=500)
EOF

# Deploy with Kafka trigger
nuctl deploy stream-processor \
  --path /tmp/stream-processor.py \
  --runtime python:3.9 \
  --handler stream-processor:handler \
  --namespace nuclio \
  --trigger '{"kafka-in":{"kind":"kafka-cluster","attributes":{"topics":[{"name":"sensor-data"}],"brokers":["kafka:9092"],"consumerGroup":"nuclio-processor"}}}'

Monitoring and Performance

# View function metrics
nuctl get function data-processor --namespace nuclio -o json | \
  python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps(d['status'], indent=2))"

# Get function logs
nuctl get function data-processor --namespace nuclio
kubectl logs -n nuclio -l nuclio.io/function-name=data-processor -f

# Check function replicas
kubectl get pods -n nuclio -l nuclio.io/function-name=data-processor

# Port-forward to Prometheus metrics
kubectl port-forward -n nuclio svc/nuclio-dashboard 8070:8070 &
# Visit: http://localhost:8070

Configure Prometheus scraping:

# Nuclio exposes Prometheus metrics at /metrics on each function pod
# Add to your Prometheus config:
cat >> /etc/prometheus/prometheus.yml << 'EOF'
  - job_name: 'nuclio-functions'
    kubernetes_sd_configs:
    - role: pod
      namespaces:
        names: ['nuclio']
    relabel_configs:
    - source_labels: [__meta_kubernetes_pod_label_nuclio_io_function_name]
      action: keep
      regex: .+
    - source_labels: [__address__]
      target_label: __address__
      regex: '([^:]+):.*'
      replacement: '${1}:8090'
EOF

Troubleshooting

Function deployment fails with image build error:

# Check build logs
nuctl get function my-function -n nuclio -o json | \
  python3 -c "import json,sys; d=json.load(sys.stdin); print(d['status'].get('message',''))"

kubectl logs -n nuclio -l nuclio.io/app=builder -f

GPU function not using GPU:

# Verify GPU is requested and available
kubectl get pods -n nuclio -l nuclio.io/function-name=ml-inference -o yaml | grep -A5 resources

# Inside the function pod
kubectl exec -n nuclio <pod-name> -- nvidia-smi
kubectl exec -n nuclio <pod-name> -- python3 -c "import torch; print(torch.cuda.is_available())"

Kafka trigger not consuming messages:

# Check trigger configuration
nuctl get function stream-processor -n nuclio -o json | \
  python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps(d['spec']['triggers'], indent=2))"

# Verify Kafka connectivity from the function pod
kubectl exec -n nuclio <pod> -- nc -zv kafka 9092

Function scaling not working:

# Check HPA
kubectl get hpa -n nuclio
kubectl describe hpa -n nuclio nuclio-data-processor

# Ensure metrics server is installed
kubectl top pods -n nuclio

Conclusion

Nuclio's strength lies in its high-performance architecture optimized for real-time data processing and AI/ML inference—native GPU support, ultra-low latency through container pre-warming, and direct integration with streaming platforms like Kafka make it the right choice when standard serverless latency is unacceptable. Deploy via the dashboard or nuctl CLI, define Kafka and HTTP triggers in function YAML specifications, and use the init_context function to load ML models once at startup rather than on every invocation to eliminate model loading overhead.