or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compute-resources.mdcontainer-images.mdcore-application-client.mdfunction-decorators-helpers.mdindex.mdinfrastructure-services.mdruntime-utilities.mdscheduling-reliability.mdstorage-data.mdutility-classes.mdweb-api-integration.md

container-images.mddocs/

0

# Container Images

1

2

Container image definitions that specify the runtime environment for functions and classes. Images define the operating system, Python version, packages, and system dependencies needed for your code to run.

3

4

## Capabilities

5

6

### Image Class

7

8

Defines container environments with pre-installed dependencies, custom configurations, and optimized builds for serverless execution.

9

10

```python { .api }

11

class Image:

12

@classmethod

13

def debian_slim(

14

cls,

15

python_version: str = None,

16

builder_version: str = None

17

):

18

"""

19

Create a Debian slim base image with Python.

20

21

Parameters:

22

- python_version: Python version (e.g., "3.11", "3.12"). Defaults to local version.

23

- builder_version: Image builder version for reproducible builds

24

25

Returns:

26

Image instance with Debian slim base

27

"""

28

29

@classmethod

30

def from_registry(

31

cls,

32

tag: str,

33

secret: Secret = None,

34

setup_dockerfile_commands: list[str] = None

35

):

36

"""

37

Create an image from a container registry (Docker Hub, ECR, etc.).

38

39

Parameters:

40

- tag: Full image tag (e.g., "python:3.11-slim", "ubuntu:22.04")

41

- secret: Secret for private registry authentication

42

- setup_dockerfile_commands: Additional setup commands to run

43

44

Returns:

45

Image instance based on registry image

46

"""

47

48

def pip_install(

49

self,

50

*packages: str,

51

find_links: str = None,

52

index_url: str = None,

53

extra_index_url: str = None,

54

pre: bool = False,

55

force_build: bool = False

56

):

57

"""

58

Install Python packages using pip.

59

60

Parameters:

61

- *packages: Package names, optionally with version specifiers

62

- find_links: Additional URLs to search for packages

63

- index_url: Base URL of package index

64

- extra_index_url: Extra URLs of package indexes

65

- pre: Include pre-release versions

66

- force_build: Force rebuild even if cached

67

68

Returns:

69

New Image instance with packages installed

70

"""

71

72

def poetry_install_from_file(

73

self,

74

poetry_pyproject_toml: str,

75

poetry_lock_file: str = None,

76

ignore_lockfile: bool = False

77

):

78

"""

79

Install dependencies from Poetry configuration files.

80

81

Parameters:

82

- poetry_pyproject_toml: Path to pyproject.toml file

83

- poetry_lock_file: Path to poetry.lock file

84

- ignore_lockfile: Install without using lockfile

85

86

Returns:

87

New Image instance with Poetry dependencies

88

"""

89

90

def run_commands(

91

self,

92

*commands: str,

93

secrets: list[Secret] = None,

94

gpu: str = None

95

):

96

"""

97

Run shell commands during image build.

98

99

Parameters:

100

- *commands: Shell commands to execute

101

- secrets: Secrets available during build

102

- gpu: GPU type for build environment

103

104

Returns:

105

New Image instance with commands executed

106

"""

107

108

def apt_install(

109

self,

110

*packages: str,

111

force_build: bool = False

112

):

113

"""

114

Install system packages using apt (Debian/Ubuntu).

115

116

Parameters:

117

- *packages: Package names to install

118

- force_build: Force rebuild even if cached

119

120

Returns:

121

New Image instance with system packages

122

"""

123

124

def copy_local_file(

125

self,

126

local_path: str,

127

remote_path: str = None

128

):

129

"""

130

Copy a local file into the image.

131

132

Parameters:

133

- local_path: Path to local file or directory

134

- remote_path: Destination path in image. Defaults to same path.

135

136

Returns:

137

New Image instance with file copied

138

"""

139

140

def copy_local_dir(

141

self,

142

local_path: str,

143

remote_path: str = None,

144

condition: callable = None

145

):

146

"""

147

Copy a local directory into the image.

148

149

Parameters:

150

- local_path: Path to local directory

151

- remote_path: Destination path in image

152

- condition: Function to filter which files to copy

153

154

Returns:

155

New Image instance with directory copied

156

"""

157

158

def add_python_packages(

159

self,

160

*python_packages: str,

161

force_build: bool = False

162

):

163

"""

164

Add Python packages from local wheel files or directories.

165

166

Parameters:

167

- *python_packages: Paths to wheel files or package directories

168

- force_build: Force rebuild even if cached

169

170

Returns:

171

New Image instance with packages added

172

"""

173

174

def dockerfile_commands(

175

self,

176

dockerfile_commands: list[str],

177

secrets: list[Secret] = None,

178

gpu: str = None,

179

context_files: dict = None

180

):

181

"""

182

Execute Dockerfile commands during build.

183

184

Parameters:

185

- dockerfile_commands: List of Dockerfile commands (RUN, COPY, etc.)

186

- secrets: Build secrets

187

- gpu: GPU type for build

188

- context_files: Files to include in build context

189

190

Returns:

191

New Image instance with Dockerfile commands applied

192

"""

193

194

def env(self, **env_vars: str):

195

"""

196

Set environment variables in the image.

197

198

Parameters:

199

- **env_vars: Environment variables as keyword arguments

200

201

Returns:

202

New Image instance with environment variables set

203

"""

204

205

def workdir(self, path: str):

206

"""

207

Set the working directory for the image.

208

209

Parameters:

210

- path: Working directory path

211

212

Returns:

213

New Image instance with working directory set

214

"""

215

```

216

217

## Usage Examples

218

219

### Basic Python Environment

220

221

```python

222

import modal

223

224

# Simple Python environment

225

image = modal.Image.debian_slim(python_version="3.11").pip_install(

226

"requests",

227

"beautifulsoup4",

228

"pandas==2.0.0"

229

)

230

231

app = modal.App("web-scraper")

232

233

@app.function(image=image)

234

def scrape_and_analyze(url: str):

235

import requests

236

import pandas as pd

237

from bs4 import BeautifulSoup

238

239

response = requests.get(url)

240

soup = BeautifulSoup(response.content, 'html.parser')

241

242

# Extract and analyze data

243

links = [a.get('href') for a in soup.find_all('a', href=True)]

244

df = pd.DataFrame({'links': links})

245

246

return {

247

'total_links': len(links),

248

'unique_domains': len(df['links'].apply(lambda x: x.split('/')[2] if x.startswith('http') else None).dropna().unique())

249

}

250

```

251

252

### Data Science Environment

253

254

```python

255

import modal

256

257

# Comprehensive data science environment

258

ds_image = (

259

modal.Image.debian_slim(python_version="3.11")

260

.apt_install("git", "curl", "build-essential")

261

.pip_install(

262

"numpy",

263

"pandas",

264

"scikit-learn",

265

"matplotlib",

266

"seaborn",

267

"jupyter",

268

"plotly",

269

"scipy"

270

)

271

.run_commands(

272

"pip install --no-deps lightgbm", # Custom installation

273

"mkdir -p /opt/data"

274

)

275

.env(

276

DATA_PATH="/opt/data",

277

PYTHONPATH="/opt/models"

278

)

279

)

280

281

app = modal.App("ml-pipeline")

282

283

@app.function(image=ds_image)

284

def train_model(dataset_path: str):

285

import pandas as pd

286

from sklearn.ensemble import RandomForestClassifier

287

from sklearn.model_selection import train_test_split

288

from sklearn.metrics import accuracy_score

289

290

# Load and prepare data

291

df = pd.read_csv(dataset_path)

292

X = df.drop('target', axis=1)

293

y = df['target']

294

295

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

296

297

# Train model

298

model = RandomForestClassifier(n_estimators=100)

299

model.fit(X_train, y_train)

300

301

# Evaluate

302

predictions = model.predict(X_test)

303

accuracy = accuracy_score(y_test, predictions)

304

305

return {"accuracy": accuracy, "model_type": "RandomForest"}

306

```

307

308

### Custom Base Image

309

310

```python

311

import modal

312

313

# Using a custom base image from Docker Hub

314

custom_image = (

315

modal.Image.from_registry("nvidia/cuda:11.8-devel-ubuntu22.04")

316

.apt_install("python3", "python3-pip", "python3-dev")

317

.run_commands(

318

"ln -s /usr/bin/python3 /usr/bin/python",

319

"pip install --upgrade pip"

320

)

321

.pip_install("torch", "torchvision", "transformers")

322

.env(CUDA_VISIBLE_DEVICES="0")

323

)

324

325

app = modal.App("gpu-ml")

326

327

@app.function(

328

image=custom_image,

329

gpu="T4" # GPU required for this function

330

)

331

def run_inference(model_name: str, input_text: str):

332

import torch

333

from transformers import AutoTokenizer, AutoModel

334

335

# Load model and tokenizer

336

tokenizer = AutoTokenizer.from_pretrained(model_name)

337

model = AutoModel.from_pretrained(model_name)

338

339

# Tokenize and run inference

340

inputs = tokenizer(input_text, return_tensors="pt")

341

with torch.no_grad():

342

outputs = model(**inputs)

343

344

return {

345

"embeddings_shape": outputs.last_hidden_state.shape,

346

"mean_embedding": outputs.last_hidden_state.mean().item()

347

}

348

```

349

350

### Development Environment with Local Code

351

352

```python

353

import modal

354

355

# Development image with local code and dependencies

356

dev_image = (

357

modal.Image.debian_slim()

358

.pip_install("fastapi", "uvicorn", "sqlalchemy", "pytest")

359

.copy_local_dir("./src", "/app/src") # Copy local source code

360

.copy_local_file("requirements.txt", "/app/requirements.txt")

361

.run_commands("pip install -r /app/requirements.txt")

362

.workdir("/app")

363

)

364

365

app = modal.App("development")

366

367

@app.function(image=dev_image)

368

def run_tests():

369

import subprocess

370

371

# Run tests using the copied code

372

result = subprocess.run(

373

["python", "-m", "pytest", "src/tests/", "-v"],

374

capture_output=True,

375

text=True,

376

cwd="/app"

377

)

378

379

return {

380

"exit_code": result.returncode,

381

"stdout": result.stdout,

382

"stderr": result.stderr

383

}

384

```

385

386

### Poetry-based Project

387

388

```python

389

import modal

390

391

# Using Poetry for dependency management

392

poetry_image = (

393

modal.Image.debian_slim()

394

.apt_install("curl")

395

.run_commands(

396

"curl -sSL https://install.python-poetry.org | python3 -",

397

"export PATH=\"/root/.local/bin:$PATH\""

398

)

399

.poetry_install_from_file(

400

"pyproject.toml",

401

"poetry.lock"

402

)

403

.copy_local_dir("./my_package", "/app/my_package")

404

.workdir("/app")

405

)

406

407

app = modal.App("poetry-app")

408

409

@app.function(image=poetry_image)

410

def process_with_poetry_deps():

411

# Use dependencies installed via Poetry

412

from my_package import main_module

413

return main_module.process_data()

414

```

415

416

### Multi-stage Build

417

418

```python

419

import modal

420

421

# Complex multi-stage build with custom compilation

422

build_image = (

423

modal.Image.debian_slim()

424

.apt_install(

425

"build-essential",

426

"cmake",

427

"git",

428

"pkg-config",

429

"libssl-dev"

430

)

431

.run_commands(

432

# Clone and build custom library

433

"git clone https://github.com/example/custom-lib.git /tmp/custom-lib",

434

"cd /tmp/custom-lib && mkdir build && cd build",

435

"cmake .. && make -j$(nproc) && make install"

436

)

437

.pip_install("numpy", "cython")

438

.copy_local_file("setup.py", "/app/setup.py")

439

.copy_local_dir("./src", "/app/src")

440

.run_commands(

441

"cd /app && python setup.py build_ext --inplace",

442

"pip install -e ."

443

)

444

.apt_install("--purge", "build-essential", "cmake") # Clean up build tools

445

.run_commands("apt-get autoremove -y && apt-get clean")

446

)

447

448

app = modal.App("optimized-build")

449

450

@app.function(image=build_image)

451

def run_optimized_computation(data):

452

# Use the custom-built optimized library

453

import my_optimized_package

454

return my_optimized_package.fast_compute(data)

455

```

456

457

## Common Patterns

458

459

### Environment Variables and Configuration

460

461

```python

462

config_image = (

463

modal.Image.debian_slim()

464

.pip_install("python-dotenv", "pydantic")

465

.env(

466

ENVIRONMENT="production",

467

LOG_LEVEL="INFO",

468

API_TIMEOUT="30"

469

)

470

.copy_local_file(".env.production", "/app/.env")

471

)

472

```

473

474

### Caching for Faster Builds

475

476

```python

477

# Use force_build=False (default) to enable caching

478

cached_image = (

479

modal.Image.debian_slim()

480

.pip_install("numpy", "pandas", force_build=False) # Will be cached

481

.copy_local_file("requirements.txt") # This will trigger rebuild if file changes

482

.pip_install("-r", "requirements.txt")

483

)

484

```

485

486

### Secrets in Build Process

487

488

```python

489

build_secret = modal.Secret.from_dict({

490

"GITHUB_TOKEN": "ghp_...",

491

"PRIVATE_REGISTRY_TOKEN": "..."

492

})

493

494

secure_image = (

495

modal.Image.debian_slim()

496

.run_commands(

497

"git clone https://${GITHUB_TOKEN}@github.com/private/repo.git /app",

498

secrets=[build_secret]

499

)

500

.pip_install("--extra-index-url", "https://token:${PRIVATE_REGISTRY_TOKEN}@pypi.private.com/simple/", "private-package", secrets=[build_secret])

501

)

502

```