Disk images
A disk image defines the root filesystem a sandbox boots from. Start from a prebuilt public image, build a custom image from OCI, or commit a running sandbox to a new image.
You can create or use disk images in three ways:
| Public image | Custom image | Committed image | |
|---|---|---|---|
| Source | Prebuilt and maintained by the platform. | Built by you from a remote OCI container image. | Built by you from a running sandbox's filesystem at commit time. |
| Best for | Getting started, or when a stock base OS or runtime is all you need. | Baking dependencies into an image you already publish to a registry. | Capturing setup that's easier to do interactively inside a sandbox than to script. |
| Referenced by | Name, via --disk. | ID, via --disk-id. | ID, via --disk-id. |
Discover public disk images
Reference public disk images by simple name when you create a sandbox. To discover available public disk images:
- In the ACA Sandboxes portal, open your sandbox group.
- Select Disk images in the left menu.
- Select the Public tab.
- Review the image names. These public images appear in the Public Disk Image dropdown when you create a sandbox.
- Bash
- PowerShell
- SDK
echo "==> Public disk images (valid --disk values):"
aca sandboxgroup disk list-public
Write-Host "==> Public disk images (valid --disk values):"
aca sandboxgroup disk list-public
import os
from azure.identity import DefaultAzureCredential
from azure.containerapps.sandbox import SandboxGroupClient, endpoint_for_region
credential = DefaultAzureCredential()
client = SandboxGroupClient(
endpoint_for_region(os.environ["ACA_SANDBOXGROUP_REGION"]),
credential,
subscription_id=os.environ["AZURE_SUBSCRIPTION_ID"],
resource_group=os.environ["ACA_RESOURCE_GROUP"],
sandbox_group=os.environ["ACA_SANDBOX_GROUP"],
)
for img in client.list_public_disk_images():
print(img.name)
Public images are provided as-is, and available versions can change without notice as new runtime versions become available.
| Name | Summary | Description |
|---|---|---|
ubuntu | General-purpose Linux sandbox | Ubuntu base with diagnostic tools, including htop, btop, dnsutils, and vim. Includes Buildah for in-sandbox Dockerfile builds, GitHub Copilot CLI, and GitHub CLI. Uses /bin/bash as the entrypoint. |
nginx | Ready-to-serve web server | NGINX 1.25 with the same diagnostic tools as the Ubuntu image. Runs NGINX in the foreground. |
copilot | Copilot CLI agent sandbox | Backs the GitHub Copilot preset. Uses systemd as PID 1 and includes GitHub Copilot CLI, GitHub CLI, Node.js 24, Python 3, and nodemon. A boot-time unit configures Git authentication. /AGENTS.md and skills are included. |
claude | Claude Code agent sandbox | Ubuntu toolchain with a pinned Claude Code CLI version. A startup script configures Git authentication and reads ANTHROPIC_API_KEY at runtime. |
azure-dev | Full Azure development environment | Systemd-based Ubuntu 26.04 environment with Azure CLI, Azure Developer CLI, Bicep, Azure Functions Core Tools, .NET 10, Node.js 24, Python and uv, Go, Java 17 and Maven, Docker, GitHub Copilot CLI, and Visual Studio Code CLI. |
python-3.12-code-interpreter | Sandboxed code execution | Exposes a Model Context Protocol (MCP) endpoint for running untrusted Python code in isolation. This image's entrypoint starts Jupyter and the combined REST/MCP server on port 6000. See Using Python Code Interpreter. |
python-3.11 to python-3.14 | Python runtimes (4) | Python runtime images for versions 3.11, 3.12, 3.13, and 3.14. |
node-22, node-24 | Node.js runtimes (2) | Node.js runtime images for versions 22 and 24. |
dotnet-8 to dotnet-10 | .NET runtimes (3) | .NET runtime images for versions 8, 9, and 10. |
php-8.3, php-8.4 | PHP-FPM runtimes (2) | PHP-FPM runtime images for versions 8.3 and 8.4. |
Build a disk image from a container image
Custom disk images are built from a remote OCI container image, so any dependencies baked into that image are available as soon as a sandbox boots. To build a custom disk image:
- In the ACA Sandboxes portal, open your sandbox group.
- Select Disk images.
- Select + Create.
- Optionally add identifying Labels for the image.
- Enter the Base Image URL. This remote OCI image is used to build your custom disk image. For example,
docker.io/library/alpine:3.19. - Configure authentication under Registry Authentication if the source registry is private. Choose No authentication, Username and token, or Managed identity.
- Select Create and wait for the image state to show Ready.
- Bash
- PowerShell
- SDK
DISK_NAME="alpine-build-example-$RANDOM"
echo "==> Building custom disk image '$DISK_NAME' from alpine:3.19..."
aca sandboxgroup disk create --image docker.io/library/alpine:3.19 --name "$DISK_NAME"
$DISK_NAME = "alpine-build-example-$(Get-Random)"
Write-Host "==> Building custom disk image '$DISK_NAME' from alpine:3.19..."
aca sandboxgroup disk create --image docker.io/library/alpine:3.19 --name $DISK_NAME
import uuid
BASE_IMAGE = "docker.io/library/alpine:3.19"
disk_name = f"alpine-build-{uuid.uuid4().hex[:8]}"
disk = client.begin_create_disk_image(
BASE_IMAGE,
name=disk_name,
polling_timeout=900,
).result()
print(disk.id, disk.status.state if disk.status else "?")
List and inspect private disk images
Disk images you create through a remote registry or by committing from a running sandbox are private and scoped to your sandbox group. To view private disk images:
- In the ACA Sandboxes portal, open your sandbox group.
- Select Disk images.
- Select the Private tab.
- Select a disk image row to open its details.
- Use filters or labels to find a specific image.
- Bash
- PowerShell
- SDK
echo "==> Listing your private disk images:"
aca sandboxgroup disk list
echo "==> Get details for the first private disk image:"
DISK_IMAGE_ID=$(aca sandboxgroup disk list -o json | jq -r '.[0].id')
aca sandboxgroup disk get --id "$DISK_IMAGE_ID"
Write-Host "==> Listing your private disk images:"
aca sandboxgroup disk list
Write-Host "==> Get details for the first private disk image:"
$DISK_IMAGE_ID = (aca sandboxgroup disk list -o json | ConvertFrom-Json)[0].id
aca sandboxgroup disk get --id $DISK_IMAGE_ID
for img in client.list_disk_images():
marker = " <-- just created" if img.id == disk.id else ""
print(f"{img.id} name={img.name or img.labels.get('name', '')}{marker}")
detail = client.get_disk_image(disk.id)
print(detail.status.state if detail.status else "?")
print(detail.image.base if detail.image else "?")
Boot a sandbox from a private disk image
Sandboxes booted from custom or committed images use the disk image ID (--disk-id), not a name.
- In the ACA Sandboxes portal, open your sandbox group.
- Select Disk images.
- Open the Private tab.
- Select + from the disk image row under the Actions column.
- Confirm CPU, memory, labels, and environment settings.
- Select Create.
- Bash
- PowerShell
- SDK
echo "==> Booting sandbox from disk-id $DISK_IMAGE_ID..."
aca sandbox create --disk-id "$DISK_IMAGE_ID"
Write-Host "==> Booting sandbox from disk-id $DISK_IMAGE_ID..."
aca sandbox create --disk-id $DISK_IMAGE_ID
sandbox = client.begin_create_sandbox(
disk_id=disk.id,
labels={"guide": "disks-a"},
).result()
result = sandbox.exec("cat /etc/alpine-release")
print(result.stdout.strip())
Commit a running sandbox
A sandbox is briefly paused while its filesystem is committed, then resumes after the disk image is created.
You can also create a disk image by committing the filesystem of a running sandbox. This captures runtime changes, such as package installs, downloads, and generated files, so any sandbox booted from the resulting image starts with that state already in place.
- In the ACA Sandboxes portal, open your sandbox group.
- Select Sandboxes.
- Select the running sandbox that you want to commit.
- In the upper-right corner, select the overflow menu (⋮).
- Select Commit Image from the dropdown.
- Select Commit to commit the sandbox to a new disk image.
- Bash
- PowerShell
- SDK
PRIMER_LABEL="disks-commit-primer-$RANDOM"
echo "==> Booting primer sandbox (default disk)..."
aca sandbox create --disk-id "$DISK_IMAGE_ID" --label name="$PRIMER_LABEL"
echo "==> Looking up primer sandbox ID by label..."
SANDBOX_ID=$(aca sandbox list -l name="$PRIMER_LABEL" -o json | jq -r '.[0].id')
echo "==> Priming: write /example.txt..."
aca sandbox exec --id "$SANDBOX_ID" -c "echo 'hello world!' >> /example.txt"
COMMITTED_DISK_NAME="committed-disk-image-$RANDOM"
echo "==> Committing primer sandbox to disk image '$COMMITTED_DISK_NAME'..."
COMMITTED_DISK_ID=$(aca sandbox commit --id "$SANDBOX_ID" --name "$COMMITTED_DISK_NAME" -o json | jq -r '.diskImage.id')
echo "==> Committed disk image id: $COMMITTED_DISK_ID"
$PRIMER_LABEL = "disks-commit-primer-$(Get-Random)"
Write-Host "==> Booting primer sandbox (default disk)..."
aca sandbox create --disk-id $DISK_IMAGE_ID --label name=$PRIMER_LABEL
Write-Host "==> Looking up primer sandbox ID by label..."
$SANDBOX_ID = (aca sandbox list -l "name=$PRIMER_LABEL" -o json | ConvertFrom-Json)[0].id
Write-Host "==> Priming: write /example.txt..."
aca sandbox exec --id $SANDBOX_ID -c "echo 'hello world!' >> /example.txt"
$COMMITTED_DISK_NAME = "committed-disk-image-$(Get-Random)"
Write-Host "==> Committing primer sandbox to disk image '$COMMITTED_DISK_NAME'..."
$COMMITTED_DISK_ID = (aca sandbox commit --id $SANDBOX_ID --name $COMMITTED_DISK_NAME -o json | ConvertFrom-Json).diskImage.id
Write-Host "==> Committed disk image id: $COMMITTED_DISK_ID"
import uuid
primer = client.begin_create_sandbox().result()
primer.exec("echo 'hello world!' >> /example.txt")
disk_name = f"committed-disk-image-{uuid.uuid4().hex[:8]}"
disk = primer.begin_commit(name=disk_name, polling_timeout=1200).result()
print(disk.id, disk.status.state if disk.status else "?")
Using Python Code Interpreter
When you create a sandbox from the code interpreter image, the MCP server runs automatically. The image's entrypoint starts Jupyter and the combined REST/MCP server on port 6000, so you don't need to install or start an MCP server yourself.
First, create the sandbox with a strong token:
$token = [Convert]::ToBase64String(
[Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
)
aca sandbox create `
--group "<sandbox_group_name>" `
--disk "python-3.12-code-interpreter" `
--env MCP_AUTH_TOKEN=$token `
--region "<Azure_region_name>" `
-g "<resource_group_name>"
Then expose port 6000:
$base = (aca sandbox port add `
--id "<SANDBOX_ID>" `
--port 6000 `
--anonymous `
--group "<sandbox_group_name>" `
--region "<Azure_region_name>" `
-g "<resource_group_name>" `
-o json | ConvertFrom-Json).url
The interpreter itself remains protected by Authorization: Bearer <MCP_AUTH_TOKEN>.
Next, test Python through the REST interface:
Invoke-RestMethod "$base/executions?identifier=test-1" `
-Method Post `
-Headers @{ Authorization = "Bearer $token" } `
-ContentType "application/json" `
-Body (@{
code = 'import sys; print("Python works"); print(sys.version)'
timeoutInSeconds = 30
executionType = "synchronous"
} | ConvertTo-Json)
Finally, connect an MCP client using the URL stored in $base, with the /mcp path and bearer header. Replace <PORT_URL> with the value of $base:
{
"servers": {
"sandbox-code-interpreter": {
"type": "http",
"url": "<PORT_URL>/mcp",
"headers": {
"Authorization": "Bearer <MCP_AUTH_TOKEN>"
}
}
}
}
The relevant article:
- Python image API specification documents port 6000,
/executions,/files, async execution, and/mnt/data.
Delete a disk image
A disk image can only be deleted after all dependent sandboxes and child (committed) disk images are deleted.
- In the ACA Sandboxes portal, open your sandbox group.
- Select Disk images.
- Select the Private tab.
- Locate the row for the disk image you want to delete, and select the bin under the Actions column.
- Confirm the deletion.
- Bash
- PowerShell
- SDK
echo "==> Deleting the source sandbox..."
aca sandbox delete --id "$SANDBOX_ID" --yes
echo "==> Deleting the committed (child) disk image first..."
aca sandboxgroup disk delete --id "$COMMITTED_DISK_ID"
echo "==> Deleting the base disk image..."
aca sandboxgroup disk delete --id "$DISK_IMAGE_ID"
Write-Host "==> Deleting the source sandbox..."
aca sandbox delete --id $SANDBOX_ID --yes
Write-Host "==> Deleting the committed (child) disk image first..."
aca sandboxgroup disk delete --id $COMMITTED_DISK_ID
Write-Host "==> Deleting the base disk image..."
aca sandboxgroup disk delete --id $DISK_IMAGE_ID
sandbox.delete()
client.delete_disk_image(disk.id)