The Problem

Moby is a "Lego set" of 13 self-contained projects for assembling container-based systems, not a single codebase. Engineers treating it as monolithic code face navigation overhead: 12509 files across 13 projects with no single architecture connecting them. The root module github.com/moby/moby/v2 targets building custom container engines, while github.com/moby/moby/client and github.com/moby/moby/api are the supported public modules. Teams needing to modify container runtime behavior must identify which of the 13 projects applies.

What This Does

Moby provides toolkit components for container build, registry, orchestration, and runtime functions. The daemon project (2016 files, 1310 code files) contains the core daemon logic - container lifecycle, networking, and storage. The client project (277 files, 269 code files) implements the Go API client with client/client.go (17 functions, 182 callers) defining NewClientWithOpts, New, and TLS configuration. The api project (201 files, 126 code files) shares types between client and server. Integration (240 files) and integration-cli (119 files) provide end-to-end test suites. Cmd (16 files) contains entry points including cmd/docker-proxy/main_linux.go which reaches 255 functions. Vendor holds 9270 files including dependencies. Recurring patterns across projects include logger registration (gelf, syslog, awslogs, fluentd - 223 repeated 6-line blocks across 107 files) and version comparison logic in client/pkg/versions/compare.go and daemon/internal/versions/compare.go.

How It Is Wired

Execution starts at main in cmd/docker-proxy/main_linux.go:30, reaching 255 functions with no incoming edges from the repo. The daemon entry start at daemon/command/daemon.go:118 reaches 225 functions, called from nothing else in the repo. The Run function in cmd/docker-proxy/network_proxy_linux_test.go:83 reaches 186 functions and is itself called from 113 places. Key hub functions with wide blast radius: New called from 389 places, WithMockClient from 242, errorMock from 125, Equal from 118. Traced paths: main -> Execute -> removePanicFile (filesystem via os.Remove); start -> Start -> loadPersistentState (filesystem via os.ReadFile); Run -> replyLoop -> Read (filesystem via io.Copy). The internal call graph has 4422 resolved edges between self-referencing functions; no circular dependencies detected across 1500 analyzed files.

Files routing the most traffic:

  • client/client.go - 17 functions/1 class, 182 callers, 12 callee files
  • client/request.go - 15 functions, 94 callers, file reads/writes
  • daemon/container/container.go - 51 functions/6 classes, 16 callers, 15 callee files, filesystem operations
  • client/filters.go - 3 functions/1 class, 64 callers
  • client/utils.go - 11 functions/2 classes, 61 callers, defines trimID, parseAPIVersion

How To Use It

Setup: This is a Go module project. Clone with:

git clone https://github.com/moses-y/moby

Build with make (Makefile present at root). Dependencies resolved via Go modules: go.mod at root, plus client/go.mod, api/go.mod. No npm/pip dependencies in the main path - detected tools include pip but Go is the primary language.

Configuration: Environment variables and config files are project-specific per component. The api/go.mod and client/go.mod define module boundaries. No single .env or config file governs all 13 projects.

Running it: To build the docker-proxy proxy: go build ./cmd/docker-proxy. Entry point: cmd/docker-proxy/main_linux.go. For daemon operations, the start command at daemon/command/daemon.go:118 initiates the daemon lifecycle.

Real-World Use

A developer building a custom container runtime imports github.com/moby/moby/client for API communication and github.com/moby/moby/api for shared types. They assemble daemon components from daemon/container/container.go (container lifecycle), daemon/logger/ (logging formats), and daemon/network/ (networking). Example workflow: create a container via client.NewClientWithOpts pointing at a custom daemon, then use daemon/container/container.go:NewBaseContainer to configure specs. The client/filters.go functions route API requests with query parameters.

Code Health & Issues

Static analysis findings (101 total, deterministic):

  • MEDIUM - Pin container base image by digest: Dockerfile uses mutable tags tonistiigi/xx:${XX_VERSION}, busybox, distribution/distribution:$REGISTRY_VERSION - today's build has different libc/CVE set than last month's with no digest record. Fix: use image:tag@sha256:<digest> and enable Dependabot docker ecosystem.
  • MEDIUM - Add non-root USER to image: Dockerfile has CMD/ENTRYPOINT with no USER directive - process runs as root, turning any container escape into a host compromise. Fix: create unprivileged user, chown required paths, end Dockerfile with USER.

Additional detected concerns (not from measured block):

  • Secret-shaped paths confirmed: client/testdata/ca.pem, client/testdata/cert.pem, client/testdata/key.pem present
  • Repo hygiene: Travis CI present, Dockerfile present, lockfile present, but committed secrets: YES
  • 13 self-contained projects mean configuration is fragmented across components

The Bottom Line

Moby delivers a modular, well-structured toolkit for building container systems - the separation into 13 projects (daemon, client, api, integration, etc.) actually improves focus compared to a monolith. Go code quality is solid with 10028 Go files analyzed, but the mutable base image tags and root-level execution in Dockerfiles are production-grade security concerns. Teams building custom container engines will find the public modules (moby/moby/client, moby/moby/api) stable and well-documented; those needing to modify daemon behavior should navigate the 13-project structure deliberately. Not ideal for teams seeking a single opinionated container runtime, but excellent for those assembling custom systems from components.