forked from kubeflow/pipelines
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add custom image sample documentation (kubeflow#678)
* Add documentation for custom sample * Add TARGET env var * Add requirements.txt and update README * kfservingsdk example * Add expected output * Update model name
- Loading branch information
Showing
12 changed files
with
1,316 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Use the official lightweight Python image. | ||
# https://hub.docker.com/_/python | ||
FROM python:3.7-slim | ||
|
||
# Copy local code to the container image. | ||
ENV APP_HOME /app | ||
WORKDIR $APP_HOME | ||
COPY app.py requirements.txt ./ | ||
|
||
# Install production dependencies. | ||
RUN pip install --no-cache-dir -r ./requirements.txt | ||
|
||
# Run the web service on container startup. Here we use the gunicorn | ||
# webserver, with one worker process and 8 threads. | ||
# For environments with multiple CPU cores, increase the number of workers | ||
# to be equal to the cores available. | ||
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Predict on a InferenceService using a Custom Image | ||
|
||
## Setup | ||
|
||
1. Your ~/.kube/config should point to a cluster with [KFServing installed](https://github.com/kubeflow/kfserving/blob/master/docs/DEVELOPER_GUIDE.md#deploy-kfserving). | ||
2. Your cluster's Istio Ingress gateway must be network accessible. | ||
|
||
## Build and push the sample Docker Image | ||
|
||
The goal of custom image support is to allow users to bring their own wrapped model inside a container and serve it with KFServing. Please note that you will need to ensure that your container is also running a web server e.g. Flask to expose your model endpoints. | ||
|
||
In this example we use Docker to build the sample python server into a container. To build and push with Docker Hub, run these commands replacing {username} with your Docker Hub username: | ||
|
||
``` | ||
# Build the container on your local machine | ||
docker build -t {username}/custom-sample . | ||
# Push the container to docker registry | ||
docker push {username}/custom-sample | ||
``` | ||
|
||
## Create the InferenceService | ||
|
||
In the `custom.yaml` file edit the container image and replace {username} with your Docker Hub username. | ||
|
||
Apply the CRD | ||
|
||
``` | ||
kubectl apply -f custom.yaml | ||
``` | ||
|
||
Expected Output | ||
|
||
``` | ||
$ inferenceservice.serving.kubeflow.org/custom-sample created | ||
``` | ||
|
||
## Run a prediction | ||
|
||
``` | ||
MODEL_NAME=custom-sample | ||
CLUSTER_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') | ||
SERVICE_HOSTNAME=$(kubectl get inferenceservice ${MODEL_NAME} -o jsonpath='{.status.url}' | cut -d "/" -f 3) | ||
curl -v -H "Host: ${SERVICE_HOSTNAME}" http://$CLUSTER_IP/v1/models/${MODEL_NAME}:predict | ||
``` | ||
|
||
Expected Output | ||
|
||
``` | ||
* Trying 184.172.247.174... | ||
* TCP_NODELAY set | ||
* Connected to 184.172.247.174 (184.172.247.174) port 31380 (#0) | ||
> GET /v1/models/custom-sample:predict HTTP/1.1 | ||
> Host: custom-sample.default.example.com | ||
> User-Agent: curl/7.64.1 | ||
> Accept: */* | ||
> | ||
< HTTP/1.1 200 OK | ||
< content-length: 31 | ||
< content-type: text/html; charset=utf-8 | ||
< date: Thu, 13 Feb 2020 21:34:54 GMT | ||
< server: istio-envoy | ||
< x-envoy-upstream-service-time: 15 | ||
< | ||
Hello Python KFServing Sample! | ||
* Connection #0 to host 184.172.247.174 left intact | ||
* Closing connection 0 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import os | ||
|
||
from flask import Flask | ||
|
||
app = Flask(__name__) | ||
|
||
|
||
@app.route('/v1/models/custom-sample:predict') | ||
def hello_world(): | ||
greeting_target = os.environ.get('GREETING_TARGET', 'World') | ||
return 'Hello {}!\n'.format(greeting_target) | ||
|
||
|
||
if __name__ == "__main__": | ||
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Flask==1.1.1 | ||
gunicorn==20.0.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Use the official lightweight Python image. | ||
# https://hub.docker.com/_/python | ||
FROM python:3.7-slim | ||
|
||
ENV APP_HOME /app | ||
WORKDIR $APP_HOME | ||
|
||
# Install production dependencies. | ||
COPY requirements.txt ./ | ||
RUN pip install --no-cache-dir -r ./requirements.txt | ||
|
||
# Copy local code to container image | ||
COPY model.py imagenet_classes.txt ./ | ||
|
||
CMD ["python", "model.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Predict on a InferenceService using a KFServing Model Server | ||
|
||
## Setup | ||
|
||
1. Your ~/.kube/config should point to a cluster with [KFServing installed](https://github.com/kubeflow/kfserving/blob/master/docs/DEVELOPER_GUIDE.md#deploy-kfserving). | ||
2. Your cluster's Istio Ingress gateway must be network accessible. | ||
|
||
## Build and push the sample Docker Image | ||
|
||
The goal of custom image support is to allow users to bring their own wrapped model inside a container and serve it with KFServing. Please note that you will need to ensure that your container is also running a web server e.g. Flask to expose your model endpoints. | ||
|
||
In this example we use Docker to build the sample python server into a container. To build and push with Docker Hub, run these commands replacing {username} with your Docker Hub username: | ||
|
||
``` | ||
# Build the container on your local machine | ||
docker build -t {username}/kfserving-custom-model . | ||
# Push the container to docker registry | ||
docker push {username}/kfserving-custom-model | ||
``` | ||
|
||
## Create the InferenceService | ||
|
||
In the `custom.yaml` file edit the container image and replace {username} with your Docker Hub username. | ||
|
||
Apply the CRD | ||
|
||
``` | ||
kubectl apply -f custom.yaml | ||
``` | ||
|
||
Expected Output | ||
|
||
``` | ||
$ inferenceservice.serving.kubeflow.org/kfserving-custom-model created | ||
``` | ||
|
||
## Run a prediction | ||
|
||
``` | ||
MODEL_NAME=kfserving-custom-model | ||
INPUT_PATH=@./input.json | ||
CLUSTER_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') | ||
SERVICE_HOSTNAME=$(kubectl get inferenceservice ${MODEL_NAME} -o jsonpath='{.status.url}' | cut -d "/" -f 3) | ||
curl -v -H "Host: ${SERVICE_HOSTNAME}" http://${CLUSTER_IP}/v1/models/${MODEL_NAME}:predict -d $INPUT_PATH | ||
``` | ||
|
||
Expected Output: | ||
``` | ||
* Trying 169.47.250.204... | ||
* TCP_NODELAY set | ||
* Connected to 169.47.250.204 (169.47.250.204) port 80 (#0) | ||
> POST /v1/models/kfserving-custom-model:predict HTTP/1.1 | ||
> Host: kfserving-custom-model.default.example.com | ||
> User-Agent: curl/7.64.1 | ||
> Accept: */* | ||
> Content-Length: 105318 | ||
> Content-Type: application/x-www-form-urlencoded | ||
> Expect: 100-continue | ||
> | ||
< HTTP/1.1 100 Continue | ||
* We are completely uploaded and fine | ||
< HTTP/1.1 200 OK | ||
< content-length: 232 | ||
< content-type: text/html; charset=UTF-8 | ||
< date: Fri, 21 Feb 2020 20:19:37 GMT | ||
< server: istio-envoy | ||
< x-envoy-upstream-service-time: 258 | ||
< | ||
* Connection #0 to host 169.47.250.204 left intact | ||
{"predictions": {"Labrador retriever": 0.4158518612384796, "golden retriever": 0.1659165322780609, "Saluki, gazelle hound": 0.16286855936050415, "whippet": 0.028539149090647697, "Ibizan hound, Ibizan Podenco": 0.023924754932522774}}* Closing connection 0 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
apiVersion: serving.kubeflow.org/v1alpha2 | ||
kind: InferenceService | ||
metadata: | ||
labels: | ||
controller-tools.k8s.io: "1.0" | ||
name: kfserving-custom-model | ||
spec: | ||
default: | ||
predictor: | ||
custom: | ||
container: | ||
image: {username}/kfserving-custom-model |
Oops, something went wrong.