Runtime Environment
Build and cache container images for compute workloads.
Every sandbox runs from an OCI container image. You can reference a
pre-built image by tag, or build one declaratively using the Image API. Images
are content-addressed — the build service hashes the full specification (base image,
installed packages, file contents) and skips any build whose hash already exists in
the cache. Rebuilds after a minor dependency change typically complete in seconds.
The Image class exposes a fluent, method-chaining API. Each method returns a new
Image instance, so intermediate images can be shared and extended without mutation.
from chalkcompute import Image
img = (
Image.debian_slim("3.12")
.pip_install(["requests", "pandas>=2.0"])
.run_commands("apt-get update && apt-get install -y git curl")
.workdir("/app")
.env({"PROJECT_ROOT": "/app"})
)
| Constructor | Description |
|---|---|
Image.debian_slim(python_version) | python:<version>-slim-bookworm — lightweight default for Python workloads |
Image.base(image) | Arbitrary OCI image reference (e.g. "node:22-slim", "ghcr.io/org/image:tag") |
Image.from_dockerfile(path) | Parse an existing Dockerfile and continue chaining on top |
Python packages — use pip_install with a list of requirement specifiers,
or point at an existing requirements file:
img = Image.debian_slim().pip_install(["torch==2.3.0", "transformers"])
# Or from a requirements file
img = Image.debian_slim().pip_install_from_requirements("requirements.txt")
System packages — use run_commands for apt, apk, or any other shell command
that should execute during the build:
img = Image.debian_slim().run_commands(
"apt-get update && apt-get install -y ffmpeg libsndfile1",
)
Raw Dockerfile instructions — for anything not covered by the builder methods:
img = Image.debian_slim().dockerfile_commands([
"EXPOSE 8080",
"RUN useradd -m worker",
"USER worker",
])
Local files can be included in the image via copy or volume mount:
# Volume mount (default) — file is uploaded at sandbox start, not baked into the image.
# Faster iteration when the file changes frequently.
img = Image.debian_slim().add_local_file("app.py", "/app/app.py")
# Copy — inlines the file contents into the image spec.
# Better for small, stable files that should be part of the cached image.
img = Image.debian_slim().add_local_file(
"app.py", "/app/app.py", strategy="copy"
)
# Entire directories work the same way
img = Image.debian_slim().add_local_dir("./src", "/app/src")
Local Python source — when the files you’re adding are Python code that a
deployed function needs to import, prefer add_local_python_source. It takes
module or package names instead of paths.
img = Image.debian_slim().add_local_python_source("helpers", "mypkg")
Use add_local_file/add_local_dir for everything that isn’t importable
Python source, like configuration or data files.
See Function dependencies in external files for how this fits nicely into function deploys.
Image builds are content-addressed. The build service computes a deterministic hash from the full image specification — base image digest, build steps, package lists, inlined file contents, and environment variables. If that hash already exists in the image registry, the build is skipped entirely and the existing image is returned.
This means:
For GPU-accelerated workloads, start from a base image that includes CUDA and the driver toolkit rather than installing them during the build. NVIDIA publishes pre-built images with CUDA, cuDNN, and popular ML frameworks:
# PyTorch with CUDA — starts from NVIDIA's pre-built image
img = (
Image.base("nvcr.io/nvidia/pytorch:24.01-py3")
.pip_install(["transformers", "accelerate"])
)
# TensorFlow
img = Image.base("nvcr.io/nvidia/tensorflow:24.01-tf2-py3")
Installing CUDA from scratch during an image build is slow and produces large layers that defeat caching. Pre-distributed images also ensure driver compatibility with the host GPU hardware.
Built images are stored in a regional OCI registry close to the compute fleet. To minimize cold-start latency, Chalk maintains an on-node image cache on each host:
Common base images (debian_slim, popular NVIDIA containers) are pre-warmed
across the fleet. If startup latency is critical for a custom image, you can
trigger a pre-warm explicitly:
chalk compute image warm --image <image-hash>
This distributes the image to nodes ahead of sandbox creation.
To build images on your own EKS or GKE cluster, link a container registry and bind it to the cluster. Chalk uses the registry to build and store images for sandboxes, scaling groups and functions.
Grant the following permissions on the container registry you’d like to use:
AWS ECR: grant to the Chalk management role:
ecr:GetAuthorizationTokenecr:DescribeImages, ecr:BatchCheckLayerAvailability, ecr:BatchGetImage,
ecr:GetDownloadUrlForLayer (pull), ecr:InitiateLayerUpload, ecr:UploadLayerPart,
ecr:CompleteLayerUpload, ecr:PutImage (push)Google GAR: grant roles/artifactregistry.writer on the repository to the workload service account
that runs docker image building.
In the team navigation (click on the Chalk logo in the top left of the page), go to Registries and create a new container registry (Link Registry). Select the registry type, provide the repository path, and link a cloud account.
| Type | Example path |
|---|---|
| AWS ECR | 123456789012.dkr.ecr.us-east-1.amazonaws.com/custom/compute |
| Google GAR | us-docker.pkg.dev/my-project/custom-images/compute |
| Azure ACR | myregistry.azurecr.io/custom/compute |
In the team navigation click on Clusters, and select the cluster. This will open the Settings tab. Under Container Registry Binding, select the registry created in step 1 and click Save Binding. This sets the default registry used by sandboxes and functions on the cluster.
The cluster also needs a volume bucket for volumes. The function queue is optional.