Docker Provider
The docker provider runs each sandbox as one long-lived container on the local Docker daemon. It shells out to the docker CLI (docker run, docker exec, docker cp, docker rm), so it needs a running daemon but no OpenSandbox server, control plane, or Kubernetes. Use it for local development, CI, and single-machine setups where Docker is the available runtime.
Setup
Install Docker and make sure the docker binary is on PATH with a running daemon. The provider does not install or start Docker; constructing it raises RuntimeError if the binary is missing, and create() fails if the daemon is unreachable.
Images can be any reference the daemon can run, such as ubuntu:22.04, python:3.12-slim, or a registry reference. An Apptainer-style docker:// prefix is tolerated and stripped. GPU passthrough needs the NVIDIA Container Toolkit; CPU and memory limits need cgroups.
Provider Config
NeMo Gym ships a Docker provider config at nemo_gym/sandbox/providers/docker/configs/docker.yaml. It defines a top-level sandbox block that agents reference with sandbox_provider: sandbox.
Run an agent with the provider config by passing it alongside the agent and model configs:
The provider constructor accepts three optional config sections:
SandboxSpec Provider Options
Set Docker-specific create options under SandboxSpec.provider_options, or under sandbox_spec.provider_options in an agent config:
Relevant SandboxSpec Fields
Resource Mapping
SandboxResources is translated into Docker CLI flags when create.apply_resource_limits is enabled:
Lifecycle
The provider runs one detached container per sandbox:
Containers are named nemo-gym-<uuid>, and the image ENTRYPOINT is overridden with a keep-alive command so images that define their own entrypoint (common for SWE benchmark images) stay up across exec() calls. State written by one command is visible to later commands in the same sandbox. --init inserts a minimal init process so the many short docker exec children are reaped instead of accumulating as zombies.
File Transfer
Uploads and downloads use docker cp in both directions, creating the target’s parent directory first on upload. Uploaded files are owned by root; read them as root or chown them for a non-root user. Download any files you need before stopping the sandbox — stopping force-removes the container.
Isolation and Security
Docker containers share the host kernel. This is process and namespace isolation, not a virtual machine, and is not a hard boundary for hostile code. For adversarial or untrusted workloads, run Docker on a disposable VM or use a stronger runtime such as gVisor, Kata Containers, or a microVM.
- Never run with
--privilegedand never mount the Docker socket into the sandbox; either grants host root. - Networking is on by default because most tasks need egress (pip, git). Set
network: noneto cut it entirely, ornetwork: <name>to attach a locked-down internal network. - Harden with
read_only: true,cap_drop: ["ALL"],security_opt: ["no-new-privileges"], andpids_limit: <n>as a fork-bomb guard. Enforceresourcesso one sandbox cannot starve the host. - Rootless Docker narrows the blast radius (container root is not host root) and is recommended for shared machines;
docker cpownership and some--userbehaviors differ under it. - Every container is labeled
nemo-gym.sandbox=1. Reap leaks from an unclean shutdown withdocker rm -f $(docker ps -aq --filter label=nemo-gym.sandbox=1).
User and Runtime Notes
The neutral user argument to exec() maps onto --user:
By default exec_shell is unset, so the provider auto-detects bash once the container is ready (conda and SWE-bench setup commands use source, which POSIX sh/dash lack) and falls back to sh. Pin exec_shell to /bin/sh or /bin/bash to skip the per-create probe.
Command failures return SandboxExecResult with the command’s exit code. A command timeout returns code 125 with error_type="timeout", and a docker runtime failure — daemon down or container gone, detected via stderr markers — returns code 125 with error_type="sandbox". A timed-out command’s in-container process is reaped when the sandbox is closed, since docker rm -f stops the whole process tree.