Custom containers

By default, Modal functions are executed within a Debian Bullseye Linux container with a basic Python installation of the same minor version that your local Python has.

Oftentimes you might need some third party Python packages, or some other pre-installed dependencies for your function. Modal provides a few different options to customize the container your function runs in.

Additional Python packages

The simplest and most common container modification is to add some third party Python package, like pandas. To do this you can create a custom modal.Image using the modal.Image.debian_slim, and then extend it with the pip_install method with a list of all of the packages you need:

E.g.

pandas_image = modal.Image.debian_slim().pip_install(["pandas"])

@stub.function(image=pandas_image)
def my_function():
    import pandas as pd
    df = pd.DataFrame()
    ...

Note that we inline the import above in the my_function body. This lets us import and run the module locally on our development machine even if we don’t have pandas installed there.

Shell commands

You can also supply shell commands that should be executed when building the container image. This can be useful for installing additional binary dependencies:

ffmpeg_image = modal.Image.debian_slim().apt_install(["ffmpeg"])

@stub.function(image=ffmpeg_image)
def process_video():
    subprocess.call(["ffmpeg", ...])

Or for preloading custom assets into the container:

image_with_model = (
    modal.Image.debian_slim()
         .apt_install(["curl"])
         .run_commands(["curl -O https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalcatface.xml"])
)
@stub.function(image=image_with_model)
def find_cats():
    content = open("/haarcascade_frontalcatface.xml").read()
    ...

Using existing Docker Hub images

Docker Hub has many pre-built images for common software packages. You can use any such image as your function container using modal.Image.from_dockerhub as long as the image conforms to the following requirements:

  • 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
sklearn_image = modal.Image.from_dockerhub("huanjason/scikit-learn")

@stub.function(image=sklearn_image)
def fit_knn():
    from sklearn.neighbors import KNeighborsClassifier
    ...

If python or pip isn’t set up properly, you can use the setup_commands to run extra commands before the Modal package is installed:

image = modal.Image.from_dockerhub(
    "gisops/valhalla:latest",
    setup_commands=["apt-get update", "apt-get install -y python3-pip"]
)

Using Conda instead of pip

Modal provides a pre-built Conda base image, if you would like to use conda for package management. The Python version available is whatever version the official miniconda3 image currently comes with (3.9.12 at this time).


pymc_image = modal.Image.conda().conda_install(["theano-pymc==1.1.2", "pymc3==3.11.2"])

@stub.function(image=pymc_image)
def fit():
    import pymc3 as pm
    ...

Using a Dockerfile

Modal also supports using a Dockerfile using the Image.from_dockerfile class. It takes a path to an existing Dockerfile. For instance:

FROM python:3.9
RUN pip install sklearn
dockerfile_image = modal.Image.from_dockerfile("Dockerfile")

@stub.function(image=dockerfile_image)
def fit():
    import sklearn
    ...