Back to Microsandbox

Images

docs/sdk/python/images.mdx

0.6.720.6 KB
Original Source

Image is the static namespace for two related things: configuring an explicit rootfs source for a sandbox (Image.oci, Image.bind, Image.disk), and managing the local OCI image cache that sandbox creation pulls into (get, list, inspect, remove, prune, load, save). Cache operations require a local backend. See Sandbox for the image= and pull_policy= creation kwargs.

python
from microsandbox import Image
<div className="msb-glance"> <p className="msb-gl"><span className="msb-dot static"></span>Source factory<span className="msb-ct">3</span></p> <a className="msb-row" href="#image-oci"><span className="msb-rn">Image.oci()</span><span className="msb-rg">OCI image rootfs source</span></a> <a className="msb-row" href="#image-bind"><span className="msb-rn">Image.bind()</span><span className="msb-rg">bind a host directory</span></a> <a className="msb-row" href="#image-disk"><span className="msb-rn">Image.disk()</span><span className="msb-rg">boot from a disk image</span></a> <p className="msb-gl"><span className="msb-dot static"></span>Cache management<span className="msb-ct">7</span></p> <a className="msb-row" href="#image-get"><span className="msb-rn">Image.get()</span><span className="msb-rg">one cached image</span></a> <a className="msb-row" href="#image-list"><span className="msb-rn">Image.list()</span><span className="msb-rg">all cached images</span></a> <a className="msb-row" href="#image-inspect"><span className="msb-rn">Image.inspect()</span><span className="msb-rg">config + layer detail</span></a> <a className="msb-row" href="#image-remove"><span className="msb-rn">Image.remove()</span><span className="msb-rg">delete a cached image</span></a> <a className="msb-row" href="#image-prune"><span className="msb-rn">Image.prune()</span><span className="msb-rg">reclaim unused data</span></a> <a className="msb-row" href="#image-load"><span className="msb-rn">Image.load()</span><span className="msb-rg">import from archive</span></a> <a className="msb-row" href="#image-save"><span className="msb-rn">Image.save()</span><span className="msb-rg">export to archive</span></a> <p className="msb-gl"><span className="msb-dot type"></span>Types</p> <div className="msb-chiprow"> <a className="msb-typepill" href="#imagesource">ImageSource</a> <a className="msb-typepill" href="#imagehandle">ImageHandle</a> <a className="msb-typepill" href="#imagedetail">ImageDetail</a> <a className="msb-typepill" href="#imageconfigdetail">ImageConfigDetail</a> <a className="msb-typepill" href="#imagelayerdetail">ImageLayerDetail</a> <a className="msb-typepill" href="#imageprunereport">ImagePruneReport</a> <a className="msb-typepill" href="#diskimageformat">DiskImageFormat</a> </div> </div> <p className="msb-label" id="typical-flow">Typical flow</p>
python
from microsandbox import Image, Sandbox

# Pull happens implicitly on creation
async with await Sandbox.create("api", image="python:3.12") as sb:
    await sb.exec("python", ["-V"])

# Later, inspect and prune the local cache
for image in await Image.list():
    print(image.reference, image.layer_count)

report = await Image.prune()
print(f"reclaimed {report.bytes_reclaimed} bytes")

Source factory

These static methods return an ImageSource you can pass as the image= kwarg to Sandbox.create(). A plain string also works (image="python:3.12"); use the factory when you need OCI-only options like the writable upper size, or to be explicit about a bind or disk source.

<span className="msb-recv">Image.</span><span className="msb-hn">oci()</span>

python
@staticmethod
def oci(reference: str, *, upper_size_mib: int | None = None) -> ImageSource
<Accordion title="Example">
python
sb = await Sandbox.create(
    "api",
    image=Image.oci("python:3.12", upper_size_mib=8192),
)
</Accordion>

Create an OCI image rootfs source. Use upper_size_mib to size the writable overlay upper layer; otherwise the default applies.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>reference</code><span className="msb-type">str</span></div> <div className="msb-param-desc">OCI image reference, e.g. <code>"python:3.12"</code>.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>upper_size_mib</code><span className="msb-type">int | None</span></div> <div className="msb-param-desc">Writable overlay upper size in MiB. <code>None</code> keeps the default.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagesource">ImageSource</a></div> <div className="msb-param-desc">Rootfs source for <code>image=</code>.</div> </div> </div>

<span className="msb-recv">Image.</span><span className="msb-hn">bind()</span>

python
@staticmethod
def bind(path: str) -> ImageSource
<Accordion title="Example">
python
sb = await Sandbox.create("api", image=Image.bind("/srv/rootfs"))
</Accordion>

Create a rootfs source that binds a host directory as the guest root filesystem.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>path</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Host directory to use as the rootfs.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagesource">ImageSource</a></div> <div className="msb-param-desc">Rootfs source for <code>image=</code>.</div> </div> </div>

<span className="msb-recv">Image.</span><span className="msb-hn">disk()</span>

python
@staticmethod
def disk(path: str, *, fstype: str | None = None) -> ImageSource
<Accordion title="Example">
python
sb = await Sandbox.create(
    "api",
    image=Image.disk("/data/root.qcow2", fstype="ext4"),
)
</Accordion>

Create a rootfs source backed by a disk image. The format is inferred from the file extension. Pass fstype when the filesystem type cannot be auto-detected.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>path</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Path to the disk image (e.g. <code>.qcow2</code>, <code>.raw</code>, <code>.vmdk</code>).</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>fstype</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Filesystem type, e.g. <code>"ext4"</code>. <code>None</code> auto-detects.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagesource">ImageSource</a></div> <div className="msb-param-desc">Rootfs source for <code>image=</code>.</div> </div> </div>

Cache management

These static methods inspect and prune images already pulled into the local OCI cache. They require a local backend; on a cloud backend they raise UnsupportedError.

<span className="msb-recv">Image.</span><span className="msb-hn">get()</span>

python
@staticmethod
async def get(reference: str) -> ImageHandle
<Accordion title="Example">
python
handle = await Image.get("python:3.12")
print(handle.reference, handle.layer_count)
</Accordion>

Fetch one cached image by reference. Raises ImageNotFoundError when the image is not present in the local cache.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>reference</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Image reference to look up.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagehandle">ImageHandle</a></div> <div className="msb-param-desc">Handle to the cached image.</div> </div> </div>

<span className="msb-recv">Image.</span><span className="msb-hn">list()</span>

python
@staticmethod
async def list() -> list[ImageHandle]
<Accordion title="Example">
python
for image in await Image.list():
    print(image.reference, image.size_bytes)
</Accordion>

Return every cached image.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagehandle">list[ImageHandle]</a></div> <div className="msb-param-desc">All cached image handles.</div> </div> </div>

<span className="msb-recv">Image.</span><span className="msb-hn">inspect()</span>

python
@staticmethod
async def inspect(reference: str) -> ImageDetail
<Accordion title="Example">
python
detail = await Image.inspect("python:3.12")
print(detail.handle.reference)
for layer in detail.layers:
    print(layer.position, layer.diff_id)
</Accordion>

Return handle metadata plus the parsed OCI config and per-layer detail.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>reference</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Image reference to inspect.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagedetail">ImageDetail</a></div> <div className="msb-param-desc">Handle, OCI config, and layers.</div> </div> </div>

<span className="msb-recv">Image.</span><span className="msb-hn">remove()</span>

python
@staticmethod
async def remove(reference: str, *, force: bool = False) -> None
<Accordion title="Example">
python
await Image.remove("python:3.12", force=True)
</Accordion>

Delete a cached image. When force is False, an image still referenced by one or more sandboxes raises ImageInUseError; pass force=True to remove it anyway.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>reference</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Image reference to delete.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>force</code><span className="msb-type">bool</span></div> <div className="msb-param-desc">Remove even if still referenced. Default <code>False</code>.</div> </div> </div>

<span className="msb-recv">Image.</span><span className="msb-hn">prune()</span>

python
@staticmethod
async def prune() -> ImagePruneReport
<Accordion title="Example">
python
report = await Image.prune()
print(f"{report.layers_removed} layers, {report.bytes_reclaimed} bytes")
</Accordion>

Remove cached image data that is not used by any sandbox or indexed snapshot. The returned report counts the removed refs, manifests, layers, fsmeta files, and VMDK files, plus any measured bytes reclaimed.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imageprunereport">ImagePruneReport</a></div> <div className="msb-param-desc">Counts of removed data and bytes reclaimed.</div> </div> </div> <Accordion title="Example">
python
report = await Image.prune()
print(f"{report.layers_removed} layers, {report.bytes_reclaimed} bytes")
</Accordion>

<span className="msb-recv">Image.</span><span className="msb-hn">load()</span>

<div className="msb-tags"><span className="msb-tag is-static">static</span><span className="msb-tag is-async">async</span></div>
python
@staticmethod
async def load(input_path: str, *, tag: str | None = None) -> list[ImageHandle]

Import images from a local archive into the cache. Accepts docker save tarballs and OCI Image Layout archives, so locally built images can be used without going through a registry.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>input_path</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Path to the archive file, or <code>"-"</code> to read the archive from stdin.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>tag</code><span className="msb-type">str | None</span></div> <div className="msb-param-desc">Extra reference applied to the first image in the archive.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#imagehandle">list[ImageHandle]</a></div> <div className="msb-param-desc">A handle for every image reference imported.</div> </div> </div> <Accordion title="Example">
python
# docker save my-image:latest -o my-image.tar
images = await Image.load(input_path="my-image.tar", tag="app:local")
for image in images:
    print(image.reference, image.layer_count)

# Or pipe it in: docker save my-image:latest | python app.py
images = await Image.load(input_path="-")
</Accordion>

<span className="msb-recv">Image.</span><span className="msb-hn">save()</span>

<div className="msb-tags"><span className="msb-tag is-static">static</span><span className="msb-tag is-async">async</span></div>
python
@staticmethod
async def save(reference: str | Sequence[str], *, output_path: str, format: str = "docker") -> None

Export one or more cached images to an archive file. Raises ImageNotFoundError when any reference is not in the local cache, and ValueError for an unknown format or an empty reference list.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>reference</code><span className="msb-type">str | Sequence[str]</span></div> <div className="msb-param-desc">Cached image reference to export, or a sequence of references written into the same archive.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>output_path</code><span className="msb-type">str</span></div> <div className="msb-param-desc">File path to write the archive to.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>format</code><span className="msb-type">str</span></div> <div className="msb-param-desc">Archive layout: <code>"docker"</code> (default, loadable with <code>docker load</code>) or <code>"oci"</code> (OCI Image Layout).</div> </div> </div> <Accordion title="Example">
python
await Image.save("python:3.12", output_path="python.tar")
await Image.save("python:3.12", output_path="python-oci.tar", format="oci")
await Image.save(["python:3.12", "app:local"], output_path="bundle.tar")
</Accordion>

Types

ImageSource

<p className="msb-backref">Returned by <a href="#image-oci">oci()</a> · <a href="#image-bind">bind()</a> · <a href="#image-disk">disk()</a></p>

Explicit rootfs image source. Build one with Image.oci(), Image.bind(), or Image.disk(), then pass it as the image= kwarg to Sandbox.create(). A frozen dataclass; treat its fields as opaque.

FieldTypeDescription
_typestrSource kind: "oci", "bind", or "disk"
_pathstr | NoneHost path for bind / disk sources
_referencestr | NoneOCI reference for oci sources
_upper_size_mibint | NoneWritable overlay upper size in MiB (OCI only)
_fstypestr | NoneFilesystem type for disk sources
_formatDiskImageFormat | NoneDisk image format (inferred from extension)

ImageHandle

<div className="msb-tags"><span className="msb-tag is-type">class</span></div> <p className="msb-backref">Returned by <a href="#image-get">get()</a> · <a href="#image-list">list()</a> · <a href="#image-load">load()</a></p>

A lightweight handle to a cached OCI image, returned by Image.get(), Image.list(), and Image.load(). Properties are read-only attributes; the two methods are async.

Property / MethodTypeDescription
referencestrImage reference
size_bytesint | NoneTotal size in bytes, or None when unknown
manifest_digeststr | NoneContent-addressable manifest digest
architecturestr | NoneResolved architecture
osstr | NoneResolved operating system
layer_countintNumber of layers
last_used_atfloat | NoneLast referenced time, milliseconds since epoch
created_atfloat | NoneFirst-pulled time, milliseconds since epoch
await inspect()ImageDetailFetch full detail for this image
await remove(*, force=False)NoneDelete this image (raises ImageInUseError unless force)

ImageDetail

<p className="msb-backref">Returned by <a href="#image-inspect">inspect()</a> · <a href="#imagehandle">ImageHandle.inspect()</a></p>

Full detail for a cached image: the core handle, the parsed OCI config block, and per-layer metadata.

PropertyTypeDescription
handleImageHandleCore cached image metadata
configImageConfigDetail | NoneParsed OCI config block
layerslist[ImageLayerDetail]Layers in bottom-to-top order

ImageConfigDetail

<p className="msb-backref">Used by <a href="#imagedetail">ImageDetail.config</a></p>

OCI image config fields extracted from the local cache.

PropertyTypeDescription
digeststrConfig blob digest
envlist[str]Environment variables (KEY=value)
cmdlist[str] | NoneDefault command
entrypointlist[str] | NoneImage entrypoint
working_dirstr | NoneDefault working directory
userstr | NoneDefault user
labelsdict[str, Any] | NoneOCI labels
stop_signalstr | NoneConfigured stop signal

ImageLayerDetail

<p className="msb-backref">Used by <a href="#imagedetail">ImageDetail.layers</a></p>

Metadata for a single image layer.

PropertyTypeDescription
diff_idstrUncompressed layer diff id
blob_digeststrCompressed blob digest
media_typestr | NoneLayer media type
compressed_size_bytesint | NoneCompressed size in bytes
erofs_size_bytesint | NoneSize of the generated EROFS sidecar in bytes
positionintLayer position (bottom to top)

ImagePruneReport

<p className="msb-backref">Returned by <a href="#image-prune">prune()</a></p>

Summary of cached image data removed by Image.prune().

PropertyTypeDescription
image_refs_removedintNumber of image refs removed
manifests_removedintNumber of manifests removed
layers_removedintNumber of layer blobs removed
fsmeta_removedintNumber of fsmeta sidecar files removed
vmdk_removedintNumber of VMDK files removed
bytes_reclaimedint | NoneMeasured bytes reclaimed, or None when not measured

DiskImageFormat

<p className="msb-backref">Used by <a href="#imagesource">ImageSource._format</a></p>

Disk image container format. A StrEnum, so the string values are accepted directly.

ValueDescription
"qcow2"QEMU copy-on-write v2
"raw"Raw block image
"vmdk"VMware disk image

Errors

Image operations raise these typed exceptions, all subclasses of MicrosandboxError.

ExceptionRaised when
ImageNotFoundErrorThe image reference could not be resolved in the local cache
ImageInUseErrorThe image is still referenced by one or more sandboxes (and force was not set)
ImagePullFailedErrorAn image pull failed
UnsupportedErrorCache operations were attempted on a backend that lacks a local cache