Users can run openshell sandbox create --from <source> to launch a sandbox with a custom container image while keeping the openshell-sandbox process supervisor in control.
The --from flag accepts four kinds of input:
| Input | Example | Behavior |
|---|---|---|
| Community sandbox name | --from openclaw |
Resolves to ghcr.io/nvidia/openshell-community/sandboxes/openclaw:latest |
| Dockerfile path | --from ./Dockerfile |
Builds the image, pushes it into the cluster, then creates the sandbox |
| Directory with Dockerfile | --from ./my-sandbox/ |
Uses the directory as the build context |
| Full image reference | --from myregistry.com/img:tag |
Uses the image directly |
The CLI classifies the value in this order:
- Existing file whose name contains "Dockerfile" (case-insensitive) — treated as a Dockerfile to build.
- Existing directory containing a
Dockerfile— treated as a build context directory. - Contains
/,:, or.— treated as a full container image reference. - Otherwise — treated as a community sandbox name, expanded to
{OPENSHELL_COMMUNITY_REGISTRY}/{name}:latest.
The community registry prefix defaults to ghcr.io/nvidia/openshell-community/sandboxes and can be overridden with the OPENSHELL_COMMUNITY_REGISTRY environment variable.
sandbox create also infers GPU intent from the final image name. The current rule matches when the last image name component contains gpu (for example ghcr.io/nvidia/openshell-community/sandboxes/nvidia-gpu:latest or registry.example.com/team/my-gpu-image:latest). When that rule matches, the sandbox request is treated the same as passing --gpu.
When --from points to a Dockerfile or directory, the CLI:
- Builds the image locally via the Docker daemon (respecting
.dockerignore). - Pushes it into the cluster's containerd runtime using
docker save/ctr import. - Creates the sandbox with the resulting image tag.
The supervisor binary (openshell-sandbox) is always side-loaded from the k3s node filesystem via a read-only hostPath volume. It is never baked into sandbox images. This applies to all sandbox pods — whether using the default community base image, a custom image, or a user-built Dockerfile.
flowchart TB
subgraph node["K3s Node"]
bin["/opt/openshell/bin/openshell-sandbox
(built into cluster image, updatable via docker cp)"]
end
node -- "hostPath (readOnly)" --> agent
subgraph pod["Pod"]
subgraph agent["Agent Container"]
agent_desc["Image: community base or custom image
Command: /opt/openshell/bin/openshell-sandbox
Volume: /opt/openshell/bin (ro hostPath)
Env: OPENSHELL_SANDBOX_ID, OPENSHELL_ENDPOINT, ...
Caps: SYS_ADMIN, NET_ADMIN, SYS_PTRACE"]
end
end
The server applies these transforms to every sandbox pod template (sandbox/mod.rs):
- Adds a
hostPathvolume namedopenshell-supervisor-binpointing to/opt/openshell/binon the node. - Mounts it read-only at
/opt/openshell/binin the agent container. - Overrides the agent container's
commandto/opt/openshell/bin/openshell-sandbox. - Sets
runAsUser: 0so the supervisor has root privileges for namespace creation, proxy setup, and Landlock/seccomp.
These transforms apply to every generated pod template. The image's Docker ENTRYPOINT is not the OpenShell startup path. To run image-specific startup logic on sandbox creation and pod restart, install a script at /etc/openshell/boot.sh; the supervisor launches it as a managed child process before starting the long-lived child process.
openshell sandbox create --from openclawopenshell sandbox create --from myimage:latest -- echo "hello from custom container"When --from is set the CLI clears the default run_as_user/run_as_group policy (which expects a sandbox user) so that arbitrary images that lack that user can start without error.
openshell sandbox create --from ./Dockerfile -- echo "built and running"
openshell sandbox create --from ./my-sandbox/ # directory with DockerfileThe openshell-sandbox supervisor adapts to arbitrary environments:
- Log file fallback: Attempts to open
/var/log/openshell.logfor append; silently falls back to stdout-only logging if the path is not writable. - Boot hook: Runs
/etc/openshell/boot.shwith/bin/shas a supervisor-managed child process on every pod start when that file exists. The script runs before the long-lived child process and must exit successfully for the sandbox to become ready. - Command resolution: After the boot hook completes, executes the command from CLI args, then the
OPENSHELL_SANDBOX_COMMANDenv var (set tosleep infinityby the server), then/bin/bashas a last resort. - Network namespace: Requires successful namespace creation for proxy isolation; startup fails in proxy mode if required capabilities (
CAP_NET_ADMIN,CAP_SYS_ADMIN) oriproute2are unavailable. If theiptablespackage is present, the supervisor installs OUTPUT chain rules (LOG + REJECT) inside the namespace to provide fast-fail behavior (immediateECONNREFUSEDinstead of a 30-second timeout) and diagnostic logging when processes attempt direct connections that bypass the HTTP CONNECT proxy. Ifiptablesis absent, the supervisor logs a warning and continues — core network isolation still works via routing.
| Decision | Rationale |
|---|---|
Unified --from flag |
Single entry point for community names, Dockerfiles, directories, and image refs — removes the need to know registry paths |
| Community name resolution | Bare names like openclaw expand to the GHCR community registry, making the common case simple |
| Auto build+push for Dockerfiles | Eliminates the two-step image push + create workflow for local development |
OPENSHELL_COMMUNITY_REGISTRY env var |
Allows organizations to host their own community sandbox registry |
| hostPath side-load | Supervisor binary lives on the node filesystem — no init container, no emptyDir, no extra image pull. Faster pod startup. |
| Read-only mount in agent | Supervisor binary cannot be tampered with by the workload |
| Command override | Ensures openshell-sandbox is the entrypoint regardless of the image's default CMD |
/etc/openshell/boot.sh hook |
Gives images a restart-safe startup hook even though Docker ENTRYPOINT is bypassed |
Clear run_as_user/group for custom images |
Prevents startup failure when the image lacks the default sandbox user |
| Non-fatal log file init | /var/log/openshell.log may be unwritable in arbitrary images; falls back to stdout |
docker save / ctr import for push |
Avoids requiring a registry for local dev; images land directly in the k3s containerd store |
Optional iptables for bypass detection |
Core network isolation works via routing alone (iproute2); iptables only adds fast-fail (ECONNREFUSED) and diagnostic LOG entries. Making it optional avoids hard failures in minimal images that lack iptables while giving better UX when it is available. |
- Distroless /
FROM scratchimages are not supported (the supervisor needs glibc and/proc) - Missing
iproute2(or required capabilities) blocks startup in proxy mode because namespace isolation is mandatory - The supervisor binary must be present on the k3s node at
/opt/openshell/bin/openshell-sandbox(embedded in the cluster image at build time)