The Docker runtime extension allows Universe to spawn instances as Docker containers instead of local processes. Each instance gets its own isolated container with configurable resource limits, networking, and image. Containers are siblings to the Universe container itself — Universe communicates with the host’s Docker daemon via the mounted Unix socket, a pattern known as Docker-out-of-Docker. This runtime is well-suited for containerized deployments where you want process isolation per instance without the complexity of a full Kubernetes cluster. It also enables full log streaming to the REST API and WebSocket live-log endpoint.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/universeclouddev/Universe/llms.txt
Use this file to discover all available pages before exploring further.
How It Works
Universe’s Docker extension uses the Docker Engine API (via the Docker Java client) to create and manage containers. When an instance is created:- Universe resolves and copies the template tree to
./running/<instanceId>/inside the Universe container. - The extension translates the instance configuration into a
CreateContainerCmd, specifying the image, command, port bindings, volume mounts, and environment variables. - The container is started. Universe polls the Docker API until the container enters
runningstate. executeCommand()callsdocker execto run a command inside the container.stop()callsdocker stopwith the configuredstopTimeout, then optionally removes the container (autoRemove: true).
GET /api/instances/{id}/logs and the WS /api/instances/{id}/live-log WebSocket) streams directly from the Docker container’s stdout/stderr via the Docker logs API.
Setup
Place the extension JAR
Copy Universe scans this directory on startup and loads all extension JARs automatically.
runtime-docker-<version>.jar into the ./extensions/ directory on the Universe data volume:Mount the Docker socket in docker-compose.yml
The extension needs access to the host Docker daemon. Mount the Unix socket into the Universe container:Containers created by the extension will be siblings of the Universe container — they appear in
docker ps on the host alongside Universe itself, not nested inside it.Create the extension config file
Create
./extensions/docker/config.json (inside the Universe data directory) with at minimum a hostDataPath value. A full example:Understanding hostDataPath
hostDataPath is the most important field to get right when Universe runs inside Docker.
When Universe is containerized, the template working directories live inside the container’s filesystem, for example at /data/running/<instanceId>/ (because docker-compose.yml mounts ./data:/data). When the Docker extension creates a new sibling container and bind-mounts this directory, the Docker daemon resolves the path on the host filesystem — not inside the Universe container.
The path /data/running/abc123 does not exist on the host. The host sees the same data at the path where ./data lives relative to docker-compose.yml.
Example: Your docker-compose.yml lives at /opt/universe/docker-compose.yml and mounts ./data:/data. Set:
./running/abc123/, the Docker daemon receives /opt/universe/data/running/abc123/ — a path that actually exists on the host — and the spawned container gets the template files.
Full Configuration Schema
All fields in./extensions/docker/config.json:
| Field | Type | Default | Description |
|---|---|---|---|
factoryName | string | "docker" | Runtime key used in instance configs ("runtime": "docker") |
hostDataPath | string | null | Host filesystem path that maps to the Universe data directory. Required when Universe runs inside Docker |
network | string | "host" | Docker network mode for spawned containers ("host", "bridge", or a named network) |
javaImage.repository | string | "azul-zulu" | Container image repository for instance containers |
javaImage.tag | string | "25-jdk-alpine" | Image tag |
javaImage.registry | string | null | Optional private registry prefix |
javaImage.platform | string | null | Optional platform override (e.g. "linux/amd64") |
volumes | array | [] | Additional bind mounts applied to every instance container (structured objects — see below) |
binds | array | [] | Additional raw bind-mount strings in "hostPath:containerPath" or "hostPath:containerPath:ro" format |
exposedPorts | array | [] | Additional ports to expose on instance containers |
autoRemove | boolean | true | Automatically remove the container when it exits |
stopTimeout | int | 30 | Seconds to wait for graceful shutdown before SIGKILL |
dockerHost | string | "unix:///var/run/docker.sock" | Docker daemon endpoint |
dockerCertPath | string | null | Path to TLS certificates for TCP Docker connections |
registryUsername | string | null | Private registry credentials |
registryPassword | string | null | Private registry credentials |
registryEmail | string | null | Private registry credentials |
registryUrl | string | null | Private registry URL |
user | string | null | User inside the container (e.g. "1000:1000") |
containerWorkDir | string | "/app" | Working directory inside the container |
volumes Array Items
Each item in thevolumes array maps a host path into every instance container:
binds Array Items
Each item is a raw Docker bind-mount string. Use this for quick one-liners when the structuredvolumes objects are unnecessary:
exposedPorts Array Items
Each item declares a port to expose on the container (in addition to the automatically bound instance port):Per-Instance Image Override
Override the Docker image for a specific instance by setting theCUSTOM_IMAGE environment variable in the configuration’s environmentVariables. The value is parsed as a full image reference and takes precedence over javaImage in the extension config:
CUSTOM_IMAGE field supports the full registry/org/image:tag format. When present, the standard javaImage config is ignored for that instance.