Skip to content

Commit

Permalink
feat(components): Add yaml support to kfserving component (#4587)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomcli authored Oct 8, 2020
1 parent 7e4d9f4 commit 2a1fe45
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 43 deletions.
6 changes: 4 additions & 2 deletions components/kubeflow/kfserving/component.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ inputs:
- {name: Default Model URI, type: String, default: '', description: 'Path of the S3 or GCS compatible directory containing default model.'}
- {name: Canary Model URI, type: String, default: '', description: 'Optional Path of the S3 or GCS compatible directory containing canary model.'}
- {name: Canary Model Traffic Percentage, type: String, default: '0', description: 'Optional Traffic to be sent to default model'}
- {name: Namespace, type: String, default: 'kubeflow', description: 'Kubernetes namespace where the KFServing service is deployed.'}
- {name: Namespace, type: String, default: 'anonymous', description: 'Kubernetes namespace where the KFServing service is deployed.'}
- {name: Framework, type: String, default: 'tensorflow', description: 'Machine Learning Framework for Model Serving.'}
- {name: Default Custom Model Spec, type: String, default: '{}', description: 'Custom runtime default custom model container spec.'}
- {name: Canary Custom Model Spec, type: String, default: '{}', description: 'Custom runtime canary custom model container spec.'}
- {name: Autoscaling Target, type: String, default: '0', description: 'Autoscaling Target Number'}
- {name: KFServing Endpoint, type: String, default: '', description: 'KFServing remote deployer API endpoint'}
- {name: Service Account, type: String, default: '', description: 'Model Service Account'}
- {name: Enable Istio Sidecar, type: Bool, default: 'True', description: 'Whether to enable istio sidecar injection'}
- {name: InferenceService YAML, type: String, default: '{}', description: 'Raw InferenceService serialized YAML for deployment'}
outputs:
- {name: Service Endpoint URI, type: String, description: 'URI of the deployed prediction service..'}
implementation:
Expand All @@ -35,5 +36,6 @@ implementation:
--autoscaling-target, {inputValue: Autoscaling Target},
--service-account, {inputValue: Service Account},
--enable-istio-sidecar, {inputValue: Enable Istio Sidecar},
--output-path, {outputPath: Service Endpoint URI}
--output-path, {outputPath: Service Endpoint URI},
--inferenceservice_yaml, {inputValue: InferenceService YAML}
]
3 changes: 2 additions & 1 deletion components/kubeflow/kfserving/src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def deploy_model_post():
canary_custom_model_spec=request.json["canary_custom_model_spec"],
autoscaling_target=request.json["autoscaling_target"],
service_account=request.json["service_account"],
enable_istio_sidecar=request.json["enable_istio_sidecar"]
enable_istio_sidecar=request.json["enable_istio_sidecar"],
inferenceservice_yaml=request.json["inferenceservice_yaml"]
)
)

Expand Down
111 changes: 71 additions & 40 deletions components/kubeflow/kfserving/src/kfservingdeployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import requests
import re
import time
import yaml
from distutils.util import strtobool

from kubernetes import client
Expand All @@ -37,6 +38,13 @@
from kfserving import V1alpha2InferenceService


def yamlStr(str):
if str == "" or str == None:
return None
else:
return yaml.safe_load(str)


def EndpointSpec(framework, storage_uri, service_account):
if framework == "tensorflow":
return V1alpha2EndpointSpec(
Expand Down Expand Up @@ -143,53 +151,62 @@ def deploy_model(
canary_custom_model_spec,
service_account,
autoscaling_target=0,
enable_istio_sidecar=True
enable_istio_sidecar=True,
inferenceservice_yaml={}
):
# Create annotation
annotations = {}
if int(autoscaling_target) != 0:
annotations["autoscaling.knative.dev/target"] = str(autoscaling_target)
if not enable_istio_sidecar:
annotations["sidecar.istio.io/inject"] = 'false'
if not annotations:
annotations = None
metadata = client.V1ObjectMeta(
name=model_name, namespace=namespace, annotations=annotations
)
KFServing = KFServingClient()

# Create Default deployment if default model uri is provided.
if framework != "custom" and default_model_uri:
default_model_spec = EndpointSpec(framework, default_model_uri, service_account)
elif framework == "custom" and default_custom_model_spec:
default_model_spec = customEndpointSpec(
default_custom_model_spec, service_account
if inferenceservice_yaml:
# Overwrite name and namespace if exist
if namespace:
inferenceservice_yaml['metadata']['namespace'] = namespace
if model_name:
inferenceservice_yaml['metadata']['name'] = model_name
kfsvc = inferenceservice_yaml
else:
# Create annotation
annotations = {}
if int(autoscaling_target) != 0:
annotations["autoscaling.knative.dev/target"] = str(autoscaling_target)
if not enable_istio_sidecar:
annotations["sidecar.istio.io/inject"] = 'false'
if not annotations:
annotations = None
metadata = client.V1ObjectMeta(
name=model_name, namespace=namespace, annotations=annotations
)

# Create Canary deployment if canary model uri is provided.
if framework != "custom" and canary_model_uri:
canary_model_spec = EndpointSpec(framework, canary_model_uri, service_account)
kfsvc = InferenceService(
metadata, default_model_spec, canary_model_spec, canary_model_traffic
)
elif framework == "custom" and canary_custom_model_spec:
canary_model_spec = customEndpointSpec(
canary_custom_model_spec, service_account
)
kfsvc = InferenceService(
metadata, default_model_spec, canary_model_spec, canary_model_traffic
)
else:
kfsvc = InferenceService(metadata, default_model_spec)
# Create Default deployment if default model uri is provided.
if framework != "custom" and default_model_uri:
default_model_spec = EndpointSpec(framework, default_model_uri, service_account)
elif framework == "custom" and default_custom_model_spec:
default_model_spec = customEndpointSpec(
default_custom_model_spec, service_account
)

KFServing = KFServingClient()
# Create Canary deployment if canary model uri is provided.
if framework != "custom" and canary_model_uri:
canary_model_spec = EndpointSpec(framework, canary_model_uri, service_account)
kfsvc = InferenceService(
metadata, default_model_spec, canary_model_spec, canary_model_traffic
)
elif framework == "custom" and canary_custom_model_spec:
canary_model_spec = customEndpointSpec(
canary_custom_model_spec, service_account
)
kfsvc = InferenceService(
metadata, default_model_spec, canary_model_spec, canary_model_traffic
)
else:
kfsvc = InferenceService(metadata, default_model_spec)

def create(kfsvc, model_name, namespace):
KFServing.create(kfsvc)
KFServing.create(kfsvc, namespace=namespace)
time.sleep(1)
KFServing.get(model_name, namespace=namespace, watch=True, timeout_seconds=120)

def update(kfsvc, model_name, namespace):
KFServing.patch(model_name, kfsvc)
KFServing.patch(model_name, kfsvc, namespace=namespace)
time.sleep(1)
KFServing.get(model_name, namespace=namespace, watch=True, timeout_seconds=120)

Expand All @@ -203,6 +220,8 @@ def update(kfsvc, model_name, namespace):
except:
update(kfsvc, model_name, namespace)
elif action == "rollout":
if inferenceservice_yaml:
raise("Rollout is not supported for inferenceservice yaml")
KFServing.rollout_canary(
model_name,
canary=canary_model_spec,
Expand Down Expand Up @@ -253,7 +272,7 @@ def update(kfsvc, model_name, namespace):
"--namespace",
type=str,
help="Kubernetes namespace where the KFServing service is deployed.",
default="kubeflow",
default="anonymous",
)
parser.add_argument(
"--framework", type=str, help="Model Serving Framework", default="tensorflow"
Expand Down Expand Up @@ -286,7 +305,16 @@ def update(kfsvc, model_name, namespace):
default="",
)
parser.add_argument(
"--enable-istio-sidecar", type=strtobool, help="Whether to inject istio sidecar", default="True"
"--enable-istio-sidecar",
type=strtobool,
help="Whether to inject istio sidecar",
default="True"
)
parser.add_argument(
"--inferenceservice_yaml",
type=yamlStr,
help="Raw InferenceService serialized YAML for deployment",
default={}
)
parser.add_argument("--output-path", type=str, help="Path to store URI output")
args = parser.parse_args()
Expand All @@ -307,6 +335,7 @@ def update(kfsvc, model_name, namespace):
autoscaling_target = int(args.autoscaling_target)
service_account = args.service_account
enable_istio_sidecar = args.enable_istio_sidecar
inferenceservice_yaml = args.inferenceservice_yaml

if kfserving_endpoint:
formData = {
Expand All @@ -321,7 +350,8 @@ def update(kfsvc, model_name, namespace):
"canary_custom_model_spec": canary_custom_model_spec,
"autoscaling_target": autoscaling_target,
"service_account": service_account,
"enable_istio_sidecar": enable_istio_sidecar
"enable_istio_sidecar": enable_istio_sidecar,
"inferenceservice_yaml": inferenceservice_yaml
}
response = requests.post(
"http://" + kfserving_endpoint + "/deploy-model", json=formData
Expand All @@ -340,7 +370,8 @@ def update(kfsvc, model_name, namespace):
canary_custom_model_spec=canary_custom_model_spec,
autoscaling_target=autoscaling_target,
service_account=service_account,
enable_istio_sidecar=enable_istio_sidecar
enable_istio_sidecar=enable_istio_sidecar,
inferenceservice_yaml=inferenceservice_yaml
)
print(model_status)
# Check whether the model is ready
Expand Down

0 comments on commit 2a1fe45

Please sign in to comment.