Build both python 3.5 and 2.7 images from the same env

This commit is contained in:
Soam Vasani
2017-11-09 14:01:02 -08:00
parent d8844ab13c
commit bcf04b1a6c
9 changed files with 25 additions and 10 deletions
+14
View File
@@ -0,0 +1,14 @@
FROM alpine:3.5
RUN apk update
RUN apk add --no-cache python3 python3-dev build-base
RUN pip3 install --upgrade pip
RUN rm -r /root/.cache
COPY . /app
WORKDIR /app
RUN pip3 install -r requirements.txt
ENTRYPOINT ["python3"]
CMD ["server.py"]
+14
View File
@@ -0,0 +1,14 @@
FROM alpine:3.5
RUN apk update
RUN apk add --no-cache python python-dev build-base py-pip
RUN pip install --upgrade pip
RUN rm -r /root/.cache
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["server.py"]
+45
View File
@@ -0,0 +1,45 @@
# Fission: Python Environment
This is the Python environment for Fission.
It's a Docker image containing a Python 3.5 runtime, along with a
dynamic loader. A few common dependencies are included in the
requirements.txt file.
## Customizing this image
To add package dependencies, edit requirements.txt to add what you
need, and rebuild this image (instructions below).
You also may want to customize what's available to the function in its
request context. You can do this by editing server.py (see the
comment in that file about customizing request context).
## Rebuilding and pushing the image
You'll need access to a Docker registry to push the image: you can
sign up for Docker hub at hub.docker.com, or use registries from
gcr.io, quay.io, etc. Let's assume you're using a docker hub account
called USER. Build and push the image to the the registry:
```
docker build -t USER/python-env . && docker push USER/python-env
```
## Using the image in fission
You can add this customized image to fission with "fission env
create":
```
fission env create --name python --image USER/python-env
```
Or, if you already have an environment, you can update its image:
```
fission env update --name python --image USER/python-env
```
After this, fission functions that have the env parameter set to the
same environment name as this command will use this environment.
+11
View File
@@ -0,0 +1,11 @@
FROM alpine:3.5
RUN apk update
RUN apk add --no-cache python3 python3-dev build-base
RUN pip3 install --upgrade pip
RUN rm -r /root/.cache
ADD defaultBuildCmd /usr/local/bin/build
ADD builder /builder
EXPOSE 8001
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
pip3 install -r ${SRC_PKG}/requirements.txt -t ${SRC_PKG} && cp -r ${SRC_PKG} ${DEPLOY_PKG}
+6
View File
@@ -0,0 +1,6 @@
Flask===0.11.1
httplib2
python-dateutil
requests==2.7.0
redis
hiredis
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env python
import logging
import sys
import imp
import os
from flask import Flask, request, abort, g
app = Flask(__name__)
userfunc = None
@app.route('/specialize', methods=['POST'])
def load():
global userfunc
# load user function from codepath
codepath = '/userfunc/user'
userfunc = (imp.load_source('user', codepath)).main
return ""
@app.route('/v2/specialize', methods=['POST'])
def loadv2():
global userfunc
body = request.get_json()
filepath = body['filepath']
handler = body['functionName']
# The value of "functionName" is consist of `<module-name>.<function-name>`.
moduleName, funcName = handler.split(".")
# check whether the destination is a directory or a file
if os.path.isdir(filepath):
# add package directory path into module search path
sys.path.append(filepath)
# find module from package path we append previously.
# Python will try to find module from the same name file under
# the package directory. If search is successful, the return
# value is a 3-element tuple; otherwise, an exception "ImportError"
# is raised.
# Second parameter of find_module enforces python to find same
# name module from the given list of directories to prevent name
# confliction with built-in modules.
f, path, desc = imp.find_module(moduleName, [filepath])
# load module
# Return module object is the load is successful; otherwise,
# an exception is raised.
try:
mod = imp.load_module(moduleName, f, path, desc)
finally:
if f:
f.close()
else:
# load source from destination python file
mod = imp.load_source(moduleName, filepath)
# load user function from module
userfunc = getattr(mod, funcName)
return ""
@app.route('/', methods=['GET', 'POST', 'PUT', 'HEAD', 'OPTIONS', 'DELETE'])
def f():
if userfunc == None:
print("Generic container: no requests supported")
abort(500)
#
# Customizing the request context
#
# If you want to pass something to the function, you can add it to 'g':
# g.myKey = myValue
# And the user func can then access that (after doing a "from flask import g").
#
return userfunc()
#
# Logging setup. TODO: Loglevel hard-coded for now. We could allow
# functions/routes to override this somehow; or we could create
# separate dev vs. prod environments.
#
def setup_logger(loglevel):
global app
root = logging.getLogger()
root.setLevel(loglevel)
ch = logging.StreamHandler(sys.stdout)
ch.setLevel(loglevel)
ch.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
app.logger.addHandler(ch)
#
# TODO: this starts the built-in server, which isn't the most
# efficient. We should use something better.
#
setup_logger(logging.DEBUG)
app.logger.info("Starting server")
app.run(host='0.0.0.0', port='8888')