Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Python Runtime

sebgoa edited this page Nov 22, 2016 · 5 revisions

Here is a toy python function called hello.py that we want to create:

import json

def handler():
    return "hello world"

We generate a configmap, with the naming convention <module_name>.<function_handler>:

kubectl create configmap hello.handler --from-file=hello.py

With AWS Lambda, the lambda is created like this:

aws lambda create-function \
...
--function-name HelloPython \
...
--handler hello_python.my_handler \
--runtime python2.7

This roughly equates to a custome resource that the user creates (via yet to be written CLI) will generate the following:

apiVersion: lambda.example.com/v1
kind: lambda
metadata:
  name: HelloPython
spec:
  runtime: python2.7
  handler: hello.handler
  lambda: |
    import json

    def handler():
        return "hello world"

The controller will detect the custom resource and populate the following configmap:

$ kubectl get configmap hello.handler -o yaml
apiVersion: v1
data:
  hello.py: |
    import json

    def handler():
        return "hello world"
kind: ConfigMap

Now to inject this into a HTTP runtime (a wrapper). We use the bottle WSGI micro framework, we could use flask as well. The code of the runtime is:

#!/usr/bin/env python

import sys
import os
import imp

from bottle import route, run, template

mod_name = os.getenv('MOD_NAME')
func_handler = os.getenv('FUNC_HANDLER')

mod_path = '/kubeless/' + mod_name + '.py'

try:
    mod = imp.load_source('lambda', mod_path)
except ImportError:
    print("No valid module found for the name: lambda, Failed to import module")

@route('/')
def handler():
    return getattr(mod, func_handler)()

run(host='0.0.0.0', port=8080)

Note that the module name (aka hello) and the function handler name (aka handler) are read as environment variables. We will need to define those in our deployment.

We can create a Docker image with:

FROM python:2.7.11-alpine
RUN apk add --no-cache python py-pip git
RUN pip install --upgrade pip
RUN pip install bottle
ADD kubeless.py /
CMD ["python", "/kubeless.py"]

And a Kubernetes deployment will look like this:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: lambda-deployment
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: lambda
    spec:
      containers:
      - name: lambda
        image: runseb/kubeless:0.0.5
        ports:
        - containerPort: 8080
        env:
        - name: FUNC_HANDLER
          value: "handler"
        - name: MOD_NAME
          value: "hello"
        volumeMounts:
        - name: lambda
          mountPath: /kubeless
      volumes:
      - name: lambda
        configMap:
          name: hello.handler

Note that we set the environment variables and the name of the config map. This will be generated by the kubeless controller on the fly.

You create the deployment and then you expose the service:

kubectl create -f lambda.yaml
kubectl expose deployment lambda-deployment --port=8080 --type=NodePort

And you can curl your function.

Clone this wiki locally