Skip to content
Fake Docker Daemon

Fake Docker Daemon

ephemerd provides a fake Docker Engine API server that translates Docker CLI calls into containerd operations. This allows CI jobs to run docker build, docker run, and docker push without a real Docker daemon or privileged containers.

Problem

CI jobs frequently call docker build, docker run, and docker push. GitHub’s hosted runners have a real Docker daemon available. Self-hosted runners behind ephemerd do not – containers run with restricted capabilities (no CAP_SYS_ADMIN) and there is no Docker daemon inside.

Users hit this when:

  • Workflows call docker build to produce container images.
  • Workflows use services: to spin up databases/caches as sidecars.
  • Workflows call docker run to test images they just built.

Architecture

+------------------------------+
|  Job Container               |
|                              |
|  docker build -t myapp .     |
|       |                      |
|       v                      |
|  /var/run/docker.sock        |
+----------+-------------------+
           | Unix socket
           v
+------------------------------+
|  ephemerd (fake Docker API)  |
|                              |
|  POST /build -> buildah bud  |
|  POST /containers/create     |
|     -> containerd            |
|  POST /images/create         |
|     -> containerd pull       |
+----------+-------------------+
           |
           v
+------------------------------+
|  containerd (embedded)       |
|                              |
|  Pulls remote images         |
|  Creates sibling containers  |
|  Same network, same firewall |
+------------------------------+

Each job gets its own fake daemon instance (pkg/dind/dind.go). The daemon maintains an in-memory image store and a temp directory for OCI layers. All state is scoped to the job and destroyed when the job exits.

API Translation

Implemented Endpoints

Docker APIephemerd actionStatus
GET /_pingReturns OK with API version 1.45 headersDone
GET /versionReturns 27.0.0-ephemerd version infoDone
GET /infoReturns minimal system info with image countDone
GET /images/jsonLists images from the in-memory storeDone
POST /images/createPulls images via containerd, stores in memory mapDone

Planned Endpoints

Docker APIephemerd actionStatus
POST /containers/createCreate sibling container via containerdNot yet
POST /containers/{id}/startStart containerd taskNot yet
POST /containers/{id}/execExec process in containerd taskNot yet
POST /containers/{id}/stopKill containerd taskNot yet
DELETE /containers/{id}Destroy container via containerdNot yet
POST /buildStream build context, run buildah budNot yet
POST /images/{name}/pushPush via buildah pushNot yet

Not Supported

Docker APIReason
docker composeCompose is a client-side tool making many API calls. Basic docker compose up may work if it only uses create + start, but no guarantees.
docker network createJobs share the ephemerd CNI network. Custom networks are not supported.
docker volume createUse bind mounts from the job’s workspace instead.
Swarm / Kubernetes APIsNot applicable.

Sibling Containers

Sidecars created via docker run are sibling containers – they run alongside the job container, not inside it. They share the same CNI network and firewall rules. From the job’s perspective, sidecars are reachable at their container IP.

This is important: there is no nested Docker. The fake daemon creates first-class containerd containers that happen to be managed through a Docker API shim.

Socket Lifecycle

  1. Job starts: ephemerd creates a Unix socket at <DataDir>/jobs/<JobID>/docker/d.sock, starts the fake daemon goroutine, mounts the socket into the container at /var/run/docker.sock.
  2. Job runs: Docker CLI in the container talks to the socket. ephemerd handles requests and creates sidecars as sibling containers.
  3. Job finishes: ephemerd destroys all sibling containers created by this job, deletes the temp directory, closes the socket. No leaked state.

Enabling

Enable with dind.enabled = true in config or the --dind flag on serve:

[dind]
enabled = true

Key Files

FilePurpose
pkg/dind/dind.goFake Docker API server, route dispatch, image pull
pkg/dind/dind_test.goTests for health and image endpoints