nemo_gym.sandbox.providers.docker.provider

View as Markdown

Docker sandbox provider: one long-lived container per sandbox, driven via the docker CLI.

Module Contents

Classes

NameDescription
DockerCreateConfig-
DockerCreateErrorRaised when Docker cannot create a sandbox.
DockerCreateVerificationErrorRaised when a new container fails its readiness probe.
DockerExecConfig-
DockerProbeConfig-
DockerProviderSandbox provider backed by the local Docker CLI / daemon.
_DockerContainer-

Functions

NameDescription
_coerce_config-
_coerce_str_list-
_http_endpoint-
_is_missing_container-
_is_runtime_failure-
_normalize_image-
_parse_port_bindingParse one docker port binding such as 127.0.0.1:49153.
_publish_arg-
_redact_argvargv copy with --env KEY=VALUE values masked, so timeouts/logs don’t leak secrets.
_require_docker-
_resource_limit_flags-
_resource_passthrough_flags-
_to_sandbox_status-

Data

CONTAINER_NAME_PREFIX

DEFAULT_KEEPALIVE_CMD

DEFAULT_KEEPALIVE_SHELL

DOCKER_MISSING_CONTAINER_MARKERS

DOCKER_RUNTIME_ERROR_MARKERS

LOGGER

READY_PROBE_COMMAND

READY_PROBE_EXPECTED

SANDBOX_LABEL

SANDBOX_RUNTIME_RETURN_CODE

API

class nemo_gym.sandbox.providers.docker.provider.DockerCreateConfig(
keepalive_shell: str = DEFAULT_KEEPALIVE_SHELL,
keepalive_cmd: str = DEFAULT_KEEPALIVE_CMD,
start_timeout_s: float | None = 600,
use_init: bool = True,
network: str | None = None,
read_only: bool = False,
cap_drop: list[str] = list(),
security_opt: list[str] = list(),
pids_limit: int | None = None,
extra_run_args: list[str] = list(),
apply_resource_limits: bool = True,
publish_host: str = '127.0.0.1'
)
Dataclass
apply_resource_limits
bool = True
cap_drop
list[str] = field(default_factory=list)
extra_run_args
list[str] = field(default_factory=list)
keepalive_cmd
str = DEFAULT_KEEPALIVE_CMD
keepalive_shell
str = DEFAULT_KEEPALIVE_SHELL
network
str | None = None
pids_limit
int | None = None
publish_host
str = '127.0.0.1'
read_only
bool = False
security_opt
list[str] = field(default_factory=list)
start_timeout_s
float | None = 600
use_init
bool = True
nemo_gym.sandbox.providers.docker.provider.DockerCreateConfig.__post_init__() -> None
class nemo_gym.sandbox.providers.docker.provider.DockerCreateError()

Bases: SandboxCreateError

Raised when Docker cannot create a sandbox.

class nemo_gym.sandbox.providers.docker.provider.DockerCreateVerificationError()

Bases: SandboxCreateVerificationError

Raised when a new container fails its readiness probe.

class nemo_gym.sandbox.providers.docker.provider.DockerExecConfig(
default_timeout_s: float | None = 180,
extra_exec_args: list[str] = list(),
concurrency: int = 32,
exec_shell: str | None = None
)
Dataclass
concurrency
int = 32
default_timeout_s
float | None = 180
exec_shell
str | None = None
extra_exec_args
list[str] = field(default_factory=list)
nemo_gym.sandbox.providers.docker.provider.DockerExecConfig.__post_init__() -> None
class nemo_gym.sandbox.providers.docker.provider.DockerProbeConfig(
command: str | None = READY_PROBE_COMMAND,
expected_stdout: str | None = READY_PROBE_EXPECTED,
timeout_s: int = 30,
deadline_s: float | None = None,
stable_count: int = 1,
stable_delay_s: float = 0.0
)
Dataclass
command
str | None = READY_PROBE_COMMAND
deadline_s
float | None = None
expected_stdout
str | None = READY_PROBE_EXPECTED
stable_count
int = 1
stable_delay_s
float = 0.0
timeout_s
int = 30
nemo_gym.sandbox.providers.docker.provider.DockerProbeConfig.__post_init__() -> None
class nemo_gym.sandbox.providers.docker.provider.DockerProvider(
exec: nemo_gym.sandbox.providers.docker.provider.DockerExecConfig | collections.abc.Mapping[str, typing.Any] | None = None,
create: nemo_gym.sandbox.providers.docker.provider.DockerCreateConfig | collections.abc.Mapping[str, typing.Any] | None = None,
probe: nemo_gym.sandbox.providers.docker.provider.DockerProbeConfig | collections.abc.Mapping[str, typing.Any] | None = None
)

Sandbox provider backed by the local Docker CLI / daemon.

_binary
= _require_docker()
_create_config
= _coerce_config(create, DockerCreateConfig)
_exec_config
= _coerce_config(exec, DockerExecConfig)
_probe
= _coerce_config(probe, DockerProbeConfig)
_semaphore
= asyncio.Semaphore(self._exec_config.concurrency)
name
= 'docker'
nemo_gym.sandbox.providers.docker.provider.DockerProvider._cleanup_failed_create_handle(
) -> None
async
nemo_gym.sandbox.providers.docker.provider.DockerProvider._force_remove(
name: str
) -> None
async
nemo_gym.sandbox.providers.docker.provider.DockerProvider._resolve_shell(
name: str
) -> str
async

Configured exec shell, else bash when the image has it (for conda source), else sh.

nemo_gym.sandbox.providers.docker.provider.DockerProvider._run(
argv: list[str],
timeout_s: float | None,
stdin: bytes | None = None
) -> tuple[int, str, str]
async

Run a docker CLI command as (return_code, stdout, stderr); SIGKILL the group on timeout.

nemo_gym.sandbox.providers.docker.provider.DockerProvider._verify_created_handle(
) -> None
async

Poll the readiness probe until it passes stable_count times or the deadline elapses.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.aclose() -> None
async
nemo_gym.sandbox.providers.docker.provider.DockerProvider.close(
) -> None
async

Force-remove the container (already-gone counts as success).

nemo_gym.sandbox.providers.docker.provider.DockerProvider.connect(
descriptor: collections.abc.Mapping[str, typing.Any]
async

Create a handle for an existing running container, rediscovering its image and shell via the Docker CLI.

sandbox_id is required. AsyncSandbox.serialize() adds a top-level ports key from the original spec; read it back here so endpoint() still works after reconnecting.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.create(
async

Start a detached keep-alive container (image ENTRYPOINT overridden) and probe readiness.

spec.ttl_s bounds the lifetime (the keep-alive sleeps for it and --rm self-removes on exit). spec.provider_options may carry volumes (-> -v) and run_args (extra run flags). A half-created container is force-removed on any failure.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.download_file(
source_path: str,
target_path: pathlib.Path
) -> None
async

Download one container file to the host.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.endpoint(
port: int
async

Resolve a dynamically-published TCP port through the Docker daemon.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.exec(
command: str,
cwd: str | None = None,
env: dict[str, str] | None = None,
timeout_s: int | float | None = None,
user: str | int | None = None,
stdin: bytes | None = None
async

Run <shell> -c <command> via docker exec; never raises for command failure.

user maps to --user (root/0 -> 0). A timeout kills the local docker client only; the in-container process is reaped when the sandbox is closed.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.serialize_handle(
scope: str | None = None
) -> dict[str, typing.Any]
async

Return a descriptor for reattaching to this container by id.

Docker recovers image and shell from the running container on connect, and docker exec runs inside the container’s own environment, so the id alone is enough; AsyncSandbox.serialize() layers the declared ports on top. scope is unused by the Docker provider.

nemo_gym.sandbox.providers.docker.provider.DockerProvider.status(
async

Container status via docker inspect (missing -> STOPPED; error/timeout -> UNKNOWN).

nemo_gym.sandbox.providers.docker.provider.DockerProvider.upload_file(
source_path: pathlib.Path,
target_path: str
) -> None
async

Upload one host file (creates the parent dir; the file lands owned by root).

class nemo_gym.sandbox.providers.docker.provider._DockerContainer(
name: str,
image: str,
shell: str = 'sh',
env: dict[str, str] = dict(),
published_ports: tuple[int, ...] = ()
)
Dataclass
env
dict[str, str] = field(default_factory=dict)
image
str
name
str
published_ports
tuple[int, ...] = ()
shell
str = 'sh'
nemo_gym.sandbox.providers.docker.provider._coerce_config(
value: typing.Any,
config_cls: type[typing.Any]
) -> typing.Any
nemo_gym.sandbox.providers.docker.provider._coerce_str_list(
value: typing.Any,
what: str
) -> list[str]
nemo_gym.sandbox.providers.docker.provider._http_endpoint(
host: str,
port: int
) -> str
nemo_gym.sandbox.providers.docker.provider._is_missing_container(
stderr: str
) -> bool
nemo_gym.sandbox.providers.docker.provider._is_runtime_failure(
stderr: str
) -> bool
nemo_gym.sandbox.providers.docker.provider._normalize_image(
image: str
) -> str
nemo_gym.sandbox.providers.docker.provider._parse_port_binding(
binding: str
) -> tuple[str, int]

Parse one docker port binding such as 127.0.0.1:49153.

nemo_gym.sandbox.providers.docker.provider._publish_arg(
host: str,
port: int
) -> str
nemo_gym.sandbox.providers.docker.provider._redact_argv(
argv: list[str]
) -> list[str]

argv copy with --env KEY=VALUE values masked, so timeouts/logs don’t leak secrets.

nemo_gym.sandbox.providers.docker.provider._require_docker() -> str
nemo_gym.sandbox.providers.docker.provider._resource_limit_flags(
) -> list[str]
nemo_gym.sandbox.providers.docker.provider._resource_passthrough_flags(
) -> list[str]
nemo_gym.sandbox.providers.docker.provider._to_sandbox_status(
state: str | None
nemo_gym.sandbox.providers.docker.provider.CONTAINER_NAME_PREFIX = 'nemo-gym-'
nemo_gym.sandbox.providers.docker.provider.DEFAULT_KEEPALIVE_CMD = 'while :; do sleep 2147483647; done'
nemo_gym.sandbox.providers.docker.provider.DEFAULT_KEEPALIVE_SHELL = '/bin/sh'
nemo_gym.sandbox.providers.docker.provider.DOCKER_MISSING_CONTAINER_MARKERS = ('no such container', 'no such object')
nemo_gym.sandbox.providers.docker.provider.DOCKER_RUNTIME_ERROR_MARKERS = ('no such container', 'is not running', 'is not paused', 'cannot connect to the ...
nemo_gym.sandbox.providers.docker.provider.LOGGER = logging.getLogger(__name__)
nemo_gym.sandbox.providers.docker.provider.READY_PROBE_COMMAND = 'printf docker-sandbox-ready'
nemo_gym.sandbox.providers.docker.provider.READY_PROBE_EXPECTED = 'docker-sandbox-ready'
nemo_gym.sandbox.providers.docker.provider.SANDBOX_LABEL = 'nemo-gym.sandbox'
nemo_gym.sandbox.providers.docker.provider.SANDBOX_RUNTIME_RETURN_CODE = 125