Archive date: 2021-02-25
This content is no longer being updated or maintained. The content is provided “as is.” Given the rapid evolution of technology, some content, steps, or illustrations may have changed.This tutorial shows you how to create a custom Appsody stack with Python Flask and OpenCV support. In order to achieve this, you create a copy of an existing Python Flask stack and add support for OpenCV. We will then build and test the stack with a sample code.
Appsody is an open source project that helps you develop containerized applications for the cloud. OpenCV is an open source computer vision and machine learning software library.
Learning objectives
In this tutorial, you will learn to:
- Create a custom Appsody stack with support for Python Flask and OpenCV.
- Build and test the stack with sample code.
- Deploy an image to an OpenShift cluster on IBM Cloud.
Prerequisites
You’ll need Appsody installed and an IBM Cloud account.
Estimated time
Completing this tutorial should take about 30 minutes.
Steps
- Create copy of python flask stack.
- Modify the Python flask stack to add support for OpenCV.
- Build the stack.
- Create an appsody project using the new stack.
- Test.
- Deploy to OpenShift cluster on IBM Cloud.
Create copy of an Appsody Python Flask stack
Run the command to make a copy:
appsody stack create python-flask-opencv --copy incubator/python-flask
You will see a python-flask-opencv
folder created.
Modify the Python Flask stack to add support for OpenCV
Now, let’s modify the stack.
$ cd python-flask-opencv
Open the file `Dockerfile-stack
under the image
folder. Add the following lines after the first line FROM python:3.7
as seen below. Save the file.
FROM python:3.7
RUN apt-get update
RUN apt-get clean
RUN pip install --upgrade pip; \
pip install opencv-python
Note: opencv-python is a wrapper package for OpenCV Python bindings. Please refer to the Python documentation for more details on usage and licensing.
Next, open the file Dockerfile
under folder image/project
. Add the following lines after the first line FROM python:3.7
as seen below.
FROM python:3.7
RUN apt-get update
RUN apt-get clean
RUN pip install --upgrade pip; \
pip install opencv-python
That’s it! You’ve added support for OpenCV. In the next steps, I’ll show you how to package the stack.
Build the stack
Go to the python-flask-opencv
folder and run the following command:
appsody stack package
This builds the stack into a local Appsody repository (called dev.local) where you can create Appsody projects based on the newly created stack.
Create an Appsody project using the new stack
Create a new empty folder and name it. I named the one here
example
. Create an Appsody project inside the newly created folder by running the following command:$ cd example $ appsody init dev.local/python-flask-opencv
Create a folder
templates
.$ mkdir templates $ cd templates
Add a file
index.html
totemplates
folder with the following content:<!doctype html> <html lang="en"> <h2>Convert image to grayscale using Python, OpenCV.</h2> <h5>Upload an image.</h5> </p> </p> <div class="upload-form"> <form action = "/uploader" method = "POST" enctype = "multipart/form-data"> <input type = "file" name = "file" /> <input value="Convert" style="background-color:green;color:white" type = "submit"/> </form> </div> </html>
Add a file
display.html" to
templates` folder with the below content:<!doctype html> <html lang="en"> <div> <h2>Converted Image!</h2> <img src="getimage"> </div> </html>
Modify the
__init__.py
fileChange the import statements and add required import statements
Make changes to existing import statements and add other required import statements. The import statements section should look like the one below:
from flask import Flask, redirect, render_template, request from werkzeug import secure_filename import os import sys from flasgger import Swagger from server import app from server.routes.prometheus import track_requests from os import path from userapp import improcess
Create and initialize variables
Add the below statements below the import section:
app=Flask(__name__,template_folder='templates')
Create a function and add a route to index.html
@app.route("/home") def home(): return render_template("index.html")
Create a function and add a route for uploader
@app.route('/uploader', methods = ['POST']) @track_requests def upload_file(): if request.method == 'POST': f = request.files['file'] # create a secure filename filename = f.filename # save file filepath = os.path.join("./userapp/",filename) f.save(filepath) # convert image to grayscale filepath_gray = improcess.convert_grayscale(filepath); return render_template("display.html")
Create a function and add a route for
getimage
@app.route('/getimage', methods = ['GET']) @track_requests def getimage(): filename_gray = "gray.png" filepath_gray = os.path.join("./userapp/",filename_gray) if path.exists(filepath_gray): f = open(filepath_gray, "rb"); print(f) print("image found!") contents = f.read() return contents; else: print("no image found!") return "";
Note: The function
getimage
is used for displaying the converted grayscale image.
Create a new Python module
improcess.py
and add the following lines. Save the file asimprocess.py
.import cv2 import os from os import path def convert_grayscale(filepath): ''' Convert image to grayscale''' image = cv2.imread(filepath,0) filename_gray = "gray.png" filepath_gray = os.path.join("./userapp/",filename_gray) print(filepath_gray) cv2.imwrite(filepath_gray,image) return filepath_gray
5Test
Now I’ll show you how to build and run the project.
Go to the
example
folder and run the following commands:$ appsody build $ appsody run
Open the URL: http://localhost:8080/home.
We will test the service for the image:
Click on Browse and upload the image.
Click on Convert after selecting the image from a local folder.
The converted image displays as shown below:
You can get the health of the container at: http://localhost:8080/health
{"status":"UP"}
You can view the metrics for the application at http://localhost:8080/metrics
... # TYPE requests_for_routes_total counter requests_for_routes_total{endpoint="/uploader",method="POST"} 1.0 requests_for_routes_total{endpoint="/getimage",method="GET"} 1.0 # TYPE requests_for_routes_created gauge requests_for_routes_created{endpoint="/uploader",method="POST"} 1.5744054798223705e+09 requests_for_routes_created{endpoint="/getimage",method="GET"} 1.5744054799005709e+09
Deploy to an OpenShift cluster on IBM Cloud
The appsody build
command will locally build a Docker image of your Appsody project.
Run the command below to view the Docker image.
$ docker images example REPOSITORY TAG IMAGE ID CREATED SIZE example latest e04e2c3f263f 12 seconds ago 1.09GB
Log in to OpenShift.
oc login https://xxxx.containers.cloud.ibm.com:xxxxx --token=xxxxxxxxxxx
Create a route for Docker registry if not created already.
$ oc project default $ oc get svc
The output appears as shown below:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE docker-registry ClusterIP 172.21.xxx.xx <none> 5000/TCP 18h kubernetes ClusterIP 172.21.x.x <none> 443/TCP,53/UDP,53/TCP 18h myfirstosdeploy ClusterIP 172.21.xx.xxx <none> 5000/TCP 17h registry-console ClusterIP 172.21.xxx.xxx <none> 9000/TCP 18h router LoadBalancer 172.21.xx.x 169.47.xxx.xxx 80:31297/TCP,443:30385/TCP 18h
Run the following command to create a route to the Docker registry.
$ oc create route reencrypt --service=docker-registry
Check the
create route
details.$ oc get route docker-registry
The output appears as shown below:
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD docker-registry docker-registry-default.clustersiteam-5290cxxxxxxxxxxd1b85xxx-0001.us-east.containers.appdomain.cloud docker-registry 5000-tcp reencrypt None
Note the Docker registry URL that is displayed with the pattern:
docker-registry-default.<cluster_name>-<ID_string>.<region>.containers.appdomain.cloud.
Set it as a variable.
export IMAGE_REGISTRY=docker-registry-default.<cluster_name>-<ID_string>.<region>.containers.appdomain.cloud
Log into the Docker registry.
docker login -u $(oc whoami) -p $(oc whoami -t) $IMAGE_REGISTRY
Create a new project.
oc new-project example
Give root permissions to the
default
service account.oc adm policy add-scc-to-user anyuid -z default
Deploy the image to the registry on OpenShift.
appsody deploy --tag example/example:latest --push-url $IMAGE_REGISTRY --push --pull-url docker-registry.default.svc:5000
Create a new OpenShift app.
oc new-app --image-stream=example --name=example
Expose the route.
oc expose svc/example
You can see the application deployed under the
example
project on the OpenShift web console.
Conclusion
Hopefully the steps in this tutorial helped you undersatnd how to create a custom Appsody stack with Python Flask and OpenCV support. Extending Appsody stacks to support other open projects is one of its benefits, and adding OpenCV support to the Python Flask stack enables you to use computer vision and machine learning software within containerized platforms.