This is an automated email from the ASF dual-hosted git repository. kuanhsun pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/submarine.git
The following commit(s) were added to refs/heads/master by this push: new c15baa7 SUBMARINE-1130. New route to serve pod c15baa7 is described below commit c15baa7fbe7bf314061559a8514be6220b66bb63 Author: jeff-901 <b07901...@ntu.edu.tw> AuthorDate: Sun Dec 12 10:31:31 2021 +0800 SUBMARINE-1130. New route to serve pod ### What is this PR for? Add a new route to serve pod. new route: http://\{submarine ip}/{model name}/{model version}/api/v1.0/predictions ### What type of PR is it? Feature ### Todos ### What is the Jira issue? https://issues.apache.org/jira/browse/SUBMARINE-1130 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Do the license files need updating? No * Are there breaking changes for older versions? No * Does this need new documentation? No Author: jeff-901 <b07901...@ntu.edu.tw> Signed-off-by: kuanhsun <kuanh...@apache.org> Closes #829 from jeff-901/SUBMARINE-1130 and squashes the following commits: 2ea9c5a6 [jeff-901] create virtual service for serve pod --- .../artifacts/submarine/submarine-rbac.yaml | 13 ++ .../serve/istio/IstioHTTPDestination.java | 54 ++++++++ .../serve/istio/IstioHTTPMatchRequest.java | 39 ++++++ .../submarine/serve/istio/IstioHTTPRoute.java | 67 +++++++++ .../submarine/serve/istio/IstioVirtualService.java | 153 +++++++++++++++++++++ .../submarine/serve/utils/IstioConstants.java | 42 ++++++ .../server/submitter/k8s/K8sSubmitter.java | 43 +++++- 7 files changed, 405 insertions(+), 6 deletions(-) diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml b/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml index f568dac..58d8264 100644 --- a/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml +++ b/submarine-cloud-v2/artifacts/submarine/submarine-rbac.yaml @@ -68,6 +68,19 @@ rules: - patch - update - apiGroups: + - networking.istio.io + resources: + - virtualservices + verbs: + - get + - list + - watch + - create + - delete + - deletecollection + - patch + - update +- apiGroups: - "" resources: - pods diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java new file mode 100644 index 0000000..fc375de --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPDestination.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.submarine.serve.istio; + +import com.google.gson.annotations.SerializedName; +import org.apache.submarine.serve.utils.IstioConstants; + +public class IstioHTTPDestination { + @SerializedName("destination") + private IstioDestination destination; + + public IstioHTTPDestination(String host){ + this.destination = new IstioDestination(host); + } + + + public static class IstioDestination{ + @SerializedName("host") + private String host; + + @SerializedName("port") + private IstioPort port; + + public IstioDestination(String host) { + this.host = host; + this.port = new IstioPort(IstioConstants.DEFAULT_SERVE_POD_PORT); + } + } + + public static class IstioPort { + @SerializedName("number") + private Integer number; + + public IstioPort(Integer port){ + this.number = port; + } + } +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java new file mode 100644 index 0000000..18e0b6c --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPMatchRequest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.submarine.serve.istio; + +import com.google.gson.annotations.SerializedName; + +public class IstioHTTPMatchRequest { + @SerializedName("uri") + private IstioPrefix prefix; + + public IstioHTTPMatchRequest(String prefix) { + this.prefix = new IstioPrefix(prefix); + } + + public static class IstioPrefix { + @SerializedName("prefix") + private String path; + + public IstioPrefix(String path){ + this.path = path; + } + } +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java new file mode 100644 index 0000000..7f7ff9a --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioHTTPRoute.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.submarine.serve.istio; + +import com.google.gson.annotations.SerializedName; +import org.apache.submarine.serve.utils.IstioConstants; + +import java.util.ArrayList; +import java.util.List; + +public class IstioHTTPRoute { + @SerializedName("match") + private List<IstioHTTPMatchRequest> match = new ArrayList<>(); + + @SerializedName("route") + private List<IstioHTTPDestination> route = new ArrayList<>(); + + @SerializedName("rewrite") + private IstioRewrite rewrite; + + public IstioHTTPRoute() { + this.rewrite = new IstioRewrite(IstioConstants.REWRITE_URL); + } + + @Override + public String toString() { + return "'rewrite': {'uri': " + rewrite.getRewrite() + "}"; + + } + + public void addHTTPMatchRequest(IstioHTTPMatchRequest match){ + this.match.add(match); + } + + public void addHTTPDestination(IstioHTTPDestination destination){ + this.route.add(destination); + } + public static class IstioRewrite{ + @SerializedName("uri") + private String uri; + + public IstioRewrite(String rewrite){ + this.uri = rewrite; + } + + public String getRewrite() { + return uri; + } + } + +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java new file mode 100644 index 0000000..dbe90de --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/istio/IstioVirtualService.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.submarine.serve.istio; + +import com.google.gson.annotations.SerializedName; +import io.kubernetes.client.models.V1ObjectMeta; +import org.apache.submarine.serve.utils.IstioConstants; + +import java.util.ArrayList; +import java.util.List; + +public class IstioVirtualService { + @SerializedName("apiVersion") + private String apiVersion = IstioConstants.API_VERSION; + + @SerializedName("kind") + private String kind = IstioConstants.KIND; + + @SerializedName("metadata") + private V1ObjectMeta metadata; + + @SerializedName("spec") + private IstioVirtualServiceSpec spec; + + // transient to avoid being serialized + private transient String group = IstioConstants.GROUP; + + private transient String version = IstioConstants.VERSION; + + private transient String plural = IstioConstants.PLURAL; + + public IstioVirtualService(String modelName, Integer modelVersion) { + V1ObjectMeta metadata = new V1ObjectMeta(); + metadata.setName(modelName); + metadata.setNamespace(IstioConstants.DEFAULT_NAMESPACE); + setMetadata(metadata); + setSpec(new IstioVirtualServiceSpec(modelName, modelVersion)); + } + + public String getApiVersion() { + return apiVersion; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public String getKind() { + return kind; + } + + public void setKind(String kind) { + this.kind = kind; + } + + public V1ObjectMeta getMetadata() { + return metadata; + } + + public void setMetadata(V1ObjectMeta metadata) { + this.metadata = metadata; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getPlural() { + return plural; + } + + public void setPlural(String plural) { + this.plural = plural; + } + + public IstioVirtualServiceSpec getSpec() { + return spec; + } + + public void setSpec(IstioVirtualServiceSpec istioVirtualServiceSpec){ + this.spec = istioVirtualServiceSpec; + } + + public static class IstioVirtualServiceSpec { + @SerializedName("hosts") + private List<String> hosts = new ArrayList<>(); + @SerializedName("gateways") + private List<String> gateways = new ArrayList<>(); + @SerializedName("http") + private List<IstioHTTPRoute> httpRoute = new ArrayList<>(); + + public IstioVirtualServiceSpec(String modelName, Integer modelVersion) { + hosts.add(IstioConstants.DEFAULT_INGRESS_HOST); + gateways.add(IstioConstants.DEFAULT_GATEWAY); + IstioHTTPDestination destination = new IstioHTTPDestination( + modelName + "-" + IstioConstants.DEFAULT_NAMESPACE); + IstioHTTPMatchRequest matchRequest = new IstioHTTPMatchRequest("/" + modelName + + "/" + String.valueOf(modelVersion) + "/"); + IstioHTTPRoute httpRoute = new IstioHTTPRoute(); + httpRoute.addHTTPDestination(destination); + httpRoute.addHTTPMatchRequest(matchRequest); + setHTTPRoute(httpRoute); + } + + public List<String> getHosts() { + return this.hosts; + } + + public void addHost(String host) { + hosts.add(host); + } + + public List<String> getGateways() { + return this.gateways; + } + + public void addGateway(String gateway) { + gateways.add(gateway); + } + + public void setHTTPRoute(IstioHTTPRoute istioHTTPRoute){ + this.httpRoute.add(istioHTTPRoute); + } + } +} diff --git a/submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java b/submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java new file mode 100644 index 0000000..10ae72d --- /dev/null +++ b/submarine-serve/src/main/java/org/apache/submarine/serve/utils/IstioConstants.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.submarine.serve.utils; + +public class IstioConstants { + public static final String API_VERSION = "networking.istio.io/v1beta1"; + + public static final String KIND = "VirtualService"; + + public static final String GROUP = "networking.istio.io"; + + public static final String VERSION = "v1beta1"; + + public static final String PLURAL = "virtualservices"; + + public static final String REWRITE_URL = "/"; + + public static final String DEFAULT_NAMESPACE = "default"; + + public static final String DEFAULT_GATEWAY = "istio-system/seldon-gateway"; + + public static final Integer DEFAULT_SERVE_POD_PORT = 8000; + + public static final String DEFAULT_INGRESS_HOST = "*"; + +} diff --git a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java index c1e8298..131e927 100644 --- a/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java +++ b/submarine-server/server-submitter/submitter-k8s/src/main/java/org/apache/submarine/server/submitter/k8s/K8sSubmitter.java @@ -57,6 +57,7 @@ import io.kubernetes.client.util.Watch; import org.apache.submarine.commons.utils.SubmarineConfiguration; import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException; +import org.apache.submarine.serve.istio.IstioVirtualService; import org.apache.submarine.serve.pytorch.SeldonPytorchServing; import org.apache.submarine.serve.seldon.SeldonDeployment; import org.apache.submarine.serve.tensorflow.SeldonTFServing; @@ -117,7 +118,6 @@ public class K8sSubmitter implements Submitter { public void initialize(SubmarineConfiguration conf) { try { String path = System.getenv(KUBECONFIG_ENV); - // path = System.getProperty("user.home") + "/.kube/config"; //TODO(tmp) KubeConfig config = KubeConfig.loadKubeConfig(new FileReader(path)); client = ClientBuilder.kubeconfig(config).build(); } catch (Exception e) { @@ -522,16 +522,39 @@ public class K8sSubmitter implements Submitter { public void createServe(ServeSpec spec) throws SubmarineRuntimeException { SeldonDeployment seldonDeployment = parseServeSpec(spec); - + IstioVirtualService istioVirtualService = new IstioVirtualService(spec.getModelName(), + spec.getModelVersion()); try { api.createNamespacedCustomObject(seldonDeployment.getGroup(), - seldonDeployment.getVersion(), + seldonDeployment.getVersion(), + "default", + seldonDeployment.getPlural(), + seldonDeployment, + "true"); + } catch (ApiException e) { + LOG.error(e.getMessage(), e); + throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); + } + try { + api.createNamespacedCustomObject(istioVirtualService.getGroup(), + istioVirtualService.getVersion(), "default", - seldonDeployment.getPlural(), - seldonDeployment, + istioVirtualService.getPlural(), + istioVirtualService, "true"); } catch (ApiException e) { LOG.error(e.getMessage(), e); + try { + api.deleteNamespacedCustomObject(seldonDeployment.getGroup(), + seldonDeployment.getVersion(), + "default", + seldonDeployment.getPlural(), + seldonDeployment.getMetadata().getName(), + new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build(), + null, null, null); + } catch (ApiException e1) { + LOG.error(e1.getMessage(), e1); + } throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); } } @@ -540,7 +563,8 @@ public class K8sSubmitter implements Submitter { public void deleteServe(ServeSpec spec) throws SubmarineRuntimeException { SeldonDeployment seldonDeployment = parseServeSpec(spec); - + IstioVirtualService istioVirtualService = new IstioVirtualService(spec.getModelName(), + spec.getModelVersion()); try { api.deleteNamespacedCustomObject(seldonDeployment.getGroup(), seldonDeployment.getVersion(), @@ -549,6 +573,13 @@ public class K8sSubmitter implements Submitter { seldonDeployment.getMetadata().getName(), new V1DeleteOptionsBuilder().withApiVersion(seldonDeployment.getApiVersion()).build(), null, null, null); + api.deleteNamespacedCustomObject(istioVirtualService.getGroup(), + istioVirtualService.getVersion(), + "default", + istioVirtualService.getPlural(), + istioVirtualService.getMetadata().getName(), + new V1DeleteOptionsBuilder().withApiVersion(istioVirtualService.getApiVersion()).build(), + null, null, null); } catch (ApiException e) { LOG.error(e.getMessage(), e); throw new SubmarineRuntimeException(e.getCode(), e.getMessage()); --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@submarine.apache.org For additional commands, e-mail: dev-h...@submarine.apache.org