Docker
Run Docker Engine inside Daytona sandboxes.
Docker runs inside a sandbox as a full Docker Engine, so workloads can build images and run containers the same way they do on a regular Linux machine. Daytona does not install Docker. When the sandbox image ships Docker Engine (dockerd), the sandbox starts it automatically on every boot; when the image does not, nothing starts.
Every Linux sandbox has storage prepared for Docker, with no create-time option. The standard Docker data roots /var/lib/docker and /var/lib/containerd are backed by the sandbox disk, so Docker images, containers, and volumes are stored with the rest of the sandbox filesystem and are kept by snapshots and persistent sandboxes.
Docker startup never blocks the sandbox: the sandbox reports as running as soon as the toolbox is reachable, and Docker reports its own readiness through the Docker status. A Docker failure leaves the sandbox usable, so you can read the logs, fix the configuration, and retry.
Use cases
Docker is used when a workload already runs in containers or builds container images.
- Multi-container applications: an application with a database, a cache, and its services runs in one sandbox. Docker Engine runs inside the sandbox as on a regular Linux machine.
- Image builds: CI jobs and agents build container images and test them before a push.
- Integration tests: tests start databases and other dependencies as containers and remove them after the run.
- Agents that run containers: an agent pulls and runs containers inside the sandbox, with no access to a Docker daemon on your machines.
- Docker-in-Docker images: an image whose entrypoint is
dockerdor the official Docker-in-Docker entrypoint script works without changes. The sandbox recognizes the entrypoint and waits for Docker to become ready. - Prepared environments: images and containers pulled once are kept by a captured image, a snapshot, or a persistent sandbox. The next sandbox does not pull them again.
- Running containers across pauses: pause and resume, a snapshot, or a fork keeps running containers with their processes intact. A persistent stop and start restarts containers according to their restart policy.
- Docker startup troubleshooting: a Docker failure leaves the sandbox usable. The Docker status and logs show the cause, and Docker is started again after the configuration is fixed.
Start Docker
Start Docker by creating a sandbox from an image that ships Docker Engine. Docker starts in the background after the sandbox is running, so wait for Docker to become ready before you run Docker commands; a command sent earlier can fail because Docker is not answering yet.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create("docker-dind")
# Block until Docker Engine answers, up to 120 seconds
sandbox.docker.wait_until_ready(timeout=120)
response = sandbox.process.run("docker run --rm hello-world")
print(response.stdout)Start modes
Choose how Docker starts with a sandbox environment variable, set when you create the sandbox. The sandbox reads it once per boot. The value is case-insensitive, and an unset, empty, or unknown value selects the default automatic mode.
In automatic mode, the sandbox first checks the image entrypoint. A recognized Docker entrypoint, which is the Docker Engine daemon itself or the official Docker-in-Docker entrypoint script when it runs the daemon, starts Docker, and the sandbox only waits for it. Otherwise, if the image has the Docker Engine daemon in a standard binary directory, the sandbox starts it as root, waits for it, and then starts the image entrypoint. Recognition is narrow: an entrypoint that starts the daemon another way, such as through a shell command or a process supervisor, is not recognized. The sandbox then starts its own daemon first, and the one the entrypoint starts typically fails against it. Use the entrypoint mode for such images.
- Recognized entrypoints:
dockerdwith any arguments;dockerd-entrypoint.shwith no arguments, a flag as the first argument, ordockerdas the first argument;docker-entrypoint.shwithdockerdordockerd-entrypoint.shas the first argument. - Daemon search path:
/usr/local/bin,/usr/bin,/usr/sbin,/bin, and/sbin. - Sandbox
PATH: not searched for the daemon.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create(
"my-dind-image",
env={"DAYTONA_DOCKER_START": "entrypoint"},
)| Value | Behavior |
|---|---|
auto (default) | |
entrypoint | The image entrypoint starts Docker. The sandbox only waits for the socket and never starts dockerd itself. |
off | The sandbox neither starts nor waits for Docker, and the state is disabled. The image entrypoint still runs, so a recognized Docker entrypoint still starts Docker; the state is then unmanaged with owner entrypoint. |
Get Docker status
Get the Docker status. The status describes Docker in the current boot and is returned immediately. Reading it never starts or restarts Docker.
| Field | Description |
|---|---|
state | Where Docker is in its startup. See the table below. |
owner | Who starts Docker: daemon (the sandbox), entrypoint (the image), or none. |
reason | Why the state is what it is, such as a failure cause; null when there is nothing to add. |
processId (process_id in Python) | The process with Docker's output, or null. |
| State | Meaning |
|---|---|
ready | The Docker socket answers. Docker commands work. |
starting | Docker is being started or waited for. |
deferred | Docker startup has not run yet in this boot (reason gate-closed), or it is skipped for the whole boot (reason function-ready-template). |
failed | Docker did not come up (start failure, early exit, or the 30-second timeout), or it exited later (reason exited). The sandbox stays usable. |
not_present | The image has no dockerd. The reason is cli-only when the image has only the docker CLI. |
disabled | DAYTONA_DOCKER_START is off. |
unmanaged | DOCKER_HOST points to a non-local engine, or DAYTONA_DOCKER_START is off and a recognized Docker entrypoint starts Docker. The sandbox does not check that engine. |
unsupported | Docker storage could not be prepared, for example because the image ships a non-empty /var/lib/docker, or the sandbox type has no Docker support. |
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create("docker-dind")
status = sandbox.docker.status()
print(status.state, status.owner, status.reason, status.process_id)Wait for Docker
Wait for Docker to become ready. The wait polls the Docker status and returns as soon as Docker is ready. It fails at once when Docker reaches a state that cannot become ready in the current boot, and fails with a timeout when Docker is still not ready at the end of the time budget.
from daytona import Daytona
from daytona.v2 import DockerNotReadyError, DockerWaitTimeoutError
daytona = Daytona()
sandbox = daytona.v2.create("docker-dind")
try:
status = sandbox.docker.wait_until_ready(timeout=120)
except DockerNotReadyError as e:
print("Docker cannot start:", e.status.state, e.status.reason)
except DockerWaitTimeoutError as e:
print("Docker is still starting:", e.status)| Parameter | Type | Description |
|---|---|---|
timeout | float | Sets how many seconds the wait lasts. 0 waits without a deadline. The default is 60. |
Docker logs
Read Docker's output. Docker's output is kept in the logs of the process that runs Docker, and the Docker status names that process. When the sandbox starts Docker itself, the process has the fixed name used in the examples below, and its logs stay readable after Docker exits. When the image entrypoint starts Docker, Docker's output is in the entrypoint's logs.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create("docker-dind")
status = sandbox.docker.status()
if status.process_id:
handle = sandbox.process.connect(status.process_id)
for frame in handle.logs().items:
print(f"[{frame.channel}]: {frame.data}")Docker storage
Docker data lives on the sandbox disk, at the standard paths for rootful Docker:
| Path | Contents |
|---|---|
/var/lib/docker | Docker's image layers, containers, and local volumes. |
/var/lib/containerd | containerd's image content, used by Docker Engine 29 and later. |
Docker shares the sandbox disk with everything else in the sandbox; there is no separate Docker allowance. To store more images or containers, raise the sandbox disk size at create time.
If the image already contains a non-empty /var/lib/docker or /var/lib/containerd, or either path is a symbolic link, the contents are left untouched, Docker storage is not prepared, and the state is unsupported. Images that preload Docker data this way are not supported.
Persistence
Because Docker data is part of the sandbox disk, it follows the sandbox's persistence:
| Operation | Docker data |
|---|---|
| Images and snapshots | Each sandbox created from a captured image or a snapshot gets its own copy of the source's Docker images, containers, and volumes, and can create new ones. |
| Persistent stop and start | Docker data survives, and Docker starts again on the next boot. |
| Pause, resume, and fork | Docker resumes from memory without restarting. |
A boot from a captured image and a persistent start are both reboots: running containers come back stopped and restart per their Docker restart policy (--restart). To resume running containers with their processes intact, use pause and resume, a snapshot, or a fork.