azure-sdk-for-python: Managed endpoint doesn't use Azure ML connections (private pip) when building image

  • Package Name: azureml-mlflow
  • Package Version: 1.37.0
  • Operating System: Windows
  • Python Version: 3.8.11

Describe the bug When using private pip feeds it is possible to set up a connection (token) which is shared across the Azure ML Studio. This works for creating an environment for training the model. If the model is saved in the MLFLOW format it also works when using an Azure Container Instance for creating a realtime endpoint very easily. But when trying to use the managed endpoint the token is not used.

To Reproduce

When using private pip feeds it is possible to set up a connection (token) which is shared across the Azure ML Studio by running 1:

ws.set_connection(
    name="private-pip",
    category= "PythonFeed",
    authType="PAT",
    target = "https://@pkgs.dev.azure.com/MY-ORG",
    value = "1234abcd"
)

2: This will then be used if you construct a environment were a private pip is referred and replace the package myprivatepackage with something in you feed:

from azureml.core import Environment
from azureml.core.conda_dependencies import CondaDependencies

env = Environment("test_env")
cd = CondaDependencies.create(
    python_version="3.8.12",
    conda_packages=["pip"],
    pip_packages=["scikit-learn", "pandas","azureml-mlflow","pyyaml","myprivatepackage"]
    )
cd.set_pip_option("--index-url https://pkgs.dev.azure.com/MY-ORG/_packaging/MY-FEED/pypi/simple/")
env.python.conda_dependencies = cd
env.register(ws)
env.build(ws)

3: If you train a model you can deploy it where it connects using the token when building the image too.

First create a training file:

## ml_project/train.py
from sklearn.linear_model import LinearRegression
import mlflow
import mlflow.sklearn
from azureml.core import Run
import yaml

from sklearn.datasets import load_iris
X, y = load_iris(as_frame=True, return_X_y=True)

run = Run.get_context()
ws = run.experiment.workspace
env = run.get_environment()
conda_env = yaml.safe_load(env.python.conda_dependencies.serialize_to_string())

with mlflow.start_run():
    X, y = load_iris(as_frame=True, return_X_y=True)
    model = LinearRegression()
    model.fit(X, y)
    mlflow.sklearn.log_model(model, "model", conda_env=conda_env)


Then then train the model


from azureml.core import Experiment, ScriptRunConfig
from azureml.core.compute import ComputeTarget

cpu_cluster = ComputeTarget(workspace=ws, name="test-cluster")
exp = Experiment(workspace=ws, name="test")

src = ScriptRunConfig(
    source_directory= "mlproject",
    script='train.py',
    compute_target=cpu_cluster,
    environment=env
)
run = exp.submit(src)

Then register the model:

import mlflow
mlflow.set_tracking_uri(ws.get_mlflow_tracking_uri())
model_info = mlflow.register_model(f"runs:/{run.id}/model", "test_model")

4: You can deploy it using Azure Container Instance which works by grabbing the token. It deploys after some time.:

from mlflow.deployments import get_deploy_client
mlflow.set_tracking_uri(ws.get_mlflow_tracking_uri())
client = get_deploy_client(mlflow.get_tracking_uri())
client.create_deployment(model_uri=f'models:/test_model/1', name="mlflow-test-aci")

5: Go to the UI for Azure Machine Learning Studio and go to the wizard for setting up a managed endpoint. As the model is of type MLFLOW it will create enviorment and scoring script for you. When the image builds it will fail as it is expecting the user to put in a password:

Instance status:
SystemSetup: Succeeded
UserContainerImagePull: Succeeded
ModelDownload: Succeeded
UserContainerStart: InProgress

Container logs:
2022-01-11T12:29:04,946980587+00:00 - rsyslog/run 
2022-01-11T12:29:04,951881106+00:00 - gunicorn/run 

2022-01-11T12:29:04,953826713+00:00 - nginx/run 
AzureML image information: mlflow-ubuntu18.04-py37-cpu-inference:20210930.v4


PATH environment variable: /opt/miniconda/envs/amlenv/bin:/opt/miniconda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PYTHONPATH environment variable: 

Pip Dependencies
---------------
applicationinsights==0.11.10
azureml-inference-server-http==0.3.2
certifi==2021.5.30
charset-normalizer==2.0.6
click==8.0.1
cloudpickle==2.0.0
databricks-cli==0.15.0
entrypoints==0.3
Flask==1.0.3
gitdb==4.0.7
GitPython==3.1.24
gunicorn==20.1.0
idna==3.2
importlib-metadata==4.8.1
inference-schema==1.3.0
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
mlflow-skinny==1.17.0
numpy==1.21.2
pandas==1.2.4
protobuf==3.18.0
python-dateutil==2.8.2
pytz==2021.1
PyYAML==5.4.1
requests==2.26.0
six==1.16.0
smmap==4.0.0
tabulate==0.8.9
typing-extensions==3.10.0.2
urllib3==1.26.7
Werkzeug==2.0.1
wrapt==1.12.1
zipp==3.6.0


Entry script directory: /var/mlflow_resources/.

Updating conda environment from /var/azureml-app/azureml-models/test_model/1/model/conda.yaml !
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done

Downloading and Extracting Packages

ca-certificates-2020 | 128 KB    |            |   0% 
ca-certificates-2020 | 128 KB    | #2         |  13% 
ca-certificates-2020 | 128 KB    | ########## | 100% 

_openmp_mutex-4.5    | 22 KB     |            |   0% 
_openmp_mutex-4.5    | 22 KB     | ########## | 100% 

libgcc-ng-11.2.0     | 887 KB    |            |   0% 
libgcc-ng-11.2.0     | 887 KB    | ########## | 100% 
libgcc-ng-11.2.0     | 887 KB    | ########## | 100% 

libzlib-1.2.11       | 59 KB     |            |   0% 
libzlib-1.2.11       | 59 KB     | ########## | 100% 

certifi-2020.6.20    | 160 KB    |            |   0% 
certifi-2020.6.20    | 160 KB    | ########## | 100% 

ld_impl_linux-64-2.3 | 667 KB    |            |   0% 
ld_impl_linux-64-2.3 | 667 KB    | ########## | 100% 
ld_impl_linux-64-2.3 | 667 KB    | ########## | 100% 

libnsl-2.0.0         | 31 KB     |            |   0% 
libnsl-2.0.0         | 31 KB     | ########## | 100% 

sqlite-3.37.0        | 1.5 MB    |            |   0% 
sqlite-3.37.0        | 1.5 MB    | ########## | 100% 
sqlite-3.37.0        | 1.5 MB    | ########## | 100% 

xz-5.2.5             | 438 KB    |            |   0% 
xz-5.2.5             | 438 KB    | ########## | 100% 
xz-5.2.5             | 438 KB    | ########## | 100% 

libstdcxx-ng-11.2.0  | 4.2 MB    |            |   0% 
libstdcxx-ng-11.2.0  | 4.2 MB    | ########## | 100% 
libstdcxx-ng-11.2.0  | 4.2 MB    | ########## | 100% 

pip-20.2.4           | 2.0 MB    |            |   0% 
pip-20.2.4           | 2.0 MB    | ########## | 100% 
pip-20.2.4           | 2.0 MB    | ########## | 100% 

readline-8.1         | 295 KB    |            |   0% 
readline-8.1         | 295 KB    | ########## | 100% 

libgomp-11.2.0       | 427 KB    |            |   0% 
libgomp-11.2.0       | 427 KB    | ########## | 100% 
libgomp-11.2.0       | 427 KB    | ########## | 100% 

ncurses-6.2          | 1.1 MB    |            |   0% 
ncurses-6.2          | 1.1 MB    | ########## | 100% 
ncurses-6.2          | 1.1 MB    | ########## | 100% 

python-3.8.12        | 26.2 MB   |            |   0% 
python-3.8.12        | 26.2 MB   | 5          |   6% 
python-3.8.12        | 26.2 MB   | ##9        |  30% 
python-3.8.12        | 26.2 MB   | ####6      |  46% 
python-3.8.12        | 26.2 MB   | ######9    |  70% 
python-3.8.12        | 26.2 MB   | ########## | 100% 
python-3.8.12        | 26.2 MB   | ########## | 100% 

wheel-0.35.1         | 36 KB     |            |   0% 
wheel-0.35.1         | 36 KB     | ########## | 100% 

_libgcc_mutex-0.1    | 3 KB      |            |   0% 
_libgcc_mutex-0.1    | 3 KB      | ########## | 100% 

libffi-3.4.2         | 57 KB     |            |   0% 
libffi-3.4.2         | 57 KB     | ########## | 100% 

zlib-1.2.11          | 86 KB     |            |   0% 
zlib-1.2.11          | 86 KB     | ########## | 100% 

openssl-3.0.0        | 2.9 MB    |            |   0% 
openssl-3.0.0        | 2.9 MB    | ########## | 100% 
openssl-3.0.0        | 2.9 MB    | ########## | 100% 

tk-8.6.11            | 3.3 MB    |            |   0% 
tk-8.6.11            | 3.3 MB    | ########## | 100% 
tk-8.6.11            | 3.3 MB    | ########## | 100% 

setuptools-50.3.0    | 902 KB    |            |   0% 
setuptools-50.3.0    | 902 KB    | ########## | 100% 
setuptools-50.3.0    | 902 KB    | ########## | 100% 
Preparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done


==> WARNING: A newer version of conda exists. <==
  current version: 4.9.2
  latest version: 4.11.0

Please update conda by running

    $ conda update -n base -c defaults conda


Pip subprocess error:
ERROR: Exception:
Traceback (most recent call last):
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py", line 228, in _main
    status = self.run(options, args)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py", line 182, in wrapper
    return func(self, options, args)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/commands/install.py", line 323, in run
    requirement_set = resolver.resolve(
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py", line 183, in resolve
    discovered_reqs.extend(self._resolve_one(requirement_set, req))
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py", line 388, in _resolve_one
    abstract_dist = self._get_abstract_dist_for(req_to_install)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py", line 339, in _get_abstract_dist_for
    self._populate_link(req)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py", line 305, in _populate_link
    req.link = self._find_requirement_link(req)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py", line 270, in _find_requirement_link
    best_candidate = self.finder.find_requirement(req, upgrade)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py", line 900, in find_requirement
    best_candidate_result = self.find_best_candidate(
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py", line 883, in find_best_candidate
    candidates = self.find_all_candidates(project_name)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py", line 827, in find_all_candidates
    package_links = self.process_project_url(
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py", line 791, in process_project_url
    html_page = self._link_collector.fetch_page(project_url)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/collector.py", line 629, in fetch_page
    return _get_html_page(location, session=self.session)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/collector.py", line 441, in _get_html_page
    resp = _get_html_response(url, session=session)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/index/collector.py", line 138, in _get_html_response
    resp = session.get(
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py", line 543, in get
    return self.request('GET', url, **kwargs)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/network/session.py", line 421, in request
    return super(PipSession, self).request(method, url, *args, **kwargs)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py", line 530, in request
    resp = self.send(prep, **send_kwargs)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py", line 650, in send
    r = dispatch_hook('response', hooks, r, **kwargs)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_vendor/requests/hooks.py", line 31, in dispatch_hook
    _hook_data = hook(hook_data, **kwargs)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/network/auth.py", line 256, in handle_401
    username, password, save = self._prompt_for_password(parsed.netloc)
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/network/auth.py", line 226, in _prompt_for_password
    username = ask_input("User for {}: ".format(netloc))
  File "/opt/miniconda/envs/userenv/lib/python3.8/site-packages/pip/_internal/utils/misc.py", line 259, in ask_input
    return input(message)
EOFError: EOF when reading a line


CondaEnvException: Pip failed

Installing pip dependencies: ...working... Ran pip subprocess with arguments:
['/opt/miniconda/envs/userenv/bin/python', '-m', 'pip', 'install', '-U', '-r', '/tmp/condaenv.i5j0upr4.requirements.txt']
Pip subprocess output:
Looking in indexes: https://pkgs.dev.azure.com/MY-ORG/_packaging/MY-FEED/pypi/simple/
User for pkgs.dev.azure.com: 
failed

6: I assume the same errro happens on managed Batch endpoint but I haven’t tried it out.

Expected behavior I expect the managed endpoint to work. I also expect it to work for batch endpoint.

Suggestion A good solution to this would be to allow for setting a variable in Azure ML studio which was always loaded (at build time) as an env var (PIP_INDEX_URL) when building an environment. That way we don’t have to specify the url in the environment/conda file and it can easily be changed if the pip feed changes it address.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 48 (7 by maintainers)

Most upvoted comments

@luigiw @vizhur What you describe is actually what I did (see top of Issue) but it failed? 😃 It only looks like updating of URLs happen in environments created by the user and not the ones created automatically by AzureML when deploying a MLFlow model to managed endpoints (where the env can’t be controlled).

or maybe @azureml-github is better?

@vizhur can I maybe convince you to ping them internally?

Hi again @mccoyp . Sorry for keeping pinging you but this blocks us from using managed endpoints 😃 I could seem that @bandsina has disabled notifications. Is it possible that you try another (internal) channel?

Hi @thomasfrederikhoeck, thanks for the ping! @bandsina, have you been able to look into this, or do you know of someone on the ML team who can?

Hi @thomasfrederikhoeck, thank you for opening an issue! I’ll tag the appropriate folks so we can look into this as soon as possible.