Developers

Image API Reference

The class is used to build custom Docker images for Chutes applications. This reference covers all methods, configuration options, and best practices for creating optimized container images.

Class Definition

from chutes.image import Image

image = Image(
    username: str,
    name: str,
    tag: str,
    readme: str = ""
)

Constructor Parameters

Required Parameters

The username or organization name for the image.

Example:

image = Image(username="mycompany", name="custom-ai", tag="1.0")

Rules:

  • Must match pattern
  • Should match your Chutes username

The name of the Docker image.

Example:

image = Image(username="mycompany", name="text-processor", tag="1.0")

Rules:

  • Must match pattern
  • Should be descriptive of the image purpose

Version tag for the image.

Examples:

# Version tag
image = Image(username="mycompany", name="ai-model", tag="1.0.0")

# Development tag
image = Image(username="mycompany", name="ai-model", tag="dev")

Best Practices:

  • Use semantic versioning (1.0.0, 1.1.0, etc.)
  • Use descriptive tags for different environments
  • Avoid using "latest" in production

Optional Parameters

Documentation for the image in Markdown format.

Example:

readme = """
# Custom AI Processing Image

This image contains optimized libraries for AI text processing.

## Features
- PyTorch 2.0 with CUDA support
- Transformers library
- Optimized for GPU inference
"""

image = Image(
    username="mycompany",
    name="ai-processor",
    tag="1.0.0",
    readme=readme
)

Default Base Image

By default, images use as the base image, which includes:

  • CUDA 12.x support
  • Python 3.12
  • OpenCL libraries
  • Common system dependencies

We highly recommend using this base image to avoid dependency issues.

Methods

Replace the base image.

Signature:

def from_base(self, base_image: str) -> Image

Examples:

# Use recommended Chutes base image (default)
image = Image("myuser", "myapp", "1.0").from_base("parachutes/python:3.12")

# Use NVIDIA CUDA base images
image = Image("myuser", "myapp", "1.0").from_base("nvidia/cuda:12.2-runtime-ubuntu22.04")

# Use Python base images
image = Image("myuser", "myapp", "1.0").from_base("python:3.11-slim")

Choosing Base Images:

  • parachutes/python:3.12: Recommended for most use cases
  • nvidia/cuda:: For GPU-accelerated applications needing specific CUDA versions
  • python:3.11-slim: Lightweight, CPU-only workloads

Execute shell commands during image build.

Signature:

def run_command(self, command: str) -> Image

Examples:

# Install Python packages
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .run_command("pip install torch transformers accelerate")
)

# Multiple commands in one call
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .run_command("""
        pip install --upgrade pip &&
        pip install torch transformers &&
        pip install accelerate datasets
    """)
)

# Install from requirements file
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .add("requirements.txt", "/tmp/requirements.txt")
    .run_command("pip install -r /tmp/requirements.txt")
)

Add files from the build context to the image.

Signature:

def add(self, source: str, dest: str) -> Image

Examples:

# Add single file
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .add("requirements.txt", "/app/requirements.txt")
)

# Add directory
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .add("src/", "/app/src/")
)

# Add multiple files
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .add("requirements.txt", "/app/requirements.txt")
    .add("config.yaml", "/app/config.yaml")
    .add("src/", "/app/src/")
)

Best Practices:

# Add requirements first for better caching
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .add("requirements.txt", "/tmp/requirements.txt")  # Add early
    .run_command("pip install -r /tmp/requirements.txt")  # Install deps
    .add("src/", "/app/src/")  # Add code last (changes frequently)
)

Set environment variables in the image.

Signature:

def with_env(self, key: str, value: str) -> Image

Examples:

# Basic environment variables
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .with_env("PYTHONPATH", "/app")
    .with_env("PYTHONUNBUFFERED", "1")
)

# Model cache configuration
image = (
    Image("myuser", "ai-app", "1.0")
    .from_base("parachutes/python:3.12")
    .with_env("TRANSFORMERS_CACHE", "/opt/models")
    .with_env("HF_HOME", "/opt/huggingface")
    .with_env("TORCH_HOME", "/opt/torch")
)

# Application configuration
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .with_env("APP_ENV", "production")
    .with_env("LOG_LEVEL", "INFO")
)

Common Environment Variables:

# Python optimization
image = image.with_env("PYTHONOPTIMIZE", "2")
image = image.with_env("PYTHONDONTWRITEBYTECODE", "1")
image = image.with_env("PYTHONUNBUFFERED", "1")

# PyTorch optimizations
image = image.with_env("TORCH_BACKENDS_CUDNN_BENCHMARK", "1")

Set the working directory for the container.

Signature:

def set_workdir(self, directory: str) -> Image

Examples:

# Set working directory
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .set_workdir("/app")
    .add("src/", "/app/src/")
)

# Multiple working directories for different stages
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .set_workdir("/tmp")
    .add("requirements.txt", "requirements.txt")
    .run_command("pip install -r requirements.txt")
    .set_workdir("/app")
    .add("src/", "src/")
)

Set the user for running commands and the container.

Signature:

def set_user(self, user: str) -> Image

Examples:

# Create and use non-root user
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .run_command("useradd -m -u 1000 appuser")
    .run_command("mkdir -p /app && chown appuser:appuser /app")
    .set_user("appuser")
    .set_workdir("/app")
)

# Use existing user
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("ubuntu:22.04")
    .set_user("nobody")
)

Install system packages using apt.

Signature:

def apt_install(self, package: str | List[str]) -> Image

Examples:

# Install single package
image = image.apt_install("git")

# Install multiple packages
image = image.apt_install(["git", "curl", "wget", "ffmpeg"])

Remove system packages using apt.

Signature:

def apt_remove(self, package: str | List[str]) -> Image

Example:

# Remove packages after use
image = (
    image
    .apt_install(["build-essential", "cmake"])
    .run_command("pip install some-package-that-needs-compilation")
    .apt_remove(["build-essential", "cmake"])
)

Install a specific version of Python from source.

Signature:

def with_python(self, version: str = "3.10.15") -> Image

Example:

# Install specific Python version
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("ubuntu:22.04")
    .with_python("3.11.5")
)

Note: This builds Python from source, which can be slow. Consider using as your base image instead.

Set the maintainer for the image.

Signature:

def with_maintainer(self, maintainer: str) -> Image

Example:

image = image.with_maintainer("[email protected]")

Set the container entrypoint.

Signature:

def with_entrypoint(self, *args) -> Image

Examples:

# Python module entrypoint
image = image.with_entrypoint("python", "-m", "myapp")

# Shell script entrypoint
image = (
    image
    .add("entrypoint.sh", "/entrypoint.sh")
    .run_command("chmod +x /entrypoint.sh")
    .with_entrypoint("/entrypoint.sh")
)

Complete Examples

Basic ML Image

from chutes.image import Image

image = (
    Image(username="myuser", name="ml-app", tag="1.0")
    .from_base("parachutes/python:3.12")
    .run_command("pip install torch transformers accelerate")
    .add("requirements.txt", "/app/requirements.txt")
    .run_command("pip install -r /app/requirements.txt")
    .add("src/", "/app/src/")
    .set_workdir("/app")
    .with_env("PYTHONPATH", "/app")
)

Optimized PyTorch Image

image = (
    Image(username="myuser", name="pytorch-app", tag="1.0",
          readme="## PyTorch Application\nOptimized for GPU inference.")
    .from_base("parachutes/python:3.12")

    # System dependencies
    .apt_install(["git", "curl", "ffmpeg"])

    # Python packages
    .run_command("""
        pip install --upgrade pip &&
        pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 &&
        pip install transformers accelerate datasets tokenizers
    """)

    # Environment optimization
    .with_env("PYTHONUNBUFFERED", "1")
    .with_env("TRANSFORMERS_CACHE", "/opt/models")
    .with_env("TORCH_BACKENDS_CUDNN_BENCHMARK", "1")

    # Application code
    .add("requirements.txt", "/app/requirements.txt")
    .run_command("pip install -r /app/requirements.txt")
    .add("src/", "/app/src/")
    .set_workdir("/app")
)

Image with System Dependencies

image = (
    Image(username="myuser", name="audio-processor", tag="1.0")
    .from_base("parachutes/python:3.12")

    # Audio processing dependencies
    .apt_install([
        "ffmpeg",
        "libsndfile1",
        "libportaudio2",
        "libsox-fmt-all"
    ])

    # Python audio libraries
    .run_command("""
        pip install soundfile librosa pydub torchaudio
    """)

    .add("src/", "/app/src/")
    .set_workdir("/app")
)

Layer Caching Best Practices

For faster builds, order your directives from least to most frequently changing:

# Good: Optimal layer ordering
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")

    # 1. System packages (rarely change)
    .apt_install(["git", "curl"])

    # 2. Python dependencies from requirements (change occasionally)
    .add("requirements.txt", "/tmp/requirements.txt")
    .run_command("pip install -r /tmp/requirements.txt")

    # 3. Application code (changes frequently)
    .add("src/", "/app/src/")

    .set_workdir("/app")
)

# Bad: Frequent changes early invalidate cache
image = (
    Image("myuser", "myapp", "1.0")
    .from_base("parachutes/python:3.12")
    .add("src/", "/app/src/")  # Changes often - invalidates all later layers!
    .apt_install(["git", "curl"])
    .run_command("pip install torch")
)

Combining Commands

Combine related commands into single layers to reduce image size:

# Good: Single layer with cleanup
image = image.run_command("""
    apt-get update &&
    apt-get install -y git curl &&
    rm -rf /var/lib/apt/lists/*
""")

# Less optimal: Multiple layers
image = (
    image
    .run_command("apt-get update")
    .run_command("apt-get install -y git curl")
    .run_command("rm -rf /var/lib/apt/lists/*")  # Cleanup in separate layer doesn't reduce size
)

Properties

The unique identifier for the image.

Type:

The name of the image.

Type:

The tag/version of the image.

Type:

The documentation for the image.

Type:

The username/organization for the image.

Type:

See Also