Skip to content

Commit 4b6a15d

Browse files
Jeff Lowreyalexellis
Jeff Lowrey
authored andcommitted
Create debian templates for the python 3 flask templates.
The current python3-flask templates use the Alpine base python image. Precompiled wheels for many important python libraries are not available for Alpine, but are easily available for Debian. Using Debian makes it much simpler and easier to use python packages like Numpy or Pillow. Updated existing Alpine Docker files to include comments. The template yaml file for the python-http-debian was modified to remove unneeded libraries. Both docker files were changed to force python 3.7. Gevent 1.4 is incompatible with Python 3.8, and the rest of the docker files use python 3.7. This has been tested with a bare bones basic function and builds, runs, and executes properly. Change listening address for WSGI server. Update the listening address for the WSGI server to use 0.0.0.0 instead of ''. This should resolve errors about Address family not supported by protocol (Python OSError Errno 97. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <[email protected]> Signed-off-by: Jeff Lowrey <[email protected]>
1 parent e2e2e9e commit 4b6a15d

File tree

15 files changed

+242
-1
lines changed

15 files changed

+242
-1
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
FROM openfaas/of-watchdog:0.7.2 as watchdog
2+
FROM python:3.7-slim-buster
3+
4+
COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
5+
RUN chmod +x /usr/bin/fwatchdog
6+
7+
ARG ADDITIONAL_PACKAGE
8+
# Alternatively use ADD https:// (which will not be cached by Docker builder)
9+
10+
RUN apt-get -qy update && apt-get -qy install gcc make ${ADDITIONAL_PACKAGE}
11+
12+
# Add non root user
13+
RUN addgroup --system app && adduser app --system --ingroup app
14+
RUN chown app /home/app
15+
16+
USER app
17+
18+
ENV PATH=$PATH:/home/app/.local/bin
19+
20+
WORKDIR /home/app/
21+
22+
COPY index.py .
23+
COPY requirements.txt .
24+
25+
USER root
26+
RUN pip install -r requirements.txt
27+
28+
#build function directory and install user specified componenets.
29+
USER app
30+
31+
RUN mkdir -p function
32+
RUN touch ./function/__init__.py
33+
WORKDIR /home/app/function/
34+
COPY function/requirements.txt .
35+
RUN pip install --user -r requirements.txt
36+
37+
WORKDIR /home/app/
38+
39+
#install function code
40+
USER root
41+
42+
COPY function function
43+
RUN chown -R app:app ./
44+
45+
#configure WSGI server and healthcheck
46+
USER app
47+
48+
ENV fprocess="python index.py"
49+
50+
ENV cgi_headers="true"
51+
ENV mode="http"
52+
ENV upstream_url="http://127.0.0.1:5000"
53+
54+
HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1
55+
56+
CMD ["fwatchdog"]

template/python3-flask-debian/function/__init__.py

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def handle(req):
2+
"""handle a request to the function
3+
Args:
4+
req (str): request body
5+
"""
6+
7+
return req

template/python3-flask-debian/function/requirements.txt

Whitespace-only changes.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) Alex Ellis 2017. All rights reserved.
2+
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
from flask import Flask, request
5+
from function import handler
6+
#from gevent.wsgi import WSGIServer
7+
from gevent.pywsgi import WSGIServer
8+
9+
app = Flask(__name__)
10+
11+
@app.before_request
12+
def fix_transfer_encoding():
13+
"""
14+
Sets the "wsgi.input_terminated" environment flag, thus enabling
15+
Werkzeug to pass chunked requests as streams. The gunicorn server
16+
should set this, but it's not yet been implemented.
17+
"""
18+
19+
transfer_encoding = request.headers.get("Transfer-Encoding", None)
20+
if transfer_encoding == u"chunked":
21+
request.environ["wsgi.input_terminated"] = True
22+
23+
@app.route("/", defaults={"path": ""}, methods=["POST", "GET"])
24+
@app.route("/<path:path>", methods=["POST", "GET"])
25+
def main_route(path):
26+
ret = handler.handle(request.get_data())
27+
return ret
28+
29+
if __name__ == '__main__':
30+
31+
http_server = WSGIServer(('0.0.0.0', 5000), app)
32+
http_server.serve_forever()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
flask
2+
gevent
3+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
language: python3-flask-debian
2+
fprocess: python index.py

template/python3-flask/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
55
RUN chmod +x /usr/bin/fwatchdog
66

77
ARG ADDITIONAL_PACKAGE
8+
# Alternatively use ADD https:// (which will not be cached by Docker builder)
9+
810
RUN apk --no-cache add musl-dev gcc make ${ADDITIONAL_PACKAGE}
911

1012
# Add non root user
@@ -19,8 +21,11 @@ WORKDIR /home/app/
1921

2022
COPY index.py .
2123
COPY requirements.txt .
24+
2225
USER root
2326
RUN pip install -r requirements.txt
27+
28+
#build function directory and install user specified componenets.
2429
USER app
2530

2631
RUN mkdir -p function
@@ -31,9 +36,13 @@ RUN pip install --user -r requirements.txt
3136

3237
WORKDIR /home/app/
3338

39+
#install function code
3440
USER root
41+
3542
COPY function function
3643
RUN chown -R app:app ./
44+
45+
#configure WSGI server and healthcheck
3746
USER app
3847

3948
ENV fprocess="python index.py"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
FROM openfaas/of-watchdog:0.7.2 as watchdog
2+
FROM python:3.7-slim-buster
3+
4+
COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
5+
RUN chmod +x /usr/bin/fwatchdog
6+
7+
ARG ADDITIONAL_PACKAGE
8+
# Alternatively use ADD https:// (which will not be cached by Docker builder)
9+
10+
RUN apt-get -qy update && apt-get -qy install ${ADDITIONAL_PACKAGE}
11+
12+
# Add non root user
13+
RUN addgroup --system app && adduser app --system --ingroup app
14+
RUN chown app /home/app
15+
16+
USER app
17+
18+
ENV PATH=$PATH:/home/app/.local/bin
19+
20+
WORKDIR /home/app/
21+
22+
COPY index.py .
23+
COPY requirements.txt .
24+
USER root
25+
RUN pip install -r requirements.txt
26+
USER app
27+
28+
RUN mkdir -p function
29+
RUN touch ./function/__init__.py
30+
WORKDIR /home/app/function/
31+
COPY function/requirements.txt .
32+
RUN pip install --user -r requirements.txt
33+
34+
WORKDIR /home/app/
35+
36+
USER root
37+
COPY function function
38+
RUN chown -R app:app ./
39+
USER app
40+
41+
# Set up of-watchdog for HTTP mode
42+
ENV fprocess="python index.py"
43+
ENV cgi_headers="true"
44+
ENV mode="http"
45+
ENV upstream_url="http://127.0.0.1:5000"
46+
47+
HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1
48+
49+
CMD ["fwatchdog"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def handle(event, context):
2+
return {
3+
"statusCode": 200,
4+
"body": "Hello from OpenFaaS!"
5+
}

template/python3-http-debian/function/requirements.txt

Whitespace-only changes.

template/python3-http-debian/index.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python
2+
from flask import Flask, request, jsonify
3+
from waitress import serve
4+
import os
5+
6+
from function import handler
7+
8+
app = Flask(__name__)
9+
10+
class Event:
11+
def __init__(self):
12+
self.body = request.get_data()
13+
self.headers = request.headers
14+
self.method = request.method
15+
self.query = request.args
16+
self.path = request.path
17+
18+
class Context:
19+
def __init__(self):
20+
self.hostname = os.environ['HOSTNAME']
21+
22+
def format_status_code(resp):
23+
if 'statusCode' in resp:
24+
return resp['statusCode']
25+
26+
return 200
27+
28+
def format_body(resp):
29+
if 'body' not in resp:
30+
return ""
31+
elif type(resp['body']) == dict:
32+
return jsonify(resp['body'])
33+
else:
34+
return str(resp['body'])
35+
36+
def format_headers(resp):
37+
if 'headers' not in resp:
38+
return []
39+
elif type(resp['headers']) == dict:
40+
headers = []
41+
for key in resp['headers'].keys():
42+
header_tuple = (key, resp['headers'][key])
43+
headers.append(header_tuple)
44+
return headers
45+
46+
return resp['headers']
47+
48+
def format_response(resp):
49+
if resp == None:
50+
return ('', 200)
51+
52+
statusCode = format_status_code(resp)
53+
body = format_body(resp)
54+
headers = format_headers(resp)
55+
56+
return (body, statusCode, headers)
57+
58+
@app.route('/', defaults={'path': ''}, methods=['GET', 'PUT', 'POST', 'PATCH', 'DELETE'])
59+
@app.route('/<path:path>', methods=['GET', 'PUT', 'POST', 'PATCH', 'DELETE'])
60+
def call_handler(path):
61+
event = Event()
62+
context = Context()
63+
response_data = handler.handle(event, context)
64+
65+
resp = format_response(response_data)
66+
return resp
67+
68+
if __name__ == '__main__':
69+
serve(app, host='0.0.0.0', port=5000)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flask
2+
waitress
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
language: python3-http-debian
2+
fprocess: python index.py

template/python3-http/Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ RUN chmod +x /usr/bin/fwatchdog
66

77
ARG ADDITIONAL_PACKAGE
88
# Alternatively use ADD https:// (which will not be cached by Docker builder)
9+
910
RUN apk --no-cache add ${ADDITIONAL_PACKAGE}
1011

1112
# Add non root user
@@ -22,6 +23,8 @@ COPY index.py .
2223
COPY requirements.txt .
2324
USER root
2425
RUN pip install -r requirements.txt
26+
27+
#build function directory and install user specified componenets.
2528
USER app
2629

2730
RUN mkdir -p function
@@ -32,12 +35,14 @@ RUN pip install --user -r requirements.txt
3235

3336
WORKDIR /home/app/
3437

38+
#install function code
3539
USER root
3640
COPY function function
3741
RUN chown -R app:app ./
42+
43+
#configure WSGI server and healthcheck
3844
USER app
3945

40-
# Set up of-watchdog for HTTP mode
4146
ENV fprocess="python index.py"
4247
ENV cgi_headers="true"
4348
ENV mode="http"

0 commit comments

Comments
 (0)