Exemple #1
0
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
Exemple #2
0
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