modal.Image
class Image(modal.object.Provider)
Base class for container images to run functions in.
Do not construct this class directly; instead use one of its static factory methods,
such as modal.Image.debian_slim
, modal.Image.from_dockerhub
, or modal.Image.conda
.
def __init__(self, load: Callable[[Resolver, str], Awaitable[H]], rep: str):
# TODO(erikbern): this is semi-deprecated - subclasses should use _from_loader
persist
@typechecked
def persist(self, label: str, namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE):
Deploy a Modal app containing this object. This object can then be imported from other apps using
the returned reference, or by calling modal.SharedVolume.from_name(label)
(or the equivalent method
on respective class).
Example Usage
import modal
volume = modal.SharedVolume().persist("my-volume")
stub = modal.Stub()
# Volume refers to the same object, even across instances of `stub`.
@stub.function(shared_volumes={"/vol": volume})
def f():
pass
from_name
@classmethod
def from_name(
cls: Type[P], app_name: str, tag: Optional[str] = None, namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE
) -> P:
Returns a reference to an Modal object of any type
Useful for referring to already created/deployed objects, e.g., Secrets
import modal
stub = modal.Stub()
@stub.function(secret=modal.Secret.from_name("my-secret-name"))
def some_function():
pass
lookup
@classmethod
def lookup(
cls: Type[P],
app_name: str,
tag: Optional[str] = None,
namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
client: Optional[_Client] = None,
) -> H:
General purpose method to retrieve Modal objects such as functions, shared volumes, and secrets.
import modal
square = modal.Function.lookup("my-shared-app", "square")
assert square(3) == 9
vol = modal.SharedVolume.lookup("my-shared-volume")
for chunk in vol.read_file("my_db_dump.csv"):
...
extend
def extend(self, **kwargs) -> "_Image":
Extend an image (named “base”) with additional options or commands.
This is a low-level command. Generally, you should prefer using functions
like Image.pip_install
or Image.apt_install
if possible.
Example
image = modal.Image.debian_slim().extend(
dockerfile_commands=[
"FROM base",
"WORKDIR /pkg",
'RUN echo "hello world" > hello.txt',
],
secrets=[secret1, secret2],
)
copy
@typechecked
def copy(self, mount: _Mount, remote_path: Union[str, Path] = ".") -> "_Image":
Copy the entire contents of a modal.Mount
into an image.
Useful when files only available locally are required during the image
build process.
Example
static_images_dir = "./static"
# place all static images in root of mount
mount = modal.Mount.from_local_dir(static_images_dir, remote_path="/")
# place mount's contents into /static directory of image.
image = modal.Image.debian_slim().copy(mount, remote_path="/static")
pip_install
@typechecked
def pip_install(
self,
*packages: Union[str, List[str]], # A list of Python packages, eg. ["numpy", "matplotlib>=3.5.0"]
find_links: Optional[str] = None, # Passes -f (--find-links) pip install
index_url: Optional[str] = None, # Passes -i (--index-url) to pip install
extra_index_url: Optional[str] = None, # Passes --extra-index-url to pip install
pre: bool = False, # Passes --pre (allow pre-releases) to pip install
) -> "_Image":
Install a list of Python packages using pip.
Example
image = modal.Image.debian_slim().pip_install("click", "httpx~=0.23.3")
pip_install_private_repos
@typechecked
def pip_install_private_repos(
self,
*repositories: str,
git_user: str,
secrets: Sequence[_Secret] = [],
) -> "_Image":
Install a list of Python packages from private git repositories using pip.
This method currently supports Github and Gitlab only.
- Github: Provide a
modal.Secret
that contains aGITHUB_TOKEN
key-value pair - Gitlab: Provide a
modal.Secret
that contains aGITLAB_TOKEN
key-value pair
These API tokens should have permissions to read the list of private repositories provided as arguments.
We recommend using Github’s ‘fine-grained’ access tokens. These tokens are repo-scoped, and avoid granting read permission across all of a user’s private repos.
Example
image = (
modal.Image
.debian_slim()
.pip_install_private_repos(
"github.com/ecorp/private-one@1.0.0",
"github.com/ecorp/private-two@main"
"github.com/ecorp/private-three@d4776502"
# install from 'inner' directory on default branch.
"github.com/ecorp/private-four#subdirectory=inner",
git_user="erikbern",
secrets=[modal.Secret.from_name("github-read-private")],
)
)
pip_install_from_requirements
@typechecked
def pip_install_from_requirements(
self,
requirements_txt: str, # Path to a requirements.txt file.
find_links: Optional[str] = None,
) -> "_Image":
Install a list of Python packages from a requirements.txt
file.
pip_install_from_pyproject
@typechecked
def pip_install_from_pyproject(
self,
pyproject_toml: str,
optional_dependencies: List[str] = [],
) -> "_Image":
Install dependencies specified by a pyproject.toml
file.
When optional_dependencies
, a list of the keys of the
optional-dependencies section(s) of the pyproject.toml
file
(e.g. test, doc, experiment, etc), is provided,
all of those packages in each section are installed as well.
poetry_install_from_file
@typechecked
def poetry_install_from_file(
self,
poetry_pyproject_toml: str,
poetry_lockfile: Optional[
str
] = None, # Path to the lockfile. If not provided, uses poetry.lock in the same directory.
ignore_lockfile: bool = False, # If set to True, it will not use poetry.lock
old_installer: bool = False, # If set to True, use old installer. See https://github.com/python-poetry/poetry/issues/3336
) -> "_Image":
Install poetry dependencies specified by a pyproject.toml file.
The path to the lockfile is inferred, if not provided. However, the
file has to exist, unless ignore_lockfile
is set to True
.
Note that the root project of the poetry project is not installed,
only the dependencies. For including local packages see modal.create_package_mounts
dockerfile_commands
@typechecked
def dockerfile_commands(
self,
dockerfile_commands: Union[str, List[str]],
context_files: Dict[str, str] = {},
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
context_mount: Optional[
_Mount
] = None, # modal.Mount with local files to supply as build context for COPY commands
) -> "_Image":
Extend an image with arbitrary Dockerfile-like commands.
run_commands
@typechecked
def run_commands(
self,
*commands: Union[str, List[str]],
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Extend an image with a list of shell commands to run.
conda
@staticmethod
@typechecked
def conda(python_version: str = "3.9") -> "_Image":
A Conda base image, using miniconda3 and derived from the official Docker Hub image.
conda_install
@typechecked
def conda_install(
self,
*packages: Union[str, List[str]], # A list of Python packages, eg. ["numpy", "matplotlib>=3.5.0"]
channels: List[str] = [], # A list of Conda channels, eg. ["conda-forge", "nvidia"]
) -> "_Image":
Install a list of additional packages using conda.
conda_update_from_environment
@typechecked
def conda_update_from_environment(
self,
environment_yml: str,
) -> "_Image":
Update conda environment using dependencies from a given environment.yml file.
micromamba
@staticmethod
@typechecked
def micromamba(python_version: str = "3.9") -> "_Image":
A Micromamba base image. Micromamba allows for fast building of small conda-based containers.
from_dockerhub
@staticmethod
@typechecked
def from_dockerhub(
tag: str, setup_dockerfile_commands: List[str] = [], setup_commands: List[str] = [], **kwargs
) -> "_Image":
Build a Modal image from a pre-existing image on Docker Hub.
This assumes the following about the image:
- Python 3.7 or above is present, and is available as
python
. pip
is installed correctly.- The image is built for the
linux/amd64
platform.
You may use setup_dockerfile_commands
to run Dockerfile commands
before the remaining commands run. This might be useful if Python or pip is
not installed, or you need to set a SHELL
for python
to be available.
Example
modal.Image.from_dockerhub(
"gisops/valhalla:latest",
setup_dockerfile_commands=["RUN apt-get update", "RUN apt-get install -y python3-pip"]
)
from_aws_ecr
@staticmethod
@typechecked
def from_aws_ecr(
tag: str,
secret: Optional[_Secret] = None,
setup_dockerfile_commands: List[str] = [],
setup_commands: List[str] = [],
**kwargs,
) -> "_Image":
Build a Modal image from a pre-existing image on a private AWS Elastic
Container Registry (ECR). You will need to pass a modal.Secret
containing
an AWS key (AWS_ACCESS_KEY_ID
) and secret (AWS_SECRET_ACCESS_KEY
)
with permissions to access the target ECR registry.
Refer to “Private repository policies” for details about IAM configuration.
The same assumptions hold from from_dockerhub
:
- Python 3.7 or above is present, and is available as
python
. pip
is installed correctly.- The image is built for the
linux/amd64
platform.
You may use setup_dockerfile_commands
to run Dockerfile commands
before the remaining commands run. This might be useful if Python or pip is
not installed, or you need to set a SHELL
for python
to be available.
Example
modal.Image.from_aws_ecr(
"000000000000.dkr.ecr.us-east-1.amazonaws.com/my-private-registry:my-version",
secret=modal.Secret.from_name("aws"),
setup_dockerfile_commands=["RUN apt-get update", "RUN apt-get install -y python3-pip"]
)
from_dockerfile
@staticmethod
@typechecked
def from_dockerfile(
path: Union[str, Path],
context_mount: Optional[
_Mount
] = None, # modal.Mount with local files to supply as build context for COPY commands
) -> "_Image":
Build a Modal image from a local Dockerfile.
Note that the following must be true about the image you provide:
- Python 3.7 or above needs to be present and available as
python
. pip
needs to be installed and available aspip
.
debian_slim
@staticmethod
@typechecked
def debian_slim(python_version: Optional[str] = None) -> "_Image":
Default image, based on the official python:X.Y.Z-slim-bullseye
Docker images.
apt_install
@typechecked
def apt_install(
self,
*packages: Union[str, List[str]], # A list of packages, e.g. ["ssh", "libpq-dev"]
) -> "_Image":
Install a list of Debian packages using apt
.
Example
image = modal.Image.debian_slim().apt_install("git")
run_function
@typechecked
def run_function(
self,
raw_f: Callable[[], Any],
*,
secret: Optional[_Secret] = None, # An optional Modal Secret with environment variables for the container
secrets: Sequence[_Secret] = (), # Plural version of `secret` when multiple secrets are needed
gpu: GPU_T = None, # GPU specification as string ("any", "T4", "A10G", ...) or object (`modal.GPU.A100()`, ...)
mounts: Sequence[_Mount] = (),
shared_volumes: Dict[str, _SharedVolume] = {},
cpu: Optional[float] = None, # How many CPU cores to request. This is a soft limit.
memory: Optional[int] = None, # How much memory to request, in MiB. This is a soft limit.
timeout: Optional[int] = 86400, # Maximum execution time of the function in seconds.
cloud: Optional[str] = None, # Cloud provider to run the function on. Possible values are aws, gcp, auto.
) -> "_Image":
Run user-defined function raw_function
as an image build step. The function runs just like an ordinary Modal
function, and any kwargs accepted by @stub.function
(such as Mount
s, SharedVolume
s, and resource requests) can
be supplied to it. After it finishes execution, a snapshot of the resulting container file system is saved as an image.
Note
Only the source code of raw_function
and the contents of **kwargs
are used to determine whether the image has changed
and needs to be rebuilt. If this function references other functions or variables, the image will not be rebuilt if you
make changes to them. You can force a rebuild by changing the function’s source code itself.
Example
def my_build_function():
open("model.pt", "w").write("parameters!")
image = (
modal.Image
.debian_slim()
.pip_install("torch")
.run_function(my_build_function, secrets=[...], mounts=[...])
)
env
@typechecked
def env(self, vars: Dict[str, str]) -> "_Image":
Sets the environmental variables of the image.
Example
image = (
modal.Image.conda()
.env({"CONDA_OVERRIDE_CUDA": "11.2"})
.conda_install("jax", "cuda-nvcc", channels=["conda-forge", "nvidia"])
.pip_install("dm-haiku", "optax")
)