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):

extend

def extend(self, **kwargs) -> "_Image":

Deprecated! This is a low-level method not intended to be part of the public API.

copy_mount

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

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

def pip_install_private_repos(
    self,
    *repositories: str,
    git_user: str,
    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
    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 a GITHUB_TOKEN key-value pair
  • Gitlab: Provide a modal.Secret that contains a GITLAB_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

def pip_install_from_requirements(
    self,
    requirements_txt: str,  # Path to a requirements.txt file.
    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 from a local requirements.txt file.

pip_install_from_pyproject

def pip_install_from_pyproject(
    self,
    pyproject_toml: str,
    optional_dependencies: List[str] = [],
    *,
    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 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

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

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

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
def conda(python_version: Optional[str] = None, 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

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

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
def micromamba(
    python_version: Optional[str] = None,
    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

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
def from_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 public or private image registry, such as Docker Hub.

The image must be built for the linux/amd64 platform.

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, 3.11, and 3.12. Otherwise, the image is expected to have Python>3.8 available on PATH as python, along with pip.

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.

To authenticate against a private registry with static credentials, you must set the secret parameter to a modal.Secret containing a username (REGISTRY_USERNAME) and an access token or password (REGISTRY_PASSWORD).

To authenticate against private registries with credentials from a cloud provider, use Image.from_gcp_artifact_registry() or Image.from_aws_ecr().

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("nvcr.io/nvidia/pytorch:22.12-py3")

from_gcp_artifact_registry

@staticmethod
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 Google Cloud Platform (GCP) Artifact Registry.

You will need to pass a modal.Secret containing your GCP service account key data as SERVICE_ACCOUNT_JSON. This can be done from the Secrets page. Your service account should be granted a specific role depending on the GCP registry used:

Note: This method does not use GOOGLE_APPLICATION_CREDENTIALS as that variable accepts a path to a JSON file, not the actual JSON string.

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
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
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, 3.11, and 3.12.

Example

image = modal.Image.from_dockerfile("./Dockerfile", add_python="3.12")

debian_slim

@staticmethod
def debian_slim(python_version: Optional[str] = None, force_build: bool = False) -> "_Image":

Default image, based on the official python Docker images.

apt_install

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

def run_function(
    self,
    raw_f: Callable,
    secrets: Sequence[_Secret] = (),  # Optional Modal Secret objects with environment variables for the container
    gpu: GPU_T = None,  # GPU specification as string ("any", "T4", "A10G", ...) or object (`modal.GPU.A100()`, ...)
    mounts: Sequence[_Mount] = (),
    shared_volumes: Dict[Union[str, PurePosixPath], _NetworkFileSystem] = {},
    network_file_systems: Dict[Union[str, PurePosixPath], _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,
    secret: Optional[_Secret] = None,  # Deprecated: use `secrets`.
    args: Sequence[Any] = (),  # Positional arguments to the function.
    kwargs: Dict[str, Any] = {},  # Keyword arguments to the function.
) -> "_Image":

Run user-defined function raw_f as an image build step. The function runs just like an ordinary Modal function, and any kwargs accepted by @stub.function (such as Mounts, NetworkFileSystems, 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_f, 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

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

def workdir(self, path: str) -> "_Image":

Set the working directory for subsequent image build steps and function execution.

Example

image = (
    modal.Image.debian_slim()
    .run_commands("git clone https://xyz app")
    .workdir("/app")
    .run_commands("yarn install")
)

imports

@contextlib.contextmanager
def imports(self):

Used to import packages in global scope that are only available when running remotely. By using this context manager you can avoid an ImportError due to not having certain packages installed locally.

Usage:

with image.imports():
    import torch

run_inside

def run_inside(self):

Image.run_inside is deprecated - use Image.imports instead.

Usage:

with image.imports():
    import torch