Skip to content

Every Job, Sandbox, Function and Agent runs in a container image. You can use a catalog image, any public or private registry image, or an Image that Nodus builds for you. When you submit work, Nodus resolves the image’s tag to a digest and records it, so a retry or a recovery runs exactly the same bytes.

Image Contents Default for
nodus/python:3.12 (also 3.10, 3.11, 3.13) Debian slim, Python, uv, git Jobs without a GPU
nodus/pytorch:2.8-cuda12.8 CUDA 12.8 runtime, Python 3.12, PyTorch 2.8 Jobs with a GPU
nodus/agent-tools Python 3.12, Node 22, git, ripgrep, the Nodus SDK Sandboxes and Agents
Terminal window
nodus get images -n nodus
nodus run --gpu L4 --image nodus/pytorch -- python -c "import torch; print(torch.cuda.get_device_name())"

Catalog images run as uid 1000 and include /bin/sh.

Current hosted deployments support catalog images and prebuilt public or private registry images. Image builds from steps, Dockerfiles and Sandbox snapshots are unavailable. Those requests return ImageBuildUnavailable with HTTP 503 before accepting a build or charging for one. Publish your image to a registry, then use its reference directly or create an Image with only base and no steps. Environment packages that need a pip build must instead name a prebuilt package.image.

Existing unstarted build requests report Failed with an explanation instead of waiting indefinitely. The build examples below describe the contract for a deployment with a configured build runner and registry.

An Image starts from a base and adds steps: aptInstall, pipInstall, uvPipInstall, uvSync, run, copy, env and workdir.

image.yaml
apiVersion: nodus.dev/v1
kind: Image
metadata:
name: ex-images-build
spec:
base: nodus/python:3.12
steps:
- aptInstall: [jq]
- pipInstall: {packages: ["requests==2.32.5"]}
- env: {APP_MODE: example}
Terminal window
nodus apply -f image.yaml
nodus wait image/ex-images-build --for=condition=Ready

The build log streams from GET …/images/{name}/log?follow=true; the Python SDK prints it while it builds.

Run on it with imageRef:

job.yaml
apiVersion: nodus.dev/v1
kind: Job
metadata:
name: ex-images-build
spec:
imageRef: {name: ex-images-build} # runs the digest the Image built, pinned at admission
command: [python, -c, "import os, requests; print('requests', requests.__version__, os.environ['APP_MODE'])"]

In Python:

image = (nodus.Image.from_registry("nodus/pytorch:2.8-cuda12.8")
.apt_install("git").pip_install("transformers==4.57.6", "peft")
.env({"HF_HUB_ENABLE_HF_TRANSFER": "1"}))

Builds run on Nodus and are billed per vCPU-second at the CPU rate. An Image whose spec matches one your org has already built, on the same base digest, reuses that digest without building (status.build.cached: true). An Image with only a base is ready at once: it is that image’s digest.

You can also build from a Dockerfile, inline or uploaded with its context:

spec:
dockerfile:
inline: |
FROM nodus/python:3.12
RUN pip install polars==1.33.1

Build-time credentials go in buildSecrets: they are mounted for the build only and never stored in a layer.

Create a Registry Secret (Secrets) and name it under imagePullSecrets, on the Job or Sandbox for image, or on the Image for a private base.

When work runs on a provider that pulls containers itself, Nodus copies the image by digest into your org’s space in the Nodus registry first, so your registry credential never reaches the provider. Such providers need /bin/sh in the image; an image without it gets the ProviderContainerNeedsShell warning and runs elsewhere.

A built Image lives in the Nodus registry under your org; status.reference holds its full reference. Log in with any username and an API key as the password, then pull it:

Terminal window
REF=$(nodus get image ex-images-build -o jsonpath='{.status.reference}')
echo "$NODUS_API_KEY" | docker login "${REF%%/*}" -u nodus --password-stdin
docker pull "$REF"

Viewers, and keys without the images:write scope, can pull but not push.

nodus get image ex-images-build shows PHASE, DIGEST and SIZE. A failed build has a reason:

Reason or error Meaning
BaseNotFound The base does not exist, or its registry refused the pull Secret
StepFailed A step exited non-zero; the build log shows which
BuildTimeout The build ran past its time limit
ImageNotFound, ImagePullFailed A Job’s image could not be resolved when you submitted it
ImageNotReady A Job or Sandbox names an Image that has not finished building