Moby — Structure#
Layout pattern#
Custom Monorepo with Sub-module Extraction in Progress
Moby began as a single Go module and is actively being decomposed: api/ and client/ are now independent Go modules (github.com/moby/moby/api, github.com/moby/moby/client) that the root module references via require. The daemon/ package is itself a deep sub-hierarchy with 247+ packages, functioning as a large internal monolith. This is not a standard cmd/internal/pkg layout—the business logic lives almost entirely inside daemon/, with pkg/ relegated to a shrinking set of utility packages.
Directory map#
repositories/moby/
├── api/ # INDEPENDENT SUB-MODULE — Docker HTTP API types, Swagger spec
│ ├── types/ # Request/response structs (container, image, network, swarm…)
│ ├── pkg/ # API-internal utilities
│ └── swagger.yaml # OpenAPI specification for the Docker Engine API
│
├── client/ # INDEPENDENT SUB-MODULE — Go client library for Docker API
│ ├── *.go # ~150 files, one per API operation (container_start.go, etc.)
│ ├── internal/ # client-internal helpers
│ └── pkg/ # client-internal packages
│
├── cmd/
│ ├── dockerd/ # Main daemon binary entry point
│ └── docker-proxy/ # Userland TCP/UDP/SCTP proxy for port mapping (Linux only)
│
├── daemon/ # THE CORE — virtually all daemon logic (247+ sub-packages)
│ ├── *.go # Top-level daemon type and methods
│ ├── builder/ # Dockerfile build engine and remote context fetching
│ ├── cluster/ # Docker Swarm mode orchestration (executor, converters)
│ ├── command/ # cobra CLI wiring, startup, shutdown, signal handling
│ ├── config/ # Daemon configuration struct and defaults
│ ├── container/ # Container state/lifecycle struct
│ ├── containerd/ # containerd image store integration (modern path)
│ ├── events/ # Internal event bus
│ ├── graphdriver/ # Legacy storage drivers (overlay2, btrfs, zfs, vfs, windows)
│ ├── images/ # Image management (legacy graphdriver path)
│ ├── initlayer/ # Linux init layer setup
│ ├── internal/ # ~45 daemon-private packages (see below)
│ ├── libnetwork/ # Embedded SDN library (bridge, overlay, macvlan, ipvlan…)
│ ├── links/ # Legacy container links
│ ├── listeners/ # TLS / Unix socket / Windows named pipe listener setup
│ ├── logger/ # Pluggable logging drivers (json-file, syslog, journald, fluentd…)
│ ├── names/ # Container name registry
│ ├── network/ # Network request/response translation
│ ├── pkg/ # daemon-local packages (oci, opts, plugin, registry)
│ ├── server/ # HTTP API server and router (one package per resource type)
│ ├── snapshotter/ # containerd snapshotter integration (modern storage path)
│ ├── stats/ # Container stats collection
│ └── volume/ # Volume management (local driver, mount tracking, safepath)
│
├── dockerversion/ # Version constants injected at build time
├── errdefs/ # Error sentinel values (wraps github.com/containerd/errdefs)
│
├── integration/ # Modern integration tests (per-resource directories)
│ ├── build/, container/, image/, network/, volume/, plugin/, service/, …
│ └── internal/ # Integration test helpers
│
├── integration-cli/ # Legacy integration test harness (deprecated, not removed)
│ ├── checker/, cli/, daemon/, environment/, fixtures/
│
├── internal/ # Root-level internal utilities
│ ├── iterutil/ # Iteration helpers
│ ├── namesgenerator/ # Random human-readable name generator
│ ├── sliceutil/ # Slice helpers
│ ├── test/ # Test helpers (request, environment)
│ └── testutil/ # Assertion helpers for tests
│
├── pkg/ # Public (exported) utility packages
│ ├── authorization/ # HTTP authorization plugin middleware
│ ├── homedir/ # Home directory resolution
│ ├── ioutils/ # I/O helpers (atomic file write, etc.)
│ ├── longpath/ # Windows long path workarounds
│ ├── meminfo/ # /proc/meminfo parsing
│ ├── parsers/ # Kernel version, OS string parsers
│ ├── pidfile/ # PID file management
│ ├── plugingetter/ # Interface for looking up installed plugins
│ ├── plugins/ # Plugin discovery, socket transport, protobuf RPC gen tool
│ ├── pools/ # bytes.Buffer pool
│ ├── process/ # Cross-platform process utilities
│ ├── sysinfo/ # Linux cgroup/kernel feature detection
│ ├── tailfile/ # Tail-from-end of file
│ └── useragent/ # HTTP User-Agent string construction
│
├── contrib/ # AppArmor profiles, SELinux policy, init scripts, OTel helper
├── docs/ # API docs (mostly stubs pointing to external docs site)
├── hack/ # Build, test, and validation scripts
│ ├── dockerfile/ # Tool installation scripts used in multi-stage Dockerfile
│ ├── make/ # Shell script build targets
│ ├── test/ # Test runner helpers
│ └── validate/ # Linting and validation scripts (vendoring, copyright, etc.)
├── man/ # man page sources (separate vendor)
├── project/ # Project governance docs (PACKAGERS.md, CONTRIBUTORS, etc.)
├── releases/ # Release notes
└── vendor/ # Vendored dependencies (full copy)Entry points#
| Binary | Path | Purpose |
|---|---|---|
dockerd | cmd/dockerd/main.go | The Docker Engine daemon. Calls reexec.Init() (for worker process re-execution), then command.NewDaemonRunner() which boots cobra CLI, reads config, starts the HTTP API server and attaches to containerd. |
dockerd (Windows) | cmd/dockerd/main_windows.go | Windows-specific service wrapper; same cobra entrypoint but wrapped in a Windows Service runner. |
docker-proxy | cmd/docker-proxy/main_linux.go | Userland network proxy for container port bindings (TCP, UDP, SCTP). A separate, minimal binary with no daemon dependency. |
Package organization#
daemon/internal/ — Private daemon packages (~45 packages)#
These are declared internal to prevent use outside daemon/ subtree:
| Package | Purpose |
|---|---|
builder-next/ | BuildKit integration adapters — bridges moby’s daemon APIs to BuildKit worker |
capabilities/ | Linux capabilities parsing |
cleanups/ | Ordered cleanup function registry for graceful shutdown |
containerfs/ | Container filesystem path abstraction |
directory/ | Recursive directory size calculation |
distribution/ | Image push/pull, registry transfer, xfer queuing |
filedescriptors/ | FD count / leak checking |
filters/ | Docker list filter parsing and matching |
idtools/ | UID/GID mapping for user namespaces |
image/ | Image store, layer management, tarexport |
layer/ | Layer chain management (legacy graphdriver path) |
libcontainerd/ | containerd client abstraction — local (in-process) and remote (gRPC) modes |
metrics/ | Prometheus metrics registration |
nri/ | Node Resource Interface hooks (CRI plugin integration) |
opts/ | CLI option types (ulimits, device mappings, etc.) |
plugin/ | Managed plugin lifecycle (v2 plugin system) |
progress/ | Progress reporting for image transfers |
quota/ | Disk quota enforcement |
refstore/ | Image reference/tag store |
restartmanager/ | Container restart policy state machine |
rootless/ | Rootless daemon detection and path adjustments |
runconfig/ | Container config validation and defaults |
stream/ | I/O stream multiplexing (stdin/stdout/stderr attach) |
system/ | OS-level helpers (xattrs, ioctl, umask) |
Public packages (pkg/)#
The pkg/ directory has been shrinking as packages migrate to standalone github.com/moby/* repositories. What remains is used by both the daemon and external integrators:
| Package | Purpose |
|---|---|
authorization/ | Middleware for HTTP auth plugin system |
plugins/ | Plugin discovery (socket, TCP), pluginrpc-gen code generator |
plugingetter/ | Interface for plugin lookup (decoupling) |
sysinfo/ | Runtime cgroup/seccomp/AppArmor capability detection |
ioutils/ | Atomic file write, temp dir management |
parsers/ | Kernel version strings, OS identification |
Layering#
The dependency flow is broadly:
cmd/dockerd
└─► daemon/command (cobra setup, bootstrap)
└─► daemon/ (core Daemon type)
├─► daemon/server/ (HTTP API)
├─► daemon/libnetwork/ (networking)
├─► daemon/internal/libcontainerd/ (container runtime)
├─► daemon/internal/distribution/ (image registry)
├─► daemon/cluster/ (Swarm orchestration)
└─► daemon/internal/layer/ + daemon/graphdriver/ (storage, legacy)
OR daemon/containerd/ + daemon/snapshotter/ (storage, modern)
api/ (independent module — type definitions only, no daemon deps)
client/ (independent module — HTTP client, depends on api/)
pkg/ (utilities — no daemon deps, usable externally)
errdefs/ (error sentinel package — minimal, no daemon deps)This is broadly a layered architecture but without strict enforcement (daemon internals freely cross-reference each other via the flat daemon.Daemon god-struct).
Build system#
- Build tool:
makewith Docker BuildKit (docker buildx bake) as the primary build executor. Local builds can also use./hack/make.shdirectly. - Key targets:
make binary— statically linkeddockerdanddocker-proxyvia BuildKitmake dynbinary— dynamically linked binariesmake binary-cross— cross-compile for non-Linux targetsmake test— unit + integration + docker-py testsmake test-integration— runs integration suite inside a Docker-in-Docker containermake test-unit— unit tests only, usable locally without Dockermake install— install binaries to system path
- Docker: Multi-stage Dockerfile with ~40+ named stages. Key stages:
base— Go toolchaincontainerd-build,runc-build,tini-build,rootlesskit-build— build runtime dependencies from sourcebinary— final daemon binarydev— development container with all tools (delve, golangci-lint, gotestsum, etc.)
- Build tags:
DOCKER_BUILDTAGSenv var injects compile-time feature flags (e.g.,seccomp,journald,exclude_graphdriver_btrfs) - Version injection:
dockerversion/constants set via-ldflags "-X ..."at build time
Notable structural decisions#
daemon/as a monolith with nestedinternal/: Rather than extracting subsystems into separate top-level packages, all daemon logic lives underdaemon/. Theinternal/subdirectory enforces that ~45 implementation packages cannot be imported outside the daemon subtree — an unusual use of Go’sinternalmechanism applied to a sub-directory, not just the root module.Dual storage paths in parallel:
daemon/graphdriver/(legacy overlay2, btrfs, zfs) anddaemon/containerd/+daemon/snapshotter/(modern containerd snapshotters) coexist. A runtime selector (daemon/image_store_choice.go) chooses the path based on daemon configuration. This structural duplication reflects a multi-year migration that hasn’t completed.Sub-module extraction as architectural signal:
api/andclient/being independent modules means they have their own versioning, go.mod, test suites, and CI — even while physically living in the same repository. This is a stepping stone toward a fully split repository (similar to howcontainerd/containerdandopencontainers/runcwere previously embedded in this repo).integration-cli/legacy coexistence: The old CLI-driven integration test harness (integration-cli/) exists alongside the newerintegration/suite, which uses the Go client library directly. The old harness is deprecated but not deleted, creating structural duplication in the test layer.libnetwork/as an embedded sub-project:daemon/libnetwork/is a standalone SDN implementation (formerly its own repository —docker/libnetwork) with its own internal hierarchy of 35+ packages includingdriverapi/,ipamapi/,networkdb/,iptables/,osl/(OS layer). Its re-integration into the moby tree trades external versioning for tighter coupling.Multi-stage Dockerfile as the authoritative build spec: The
Dockerfile(notMakefile) is the single source of truth for building — it specifies exact tool versions forcontainerd,runc,tini,rootlesskit, and Go itself. TheMakefilesimply invokesdocker buildx bake, delegating all build logic to BuildKit.Platform compilation coverage: Nearly every subsystem has
_linux.go,_windows.go,_unix.go,_freebsd.go, and_unsupported.govariants, reflecting genuine multi-platform support rather than just Linux. Thedaemon/command/directory alone has 8 platform-variant files.