> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.nvidia.com/nemo/gym/main/nemo-gym/nemo_gym/sandbox/providers/docker/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/gym/_mcp/server. # nemo_gym.sandbox.providers.docker Docker provider package. ## Submodules * **[`nemo_gym.sandbox.providers.docker.provider`](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers/docker/provider)** * **[`nemo_gym.sandbox.providers.docker.pty`](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers/docker/pty)** ## Package Contents ### Classes | Name | Description | | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | | [`DockerCreateConfig`](#nemo_gym-sandbox-providers-docker-provider-DockerCreateConfig) | - | | [`DockerCreateError`](#nemo_gym-sandbox-providers-docker-provider-DockerCreateError) | Raised when Docker cannot create a sandbox. | | [`DockerCreateVerificationError`](#nemo_gym-sandbox-providers-docker-provider-DockerCreateVerificationError) | Raised when a new container fails its readiness probe. | | [`DockerExecConfig`](#nemo_gym-sandbox-providers-docker-provider-DockerExecConfig) | - | | [`DockerProbeConfig`](#nemo_gym-sandbox-providers-docker-provider-DockerProbeConfig) | - | | [`DockerProvider`](#nemo_gym-sandbox-providers-docker-provider-DockerProvider) | Sandbox provider backed by the local Docker CLI / daemon. | ### API ```python class nemo_gym.sandbox.providers.docker.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', transport_retries: int = 2, transport_retry_delay_s: float = 1.0 ) ``` 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` --- **`transport_retries`** `int = 2` --- **`transport_retry_delay_s`** `float = 1.0` --- **`use_init`** `bool = True` --- ```python nemo_gym.sandbox.providers.docker.DockerCreateConfig.__post_init__() -> None ``` ```python class nemo_gym.sandbox.providers.docker.DockerCreateError() ``` **Bases:** [SandboxCreateError](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers/base#nemo_gym-sandbox-providers-base-SandboxCreateError) Raised when Docker cannot create a sandbox. ```python class nemo_gym.sandbox.providers.docker.DockerCreateVerificationError() ``` **Bases:** [SandboxCreateVerificationError](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers/base#nemo_gym-sandbox-providers-base-SandboxCreateVerificationError) Raised when a new container fails its readiness probe. ```python class nemo_gym.sandbox.providers.docker.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)` --- ```python nemo_gym.sandbox.providers.docker.DockerExecConfig.__post_init__() -> None ``` ```python class nemo_gym.sandbox.providers.docker.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` --- ```python nemo_gym.sandbox.providers.docker.DockerProbeConfig.__post_init__() -> None ``` ```python class nemo_gym.sandbox.providers.docker.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. **`SERVICE_OPTION_FIELDS`** --- **`_binary`** `= _require_docker()` --- **`_create_config`** `= _coerce_config(create, DockerCreateConfig)` --- **`_exec_config`** `= _coerce_config(exec, DockerExecConfig)` --- **`_probe`** `= _coerce_config(probe, DockerProbeConfig)` --- **`_pty_sessions`** `dict[str, set[DockerPtySession]] = {}` --- **`_semaphore`** `= asyncio.Semaphore(self._exec_config.concurrency)` --- **`_spawn_pty`** `= staticmethod(docker_pty.spawn)` --- **`name`** `= 'docker'` --- ```python nemo_gym.sandbox.providers.docker.DockerProvider._cleanup_failed_create_handle( handle: nemo_gym.sandbox.providers.base.SandboxHandle ) -> None ``` async ```python nemo_gym.sandbox.providers.docker.DockerProvider._force_remove( name: str ) -> None ``` async ```python nemo_gym.sandbox.providers.docker.DockerProvider._inspect_owned_container( name: str, image: str ) -> str | None ``` async Return state for an exact owned container, `None` when it cannot be resolved. ```python nemo_gym.sandbox.providers.docker.DockerProvider._pty_argv( handle: nemo_gym.sandbox.providers.base.SandboxHandle, spec: nemo_gym.sandbox.providers.base.SandboxPtySpec, session_id: str ) -> list[str] ``` The `docker exec` command line of one PTY session: interactive, with a terminal in PTY mode. The session's marker (`NEMO_GYM_PTY_SESSION=`) goes last among the `--env` flags so no spec env can override it: it is how the recorded pid is known to be this session's process. ```python nemo_gym.sandbox.providers.docker.DockerProvider._reconcile_created_container( name: str, image: str ) -> bool ``` async Recover the exact Sandbox-owned container after an ambiguous `docker run`. ```python nemo_gym.sandbox.providers.docker.DockerProvider._release_pty_session( session: nemo_gym.sandbox.providers.base.SandboxPtySession, name: str, abandon: bool ) -> None ``` async One session of `_release_pty_sessions`; a failure is logged, never raised into the caller. ```python nemo_gym.sandbox.providers.docker.DockerProvider._release_pty_sessions( name: str, abandon: bool ) -> None ``` async Close (or, when the container goes away, abandon) the live sessions of container `name`. ```python nemo_gym.sandbox.providers.docker.DockerProvider._resolve_shell( name: str ) -> str ``` async Configured exec shell, else bash when the image has it (for conda `source`), else sh. ```python nemo_gym.sandbox.providers.docker.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. ```python nemo_gym.sandbox.providers.docker.DockerProvider._run_create_with_reconciliation( argv: list[str], name: str, image: str ) -> None ``` async Run `docker run` without leaking a container when its response is lost. A fixed, random name makes retry idempotent. After a timeout, transport error, or same-name conflict, inspect that exact name before retrying. Reuse it only when both the Sandbox ownership label and requested image match; never remove an unrelated collision. ```python nemo_gym.sandbox.providers.docker.DockerProvider._start_reconciled_container( name: str, image: str ) -> bool ``` async Finish a `docker run` that created its container but lost the start response. ```python nemo_gym.sandbox.providers.docker.DockerProvider._verify_created_handle( handle: nemo_gym.sandbox.providers.base.SandboxHandle ) -> None ``` async Poll the readiness probe until it passes `stable_count` times or the deadline elapses. ```python nemo_gym.sandbox.providers.docker.DockerProvider.aclose() -> None ``` async Close the PTY sessions still open; the containers themselves belong to their handles. ```python nemo_gym.sandbox.providers.docker.DockerProvider.close( handle: nemo_gym.sandbox.providers.base.SandboxHandle ) -> None ``` async Force-remove the container (already-gone counts as success); its PTY clients are released first. ```python nemo_gym.sandbox.providers.docker.DockerProvider.connect( descriptor: collections.abc.Mapping[str, typing.Any] ) -> nemo_gym.sandbox.providers.base.SandboxHandle ``` 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. ```python nemo_gym.sandbox.providers.docker.DockerProvider.create( spec: nemo_gym.sandbox.providers.base.SandboxSpec ) -> nemo_gym.sandbox.providers.base.SandboxHandle ``` 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. ```python nemo_gym.sandbox.providers.docker.DockerProvider.create_pty( handle: nemo_gym.sandbox.providers.base.SandboxHandle, spec: nemo_gym.sandbox.providers.base.SandboxPtySpec ) -> nemo_gym.sandbox.providers.base.SandboxPtySession ``` async Open an interactive terminal in the container: one `docker exec -it` client under a host pty. `cwd`, `env` and `user` map to the exec flags, `rows`/`cols` size the terminal before the client starts, `pty=False` runs the client on pipes. The client process is not counted against `exec.concurrency`: it lives as long as the session. The session's pid is recorded under `/tmp` in the container (under `/dev/shm` when `/tmp` refuses the write, as under `create.read_only: true`; a session that can record it nowhere ends at once with a message instead of running unsignallable), read as the session's own user and signalled as root (no `CAP_SYS_PTRACE` needed). This returns as soon as the client is spawned: `send_signal()`/`close()` wait up to two seconds for the record when they come first, refuse at once a record that is not a regular file, and read it under a timeout of their own (`PID_READ_TIMEOUT_S`) rather than `exec.default_timeout_s`. A client that exits without having started the program (the daemon refused the exec: the container paused or gone, the daemon unreachable, told by the client's stderr as `exec()` tells a runtime failure) ends the session with `SandboxPtyError` from `wait_exit()` and `read()` rather than as the program's exit; a container closed while the session was being opened has it abandoned and `SandboxPtyError` raised here. See `nemo_gym.sandbox.providers.docker.pty`. ```python nemo_gym.sandbox.providers.docker.DockerProvider.download_file( handle: nemo_gym.sandbox.providers.base.SandboxHandle, source_path: str, target_path: pathlib.Path ) -> None ``` async Download one container file to the host. ```python nemo_gym.sandbox.providers.docker.DockerProvider.endpoint( handle: nemo_gym.sandbox.providers.base.SandboxHandle, port: int ) -> nemo_gym.sandbox.providers.base.SandboxEndpoint ``` async Resolve a dynamically-published TCP port through the Docker daemon. ```python nemo_gym.sandbox.providers.docker.DockerProvider.exec( handle: nemo_gym.sandbox.providers.base.SandboxHandle, 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 ) -> nemo_gym.sandbox.providers.base.SandboxExecResult ``` async Run ` -c ` 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. ```python nemo_gym.sandbox.providers.docker.DockerProvider.pull_policy_options( policy: str ) -> dict[str, typing.Any] ``` Compose's `pull_policy` as `docker run --pull`; only `always`, `missing` and `never` exist. ```python nemo_gym.sandbox.providers.docker.DockerProvider.serialize_handle( handle: nemo_gym.sandbox.providers.base.SandboxHandle, 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. ```python nemo_gym.sandbox.providers.docker.DockerProvider.service_options( tmpfs: tuple[str, ...] = (), ulimits: collections.abc.Mapping[str, typing.Any] | None = None, sysctls: collections.abc.Mapping[str, str] | None = None, security_opt: tuple[str, ...] = () ) -> dict[str, typing.Any] ``` Compose service options as `run_args`: `--tmpfs`, `--ulimit`, `--sysctl`, `--security-opt`. ```python nemo_gym.sandbox.providers.docker.DockerProvider.status( handle: nemo_gym.sandbox.providers.base.SandboxHandle ) -> nemo_gym.sandbox.providers.base.SandboxStatus ``` async Container status via `docker inspect` (missing -> STOPPED; error/timeout -> UNKNOWN). ```python nemo_gym.sandbox.providers.docker.DockerProvider.upload_file( handle: nemo_gym.sandbox.providers.base.SandboxHandle, source_path: pathlib.Path, target_path: str ) -> None ``` async Upload one host file (creates the parent dir; the file lands owned by root). ## Docs - [nemo_gym.sandbox.providers.docker.provider](https://docs.nvidia.com/nemo/gym/main/nemo-gym/nemo_gym/sandbox/providers/docker/provider.md) - [nemo_gym.sandbox.providers.docker.pty](https://docs.nvidia.com/nemo/gym/main/nemo-gym/nemo_gym/sandbox/providers/docker/pty.md)