How to Implement a Custom Runtime for OpenSandbox: A 5-Step Technical Guide
To implement a custom runtime for OpenSandbox, extend the RuntimeConfig type enumeration, create a concrete class inheriting from SandboxService, implement the required lifecycle methods (create_sandbox, delete_sandbox, pause_sandbox, resume_sandbox), and register the runtime-to-class mapping in the service factory.
OpenSandbox is an open-source sandbox platform developed by Alibaba that abstracts container runtimes behind a unified API. When you need to integrate a proprietary orchestrator or an unsupported container engine, you must implement a custom runtime for OpenSandbox to handle sandbox lifecycle operations according to the SandboxService contract. This guide walks through the exact source code locations and implementation patterns required to extend the pluggable runtime layer without modifying client SDKs.
Step 1: Extend the Runtime Configuration in config.py
The server determines which runtime to instantiate based on the type field in RuntimeConfig. To add a new runtime option, modify the Literal type definition in server/src/config.py.
Locate the RuntimeConfig class (lines 307-321) and add your runtime identifier to the type field:
# server/src/config.py
from typing import Literal
from pydantic import BaseModel, Field
class RuntimeConfig(BaseModel):
"""Runtime selection (docker, kubernetes, etc.)."""
type: Literal["docker", "kubernetes", "mycustom"] = Field(
...,
description="Active sandbox runtime implementation."
)
execd_image: str = Field(
...,
description="Container image that contains the execd binary for sandbox initialization.",
)
If your runtime supports secure sandboxing, also update SecureRuntimeConfig (lines 321-330) to include the new type in its Literal definition.
Step 2: Implement the SandboxService Interface
Create a new file in server/src/services/ (for example, mycustom.py) that inherits from the abstract SandboxService base class defined in server/src/services/sandbox_service.py. This class acts as the runtime contract that OpenSandbox uses to manage sandbox lifecycles.
Required Lifecycle Methods
Your concrete implementation must override these abstract methods:
create_sandbox– Provision the sandbox in your platform, inject theexecddaemon, and return aSandboxStatusobjectdelete_sandbox– Clean up resources and terminate the sandboxpause_sandbox– Suspend execution (optional depending on platform capabilities)resume_sandbox– Resume execution from paused state
# server/src/services/mycustom.py
from src.services.sandbox_service import SandboxService
from src.models import CreateSandboxRequest, SandboxStatus
class MyCustomRuntimeService(SandboxService):
"""Concrete runtime that talks to MyCustom orchestrator."""
async def create_sandbox(self, req: CreateSandboxRequest) -> SandboxStatus:
# 1. Provision the sandbox in MyCustom platform
sandbox_id = await mycustom_client.create_sandbox(
image=req.image.uri,
entrypoint=req.entrypoint,
resources=req.resourceLimits,
)
# 2. Inject execd binary (same process as Docker/K8s)
await mycustom_client.inject_execd(sandbox_id, req.execd_image)
# 3. Return initial status
return SandboxStatus(
id=sandbox_id,
state="Pending",
reason="Provisioning",
message="Sandbox is being prepared."
)
async def delete_sandbox(self, sandbox_id: str) -> None:
await mycustom_client.delete_sandbox(sandbox_id)
async def pause_sandbox(self, sandbox_id: str) -> None:
await mycustom_client.pause_sandbox(sandbox_id)
async def resume_sandbox(self, sandbox_id: str) -> None:
await mycustom_client.resume_sandbox(sandbox_id)
Execd Injection Requirement
The execd daemon is mandatory for OpenSandbox's command execution protocol. Your create_sandbox implementation must inject the execd binary (specified by req.execd_image) into the sandbox environment, mirroring the approach used in the reference Docker and Kubernetes implementations.
Step 3: Register Your Runtime in the Service Factory
OpenSandbox uses a factory pattern to instantiate the correct runtime service. Add your runtime-to-class mapping in server/src/services/factory.py within the SERVICE_MAP dictionary (lines 55-62):
# server/src/services/factory.py
from src.services.mycustom import MyCustomRuntimeService
from src.services.docker import DockerSandboxService
from src.services.k8s.kubernetes_service import KubernetesSandboxService
SERVICE_MAP: dict[str, type[SandboxService]] = {
"docker": DockerSandboxService,
"kubernetes": KubernetesSandboxService,
# Register the new runtime here
"mycustom": MyCustomRuntimeService,
}
When the server configuration specifies runtime.type: mycustom, the factory instantiates MyCustomRuntimeService to handle all sandbox operations.
Step 4: Configure Secure Runtime Mappings (Optional)
If your custom runtime requires a specific OCI runtime (for Docker) or Kubernetes RuntimeClass, extend the SecureRuntimeResolver in server/src/services/runtime_resolver.py. This resolver translates high-level secure runtime names into backend-specific flags.
Update the default mapping tables to include your runtime:
# server/src/services/runtime_resolver.py
class SecureRuntimeResolver:
DEFAULT_DOCKER_RUNTIMES = {
"gvisor": "runsc",
"kata": "kata-runtime",
# Add custom mapping
"mysecure": "mycustom-runtime",
}
DEFAULT_K8S_RUNTIME_CLASSES = {
"gvisor": "gvisor",
"kata": "kata-qemu",
"firecracker": "kata-fc",
# Custom class example
"mysecure": "mycustom-runtimeclass",
}
Step 5: Document and Test Your Implementation
Update the architecture documentation at docs/architecture.md in the Custom Runtime section to describe your runtime's specific behaviors and requirements. Write integration tests under tests/python/ that verify:
- Sandbox creation returns correct
SandboxStatus - Lifecycle transitions (pause/resume) propagate correctly
- Resource cleanup occurs on
delete_sandbox - Execd injection succeeds and the daemon responds to the OpenAPI spec (
specs/execd-api.yaml)
How the Pluggable Runtime Architecture Works
OpenSandbox follows a protocol-first, plug-in-first design that decouples the API layer from runtime implementations. The server only recognizes an abstract runtime type string and delegates all concrete operations to the registered SandboxService implementation.
This architecture relies on three core contracts:
- OpenAPI Specifications (
specs/execd-api.yaml,specs/sandbox-lifecycle.yml) define the external interaction protocols - SandboxService Interface (
server/src/services/sandbox_service.py) establishes the internal contract for lifecycle operations - Service Factory (
server/src/services/factory.py) provides runtime selection without code changes to the API server or client SDKs
Because client libraries in sdks/sandbox/python communicate through the REST API and lifecycle events, they automatically support any registered runtime without modification.
Summary
- Extend
RuntimeConfiginserver/src/config.pyto add your runtime type to the allowed Literal values - Implement
SandboxServicein a new file underserver/src/services/, ensuring you handle execd injection and the four required lifecycle methods - Register the mapping in
server/src/services/factory.pyto link the configuration type string to your concrete class - Configure secure runtimes in
server/src/services/runtime_resolver.pyif using custom OCI runtimes or Kubernetes RuntimeClasses - Reference existing implementations in
server/src/services/docker.pyandserver/src/services/k8s/kubernetes_service.pyfor patterns on execd injection and resource management
Frequently Asked Questions
What methods must I implement in SandboxService?
You must implement create_sandbox, delete_sandbox, pause_sandbox, and resume_sandbox. The create_sandbox method must provision resources in your platform, inject the execd daemon using the provided execd_image, and return a SandboxStatus object tracking the sandbox state. These methods are defined as abstract in server/src/services/sandbox_service.py.
Do client SDKs require updates for new runtimes?
No. Client SDKs in sdks/sandbox/python communicate through the OpenSandbox REST API and do not interact directly with runtime implementations. Once you register your runtime in the factory and configure the server to use it via runtime.type, existing SDKs automatically work with your custom runtime without code changes.
How does the execd daemon injection work in custom runtimes?
Your create_sandbox implementation must pull the container image specified by req.execd_image and inject the binary into the sandbox environment. This typically involves copying the execd binary into a shared volume or sidecar container, then starting the daemon process. Refer to the Docker and Kubernetes implementations in server/src/services/docker.py for specific injection patterns using the execd_image configuration field.
Where can I find reference implementations?
Study server/src/services/docker.py for container-based runtimes and server/src/services/k8s/kubernetes_service.py for orchestrator-based implementations. Both demonstrate how to handle the CreateSandboxRequest model, manage resource limits, and report state transitions through the Lifecycle API defined in specs/sandbox-lifecycle.yml.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →