Compute
Run a single managed container with image building, file uploads, and exec-style command invocation.
A Container is one rung above a Sandbox: same
gVisor-isolated runtime underneath, but wrapped with image building, local file
upload, secret injection, and an exec-style invocation API. Use a container
for one-off batch jobs, interactive sessions, or long-running processes that
don’t need replication.
If you need replicated HTTP-fronted workloads with autoscaling, use a Scaling Group instead. If you need a serverless, fan-out invocation model with a Python function as the interface, use Functions.
from chalkcompute import Container, Image
c = Container(
image=Image.debian_slim("3.12").pip_install(["requests"]),
name="hello-container",
cpu="1",
memory="2Gi",
).run()
result = c.exec("python", "-c", "import requests; print(requests.__version__)")
print(result.stdout_text)
print(f"exit code: {result.exit_code}")
c.stop()Container(...).run() does three things in sequence:
Image (or skips if the spec is already
cached, since images are content-addressed).add_local_file / add_local_dir to
a volume and mounts it into the container.Running state..run() returns self, so you can chain it.
CPU, memory, and GPU are passed at construction time and follow Kubernetes conventions:
c = Container(
image=Image.debian_slim("3.12"),
name="batch-job",
cpu="4", # cores, e.g. "500m" for half a core
memory="16Gi", # Mi / Gi suffixes
gpu="nvidia-l4:1", # type:count, or just count
).run()If you omit these flags, the service applies defaults from your environment’s resource configuration. GPU support and the set of available GPU types depend on the node pools provisioned in your cluster — see Sandbox § GPU.
Inject configuration via env (plaintext) or secrets (resolved from Chalk’s
managed secret store, an integration, or your local environment):
from chalkcompute import Container, Image, Secret
c = Container(
image=Image.debian_slim("3.12"),
name="api-client",
env={"LOG_LEVEL": "INFO"},
secrets=[
Secret.from_env("OPENAI_API_KEY"),
Secret.from_integration("prod_postgres"),
],
).run()See the Secrets section of the Compute overview
for the full list of Secret constructors.
Attach a Volume to share durable state between runs or expose a large dataset without baking it into the image:
from chalkcompute import Container, Image, Volume
vol = Volume("training-data")
vol.put_file("inputs/example.txt", b"hello\n")
c = Container(
image=Image.debian_slim("3.12"),
name="trainer",
volumes=[("training-data", "/data")],
).run()
result = c.exec("cat", "/data/inputs/example.txt")
print(result.stdout_text) # "hello\n"Volumes mounted this way are persistent across container restarts and shared across other containers that mount the same volume.
Container.exec(*command, timeout_secs=...) runs a one-shot process inside the
already-started container, blocking until the command finishes:
result = c.exec("ls", "-la", "/app")
print(result.stdout_text)
print(result.stderr_text)
print(result.exit_code)exec captures stdout and stderr in full and returns them at the end. If you
need streaming output, stdin, or signal handling, drop down to the lower-level
Sandbox API — Container is a wrapper over the
same primitive.
If your container runs a long-lived server (HTTP, gRPC, etc.) that you want to
reach from inside the cluster, pass port:
c = Container(
image=Image.debian_slim("3.12").pip_install(["flask"]),
name="api",
port=8080,
entrypoint=["python", "-m", "flask", "run", "--host=0.0.0.0", "--port=8080"],
).run()For externally addressable, replicated, autoscaling HTTP services, prefer a Scaling Group — it gives you a public DNS name, TLS termination, and replica management out of the box.
c = Container.from_name("hello-container")
# or
c = Container.from_id("550e8400-e29b-41d4-a716-446655440000")This is useful for reconnecting to a long-lived container from a different
process without re-running .run() (which would attempt to recreate it).
c.refresh() # re-fetch from the server
print(c.info.status) # 'Running', 'Failed', etc.
print(c.id)
print(c.image_uri)c.stop() # immediate stop + cleanup
c.stop(grace_period_seconds=30) # SIGTERM, wait 30s, then SIGKILLstop() also removes any temporary volumes created from add_local_file
uploads and deletes any secrets that were upserted from your local environment
for this run (e.g. via Secret.from_local_env).
See Choosing the right primitive on the Compute overview for the full decision table.