Deploy a Python App using OpenFaaS: Serverless Functions Made Simple

Deploy a Python App using OpenFaaS: Serverless Functions Made Simple

Learn how to deploy serverless Python functions using OpenFaaS. Build, deploy, and scale your functions with Docker containers and focus on code, not infrastructure.

Saurabh
October 10, 2018
6 min read

Deploy a Python App using OpenFaaS: Serverless Functions Made Simple

OpenFaaS (Functions as a Service) provides a powerful framework for building serverless functions on top of containers. With OpenFaaS, developers can focus on writing code rather than managing servers and deployments.

What is OpenFaaS?

OpenFaaS transforms any container into a serverless function. Key benefits include:

  • Pay-per-execution: Only pay for actual computation time
  • Auto-scaling: Functions scale based on demand
  • Language agnostic: Support for multiple programming languages
  • Docker-based: Runs on Docker Swarm or Kubernetes

Note: If you haven't installed OpenFaaS yet, follow the installation guide before proceeding.

Building Your First Python Function

Let's create a simple Python function that calculates the sum of numbers.

Step 1: Project Setup

Create a new directory for your project:

mkdir myapp && cd myapp

Download the official templates:

faas-cli template pull

Step 2: Create Function Scaffold

Use the FaaS CLI to create a new Python function:

faas-cli new --lang python3 elements-sum --prefix="<your-docker-username>"

This creates the following structure:

./elements-sum.yml          # Function configuration
./elements-sum/
├── handler.py              # Your function code
└── requirements.txt        # Python dependencies

Step 3: Implement the Function Logic

The default handler.py contains a simple echo function:

def handle(req):
    """handle a request to the function
    Args:
        req (str): request body
    """
    return req

Let's modify it to calculate the sum of comma-separated numbers:

def handle(req):
    """Calculate sum of comma-separated numbers
    Args:
        req (str): comma-separated numbers (e.g., "10,20,30")
    Returns:
        str: sum of the numbers
    """
    try:
        # Parse comma-separated values
        numbers = [int(x.strip()) for x in req.split(",")]

        # Calculate sum
        total = sum(numbers)

        return str(total)
    except ValueError:
        return "Error: Please provide valid comma-separated numbers"
    except Exception as e:
        return f"Error: {str(e)}"

Step 4: Add Dependencies (Optional)

If your function requires additional Python packages, add them to requirements.txt:

# Add any required packages here
# requests==2.28.1
# numpy==1.21.0

Deployment

Build, Push, and Deploy

Deploy your function with a single command:

faas-cli up -f elements-sum.yml

This command:

  1. Builds the Docker image
  2. Pushes it to Docker Hub
  3. Deploys the function to OpenFaaS

Tip: If you encounter authentication errors, login to Docker Hub first: docker login

Verify Deployment

Once deployed, your function will be available at the OpenFaaS UI: http://127.0.0.1:8080/ui/

Testing Your Function

Using the Web UI

  1. Navigate to the OpenFaaS UI
  2. Select your elements-sum function
  3. Enter test input: 10,20,30,40,50
  4. Click Invoke
  5. Expected output: 150

Using the CLI

Test your function from the command line:

echo "10,20,30,40,50" | faas-cli invoke elements-sum

Using cURL

Make HTTP requests directly:

curl -X POST http://127.0.0.1:8080/function/elements-sum \
  -H "Content-Type: text/plain" \
  -d "10,20,30,40,50"

Advanced Function Features

Environment Variables

Add environment variables to your function configuration:

# elements-sum.yml
version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:8080

functions:
  elements-sum:
    lang: python3
    handler: ./elements-sum
    image: <your-username>/elements-sum:latest
    environment:
      DEBUG: "true"
      MAX_NUMBERS: "100"

Function Annotations

Configure resource limits and scaling:

functions:
  elements-sum:
    # ... other config
    annotations:
      com.openfaas.scale.min: "1"
      com.openfaas.scale.max: "10"
      com.openfaas.scale.factor: "20"
    limits:
      memory: "128Mi"
      cpu: "100m"
    requests:
      memory: "64Mi"
      cpu: "50m"

Best Practices

1. Error Handling

Always implement proper error handling:

def handle(req):
    try:
        # Your function logic
        result = process_request(req)
        return result
    except ValidationError as e:
        return f"Validation Error: {str(e)}"
    except Exception as e:
        # Log error for debugging
        print(f"Unexpected error: {str(e)}")
        return "Internal Server Error"

2. Input Validation

Validate input data before processing:

import json

def handle(req):
    try:
        # Parse JSON input
        data = json.loads(req)

        # Validate required fields
        if 'numbers' not in data:
            return json.dumps({"error": "Missing 'numbers' field"})

        # Process valid input
        numbers = data['numbers']
        result = sum(numbers)

        return json.dumps({"sum": result})
    except json.JSONDecodeError:
        return json.dumps({"error": "Invalid JSON format"})

3. Performance Optimization

  • Keep functions lightweight and focused
  • Minimize cold start times
  • Use connection pooling for databases
  • Cache frequently used data

Monitoring and Logging

Function Metrics

OpenFaaS provides built-in metrics for:

  • Invocation count
  • Response time
  • Error rate
  • Replica count

Custom Logging

Add structured logging to your functions:

import json
import sys
from datetime import datetime

def log(level, message, **kwargs):
    log_entry = {
        "timestamp": datetime.utcnow().isoformat(),
        "level": level,
        "message": message,
        **kwargs
    }
    print(json.dumps(log_entry), file=sys.stderr)

def handle(req):
    log("INFO", "Function invoked", input_length=len(req))

    try:
        result = process_request(req)
        log("INFO", "Function completed successfully")
        return result
    except Exception as e:
        log("ERROR", "Function failed", error=str(e))
        raise

Conclusion

OpenFaaS provides an excellent platform for deploying serverless Python functions. With its Docker-based approach, you get:

  • Flexibility: Use any Python libraries
  • Portability: Run anywhere Docker runs
  • Scalability: Auto-scale based on demand
  • Simplicity: Focus on code, not infrastructure

Start building your serverless functions today and experience the power of FaaS architecture!

Next Steps

  • Explore more OpenFaaS templates
  • Integrate with databases and external APIs
  • Set up CI/CD pipelines for function deployment
  • Monitor function performance in production

Written by

Saurabh

Related Articles

Enjoyed this article?

Check out more of my writing on frontend development and web technologies