> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/gym/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.provider

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

## Module 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. |
| [`_DockerContainer`](#nemo_gym-sandbox-providers-docker-provider-_DockerContainer)                           | -                                                         |

### Functions

| Name                                                                                                     | Description                                                                          |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| [`_coerce_config`](#nemo_gym-sandbox-providers-docker-provider-_coerce_config)                           | -                                                                                    |
| [`_coerce_str_list`](#nemo_gym-sandbox-providers-docker-provider-_coerce_str_list)                       | -                                                                                    |
| [`_http_endpoint`](#nemo_gym-sandbox-providers-docker-provider-_http_endpoint)                           | -                                                                                    |
| [`_is_missing_container`](#nemo_gym-sandbox-providers-docker-provider-_is_missing_container)             | -                                                                                    |
| [`_is_runtime_failure`](#nemo_gym-sandbox-providers-docker-provider-_is_runtime_failure)                 | -                                                                                    |
| [`_normalize_image`](#nemo_gym-sandbox-providers-docker-provider-_normalize_image)                       | -                                                                                    |
| [`_parse_port_binding`](#nemo_gym-sandbox-providers-docker-provider-_parse_port_binding)                 | Parse one `docker port` binding such as `127.0.0.1:49153`.                           |
| [`_publish_arg`](#nemo_gym-sandbox-providers-docker-provider-_publish_arg)                               | -                                                                                    |
| [`_redact_argv`](#nemo_gym-sandbox-providers-docker-provider-_redact_argv)                               | argv copy with `--env KEY=VALUE` values masked, so timeouts/logs don't leak secrets. |
| [`_require_docker`](#nemo_gym-sandbox-providers-docker-provider-_require_docker)                         | -                                                                                    |
| [`_resource_limit_flags`](#nemo_gym-sandbox-providers-docker-provider-_resource_limit_flags)             | -                                                                                    |
| [`_resource_passthrough_flags`](#nemo_gym-sandbox-providers-docker-provider-_resource_passthrough_flags) | -                                                                                    |
| [`_to_sandbox_status`](#nemo_gym-sandbox-providers-docker-provider-_to_sandbox_status)                   | -                                                                                    |

### Data

[`CONTAINER_NAME_PREFIX`](#nemo_gym-sandbox-providers-docker-provider-CONTAINER_NAME_PREFIX)

[`DEFAULT_KEEPALIVE_CMD`](#nemo_gym-sandbox-providers-docker-provider-DEFAULT_KEEPALIVE_CMD)

[`DEFAULT_KEEPALIVE_SHELL`](#nemo_gym-sandbox-providers-docker-provider-DEFAULT_KEEPALIVE_SHELL)

[`DOCKER_MISSING_CONTAINER_MARKERS`](#nemo_gym-sandbox-providers-docker-provider-DOCKER_MISSING_CONTAINER_MARKERS)

[`DOCKER_RUNTIME_ERROR_MARKERS`](#nemo_gym-sandbox-providers-docker-provider-DOCKER_RUNTIME_ERROR_MARKERS)

[`LOGGER`](#nemo_gym-sandbox-providers-docker-provider-LOGGER)

[`READY_PROBE_COMMAND`](#nemo_gym-sandbox-providers-docker-provider-READY_PROBE_COMMAND)

[`READY_PROBE_EXPECTED`](#nemo_gym-sandbox-providers-docker-provider-READY_PROBE_EXPECTED)

[`SANDBOX_LABEL`](#nemo_gym-sandbox-providers-docker-provider-SANDBOX_LABEL)

[`SANDBOX_RUNTIME_RETURN_CODE`](#nemo_gym-sandbox-providers-docker-provider-SANDBOX_RUNTIME_RETURN_CODE)

### 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'
)
```

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`

---

```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.

**`_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'`

---

```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._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._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

```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).

```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.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 `&lt;shell&gt; -c &lt;command&gt;` 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.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.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).

```python
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'`

---

```python
nemo_gym.sandbox.providers.docker.provider._coerce_config(
    value: typing.Any,
    config_cls: type[typing.Any]
) -> typing.Any
```

```python
nemo_gym.sandbox.providers.docker.provider._coerce_str_list(
    value: typing.Any,
    what: str
) -> list[str]
```

```python
nemo_gym.sandbox.providers.docker.provider._http_endpoint(
    host: str,
    port: int
) -> str
```

```python
nemo_gym.sandbox.providers.docker.provider._is_missing_container(
    stderr: str
) -> bool
```

```python
nemo_gym.sandbox.providers.docker.provider._is_runtime_failure(
    stderr: str
) -> bool
```

```python
nemo_gym.sandbox.providers.docker.provider._normalize_image(
    image: str
) -> str
```

```python
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`.

```python
nemo_gym.sandbox.providers.docker.provider._publish_arg(
    host: str,
    port: int
) -> str
```

```python
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.

```python
nemo_gym.sandbox.providers.docker.provider._require_docker() -> str
```

```python
nemo_gym.sandbox.providers.docker.provider._resource_limit_flags(
    resources: nemo_gym.sandbox.providers.base.SandboxResources
) -> list[str]
```

```python
nemo_gym.sandbox.providers.docker.provider._resource_passthrough_flags(
    resources: nemo_gym.sandbox.providers.base.SandboxResources
) -> list[str]
```

```python
nemo_gym.sandbox.providers.docker.provider._to_sandbox_status(
    state: str | None
) -> nemo_gym.sandbox.providers.base.SandboxStatus
```

```python
nemo_gym.sandbox.providers.docker.provider.CONTAINER_NAME_PREFIX = 'nemo-gym-'
```

```python
nemo_gym.sandbox.providers.docker.provider.DEFAULT_KEEPALIVE_CMD = 'while :; do sleep 2147483647; done'
```

```python
nemo_gym.sandbox.providers.docker.provider.DEFAULT_KEEPALIVE_SHELL = '/bin/sh'
```

```python
nemo_gym.sandbox.providers.docker.provider.DOCKER_MISSING_CONTAINER_MARKERS = ('no such container', 'no such object')
```

```python
nemo_gym.sandbox.providers.docker.provider.DOCKER_RUNTIME_ERROR_MARKERS = ('no such container', 'is not running', 'is not paused', 'cannot connect to the ...
```

```python
nemo_gym.sandbox.providers.docker.provider.LOGGER = logging.getLogger(__name__)
```

```python
nemo_gym.sandbox.providers.docker.provider.READY_PROBE_COMMAND = 'printf docker-sandbox-ready'
```

```python
nemo_gym.sandbox.providers.docker.provider.READY_PROBE_EXPECTED = 'docker-sandbox-ready'
```

```python
nemo_gym.sandbox.providers.docker.provider.SANDBOX_LABEL = 'nemo-gym.sandbox'
```

```python
nemo_gym.sandbox.providers.docker.provider.SANDBOX_RUNTIME_RETURN_CODE = 125
```