Skip to content

Commit 49430ea

Browse files
author
Miguel Varela Ramos
authored
Allow custom dependency paths (#1896)
1 parent 905a0de commit 49430ea

File tree

8 files changed

+150
-16
lines changed

8 files changed

+150
-16
lines changed

docs/workloads/batch/configuration.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ predictor:
2323
env: <string: string> # dictionary of environment variables
2424
log_level: <string> # log level that can be "debug", "info", "warning" or "error" (default: "info")
2525
shm_size: <string> # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null)
26+
dependencies: # (optional)
27+
pip: <string> # relative path to requirements.txt (default: requirements.txt)
28+
conda: <string> # relative path to conda-packages.txt (default: conda-packages.txt)
29+
shell: <string> # relative path to a shell script for system package installation (default: dependencies.sh)
2630
```
2731
2832
### TensorFlow Predictor
@@ -50,6 +54,10 @@ predictor:
5054
env: <string: string> # dictionary of environment variables
5155
log_level: <string> # log level that can be "debug", "info", "warning" or "error" (default: "info")
5256
shm_size: <string> # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null)
57+
dependencies: # (optional)
58+
pip: <string> # relative path to requirements.txt (default: requirements.txt)
59+
conda: <string> # relative path to conda-packages.txt (default: conda-packages.txt)
60+
shell: <string> # relative path to a shell script for system package installation (default: dependencies.sh)
5361
```
5462
5563
### ONNX Predictor
@@ -71,6 +79,10 @@ predictor:
7179
env: <string: string> # dictionary of environment variables
7280
log_level: <string> # log level that can be "debug", "info", "warning" or "error" (default: "info")
7381
shm_size: <string> # size of shared memory (/dev/shm) for sharing data between multiple processes, e.g. 64Mi or 1Gi (default: Null)
82+
dependencies: # (optional)
83+
pip: <string> # relative path to requirements.txt (default: requirements.txt)
84+
conda: <string> # relative path to conda-packages.txt (default: conda-packages.txt)
85+
shell: <string> # relative path to a shell script for system package installation (default: dependencies.sh)
7486
```
7587
7688
## Compute

docs/workloads/dependencies/python-packages.md

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## PyPI packages
44

5-
You can install your required PyPI packages and import them in your Python files using pip. Cortex looks for a `requirements.txt` file in the top level Cortex project directory (i.e. the directory which contains `cortex.yaml`):
5+
You can install your required PyPI packages and import them in your Python files using pip. Cortex looks for
6+
a `requirements.txt` file in the top level Cortex project directory (i.e. the directory which contains `cortex.yaml`):
67

78
```text
89
./my-classifier/
@@ -14,11 +15,13 @@ You can install your required PyPI packages and import them in your Python files
1415

1516
If you want to use `conda` to install your python packages, see the [Conda section](#conda-packages) below.
1617

17-
Note that some packages are pre-installed by default (see "pre-installed packages" for your Predictor type in the Realtime API Predictor documentation and Batch API Predictor documentation).
18+
Note that some packages are pre-installed by default (see "pre-installed packages" for your Predictor type in the
19+
Realtime API Predictor documentation and Batch API Predictor documentation).
1820

1921
## Private PyPI packages
2022

21-
To install packages from a private PyPI index, create a `pip.conf` inside the same directory as `requirements.txt`, and add the following contents:
23+
To install packages from a private PyPI index, create a `pip.conf` inside the same directory as `requirements.txt`, and
24+
add the following contents:
2225

2326
```text
2427
[global]
@@ -35,7 +38,8 @@ You may now add packages to `requirements.txt` which are found in the private in
3538

3639
## GitHub packages
3740

38-
You can also install public/private packages from git registries (such as GitHub) by adding them to `requirements.txt`. Here's an example for GitHub:
41+
You can also install public/private packages from git registries (such as GitHub) by adding them to `requirements.txt`.
42+
Here's an example for GitHub:
3943

4044
```text
4145
# requirements.txt
@@ -47,11 +51,14 @@ git+https://github.com/<username>/<repo name>.git@<tag or branch name>#egg=<pack
4751
git+https://<personal access token>@github.com/<username>/<repo name>.git@<tag or branch name>#egg=<package name>
4852
```
4953

50-
On GitHub, you can generate a personal access token by following [these steps](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line).
54+
On GitHub, you can generate a personal access token by
55+
following [these steps](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)
56+
.
5157

5258
## Installing with Setup
5359

54-
Python packages can also be installed by providing a `setup.py` that describes your project's modules. Here's an example directory structure:
60+
Python packages can also be installed by providing a `setup.py` that describes your project's modules. Here's an example
61+
directory structure:
5562

5663
```text
5764
./my-classifier/
@@ -65,6 +72,7 @@ Python packages can also be installed by providing a `setup.py` that describes y
6572
```
6673

6774
In this case, `requirements.txt` will have this form:
75+
6876
```text
6977
# requirements.txt
7078
@@ -73,7 +81,9 @@ In this case, `requirements.txt` will have this form:
7381

7482
## Conda packages
7583

76-
Cortex supports installing Conda packages. We recommend only using Conda when your required packages are not available in PyPI. Cortex looks for a `conda-packages.txt` file in the top level Cortex project directory (i.e. the directory which contains `cortex.yaml`):
84+
Cortex supports installing Conda packages. We recommend only using Conda when your required packages are not available
85+
in PyPI. Cortex looks for a `conda-packages.txt` file in the top level Cortex project directory (i.e. the directory
86+
which contains `cortex.yaml`):
7787

7888
```text
7989
./my-classifier/
@@ -83,16 +93,48 @@ Cortex supports installing Conda packages. We recommend only using Conda when yo
8393
└── conda-packages.txt
8494
```
8595

86-
The `conda-packages.txt` file follows the format of `conda list --export`. Each line of `conda-packages.txt` should follow this pattern: `[channel::]package[=version[=buildid]]`.
96+
The `conda-packages.txt` file follows the format of `conda list --export`. Each line of `conda-packages.txt` should
97+
follow this pattern: `[channel::]package[=version[=buildid]]`.
8798

8899
Here's an example of `conda-packages.txt`:
100+
89101
```text
90102
conda-forge::rdkit
91103
conda-forge::pygpu
92104
```
93105

94-
In situations where both `requirements.txt` and `conda-packages.txt` are provided, Cortex installs Conda packages in `conda-packages.txt` followed by PyPI packages in `requirements.txt`. Conda and Pip package managers install packages and dependencies independently. You may run into situations where Conda and pip package managers install different versions of the same package because they install and resolve dependencies independently from one another. To resolve package version conflicts, it may be in your best interest to specify their exact versions in `conda-packages.txt`.
106+
In situations where both `requirements.txt` and `conda-packages.txt` are provided, Cortex installs Conda packages
107+
in `conda-packages.txt` followed by PyPI packages in `requirements.txt`. Conda and Pip package managers install packages
108+
and dependencies independently. You may run into situations where Conda and pip package managers install different
109+
versions of the same package because they install and resolve dependencies independently from one another. To resolve
110+
package version conflicts, it may be in your best interest to specify their exact versions in `conda-packages.txt`.
95111

96-
The current version of Python is `3.6.9`. Updating Python to a different version is possible with Conda, but there are no guarantees that Cortex's web server will continue functioning correctly. If there's a change in Python's version, the necessary core packages for the web server will be reinstalled. If you are using a custom base image, any other Python packages that are built in to the image won't be accessible at runtime.
112+
The current version of Python is `3.6.9`. Updating Python to a different version is possible with Conda, but there are
113+
no guarantees that Cortex's web server will continue functioning correctly. If there's a change in Python's version, the
114+
necessary core packages for the web server will be reinstalled. If you are using a custom base image, any other Python
115+
packages that are built in to the image won't be accessible at runtime.
97116

98117
Check the [best practices](https://www.anaconda.com/using-pip-in-a-conda-environment/) on using `pip` inside `conda`.
118+
119+
## Customizing Dependency Paths
120+
121+
Cortex allows you to specify different dependency paths other than the default ones. This can be useful when deploying
122+
different versions of the same API (e.g. CPU vs GPU dependencies).
123+
124+
To customize the path for your dependencies, you can specify `predictor.dependencies` in your API's configuration file. You can set
125+
one or more fields to specify the path for each dependency type. Each path should be a relative path with respect to the current file.
126+
127+
For example:
128+
129+
```yaml
130+
# cortex.yaml
131+
132+
- name: my-classifier
133+
kind: RealtimeAPI
134+
predictor:
135+
(...)
136+
dependencies:
137+
pip: requirement-gpu.txt
138+
conda: conda-packages-gpu.txt
139+
shell: dependencies-gpu.sh
140+
```

docs/workloads/dependencies/system-packages.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,22 @@ conda install -n env python=3.8.5
4040
# re-install cortex core dependencies
4141
/usr/local/cortex/install-core-dependencies.sh
4242
```
43+
44+
## Customizing Dependency Paths
45+
46+
Cortex allows you to specify a path for this script other than `dependencies.sh`. This can be useful when deploying
47+
different versions of the same API (e.g. CPU vs GPU dependencies). The path should be a relative path with respect
48+
to the API configuration file, and is specified via `predictor.dependencies.shell`.
49+
50+
For example:
51+
52+
```yaml
53+
# cortex.yaml
54+
55+
- name: my-classifier
56+
kind: RealtimeAPI
57+
predictor:
58+
(...)
59+
dependencies:
60+
shell: dependencies-gpu.sh
61+
```

docs/workloads/realtime/configuration.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
predictor:
2020
type: python
2121
path: <string> # path to a python file with a PythonPredictor class definition, relative to the Cortex root (required)
22+
dependencies: # (optional)
23+
pip: <string> # relative path to requirements.txt (default: requirements.txt)
24+
conda: <string> # relative path to conda-packages.txt (default: conda-packages.txt)
25+
shell: <string> # relative path to a shell script for system package installation (default: dependencies.sh)
2226
multi_model_reloading: # use this to serve one or more models with live reloading (optional)
2327
path: <string> # S3/GCS path to an exported model directory (e.g. s3://my-bucket/exported_model/) (either this, 'dir', or 'paths' must be provided if 'multi_model_reloading' is specified)
2428
paths: # list of S3/GCS paths to exported model directories (either this, 'dir', or 'path' must be provided if 'multi_model_reloading' is specified)
@@ -48,6 +52,10 @@ predictor:
4852
predictor:
4953
type: tensorflow
5054
path: <string> # path to a python file with a TensorFlowPredictor class definition, relative to the Cortex root (required)
55+
dependencies: # (optional)
56+
pip: <string> # relative path to requirements.txt (default: requirements.txt)
57+
conda: <string> # relative path to conda-packages.txt (default: conda-packages.txt)
58+
shell: <string> # relative path to a shell script for system package installation (default: dependencies.sh)
5159
models: # (required)
5260
path: <string> # S3/GCS path to an exported SavedModel directory (e.g. s3://my-bucket/exported_model/) (either this, 'dir', or 'paths' must be provided)
5361
paths: # list of S3/GCS paths to exported SavedModel directories (either this, 'dir', or 'path' must be provided)
@@ -80,6 +88,10 @@ predictor:
8088
predictor:
8189
type: onnx
8290
path: <string> # path to a python file with an ONNXPredictor class definition, relative to the Cortex root (required)
91+
dependencies: # (optional)
92+
pip: <string> # relative path to requirements.txt (default: requirements.txt)
93+
conda: <string> # relative path to conda-packages.txt (default: conda-packages.txt)
94+
shell: <string> # relative path to a shell script for system package installation (default: dependencies.sh)
8395
models: # (required)
8496
path: <string> # S3/GCS path to an exported model directory (e.g. s3://my-bucket/exported_model/) (either this, 'dir', or 'paths' must be provided)
8597
paths: # list of S3/GCS paths to exported model directories (either this, 'dir', or 'path' must be provided)

pkg/cortex/serve/init/bootloader.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,20 @@ function install_deps() {
5555
eval $source_env_file_cmd
5656

5757
# execute script if present in project's directory
58-
if [ -f "/mnt/project/dependencies.sh" ]; then
59-
bash -e /mnt/project/dependencies.sh
58+
if [ -f "/mnt/project/${CORTEX_DEPENDENCIES_SHELL}" ]; then
59+
bash -e "/mnt/project/${CORTEX_DEPENDENCIES_SHELL}"
6060
fi
6161

6262
# install from conda-packages.txt
63-
if [ -f "/mnt/project/conda-packages.txt" ]; then
63+
if [ -f "/mnt/project/${CORTEX_DEPENDENCIES_CONDA}" ]; then
6464
# look for packages in defaults and then conda-forge to improve chances of finding the package (specifically for python reinstalls)
6565
conda config --append channels conda-forge
66-
conda install -y --file /mnt/project/conda-packages.txt
66+
conda install -y --file "/mnt/project/${CORTEX_DEPENDENCIES_CONDA}"
6767
fi
6868

6969
# install pip packages
70-
if [ -f "/mnt/project/requirements.txt" ]; then
71-
pip --no-cache-dir install -r /mnt/project/requirements.txt
70+
if [ -f "/mnt/project/${CORTEX_DEPENDENCIES_PIP}" ]; then
71+
pip --no-cache-dir install -r "/mnt/project/${CORTEX_DEPENDENCIES_PIP}"
7272
fi
7373

7474
# install core cortex dependencies if required

pkg/operator/operator/k8s.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,18 @@ func getEnvVars(api *spec.API, container string) []kcore.EnvVar {
593593
Name: "CORTEX_PROJECT_DIR",
594594
Value: path.Join(_emptyDirMountPath, "project"),
595595
},
596+
kcore.EnvVar{
597+
Name: "CORTEX_DEPENDENCIES_PIP",
598+
Value: api.Predictor.Dependencies.Pip,
599+
},
600+
kcore.EnvVar{
601+
Name: "CORTEX_DEPENDENCIES_CONDA",
602+
Value: api.Predictor.Dependencies.Conda,
603+
},
604+
kcore.EnvVar{
605+
Name: "CORTEX_DEPENDENCIES_SHELL",
606+
Value: api.Predictor.Dependencies.Shell,
607+
},
596608
)
597609

598610
if api.Kind == userconfig.RealtimeAPIKind {

pkg/types/spec/validations.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ func predictorValidation() *cr.StructFieldValidation {
243243
multiModelValidation("Models"),
244244
multiModelValidation("MultiModelReloading"),
245245
serverSideBatchingValidation(),
246+
dependencyPathValidation(),
246247
},
247248
},
248249
}
@@ -639,6 +640,35 @@ func serverSideBatchingValidation() *cr.StructFieldValidation {
639640
}
640641
}
641642

643+
func dependencyPathValidation() *cr.StructFieldValidation {
644+
return &cr.StructFieldValidation{
645+
StructField: "Dependencies",
646+
StructValidation: &cr.StructValidation{
647+
Required: false,
648+
StructFieldValidations: []*cr.StructFieldValidation{
649+
{
650+
StructField: "Pip",
651+
StringValidation: &cr.StringValidation{
652+
Default: "requirements.txt",
653+
},
654+
},
655+
{
656+
StructField: "Conda",
657+
StringValidation: &cr.StringValidation{
658+
Default: "conda-packages.txt",
659+
},
660+
},
661+
{
662+
StructField: "Shell",
663+
StringValidation: &cr.StringValidation{
664+
Default: "dependencies.sh",
665+
},
666+
},
667+
},
668+
},
669+
}
670+
}
671+
642672
var resourceStructValidation = cr.StructValidation{
643673
AllowExtraFields: true,
644674
StructFieldValidations: resourceStructValidations,

pkg/types/userconfig/api.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ type Predictor struct {
6161
TensorFlowServingImage string `json:"tensorflow_serving_image" yaml:"tensorflow_serving_image"`
6262
Config map[string]interface{} `json:"config" yaml:"config"`
6363
Env map[string]string `json:"env" yaml:"env"`
64+
Dependencies *Dependencies `json:"dependencies" yaml:"dependencies"`
6465
}
6566

6667
type TaskDefinition struct {
@@ -97,6 +98,12 @@ type ServerSideBatching struct {
9798
BatchInterval time.Duration `json:"batch_interval" yaml:"batch_interval"`
9899
}
99100

101+
type Dependencies struct {
102+
Pip string `json:"pip" yaml:"pip"`
103+
Conda string `json:"conda" yaml:"conda"`
104+
Shell string `json:"shell" yaml:"shell"`
105+
}
106+
100107
type Networking struct {
101108
Endpoint *string `json:"endpoint" yaml:"endpoint"`
102109
}

0 commit comments

Comments
 (0)