Docker in spaces
Add the docker package to a stack and every space on it gets its own Docker daemon. The agent builds images, runs containers and brings up docker compose stacks next to your code, and every container stays inside the space’s network policy.
What you can do with it
- Build and test an image. The agent edits a Dockerfile, runs
docker buildon the workspace, and runs the result to check it. - Run integration tests. A
compose.yamlstarts your service with its database and queue, and the tests run against the real thing. - Use a tool from an image. Run a linter, a code generator or a CLI from its image against the files in your workspace.
How it works
The daemon runs in its own container next to the agent, as the same user as the agent, inside a user namespace. Root in a container is you: files a container writes into the workspace belong to you, and you can edit or delete them afterwards.
The agent talks to the daemon through Marshal, which checks every request. Containers run unprivileged. Requests for privileged containers, host network, PID, IPC or user namespaces, devices, and capabilities outside a safe set are refused with a clear message, for example privileged mode is not allowed. Even a container that reaches the daemon directly gets no privileges on the node: the daemon itself runs without them.
Container traffic leaves through Marshal like the agent’s own traffic:
- HTTP and HTTPS go through the Marshal proxy, so the space’s network policy, HTTP secrets and registry credentials apply, and every request shows on the Audit page.
- Other TCP, such as SSH on 22 or a database on 5432, is allowed when the network policy has a
tcprule for that host and port. Every connection is audited. - Image pulls and pushes sign in through the registry packages, such as
docker-huborprivate-registry, so a build needs nodocker login.
Builds that make HTTPS calls
HTTPS from a RUN step goes through the Marshal proxy, which presents a certificate signed by the space’s own CA. Marshal passes that CA to every build as the MARSHAL_CA_CERT build argument. Add these lines after FROM, in each stage that makes HTTPS calls:
ARG MARSHAL_CA_CERT=""
RUN if [ -n "$MARSHAL_CA_CERT" ]; then \
mkdir -p /usr/local/share/ca-certificates && \
echo "$MARSHAL_CA_CERT" | base64 -d \
> /usr/local/share/ca-certificates/marshal.crt && \
update-ca-certificates; \
fiThe snippet does nothing when the argument is empty, so the same Dockerfile builds anywhere. On Red Hat based images, such as Rocky Linux, AlmaLinux, Fedora or Amazon Linux, write the certificate to /etc/pki/ca-trust/source/anchors/marshal.crt and run update-ca-trust instead. Node and Python tools also read NODE_EXTRA_CA_CERTS and REQUESTS_CA_BUNDLE.
Keep a host end to end
Some clients only accept a server’s own certificate, for example a tool that pins it. For those hosts, an admin adds a passthrough rule to the space’s network policy. Marshal then allows the host without decrypting the traffic: the container sees the site’s real certificate, needs no CA, and the Audit page records the host. Secrets and registry credentials are not added to that traffic, because Marshal never reads it. The rule covers everything in the space, the agent included.
An admin adds the rule through the Marshal MCP server with network_policies_update, for example:
{ "protocol": "https", "domains": ["pinned.example.com"], "action": "passthrough" }The Network policies page shows the rule with the note Allowed without decrypting.
How containers behave
- Writing to the workspace: run containers as root, which is the default for most images. Root in the container writes as you. A container that runs as another user, such as
-u 1000or an image with a non-root default user, reads the workspace but cannot create files in it. Give it-u 0. - Resources: all containers share the space’s CPU and memory.
--memoryand--cpuson a single container have no effect, so size the space for the work. See Compute sizes. - Images and layers live with the space while it runs. A stop clears them, so the first build after a resume pulls again. See Spaces and storage.
Configure it
The docker package has two settings. A stack owner sets them on the docker package in the stack.
| Setting | Default | What it does |
|---|---|---|
| Allow externally-routable Docker networks | Off | New Docker networks are created as internal networks. Turn this on for compose stacks or tools that need a regular network. Egress still goes through Marshal either way. |
| Expose space databases to containers | Off | Mounts the space’s database sockets at /run/db so a container can reach the space’s PostgreSQL and Redis. Credentials stay in Marshal. |
Try it
Add docker and egress-dockerhub to a stack, start a space, and run:
docker run --rm hello-worldWhat you should see: Hello from Docker!