def create_and_push_docker_image_to_ecr( region, bento_name, bento_version, snapshot_path ): """Create BentoService sagemaker image and push to AWS ECR Example: https://github.com/awslabs/amazon-sagemaker-examples/blob/\ master/advanced_functionality/scikit_bring_your_own/container/build_and_push.sh 1. get aws account info and login ecr 2. create ecr repository, if not exist 3. build tag and push docker image Args: region(String) bento_name(String) bento_version(String) snapshot_path(Path) Returns: str: AWS ECR Tag """ ecr_client = boto3.client("ecr", region) token = ecr_client.get_authorization_token() logger.debug("Getting docker login info from AWS") username, password = ( base64.b64decode(token["authorizationData"][0]["authorizationToken"]) .decode("utf-8") .split(":") ) registry_url = token["authorizationData"][0]["proxyEndpoint"] auth_config_payload = {"username": username, "password": password} docker_api = docker.APIClient() image_name = bento_name.lower() + "-sagemaker" ecr_tag = strip_scheme( "{registry_url}/{image_name}:{version}".format( registry_url=registry_url, image_name=image_name, version=bento_version ) ) logger.debug("Building docker image: %s", ecr_tag) for line in docker_api.build( path=snapshot_path, dockerfile="Dockerfile-sagemaker", tag=ecr_tag ): process_docker_api_line(line) try: ecr_client.describe_repositories(repositoryNames=[image_name])["repositories"] except ecr_client.exceptions.RepositoryNotFoundException: ecr_client.create_repository(repositoryName=image_name) logger.debug("Pushing image to AWS ECR at %s", ecr_tag) for line in docker_api.push(ecr_tag, stream=True, auth_config=auth_config_payload): process_docker_api_line(line) logger.debug("Finished pushing image: %s", ecr_tag) return ecr_tag
def deploy_bentoml(clipper_conn, bundle_path, api_name, model_name=None, labels=None, build_envs=None): """Deploy bentoml bundle to clipper cluster Args: clipper_conn(clipper_admin.ClipperConnection): Clipper connection instance bundle_path(str): Path to the saved BentomlService bundle. api_name(str): name of the api that will be used as prediction function for clipper cluster model_name(str): Model's name for clipper cluster labels(:obj:`list(str)`, optional): labels for clipper model Returns: tuple: Model name and model version that deployed to clipper """ track("clipper-deploy", {'bento_service_bundle_path': bundle_path}) build_envs = {} if build_envs is None else build_envs # docker is required to build clipper model image ensure_docker_available_or_raise() if not clipper_conn.connected: raise BentoMLException( "No connection to Clipper cluster. CallClipperConnection.connect to " "connect to an existing cluster or ClipperConnection.start_clipper to " "create a new one") bento_service_metadata = load_bento_service_metadata(bundle_path) try: api_metadata = next((api for api in bento_service_metadata.apis if api.name == api_name)) except StopIteration: raise BentoMLException( "Can't find API '{}' in BentoService bundle {}".format( api_name, bento_service_metadata.name)) if api_metadata.input_type not in ADAPTER_TYPE_TO_INPUT_TYPE: raise BentoMLException( "Only BentoService APIs using ClipperInput can be deployed to Clipper" ) input_type = ADAPTER_TYPE_TO_INPUT_TYPE[api_metadata.input_type] model_name = model_name or get_clipper_compatible_string( bento_service_metadata.name + "-" + api_metadata.name) model_version = get_clipper_compatible_string( bento_service_metadata.version) with TempDirectory() as tempdir: entry_py_content = CLIPPER_ENTRY.format(api_name=api_name) build_path = os.path.join(tempdir, "bento") shutil.copytree(bundle_path, build_path) with open(os.path.join(build_path, "clipper_entry.py"), "w") as f: f.write(entry_py_content) if bento_service_metadata.env.python_version.startswith("3.6"): base_image = "clipper/python36-closure-container:0.4.1" elif bento_service_metadata.env.python_version.startswith("2.7"): base_image = "clipper/python-closure-container:0.4.1" else: raise BentoMLException( "Python version {} is not supported in Clipper".format( bento_service_metadata.env.python_version)) docker_content = CLIPPER_DOCKERFILE.format( model_name=model_name, model_version=model_version, base_image=base_image, pip_index_url=build_envs.get("PIP_INDEX_URL", ""), pip_trusted_url=build_envs.get("PIP_TRUSTED_HOST", ""), ) with open(os.path.join(build_path, "Dockerfile-clipper"), "w") as f: f.write(docker_content) docker_api = docker.APIClient() clipper_model_docker_image_tag = "clipper-model-{}:{}".format( bento_service_metadata.name.lower(), bento_service_metadata.version) for line in docker_api.build( path=build_path, dockerfile="Dockerfile-clipper", tag=clipper_model_docker_image_tag, ): process_docker_api_line(line) logger.info( "Successfully built docker image %s for Clipper deployment", clipper_model_docker_image_tag, ) clipper_conn.deploy_model( name=model_name, version=model_version, input_type=input_type, image=clipper_model_docker_image_tag, labels=labels, ) track("clipper-deploy-success", {'bento_service_bundle_path': bundle_path}) return model_name, model_version