OpenFaaS Installation for Serverless Functions
OpenFaaS (Functions as a Service) is an open-source framework for deploying serverless functions on Linux using Docker or Kubernetes, handling auto-scaling, async invocation, and observability. This guide covers installing OpenFaaS on Docker Swarm and Kubernetes, creating function templates, deploying functions, configuring auto-scaling, and monitoring your serverless workloads.
Prerequisites
- Ubuntu 20.04+ or CentOS/Rocky 8+ with at least 2GB RAM
- Docker installed:
curl -fsSL https://get.docker.com | bash - Either Docker Swarm (single/multi-node) or Kubernetes cluster
- Access to a container registry (Docker Hub, or self-hosted)
Installing OpenFaaS on Docker Swarm
# Initialize Docker Swarm (if not already done)
docker swarm init --advertise-addr $(curl -s ifconfig.me)
# Verify swarm is active
docker info | grep Swarm
docker node ls
Deploy OpenFaaS using the official stack:
# Clone OpenFaaS deployment repo
git clone https://github.com/openfaas/faas /tmp/faas
cd /tmp/faas
# Create the docker-compose stack deployment
./deploy_stack.sh --no-auth
# For production with authentication:
# ./deploy_stack.sh
# Verify all services are running
docker service ls
# Should show: func_gateway, func_prometheus, func_alertmanager, func_nats, etc.
# Check gateway is responding
curl http://localhost:8080/healthz
Deploy with authentication (recommended for production):
# Generate credentials
export BASIC_AUTH_PASSWORD=$(head -c 16 /dev/urandom | shasum | cut -d " " -f1)
echo "Password: $BASIC_AUTH_PASSWORD"
# Create secrets
echo -n "admin" | docker secret create basic-auth-user -
echo -n "$BASIC_AUTH_PASSWORD" | docker secret create basic-auth-password -
# Deploy with auth
cd /tmp/faas
docker stack deploy func --compose-file docker-compose.yml
Access the OpenFaaS web UI:
# Gateway runs on port 8080
# Open http://YOUR_SERVER_IP:8080/ui/
# Login with faas-cli
echo -n "$BASIC_AUTH_PASSWORD" | faas-cli login \
--username admin \
--password-stdin \
--gateway http://localhost:8080
Installing faas-cli
# Install faas-cli
curl -sSL https://cli.openfaas.com | sudo sh
# Verify
faas-cli version
# Login to gateway
export OPENFAAS_URL=http://localhost:8080
faas-cli login --username admin --password "$BASIC_AUTH_PASSWORD"
Creating and Deploying Functions
# List available function templates
faas-cli template store list
# Pull commonly used templates
faas-cli template store pull python3
faas-cli template store pull node18
faas-cli template store pull golang-middleware
faas-cli template store pull java11
# Create a new function from template
mkdir -p /opt/functions/my-functions
cd /opt/functions/my-functions
faas-cli new hello-world --lang python3
Edit the function handler:
cat > /opt/functions/my-functions/hello-world/handler.py << 'EOF'
import json
def handle(req):
"""
OpenFaaS function handler.
req: HTTP request body as string
returns: response body
"""
try:
data = json.loads(req) if req else {}
name = data.get("name", "World")
return json.dumps({
"message": f"Hello, {name}!",
"status": "success"
})
except json.JSONDecodeError:
return json.dumps({
"message": f"Hello, {req or 'World'}!",
"status": "success"
})
EOF
Configure the function in hello-world.yml:
version: 1.0
provider:
name: openfaas
gateway: http://localhost:8080
functions:
hello-world:
lang: python3
handler: ./hello-world
image: yourdockeruser/hello-world:latest
environment:
write_debug: true
limits:
memory: 128m
cpu: 0.5
requests:
memory: 64m
cpu: 0.1
labels:
com.openfaas.scale.min: "1"
com.openfaas.scale.max: "10"
com.openfaas.scale.factor: "5"
Build, push, and deploy:
cd /opt/functions/my-functions
# Build the function container
faas-cli build -f hello-world.yml
# Push to registry (Docker Hub)
faas-cli push -f hello-world.yml
# Deploy to OpenFaaS
faas-cli deploy -f hello-world.yml
# Or do all three at once
faas-cli up -f hello-world.yml
# Test the function
echo '{"name": "OpenFaaS"}' | faas-cli invoke hello-world
# Or via curl
curl -X POST http://localhost:8080/function/hello-world \
-H "Content-Type: application/json" \
-d '{"name": "OpenFaaS"}'
Function Templates
Create a custom template for your organization's standards:
# Node.js function with dependencies
faas-cli new image-processor --lang node18
cd image-processor
# Add npm dependencies
cat > package.json << 'EOF'
{
"name": "image-processor",
"version": "1.0.0",
"description": "OpenFaaS image processing function",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"sharp": "^0.33.0"
}
}
EOF
cat > handler.js << 'EOF'
'use strict';
const sharp = require('sharp');
module.exports = async (event, context) => {
try {
if (!event.body) {
return context
.status(400)
.fail('No image data provided');
}
// Process image
const imageBuffer = Buffer.from(event.body, 'base64');
const processed = await sharp(imageBuffer)
.resize(800, 600, { fit: 'inside' })
.webp({ quality: 80 })
.toBuffer();
return context
.status(200)
.headers({ 'Content-Type': 'image/webp' })
.succeed(processed);
} catch (err) {
console.error(err);
return context.status(500).fail(err.message);
}
};
EOF
Installing OpenFaaS on Kubernetes
# Add OpenFaaS Helm chart repo
helm repo add openfaas https://openfaas.github.io/faas-netes/
helm repo update
# Create namespaces
kubectl create namespace openfaas
kubectl create namespace openfaas-fn
# Create basic auth credentials
export BASIC_AUTH_PASSWORD=$(head -c 16 /dev/urandom | shasum | cut -d " " -f1)
kubectl -n openfaas create secret generic basic-auth \
--from-literal=basic-auth-user=admin \
--from-literal=basic-auth-password="$BASIC_AUTH_PASSWORD"
# Install OpenFaaS
helm upgrade --install openfaas openfaas/openfaas \
--namespace openfaas \
--set functionNamespace=openfaas-fn \
--set basic_auth=true \
--set generateBasicAuth=false \
--set serviceType=NodePort
# Check deployment
kubectl get pods -n openfaas
# Get gateway URL
kubectl get svc -n openfaas gateway-external -o wide
export OPENFAAS_URL=http://$(kubectl get svc -n openfaas gateway-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):8080
# Login
echo -n "$BASIC_AUTH_PASSWORD" | faas-cli login \
--username admin \
--password-stdin
Deploy function on Kubernetes:
# Update function YAML for Kubernetes
cat > hello-world.yml << 'EOF'
version: 1.0
provider:
name: openfaas
gateway: http://YOUR_GATEWAY:8080
functions:
hello-world:
lang: python3
handler: ./hello-world
image: yourdockeruser/hello-world:latest
namespace: openfaas-fn
environment:
write_debug: "true"
annotations:
topic: "hello-topic"
EOF
faas-cli deploy -f hello-world.yml
Auto-Scaling Configuration
OpenFaaS uses Prometheus alerts to trigger scaling:
# Configure scale-to-zero (functions scale to 0 when idle)
# Add labels to function deployment:
cat >> hello-world.yml << 'EOF'
labels:
com.openfaas.scale.min: "0" # Scale to zero when idle
com.openfaas.scale.max: "20" # Max instances
com.openfaas.scale.factor: "10" # Scale by this % per trigger
com.openfaas.scale.zero: "true" # Enable scale to zero
EOF
faas-cli deploy -f hello-world.yml
Configure scale-to-zero inactivity timeout:
# In Docker Swarm, update the faas-idler service
docker service update \
--env-add inactivity_duration=5m \
func_faas-idler
# In Kubernetes, update the helm deployment
helm upgrade openfaas openfaas/openfaas \
--namespace openfaas \
--set faasIdler.inactivityDuration=5m \
--reuse-values
Async Function Invocation
# Invoke a function asynchronously (non-blocking)
curl -X POST http://localhost:8080/async-function/hello-world \
-H "Content-Type: application/json" \
-H "X-Callback-Url: http://callback-service:8080/results" \
-d '{"name": "async test"}'
# The function runs in the background
# OpenFaaS uses NATS for async queue
# Check NATS queue status
curl http://localhost:8080/system/info | python3 -m json.tool
Monitoring OpenFaaS
# Built-in Prometheus metrics at port 9090
curl http://localhost:9090/metrics | grep openfaas
# Function invocation count
curl 'http://localhost:9090/api/v1/query?query=gateway_function_invocation_total'
# Function duration histogram
curl 'http://localhost:9090/api/v1/query?query=gateway_functions_seconds_bucket'
# Active replicas per function
faas-cli describe hello-world
# List deployed functions with replica count
faas-cli list --verbose
# Scale a function manually
faas-cli scale hello-world --replicas=3
Access the built-in Grafana dashboard (if deployed):
# Deploy Grafana with OpenFaaS
docker service create \
--name func_grafana \
--network func_functions \
--publish 3000:3000 \
-e GF_AUTH_ANONYMOUS_ENABLED=true \
grafana/grafana:latest
Troubleshooting
Function times out on first cold invocation:
# Increase timeout in function YAML
cat >> hello-world.yml << 'EOF'
environment:
exec_timeout: "30s"
write_timeout: "30s"
read_timeout: "30s"
EOF
faas-cli deploy -f hello-world.yml
Function container fails to start:
# Check function logs
faas-cli logs hello-world
# For Kubernetes
kubectl logs -n openfaas-fn deployment/hello-world -f
"Unable to resolve function" error:
# List deployed functions
faas-cli list
# Check gateway connectivity
faas-cli version --verbose
curl http://localhost:8080/healthz
Docker Swarm function replicas at 0:
docker service ls | grep hello-world
docker service ps func_hello-world
docker service logs func_hello-world
Conclusion
OpenFaaS provides a developer-friendly serverless platform that runs on your own infrastructure, avoiding cloud vendor lock-in. Deploy it on Docker Swarm for simplicity or Kubernetes for production scale. The faas-cli tool handles the build/push/deploy workflow efficiently, and built-in Prometheus metrics make it easy to monitor function invocations and response times. Enable scale-to-zero for infrequently used functions to conserve resources, and use async invocation with NATS for workloads that don't require an immediate response.


