From 358bad6d74de1d595962689b81eaf13b39d3240a Mon Sep 17 00:00:00 2001 From: Ardaman Singh Date: Fri, 7 Sep 2018 09:30:23 -0700 Subject: [PATCH 1/4] support passing secret names for registry to kubernetes container manager --- clipper_admin/clipper_admin/VERSION.txt | 2 +- clipper_admin/clipper_admin/clipper_admin.py | 11 +++++++++-- .../docker/docker_container_manager.py | 4 ++-- .../kubernetes/kubernetes_container_manager.py | 14 +++++++++++--- .../kubernetes/model-container-template.yaml | 4 ++++ .../kubernetes/query-frontend-deployment.yaml | 1 - 6 files changed, 27 insertions(+), 9 deletions(-) diff --git a/clipper_admin/clipper_admin/VERSION.txt b/clipper_admin/clipper_admin/VERSION.txt index 6563189c5..0d91a54c7 100644 --- a/clipper_admin/clipper_admin/VERSION.txt +++ b/clipper_admin/clipper_admin/VERSION.txt @@ -1 +1 @@ -develop +0.3.0 diff --git a/clipper_admin/clipper_admin/clipper_admin.py b/clipper_admin/clipper_admin/clipper_admin.py index e40c67ae9..c26d42e09 100644 --- a/clipper_admin/clipper_admin/clipper_admin.py +++ b/clipper_admin/clipper_admin/clipper_admin.py @@ -348,7 +348,7 @@ def build_and_deploy_model(self, raise UnconnectedException() image = self.build_model(name, version, model_data_path, base_image, container_registry, pkgs_to_install) - self.deploy_model(name, version, input_type, image, labels, + self.deploy_model(name, version, input_type, container_registry, image, labels, num_replicas, batch_size) def build_model(self, @@ -389,7 +389,7 @@ def build_model(self, container RPC client. container_registry : str, optional The Docker container registry to push the freshly built model to. Note - that if you are running Clipper on Kubernetes, this registry must be accesible + that if you are running Clipper on Kubernetes, this registry must be accessible to the Kubernetes cluster in order to fetch the container from the registry. pkgs_to_install : list (of strings), optional A list of the names of packages to install, using pip, in the container. @@ -480,6 +480,7 @@ def deploy_model(self, name, version, input_type, + container_registry, image, labels=None, num_replicas=1, @@ -515,6 +516,11 @@ def deploy_model(self, one of "integers", "floats", "doubles", "bytes", or "strings". See the `User Guide `_ for more details on picking the right input type for your application. + container_registry : str, optional + The Docker container registry to push the freshly built model to. Note + that if you are running Clipper on Kubernetes, you should create kubernetes secret with the + credentials needed to access the registry, and pass the secret name using `registry_secret_names` + parameter in the KubernetesContainerManager constructor. image : str The fully specified Docker image to deploy. If using a custom registry, the registry name must be prepended to the image. For example, @@ -556,6 +562,7 @@ def deploy_model(self, name=name, version=version, input_type=input_type, + container_registry=container_registry, image=image, num_replicas=num_replicas) self.register_model( diff --git a/clipper_admin/clipper_admin/docker/docker_container_manager.py b/clipper_admin/clipper_admin/docker/docker_container_manager.py index 2b6ddf827..6ca8a0548 100644 --- a/clipper_admin/clipper_admin/docker/docker_container_manager.py +++ b/clipper_admin/clipper_admin/docker/docker_container_manager.py @@ -268,11 +268,11 @@ def connect(self): self.prometheus_port = all_labels[CLIPPER_DOCKER_PORT_LABELS['metric']] self.prom_config_path = all_labels[CLIPPER_METRIC_CONFIG_LABEL] - def deploy_model(self, name, version, input_type, image, num_replicas=1): + def deploy_model(self, name, version, input_type, image, container_registry, num_replicas=1): # Parameters # ---------- # image : str - # The fully specified Docker imagesitory to deploy. If using a custom + # The fully specified Docker image to deploy. If using a custom # registry, the registry name must be prepended to the image. For example, # "localhost:5000/my_model_name:my_model_version" or # "quay.io/my_namespace/my_model_name:my_model_version" diff --git a/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py b/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py index 70c2f8258..bfed20c66 100644 --- a/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py +++ b/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py @@ -68,7 +68,8 @@ def __init__(self, redis_port=6379, useInternalIP=False, namespace='default', - create_namespace_if_not_exists=False): + create_namespace_if_not_exists=False, + registry_secret_names={}): """ Parameters @@ -105,6 +106,10 @@ def __init__(self, Create a k8s namespace if the namespace doesnt already exist. If this argument is provided and the k8s namespace does not exist a new k8s namespace will be created. + registry_secret_names: Dictionary, None + A mapping between the container registry where the images reside and the name of the + secret that contains the credentials to access the registry. E.g. + registry_secret_names = {"localhost:5000": "myregistrykey"} Note ---- @@ -129,6 +134,7 @@ def __init__(self, configuration.assert_hostname = False self._k8s_v1 = client.CoreV1Api() self._k8s_beta = client.ExtensionsV1beta1Api() + self.registry_secret_names = registry_secret_names # Create the template engine # Config: Any variable missing -> Error @@ -368,11 +374,12 @@ def connect(self): "Could not connect to Clipper Kubernetes cluster. " "Reason: {}".format(e)) - def deploy_model(self, name, version, input_type, image, num_replicas=1): + def deploy_model(self, name, version, input_type, image, container_registry, num_replicas=1): for query_frontend_id in range(self.num_frontend_replicas): deployment_name = get_model_deployment_name( name, version, query_frontend_id, self.cluster_name) + secret_name = self.registry_secret_names.get(container_registry, "") generated_body = self._generate_config( CONFIG_FILES['model']['deployment'], deployment_name=deployment_name, @@ -383,7 +390,8 @@ def deploy_model(self, name, version, input_type, image, num_replicas=1): query_frontend_id=query_frontend_id, input_type=input_type, image=image, - cluster_name=self.cluster_name) + cluster_name=self.cluster_name, + image_secret_name=secret_name) with _pass_conflicts(): self._k8s_beta.create_namespaced_deployment( diff --git a/clipper_admin/clipper_admin/kubernetes/model-container-template.yaml b/clipper_admin/clipper_admin/kubernetes/model-container-template.yaml index 8610ff478..78542e7dd 100644 --- a/clipper_admin/clipper_admin/kubernetes/model-container-template.yaml +++ b/clipper_admin/clipper_admin/kubernetes/model-container-template.yaml @@ -43,3 +43,7 @@ spec: - /model_is_ready.check initialDelaySeconds: 3 periodSeconds: 3 + {% if image_secret_name %} + imagePullSecrets: + - name: {{ image_secret_name }} + {% endif %} diff --git a/clipper_admin/clipper_admin/kubernetes/query-frontend-deployment.yaml b/clipper_admin/clipper_admin/kubernetes/query-frontend-deployment.yaml index 02487357a..7e4f97b09 100644 --- a/clipper_admin/clipper_admin/kubernetes/query-frontend-deployment.yaml +++ b/clipper_admin/clipper_admin/kubernetes/query-frontend-deployment.yaml @@ -38,4 +38,3 @@ spec: ports: - containerPort: 1390 restartPolicy: Always - From 8c06c662cc11a71434a6fca28c67fe39da9701d1 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 10 Sep 2018 19:20:41 +0000 Subject: [PATCH 2/4] fix doc, test case --- .../clipper_admin/kubernetes/kubernetes_container_manager.py | 2 +- integration-tests/clipper_admin_tests.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py b/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py index bfed20c66..12820e0a4 100644 --- a/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py +++ b/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py @@ -106,7 +106,7 @@ def __init__(self, Create a k8s namespace if the namespace doesnt already exist. If this argument is provided and the k8s namespace does not exist a new k8s namespace will be created. - registry_secret_names: Dictionary, None + registry_secret_names: Dictionary, {} A mapping between the container registry where the images reside and the name of the secret that contains the credentials to access the registry. E.g. registry_secret_names = {"localhost:5000": "myregistrykey"} diff --git a/integration-tests/clipper_admin_tests.py b/integration-tests/clipper_admin_tests.py index 9afd358cf..f46b9da0c 100644 --- a/integration-tests/clipper_admin_tests.py +++ b/integration-tests/clipper_admin_tests.py @@ -274,6 +274,7 @@ def test_stop_models(self): model_name, version, input_type, + clipper_registry, container_name, num_replicas=1) From 5f7d15abe474c338b513bb166415c56dc5b83566 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 10 Sep 2018 23:02:18 +0000 Subject: [PATCH 3/4] pin cloudpickle to 0.5.5 to ensure compatibility, use warning() instead of warn() for Py version compatibility --- clipper_admin/clipper_admin/deployers/pyspark.py | 2 +- clipper_admin/clipper_admin/deployers/tensorflow.py | 2 +- .../kubernetes/kubernetes_container_manager.py | 10 +++++----- clipper_admin/setup.py | 2 +- dockerfiles/ClipperDevDockerfile | 2 +- dockerfiles/ClipperPy35DevDockerfile | 2 +- dockerfiles/Py2RPCDockerfile | 2 +- dockerfiles/Py35RPCDockerfile | 2 +- dockerfiles/Py36RPCDockerfile | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clipper_admin/clipper_admin/deployers/pyspark.py b/clipper_admin/clipper_admin/deployers/pyspark.py index e3fe50510..467257c81 100644 --- a/clipper_admin/clipper_admin/deployers/pyspark.py +++ b/clipper_admin/clipper_admin/deployers/pyspark.py @@ -222,7 +222,7 @@ def predict(spark, model, inputs): else: pyspark_model.save(sc, spark_model_save_loc) except Exception as e: - logger.warn("Error saving spark model: %s" % e) + logger.warning("Error saving spark model: %s" % e) raise e # extract the pyspark class name. This will be something like diff --git a/clipper_admin/clipper_admin/deployers/tensorflow.py b/clipper_admin/clipper_admin/deployers/tensorflow.py index 1ff45eb68..25b87f854 100644 --- a/clipper_admin/clipper_admin/deployers/tensorflow.py +++ b/clipper_admin/clipper_admin/deployers/tensorflow.py @@ -191,7 +191,7 @@ def predict(sess, inputs): save_path = saver.save(tf_sess_or_saved_model_path, tf_sess_save_loc) except Exception as e: - logger.warn("Error saving Tensorflow model: %s" % e) + logger.warning("Error saving Tensorflow model: %s" % e) raise e logger.info("TensorFlow model saved at: %s " % save_path) else: diff --git a/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py b/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py index 12820e0a4..2683e391b 100644 --- a/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py +++ b/clipper_admin/clipper_admin/kubernetes/kubernetes_container_manager.py @@ -307,7 +307,7 @@ def connect(self): if len(external_node_hosts) == 0 and (self.useInternalIP): msg = "No external node addresses found. Using Internal IP address" - self.logger.warn(msg) + self.logger.warning(msg) for addr in node.status.addresses: if addr.type == "InternalIP": external_node_hosts.append(addr.address) @@ -367,7 +367,7 @@ def connect(self): self.clipper_metric_port)) except ApiException as e: - logging.warn( + logging.warning( "Exception connecting to Clipper Kubernetes cluster: {}". format(e)) raise ClipperException( @@ -470,7 +470,7 @@ def stop_models(self, models): cluster_label=CLIPPER_DOCKER_LABEL, cluster_name=self.cluster_name)) except ApiException as e: - self.logger.warn( + self.logger.warning( "Exception deleting kubernetes deployments: {}".format(e)) raise e @@ -484,7 +484,7 @@ def stop_all_model_containers(self): cluster_label=CLIPPER_DOCKER_LABEL, cluster_name=self.cluster_name)) except ApiException as e: - self.logger.warn( + self.logger.warning( "Exception deleting kubernetes deployments: {}".format(e)) raise e @@ -519,7 +519,7 @@ def stop_all(self, graceful=True): self._k8s_v1.delete_collection_namespaced_config_map( namespace=self.k8s_namespace, label_selector=cluster_selecter) except ApiException as e: - logging.warn( + logging.warning( "Exception deleting kubernetes resources: {}".format(e)) def get_registry(self): diff --git a/clipper_admin/setup.py b/clipper_admin/setup.py index aeda894d4..c0afabd38 100644 --- a/clipper_admin/setup.py +++ b/clipper_admin/setup.py @@ -25,7 +25,7 @@ install_requires=[ 'requests', 'numpy', 'subprocess32; python_version<"3"', 'pyyaml', 'docker>=3.0', 'kubernetes>=6.0.0', 'prometheus_client', - 'cloudpickle>=0.5', 'enum34; python_version<"3.4"', 'redis', 'psutil', + 'cloudpickle==0.5.5', 'enum34; python_version<"3.4"', 'redis', 'psutil', 'jsonschema', 'jinja2' ], extras_require={ diff --git a/dockerfiles/ClipperDevDockerfile b/dockerfiles/ClipperDevDockerfile index 48e7851d5..100440157 100644 --- a/dockerfiles/ClipperDevDockerfile +++ b/dockerfiles/ClipperDevDockerfile @@ -66,7 +66,7 @@ RUN set -ex; \ # see CA_CERTIFICATES_JAVA_VERSION notes above RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure -RUN pip install cloudpickle==0.5.* pyzmq==17.0.* requests==2.18.* subprocess32==3.2.* scikit-learn==0.19.* \ +RUN pip install cloudpickle==0.5.5 pyzmq==17.0.* requests==2.18.* subprocess32==3.2.* scikit-learn==0.19.* \ numpy==1.14.* pyyaml==3.12.* docker==3.1.* kubernetes==6.0.* tensorflow==1.6.* mxnet==1.1.* pyspark==2.3.* \ xgboost==0.7.* jsonschema==2.6.* psutil==5.4.* prometheus_client diff --git a/dockerfiles/ClipperPy35DevDockerfile b/dockerfiles/ClipperPy35DevDockerfile index b13c63403..d80c3a0aa 100644 --- a/dockerfiles/ClipperPy35DevDockerfile +++ b/dockerfiles/ClipperPy35DevDockerfile @@ -71,7 +71,7 @@ RUN set -ex; \ # see CA_CERTIFICATES_JAVA_VERSION notes above RUN /var/lib/dpkg/info/ca-certificates-java.postinst configure -RUN pip3 install cloudpickle==0.5.* pyzmq==17.0.* requests==2.18.* scikit-learn==0.19.* \ +RUN pip3 install cloudpickle==0.5.5 pyzmq==17.0.* requests==2.18.* scikit-learn==0.19.* \ numpy==1.14.* pyyaml==3.12.* docker==3.1.* kubernetes==5.0.* tensorflow==1.6.* mxnet==1.1.* pyspark==2.3.* \ xgboost==0.7.* diff --git a/dockerfiles/Py2RPCDockerfile b/dockerfiles/Py2RPCDockerfile index 0c835fd05..befa81ab8 100644 --- a/dockerfiles/Py2RPCDockerfile +++ b/dockerfiles/Py2RPCDockerfile @@ -9,7 +9,7 @@ RUN mkdir -p /model \ && apt-get update \ && apt-get install -y libzmq5 libzmq5-dev redis-server libsodium18 build-essential -RUN pip install cloudpickle==0.5.* pyzmq==17.0.* prometheus_client==0.1.* \ +RUN pip install cloudpickle==0.5.5 pyzmq==17.0.* prometheus_client==0.1.* \ pyyaml==3.12.* jsonschema==2.6.* redis==2.10.* psutil==5.4.* flask==0.12.2 \ numpy==1.14.* subprocess32==3.2.* diff --git a/dockerfiles/Py35RPCDockerfile b/dockerfiles/Py35RPCDockerfile index 79612a20d..1bf58493d 100644 --- a/dockerfiles/Py35RPCDockerfile +++ b/dockerfiles/Py35RPCDockerfile @@ -9,7 +9,7 @@ RUN mkdir -p /model \ && apt-get update \ && apt-get install -y libzmq3 libzmq3-dev redis-server libsodium13 build-essential -RUN pip install cloudpickle==0.5.* pyzmq==17.0.* prometheus_client==0.1.* \ +RUN pip install cloudpickle==0.5.5 pyzmq==17.0.* prometheus_client==0.1.* \ pyyaml==3.12.* jsonschema==2.6.* redis==2.10.* psutil==5.4.* flask==0.12.2 \ numpy==1.14.* diff --git a/dockerfiles/Py36RPCDockerfile b/dockerfiles/Py36RPCDockerfile index 70e04b61c..9353509e6 100644 --- a/dockerfiles/Py36RPCDockerfile +++ b/dockerfiles/Py36RPCDockerfile @@ -9,7 +9,7 @@ RUN mkdir -p /model \ && apt-get update \ && apt-get install -y libzmq5 libzmq5-dev redis-server libsodium18 build-essential -RUN pip install cloudpickle==0.5.* pyzmq==17.0.* prometheus_client==0.1.* \ +RUN pip install cloudpickle==0.5.5 pyzmq==17.0.* prometheus_client==0.1.* \ pyyaml==3.12.* jsonschema==2.6.* redis==2.10.* psutil==5.4.* flask==0.12.2 \ numpy==1.14.* From 582327cbb36dd2200225ea2145724c789c7313a5 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 12 Sep 2018 21:43:55 +0000 Subject: [PATCH 4/4] restore version to develop --- clipper_admin/clipper_admin/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clipper_admin/clipper_admin/VERSION.txt b/clipper_admin/clipper_admin/VERSION.txt index 0d91a54c7..6563189c5 100644 --- a/clipper_admin/clipper_admin/VERSION.txt +++ b/clipper_admin/clipper_admin/VERSION.txt @@ -1 +1 @@ -0.3.0 +develop