Skip to content

Commit

Permalink
Update example (#1009)
Browse files Browse the repository at this point in the history
  • Loading branch information
halamix2 authored Jun 10, 2024
1 parent 0188c5b commit b3dda91
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 163 deletions.
24 changes: 19 additions & 5 deletions examples/custom-serverless-runtime-image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
FROM python:3.10-bullseye
FROM python:3.12.3-slim-bookworm

COPY kubeless/requirements.txt /kubeless/requirements.txt
RUN pip install -r /kubeless/requirements.txt
RUN pip install protobuf==3.20.* --force-reinstall
# Serverless
LABEL source = [email protected]:kyma-project/serverless.git

COPY kubeless/ /
# build-base and linux-headers are needed to install all requirements
RUN apt update && apt install -y build-essential linux-headers-generic && \
rm -rf /var/lib/apt/lists/*

COPY ./lib/requirements.txt /kubeless/requirements.txt
RUN chmod 644 /kubeless/requirements.txt

RUN pip install --no-cache-dir -r /kubeless/requirements.txt

COPY ./lib /
RUN chmod -R 755 /lib
COPY ./kubeless.py /
RUN chmod 644 /kubeless.py

WORKDIR /

USER 1000
# Tracing propagators are configured based on OTEL_PROPAGATORS env variable https://opentelemetry.io/docs/instrumentation/python/manual/#using-environment-variables
ENV OTEL_PROPAGATORS=tracecontext,baggage,b3multi
ENV OTEL_PYTHON_REQUESTS_EXCLUDED_URLS="healthz,favicon.ico,metrics"

CMD ["python", "/kubeless.py"]
2 changes: 1 addition & 1 deletion examples/custom-serverless-runtime-image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Overview

This example shows how to create own custom runtime for a Serverless Function based on the Python runtime and the `debian:bullseye-slim` base image to provide support for glibc.
This example shows how to create own custom runtime for a Serverless Function based on the Python 3.12 runtime and the `python:3.12.3--slim-bookworm` base image to provide support for glibc.

## Prerequisites

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,17 @@
import importlib
import os
import queue
import sys
import threading

import bottle
import prometheus_client as prom
import sys

import tracing
from ce import Event
from tracing import set_req_context


def create_service_name(pod_name: str, service_namespace: str) -> str:
# remove generated pods suffix ( two last sections )
deployment_name = '-'.join(pod_name.split('-')[0:pod_name.count('-') - 1])
return '.'.join([deployment_name, service_namespace])


# The reason this file has an underscore prefix in its name is to avoid a
# name collision with the user-defined module.
module_name = os.getenv('MOD_NAME')
Expand All @@ -31,7 +25,8 @@ def create_service_name(pod_name: str, service_namespace: str) -> str:
print('Module cannot be named {} as current module'.format(current_mod), flush=True)
exit(2)

sys.path.append('/kubeless')
function_location = os.getenv('FUNCTION_PATH', default='/kubeless')
sys.path.append(function_location)

mod = importlib.import_module(module_name)
func_name = os.getenv('FUNC_HANDLER')
Expand All @@ -49,28 +44,30 @@ def create_service_name(pod_name: str, service_namespace: str) -> str:
app = application = bottle.app()

function_context = {
'function-name': func.__name__,
'function-name': os.getenv('FUNC_NAME'),
'namespace': os.getenv('SERVICE_NAMESPACE'),
'timeout': timeout,
'runtime': os.getenv('FUNC_RUNTIME'),
'memory-limit': os.getenv('FUNC_MEMORY_LIMIT'),
}

tracecollector_endpoint = os.getenv('TRACE_COLLECTOR_ENDPOINT')
pod_name = os.getenv('HOSTNAME')
service_namespace = os.getenv('SERVICE_NAMESPACE')
service_name = create_service_name(pod_name, service_namespace)

tracer_provider = None
# To not create several tracer providers, when the server start forking.
if __name__ == "__main__":
tracer_provider = tracing.ServerlessTracerProvider(tracecollector_endpoint, service_name)
tracer = tracing._setup_tracer()


def func_with_context(e, function_context):
ex = e.ceHeaders["extensions"]
with set_req_context(ex["request"]):
return func(e, function_context)
with tracer.start_as_current_span("userFunction"):
try:
return func(e, function_context)
except Exception as e:
return e


@app.get('/favicon.ico')
def favicon():
return bottle.HTTPResponse(status=204)

@app.get('/healthz')
def healthz():
Expand All @@ -84,14 +81,13 @@ def metrics():


@app.error(500)
def exception_handler():
def exception_handler(err):
return 'Internal server error'


@app.route('/<:re:.*>', method=['GET', 'POST', 'PATCH', 'DELETE'])
def handler():
req = bottle.request
tracer = tracer_provider.get_tracer(req)
event = Event(req, tracer)

method = req.method
Expand All @@ -103,12 +99,14 @@ def handler():
t.start()
try:
res = que.get(block=True, timeout=timeout)
if hasattr(res, 'headers') and res.headers["content-type"]:
if hasattr(res, 'headers') and 'content-type' in res.headers:
bottle.response.content_type = res.headers["content-type"]
except queue.Empty:
return bottle.HTTPError(408, "Timeout while processing the function")
else:
t.join()
if isinstance(res, Exception):
raise res
return res


Expand All @@ -120,13 +118,18 @@ def preload():
if __name__ == '__main__':
import logging
import multiprocessing as mp
from multiprocessing import util
import requestlogger

# TODO: this is workaround for: CVE-2022-42919
# More details: https://github.com/python/cpython/issues/97514
util.abstract_sockets_supported = False

mp_context = os.getenv('MP_CONTEXT', 'forkserver')

if mp_context == "fork":
raise ValueError(
'"fork" multiprocessing context is not supported because cherrypy is a '
'"fork" multiprocessing context is not supported because cheroot is a '
'multithreaded server and safely forking a multithreaded process is '
'problematic'
)
Expand Down Expand Up @@ -182,12 +185,12 @@ def preload():

bottle.run(
loggedapp,
server='cherrypy',
server='cheroot',
host='0.0.0.0',
port=func_port,
# Set this flag to True to auto-reload the server after any source files change
reloader=os.getenv('CHERRYPY_RELOADED', False),
# Number of requests that can be handled in parallel (default = 50).
numthreads=int(os.getenv('CHERRYPY_NUMTHREADS', 50)),
quiet='KYMA_BOTTLE_QUIET_OPTION_DISABLED' not in os.environ,
)
)
11 changes: 0 additions & 11 deletions examples/custom-serverless-runtime-image/kubeless/requirements.txt

This file was deleted.

92 changes: 0 additions & 92 deletions examples/custom-serverless-runtime-image/kubeless/tracing.py

This file was deleted.

Loading

0 comments on commit b3dda91

Please sign in to comment.