Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenVINO Model Server deployer #1008

Merged
merged 4 commits into from
Mar 23, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions contrib/components/openvino/ovms-deployer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Deployer of OpenVINO Model Server

This component triggers deployment of [OpenVINO Model Server](https://github.com/IntelAI/OpenVINO-model-server) in Kubernetes.

It applies the passed component parameters on jinja template and applied deployment and server records.



```bash
./deploy.sh
--model-export-path
--cluster-name
--namespace
--server-name
--replicas
--batch-size
--model-version-policy
--log-level
```


## building docker image


```bash
docker build --build-arg http_proxy=$http_proxy --build-arg https_proxy=$https_proxy .
```

## testing the image locally


```
53 changes: 53 additions & 0 deletions contrib/components/openvino/ovms-deployer/containers/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
FROM intelpython/intelpython3_core

RUN apt-get update -q && apt-get upgrade -y && \
apt-get install -y -qq --no-install-recommends \
apt-transport-https \
ca-certificates \
git \
gnupg \
lsb-release \
unzip \
wget && \
wget -O /opt/ks_0.12.0_linux_amd64.tar.gz \
https://github.com/ksonnet/ksonnet/releases/download/v0.12.0/ks_0.12.0_linux_amd64.tar.gz && \
tar -C /opt -xzf /opt/ks_0.12.0_linux_amd64.tar.gz && \
cp /opt/ks_0.12.0_linux_amd64/ks /bin/. && \
rm -f /opt/ks_0.12.0_linux_amd64.tar.gz && \
wget -O /bin/kubectl \
https://storage.googleapis.com/kubernetes-release/release/v1.11.2/bin/linux/amd64/kubectl && \
chmod u+x /bin/kubectl && \
wget -O /opt/kubernetes_v1.11.2 \
https://github.com/kubernetes/kubernetes/archive/v1.11.2.tar.gz && \
mkdir -p /src && \
tar -C /src -xzf /opt/kubernetes_v1.11.2 && \
rm -rf /opt/kubernetes_v1.11.2 && \
wget -O /opt/google-apt-key.gpg \
https://packages.cloud.google.com/apt/doc/apt-key.gpg && \
apt-key add /opt/google-apt-key.gpg && \
export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" >> \
/etc/apt/sources.list.d/google-cloud-sdk.list && \
apt-get update -q && \
apt-get install -y -qq --no-install-recommends google-cloud-sdk && \
gcloud config set component_manager/disable_update_check true

ENV KUBEFLOW_VERSION v0.2.5

# Checkout the kubeflow packages at image build time so that we do not
# require calling in to the GitHub API at run time.
RUN cd /src && \
mkdir -p github.com/kubeflow && \
cd github.com/kubeflow && \
git clone https://github.com/kubeflow/kubeflow && \
cd kubeflow && \
git checkout ${KUBEFLOW_VERSION}

ADD . /deploy/
WORKDIR /deploy
RUN pip install -r requirements.txt
ENTRYPOINT ["./deploy.sh"]




Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from jinja2 import Template
import os


f = open("ovms.j2","r")
ovms_template = f.read()
t = Template(ovms_template)
ovms_k8s = t.render(os.environ)
f.close
f = open("ovms.yaml", "w")
f.write(ovms_k8s)
f.close

print(ovms_k8s)
153 changes: 153 additions & 0 deletions contrib/components/openvino/ovms-deployer/containers/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/bin/bash -e

set -x

KUBERNETES_NAMESPACE="${KUBERNETES_NAMESPACE:-kubeflow}"
SERVER_NAME="${SERVER_NAME:-model-server}"
SERVER_ENDPOINT_OUTPUT_FILE="${SERVER_ENDPOINT_OUTPUT_FILE:-/tmp/server_endpoint/data}"

Ark-kun marked this conversation as resolved.
Show resolved Hide resolved
while (($#)); do
case $1 in
"--model-export-path")
shift
export MODEL_EXPORT_PATH="$1"
shift
;;
"--cluster-name")
shift
CLUSTER_NAME="$1"
shift
;;
"--namespace")
shift
KUBERNETES_NAMESPACE="$1"
shift
;;
"--server-name")
Ark-kun marked this conversation as resolved.
Show resolved Hide resolved
shift
SERVER_NAME="$1"
shift
;;
"--replicas")
shift
export REPLICAS="$1"
shift
;;
"--batch-size")
shift
export BATCH_SIZE="$1"
shift
;;
"--model-version-policy")
shift
export MODEL_VERSION_POLICY="$1"
shift
;;
"--log-level")
shift
export LOG_LEVEL="$1"
shift
;;
"--server-endpoint-output-file")
shift
SERVER_ENDPOINT_OUTPUT_FILE = "$1"
shift
;;
*)
echo "Unknown argument: '$1'"
exit 1
;;
esac
done

if [ -z "${MODEL_EXPORT_PATH}" ]; then
echo "You must specify a path to the saved model"
exit 1
fi

echo "Deploying the model '${MODEL_EXPORT_PATH}'"

if [ -z "${CLUSTER_NAME}" ]; then
CLUSTER_NAME=$(wget -q -O- --header="Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-name)
fi

# Ensure the server name is not more than 63 characters.
export SERVER_NAME="${SERVER_NAME:0:63}"
# Trim any trailing hyphens from the server name.
while [[ "${SERVER_NAME:(-1)}" == "-" ]]; do SERVER_NAME="${SERVER_NAME::-1}"; done

echo "Deploying ${SERVER_NAME} to the cluster ${CLUSTER_NAME}"

# Connect kubectl to the local cluster
kubectl config set-cluster "${CLUSTER_NAME}" --server=https://kubernetes.default --certificate-authority=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
kubectl config set-credentials pipeline --token "$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
kubectl config set-context kubeflow --cluster "${CLUSTER_NAME}" --user pipeline
kubectl config use-context kubeflow

python apply_template.py

kubectl apply -f ovms.yaml

sleep 10
echo "Waiting for the TF Serving deployment to have at least one available replica..."
timeout="1000"
start_time=`date +%s`
while [[ $(kubectl get deploy --namespace "${KUBERNETES_NAMESPACE}" --selector=app="ovms-${SERVER_NAME}" --output=jsonpath='{.items[0].status.availableReplicas}') < "1" ]]; do
current_time=`date +%s`
elapsed_time=$(expr $current_time + 1 - $start_time)
if [[ $elapsed_time -gt $timeout ]];then
echo "timeout"
exit 1
fi
sleep 5
done

echo "Obtaining the pod name..."
start_time=`date +%s`
pod_name=""
while [[ $pod_name == "" ]];do
pod_name=$(kubectl get pods --namespace "${KUBERNETES_NAMESPACE}" --selector=app="ovms-${SERVER_NAME}" --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
current_time=`date +%s`
elapsed_time=$(expr $current_time + 1 - $start_time)
if [[ $elapsed_time -gt $timeout ]];then
echo "timeout"
exit 1
fi
sleep 2
done
echo "Pod name is: " $pod_name

# Wait for the pod container to start running
echo "Waiting for the TF Serving pod to start running..."
start_time=`date +%s`
exit_code="1"
while [[ $exit_code != "0" ]];do
kubectl get po ${pod_name} --namespace "${KUBERNETES_NAMESPACE}" -o jsonpath='{.status.containerStatuses[0].state.running}'
exit_code=$?
current_time=`date +%s`
elapsed_time=$(expr $current_time + 1 - $start_time)
if [[ $elapsed_time -gt $timeout ]];then
echo "timeout"
exit 1
fi
sleep 2
done

start_time=`date +%s`
while [ -z "$(kubectl get po ${pod_name} --namespace "${KUBERNETES_NAMESPACE}" -o jsonpath='{.status.containerStatuses[0].state.running}')" ]; do
current_time=`date +%s`
elapsed_time=$(expr $current_time + 1 - $start_time)
if [[ $elapsed_time -gt $timeout ]];then
echo "timeout"
exit 1
fi
sleep 5
done

# Wait a little while and then grab the logs of the running server
sleep 10
echo "Logs from the TF Serving pod:"
kubectl logs ${pod_name} --namespace "${KUBERNETES_NAMESPACE}"

mkdir -p "$(dirname "$SERVER_ENDPOINT_OUTPUT_FILE")"
echo "ovms-${SERVER_NAME}:80" > "$SERVER_ENDPOINT_OUTPUT_FILE"
39 changes: 39 additions & 0 deletions contrib/components/openvino/ovms-deployer/containers/ovms.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ovms-{{ SERVER_NAME }}
labels:
app: ovms-{{ SERVER_NAME }}
spec:
selector:
matchLabels:
app: ovms-{{ SERVER_NAME }}
replicas: {{ REPLICAS }}
template:
metadata:
labels:
app: ovms-{{ SERVER_NAME }}
spec:
containers:
- name: ovms-{{ SERVER_NAME }}
image: intelaipg/openvino-model-server:latest
ports:
- containerPort: 80
env:
- name: LOG_LEVEL
value: "{{ LOG_LEVEL }}"
command: ["/ie-serving-py/start_server.sh"]
args: ["ie_serving", "model", "--model_path", "{{ MODEL_EXPORT_PATH }}", "--model_name", "{{ SERVER_NAME }}", "--port", "80", "--batch_size", "{{ BATCH_SIZE }}"]
---
apiVersion: v1
kind: Service
metadata:
name: ovms-{{ SERVER_NAME }}
spec:
selector:
app: ovms-{{ SERVER_NAME }}
ports:
- protocol: TCP
port: 80
targetPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
jinja2==2.10
12 changes: 12 additions & 0 deletions contrib/samples/openvino/deployer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# OpenVINO Model Server deployment pipeline

This is an example of a one step pipeline implementation for [OpenVINO Model Server deployer](../../../components/openvino/ovms-deployer).

## Parameters

- model_export_path - local or gs path to the folder with numerical subfolders storing OpenVINO models
- server_name - Kubernetes service name to be deployed which is equal to service model name
- log_level - DEBUG/INFO/ERROR
- batch_size - which batch size should be loaded in the served model: 'auto' or numerical values
- model_version_policy - parameter defining which version should be served in OVMS. Examples: '{"latest": { "num_versions":2 }}') /
{"specific": { "versions":[1, 3] }} / {"all": {}}
Loading