Source code for ray.experimental.sandbox

from typing import Dict, List, Optional, Union

from ray.actor import ActorHandle
from ray.experimental.sandbox.backend.base import (
    BaseSandboxBackend,
    ExecResult,
    ExecutionResult,
    SandboxStatus,
)
from ray.experimental.sandbox.backend.checkpoint_utils import (
    CheckpointPath,
    load_checkpoint_manifest,
)
from ray.experimental.sandbox.backend.gvisor import GVisorSandboxBackend
from ray.experimental.sandbox.config import (
    ALLOW_ALL_CIDRS,
    DEFAULT_PUBLIC_ALLOWLIST,
    DEFAULT_PUBLIC_DNS,
    DOCKER_DEFAULT_CAPABILITIES,
    parse_memory_bytes,
)
from ray.experimental.sandbox.exceptions import (
    SandboxCreationError,
    SandboxError,
    SandboxExecError,
    SandboxNotFoundError,
    SandboxTimeoutError,
)
from ray.experimental.sandbox.image_manager import (
    BaseImageManager,
    ImageManager,
    get_default_oci_spec,
)
from ray.experimental.sandbox.runtime import SandboxRuntime
from ray.experimental.sandbox.sandbox import Sandbox
from ray.util.annotations import PublicAPI
from ray.util.scheduling_strategies import NodeAffinitySchedulingStrategy


[docs] @PublicAPI(stability="alpha") def create( image: str, cpu: Optional[float] = None, memory: Optional[Union[str, int, float]] = None, env: Optional[Dict[str, str]] = None, workdir: Optional[str] = None, ttl_seconds: Optional[int] = None, timeout_seconds: float = 30.0, rootless: bool = True, network: str = "none", dns: Optional[List[str]] = None, cidr_allowlist: Optional[List[str]] = None, capabilities: Optional[List[str]] = None, resources: Optional[Dict[str, float]] = None, readonly: bool = True, disk: Union[str, int, float] = 0, **kwargs, ) -> ActorHandle: """Create a remote sandbox environment managed by a Ray actor. Spawns a :class:`~ray.experimental.sandbox.Sandbox` actor on the Ray cluster to manage the sandbox lifecycle and returns an :class:`~ray.actor.ActorHandle`. For low-level local sandbox management on the current node (e.g., inside custom worker actors), use :class:`~ray.experimental.sandbox.runtime.SandboxRuntime` instead. Args: image: Container image for the sandbox environment. cpu: Number of CPU cores allocated to the sandbox. memory: Amount of memory allocated to the sandbox (e.g. "1Gi", "512Mi"). env: Environment variables to inject into the sandbox. workdir: Working directory for commands; None uses the image's WORKDIR. On a readonly rootfs an explicit workdir is also the sandbox's only writable path; see :class:`~ray.experimental.sandbox.config.SandboxConfig`. ttl_seconds: Optional time-to-live in seconds, wall-clock from creation (not idle time). None (default) or <= 0 disables it. timeout_seconds: Timeout in seconds for sandbox creation. rootless: If True, run gVisor in rootless mode. network: Network mode ("none", "public", "host", "sandbox"); see :class:`~ray.experimental.sandbox.config.SandboxConfig`. "public" is the recommended internet-access mode. dns: Optional nameserver IPs for the generated /etc/resolv.conf (public resolvers by default for "public"). cidr_allowlist: Optional egress allowlist for network="public": only the listed destinations are reachable (plus DNS to the ``dns`` resolvers). None means the public internet, with internal addresses left out as a best effort, and a denylist keeps instance metadata and the Kubernetes API service closed whatever the list says; see :class:`~ray.experimental.sandbox.config.SandboxConfig`. capabilities: Linux capabilities, written exactly (None keeps the runtime default; ``[]`` means none). Use ``DOCKER_DEFAULT_CAPABILITIES`` for Docker parity. resources: Custom logical resource requirements. readonly: If True (default), mount container image rootfs in read-only mode such that only ``workdir`` is writable. If False, the entire root filesystem is writable. Writes are isolated within a per-sandbox copy-on-write overlay filesystem, ensuring multiple sandboxes running the same container image do not interfere with each other or modify the base image. disk: Size cap of the writable rootfs (e.g. "10Gi"); writes past it fail with ENOSPC. Zero (default) means no cap. Requires ``readonly=False`` or a ``workdir``; see :class:`~ray.experimental.sandbox.config.SandboxConfig`. **kwargs: Additional options. Returns: A Sandbox actor handle. """ actor_opts = {} # Separate Ray actor options from Sandbox container configuration from ray._common.ray_option_utils import actor_options as _RAY_ACTOR_OPTIONS_SCHEMA for key in list(kwargs.keys()): if key in _RAY_ACTOR_OPTIONS_SCHEMA: actor_opts[key] = kwargs.pop(key) # Ray actors default to num_cpu=1 if not set if cpu is not None and cpu >= 0: actor_opts["num_cpus"] = cpu if memory is not None: parsed_mem = parse_memory_bytes(memory) if parsed_mem is not None and parsed_mem > 0: actor_opts["memory"] = parsed_mem if resources: actor_opts["resources"] = resources return Sandbox.options(**actor_opts).remote( image=image, cpu=cpu, memory=memory, env=env, workdir=workdir, ttl_seconds=ttl_seconds, timeout_seconds=timeout_seconds, rootless=rootless, network=network, dns=dns, cidr_allowlist=cidr_allowlist, capabilities=capabilities, readonly=readonly, disk=disk, **kwargs, )
[docs] @PublicAPI(stability="alpha") def restore( checkpoint_path: Union[str, CheckpointPath], cpu: Optional[float] = None, memory: Optional[Union[str, int, float]] = None, ttl_seconds: Optional[int] = None, timeout_seconds: float = 30.0, resources: Optional[Dict[str, float]] = None, **kwargs, ) -> ActorHandle: """Restore a remote sandbox environment from a checkpoint managed by a Ray actor. The restored sandbox preserves the full execution state, network mode, mounts, Linux capabilities, and process environment of the checkpointed sandbox. Cgroup resource allocations (cpu, memory) and lifecycle limits (ttl_seconds, timeout_seconds) can optionally be overridden. A checkpoint lives on the node that took it, so the restored actor is scheduled there, with the checkpointed sandbox's CPU and memory unless overridden. Args: checkpoint_path: Path to the checkpoint bundle directory, or a :class:`~ray.experimental.sandbox.backend.checkpoint_utils.CheckpointPath` instance returned by ``Sandbox.checkpoint()`` or ``SandboxRuntime.checkpoint()``. cpu: Optional CPU allocation override. memory: Optional memory allocation override. ttl_seconds: Optional time-to-live in seconds. timeout_seconds: Timeout in seconds for restore. resources: Custom logical resource requirements for the Ray actor. **kwargs: Additional options. Returns: A Sandbox actor handle. """ recorded_cpu = None recorded_memory = None target_node_id = None if isinstance(checkpoint_path, CheckpointPath): recorded_cpu = checkpoint_path.cpu recorded_memory = checkpoint_path.memory target_node_id = checkpoint_path.node_id else: # A plain path must be readable here to find the node and resources. manifest, _ = load_checkpoint_manifest(str(checkpoint_path)) recorded_config = manifest.get("config", {}) recorded_cpu = recorded_config.get("cpu") recorded_memory = recorded_config.get("memory") target_node_id = manifest.get("node_id") effective_cpu = cpu if cpu is not None else recorded_cpu effective_memory = memory if memory is not None else recorded_memory actor_opts = {} from ray._common.ray_option_utils import actor_options as _RAY_ACTOR_OPTIONS_SCHEMA for key in list(kwargs.keys()): if key in _RAY_ACTOR_OPTIONS_SCHEMA: actor_opts[key] = kwargs.pop(key) if effective_cpu is not None and effective_cpu >= 0: actor_opts["num_cpus"] = effective_cpu if effective_memory is not None: parsed_mem = parse_memory_bytes(effective_memory) if parsed_mem is not None and parsed_mem > 0: actor_opts["memory"] = parsed_mem if resources: actor_opts["resources"] = resources if target_node_id and "scheduling_strategy" not in actor_opts: try: actor_opts["scheduling_strategy"] = NodeAffinitySchedulingStrategy( node_id=target_node_id, soft=False, ) except (ValueError, TypeError): # A checkpoint taken outside Ray records a hostname, which can't # pin the actor; the backend still rejects a restore elsewhere. pass return Sandbox.options(**actor_opts).remote( restore_from=checkpoint_path, cpu=cpu, memory=memory, ttl_seconds=ttl_seconds, timeout_seconds=timeout_seconds, **kwargs, )
__all__ = [ "create", "ALLOW_ALL_CIDRS", "DEFAULT_PUBLIC_ALLOWLIST", "restore", "CheckpointPath", "DEFAULT_PUBLIC_DNS", "DOCKER_DEFAULT_CAPABILITIES", "Sandbox", "SandboxRuntime", "BaseImageManager", "ImageManager", "get_default_oci_spec", "BaseSandboxBackend", "GVisorSandboxBackend", "ExecResult", "ExecutionResult", "SandboxStatus", "SandboxError", "SandboxCreationError", "SandboxTimeoutError", "SandboxExecError", "SandboxNotFoundError", ]