modal.Image
class Image(modal.object.Object)
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_registry
, or modal.Image.conda
.
def __init__(self, *args, **kwargs):
from_id
@classmethod
def from_id(cls: Type[O], object_id: str, client: Optional[_Client] = None) -> O:
Retrieve an object from its unique ID (accessed through obj.object_id
).
persist
def persist(
self, label: str, namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE, environment_name: Optional[str] = None
):
Object.persist
is deprecated for generic objects. See NetworkFileSystem.persisted
or Dict.persisted
.
from_name
@classmethod
def from_name(
cls: Type[O],
app_name: str,
tag: Optional[str] = None,
namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
environment_name: Optional[str] = None,
) -> O:
Retrieve an object with a given name and tag.
Useful for referencing secrets, as well as calling a function from a different app. Use this when attaching the object to a stub or function.
Examples
# Retrieve a secret
stub.my_secret = Secret.from_name("my-secret")
# Retrieve a function from a different app
stub.other_function = Function.from_name("other-app", "function")
# Retrieve a persisted Volume, Queue, or Dict
stub.my_volume = Volume.from_name("my-volume")
stub.my_queue = Queue.from_name("my-queue")
stub.my_dict = Dict.from_name("my-dict")
lookup
@classmethod
def lookup(
cls: Type[O],
app_name: str,
tag: Optional[str] = None,
namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
client: Optional[_Client] = None,
environment_name: Optional[str] = None,
) -> O:
Lookup an object with a given name and tag.
This is a general-purpose method for objects like functions, network file systems, and secrets. It gives a reference to the object in a running app.
Examples
# Lookup a secret
my_secret = Secret.lookup("my-secret")
# Lookup a function from a different app
other_function = Function.lookup("other-app", "function")
# Lookup a persisted Volume, Queue, or Dict
my_volume = Volume.lookup("my-volume")
my_queue = Queue.lookup("my-queue")
my_dict = Dict.lookup("my-dict")
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_mount
@typechecked
def copy_mount(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(mount, remote_path="/static")
copy_local_file
def copy_local_file(self, local_path: Union[str, Path], remote_path: Union[str, Path] = "./") -> "_Image":
Copy a file into the image as a part of building it.
This works in a similar way to COPY
in a Dockerfile
.
copy_local_dir
def copy_local_dir(self, local_path: Union[str, Path], remote_path: Union[str, Path] = ".") -> "_Image":
Copy a directory into the image as a part of building the image.
This works in a similar way to COPY
in a Dockerfile
.
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
force_build: bool = False,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_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,
gpu: GPU_T = None,
secrets: Sequence[_Secret] = [],
force_build: bool = False,
) -> "_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,
force_build: bool = False,
*,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Install a list of Python packages from a local requirements.txt
file.
pip_install_from_pyproject
@typechecked
def pip_install_from_pyproject(
self,
pyproject_toml: str,
optional_dependencies: List[str] = [],
force_build: bool = False,
*,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Install dependencies specified by a local pyproject.toml
file.
optional_dependencies
is a list of the keys of the
optional-dependencies section(s) of the pyproject.toml
file
(e.g. test, doc, experiment, etc). When provided,
all of the packages in each listed section are installed as well.
poetry_install_from_file
@typechecked
def poetry_install_from_file(
self,
poetry_pyproject_toml: str,
# Path to the lockfile. If not provided, uses poetry.lock in the same directory.
poetry_lockfile: Optional[str] = None,
# If set to True, it will not use poetry.lock
ignore_lockfile: bool = False,
# If set to True, use old installer. See https://github.com/python-poetry/poetry/issues/3336
old_installer: bool = False,
force_build: bool = False,
# Selected optional dependency groups to install (See https://python-poetry.org/docs/cli/#install)
with_: List[str] = [],
# Selected optional dependency groups to exclude (See https://python-poetry.org/docs/cli/#install)
without: List[str] = [],
# Only install dependency groups specifed in this list.
only: List[str] = [],
*,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Install poetry dependencies specified by a local pyproject.toml
file.
If not provided as argument the path to the lockfile is inferred. 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.Mount.from_local_python_packages
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,
# modal.Mount with local files to supply as build context for COPY commands
context_mount: Optional[_Mount] = None,
force_build: bool = False,
) -> "_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,
force_build: bool = False,
) -> "_Image":
Extend an image with a list of shell commands to run.
conda
@staticmethod
@typechecked
def conda(python_version: str = "3.9", force_build: bool = False) -> "_Image":
A Conda base image, using miniconda3 and derived from the official Docker Hub image.
In most cases, using Image.micromamba()
with micromamba_install
is recommended over Image.conda()
, as it leads to significantly faster image build times.
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"]
force_build: bool = False,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Install a list of additional packages using Conda. Note that in most cases, using Image.micromamba()
with micromamba_install
is recommended over conda_install
, as it leads to significantly faster image build times.
conda_update_from_environment
@typechecked
def conda_update_from_environment(
self,
environment_yml: str,
force_build: bool = False,
*,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Update a Conda environment using dependencies from a given environment.yml file.
micromamba
@staticmethod
@typechecked
def micromamba(
python_version: str = "3.9",
force_build: bool = False,
) -> "_Image":
A Micromamba base image. Micromamba allows for fast building of small Conda-based containers.
In most cases it will be faster than using Image.conda()
.
micromamba_install
@typechecked
def micromamba_install(
self,
# A list of Python packages, eg. ["numpy", "matplotlib>=3.5.0"]
*packages: Union[str, List[str]],
# A list of Conda channels, eg. ["conda-forge", "nvidia"]
channels: List[str] = [],
force_build: bool = False,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_Image":
Install a list of additional packages using micromamba.
from_registry
@staticmethod
@typechecked
def from_registry(
tag: str,
*,
setup_dockerfile_commands: List[str] = [],
force_build: bool = False,
add_python: Optional[str] = None,
**kwargs,
) -> "_Image":
Build a Modal image from a public image registry, such as Docker Hub.
The image must be built for the linux/amd64
platform and have Python 3.7 or above
installed and available on PATH as python
. It should also have pip
.
If your image does not come with Python installed, you can use the add_python
parameter
to specify a version of Python to add to the image. Supported versions are 3.8
, 3.9
,
3.10
, and 3.11
. For Alpine-based images, use 3.8-musl
through 3.11-musl
, which
are statically-linked Python installations.
You may also use setup_dockerfile_commands
to run Dockerfile commands before the
remaining commands run. This might be useful if you want a custom Python installation or to
set a SHELL
. Prefer run_commands()
when possible though.
Examples
modal.Image.from_registry("python:3.11-slim-bookworm")
modal.Image.from_registry("ubuntu:22.04", add_python="3.11")
modal.Image.from_registry("alpine:3.18.3", add_python="3.11-musl")
from_dockerhub
@staticmethod
@typechecked
def from_dockerhub(
tag: str,
setup_dockerfile_commands: List[str] = [],
force_build: bool = False,
**kwargs,
) -> "_Image":
from_gcp_artifact_registry
@staticmethod
@typechecked
def from_gcp_artifact_registry(
tag: str,
secret: Optional[_Secret] = None,
*,
setup_dockerfile_commands: List[str] = [],
force_build: bool = False,
add_python: Optional[str] = None,
**kwargs,
) -> "_Image":
Build a Modal image from a private image in GCP Artifact Registry.
You will need to pass a modal.Secret
containing your GCP service account key
as SERVICE_ACCOUNT_JSON
. This can be done from the Secrets page.
The service account needs to have at least an “Artifact Registry Reader” role.
See Image.from_registry()
for information about the other parameters.
Example
modal.Image.from_gcp_artifact_registry(
"us-east1-docker.pkg.dev/my-project-1234/my-repo/my-image:my-version",
secret=modal.Secret.from_name("my-gcp-secret"),
add_python="3.11",
)
from_aws_ecr
@staticmethod
@typechecked
def from_aws_ecr(
tag: str,
secret: Optional[_Secret] = None,
*,
setup_dockerfile_commands: List[str] = [],
force_build: bool = False,
add_python: Optional[str] = None,
**kwargs,
) -> "_Image":
Build a Modal image from a private image in 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.
IAM configuration details can be found in the AWS documentation for “Private repository policies”.
See Image.from_registry()
for information about the other parameters.
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"),
add_python="3.11",
)
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
force_build: bool = False,
*,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
add_python: Optional[str] = None,
) -> "_Image":
Build a Modal image from a local Dockerfile.
If your Dockerfile does not have Python installed, you can use the add_python
parameter
to specify a version of Python to add to the image. Supported versions are 3.8
, 3.9
,
3.10
, and 3.11
. For Alpine-based images, use 3.8-musl
through 3.11-musl
, which
are statically-linked Python installations.
Example
image = modal.Image.from_dockerfile("./Dockerfile", add_python="3.10")
debian_slim
@staticmethod
@typechecked
def debian_slim(python_version: Optional[str] = None, force_build: bool = False) -> "_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"]
force_build: bool = False,
secrets: Sequence[_Secret] = [],
gpu: GPU_T = None,
) -> "_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[Union[str, os.PathLike], _NetworkFileSystem] = {},
network_file_systems: Dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
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.
force_build: bool = False,
) -> "_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, NetworkFileSystem
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
, the contents of **kwargs
, and any referenced global variables 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")
)
workdir
@typechecked
def workdir(self, path: str) -> "_Image":
Sets the working directory for subequent image build steps.
Example
image = (
modal.Image.debian_slim()
.run_commands("git clone https://xyz app")
.workdir("/app")
.run_commands("yarn install")
)