Moby — Interfaces#
Sampling strategy#
Moby is an XL project (2000+ Go files) with 289 non-test interface definitions. This analysis focused on the architecturally critical interface families identified from the prior architecture result. Files sampled:
client/client_interfaces.go— the complete client-side API contractdaemon/image_service.go— the ImageService dual-implementation gatewaydaemon/internal/libcontainerd/types/types.go— runtime abstraction layerdaemon/graphdriver/driver.go— legacy storage driver hierarchydaemon/internal/layer/layer.go— layer management (read-only and read-write)daemon/volume/volume.go— volume driver abstractiondaemon/logger/logger.go— logging driver contractdaemon/libnetwork/driverapi/driverapi.go— network driver APIdaemon/libnetwork/ipamapi/contract.go— IPAM (IP Address Management) APIdaemon/container/store.go— container registrydaemon/cluster.go— Swarm cluster facadedaemon/server/router/router.go— HTTP routing systemdaemon/server/middleware/middleware.go— HTTP middleware chaindaemon/server/router/container/backend.go— fine-grained container API splitdaemon/builder/builder.go— build system abstractionerrdefs/defs.go— error classification systempkg/plugingetter/getter.go— plugin access abstraction
Interface catalog#
ImageService#
- Package:
github.com/moby/moby/v2/daemon - File:
daemon/image_service.go - Methods (35): Full image lifecycle —
PullImage,PushImage,CreateImage,ImageDelete,ExportImage,LoadImage,Images,CountImages,ImagePrune,ImportImage,TagImage,GetImage,ImageHistory,CommitImage,SquashImage,ImageInspect,ImageDiskUsage,LogImageEvent; layer operations —GetImageAndReleasableLayer,CreateLayer,CreateLayerFromImage,GetLayerByID,LayerStoreStatus,GetLayerMountID,ReleaseLayer,GetContainerLayerSize,Changes; build support —MakeImageCache,CommitBuildStep; utilities —DistributionServices,Children,Cleanup,StorageDriver,UpdateConfig - Purpose: Single contract point for all image and layer operations, enabling dual storage backend coexistence (legacy graphdriver vs. modern containerd snapshotter). The comment calls it “a temporary interface to assist in the migration to the containerd image-store.”
- Implementations:
daemon/images.imageService(legacy graphdriver + bbolt),daemon/containerd.imageService(containerd-native). Selected at startup bydetermineImageStoreChoice(). - Design quality: This interface is intentionally too broad — 35 methods spanning images, layers, distribution, build support, and utilities. It is an architectural migration seam rather than a clean abstraction. The “temporary” comment acknowledges this, but the interface has been stable for years. Violates Interface Segregation Principle by design: the two implementations share the same surface even though they delegate very differently internally.
libcontainerd.Client#
- Package:
github.com/moby/moby/v2/daemon/internal/libcontainerd/types - File:
daemon/internal/libcontainerd/types/types.go - Methods (3):
Version(ctx) (containerd.Version, error),LoadContainer(ctx, containerID) (Container, error),NewContainer(ctx, containerID, spec, shim, runtimeOptions, ...opts) (Container, error) - Purpose: Minimal gateway to the containerd runtime, returning
Containerobjects for further operation. Deliberately narrow — just enough to create and load containers. All deeper operations are on the returned typed interfaces. - Implementations:
daemon/internal/libcontainerd/remote.client(gRPC to external containerd, the primary path),daemon/internal/libcontainerd/local.client(deprecated in-process containerd) - Design quality: Excellent ISP adherence. The interface itself is small (3 methods). Richness lives in the returned
ContainerandTasktypes, which are themselves interfaces. Clean separation of concerns: theClientdoes not expose task or process operations directly.
libcontainerd.Container#
- Package:
github.com/moby/moby/v2/daemon/internal/libcontainerd/types - File:
daemon/internal/libcontainerd/types/types.go - Methods (4):
NewTask(ctx, checkpointDir, withStdin, attachStdio) (Task, error),Task(ctx) (Task, error),AttachTask(ctx, attachStdio) (Task, error),Delete(ctx) error - Purpose: Represents a containerd container record (metadata, spec). Does not imply a running process — that requires a
Task. The comment onAttachTaskexplicitly warns that only one reader may be attached at a time. - Design quality: Well-segregated. Container lifecycle (create/delete) is separate from process lifecycle (task). The
StdioCallbacktype alias for the I/O attachment function is a clean design for stdio wiring.
libcontainerd.Task#
- Package:
github.com/moby/moby/v2/daemon/internal/libcontainerd/types - File:
daemon/internal/libcontainerd/types/types.go - Methods (12 + 4 from Process): Embeds
Process(Pid,Kill,Resize,Delete); addsStart,Pause,Resume,Stats,Pids,Summary,ForceDelete,Status,Exec,UpdateResources,CreateCheckpoint - Purpose: Represents a running process inside a container. Includes process control, monitoring, and exec (creating sub-processes).
Execreturns aProcess, creating a clean hierarchy: Task → Process. - Design quality: Good embedding —
TaskIS-AProcess, which is semantically correct. The inclusion ofCreateCheckpoint(CRIU) slightly broadens the interface but is justified by the feature’s tight coupling to task state.
libcontainerd.Backend#
- Package:
github.com/moby/moby/v2/daemon/internal/libcontainerd/types - File:
daemon/internal/libcontainerd/types/types.go - Methods (1):
ProcessEvent(containerID string, event EventType, ei EventInfo) error - Purpose: Callback interface from the libcontainerd layer back to the daemon. When containerd signals an event (exit, OOM, pause, exec), libcontainerd calls
ProcessEventon the Backend, which is implemented bydaemon.Daemon. Classic dependency inversion: the lower layer (libcontainerd) depends on an interface owned by itself, not on the concrete upper layer (daemon.Daemon). - Design quality: Exemplary — minimum viable callback surface (1 method). The entire event protocol is reduced to a single method with an enum + struct payload.
daemon.ImageService (router-level backend splits)#
The daemon/server/router/ packages further decompose the ImageService contract for the HTTP layer. Each sub-interface is defined consumer-side:
imageBackend(7 methods):ImageDelete,ImageHistory,ImageInspect, etc.importExportBackend(3 methods):ExportImage,LoadImage,ImportImageregistryBackend(2 methods):PullImage,PushImageSearcher(1 method):SearchRegistryForImages- The combined
Backendfor the image router embeds all four.
This is an excellent example of Interface Segregation at the API layer: handlers for image export don’t need to compile against the full ImageService; they only see importExportBackend.
graphdriver.Driver#
- Package:
github.com/moby/moby/v2/daemon/graphdriver - File:
daemon/graphdriver/driver.go - Methods (14): Composes
ProtoDriver(10 methods:String,CreateReadWrite,Create,Remove,Get,Put,Exists,Status,GetMetadata,Cleanup) +DiffDriver(4 methods:Diff,Changes,ApplyDiff,DiffSize) - Purpose: The legacy union filesystem abstraction for content-addressable layer storage. Implementations include overlay2, btrfs, zfs, and vfs. The split between
ProtoDriverandDiffDriverallows clients that only need basic operations to depend on the smaller interface. - Implementations:
daemon/graphdriver/overlay2,daemon/graphdriver/btrfs,daemon/graphdriver/zfs,daemon/graphdriver/vfs,daemon/graphdriver/windows/windowsgraphdriver - Design quality: The interface is mature and stable.
DiffGetterDriveris an optional extension interface (Driver + DiffGetter) for tar-split optimization — a correct use of optional interface widening via type assertion rather than mandatory extension.
layer.Layer and layer.RWLayer#
- Package:
github.com/moby/moby/v2/daemon/internal/layer - File:
daemon/internal/layer/layer.go Layermethods (8):TarStream,TarStreamFrom,ChainID,DiffID,Parent,Size,DiffSize,Metadata— embedsTarStreamerRWLayermethods (9):TarStream,Name,Parent,Mount,Unmount,Size,Changes,Metadata,ApplyDiff— embedsTarStreamer- Purpose:
Layermodels a read-only, content-addressable filesystem snapshot.RWLayerextends it with write capability, mounting, and change tracking. The content-addressability throughChainID/DiffID(SHA256 digests) is intrinsic to the interface. layer.Storemethods (13): Full CRUD for both layer types —Register,Get,Map,Release,CreateRWLayer,GetRWLayer,GetMountID,ReleaseRWLayer,Cleanup,DriverStatus,DriverName- Design quality:
TarStreamerextraction (1 method) is good ISP. TheDescribableStoreextension interface (for OCI descriptors) is a correct optional extension rather than polluting the base interface.
volume.Driver and volume.Volume#
- Package:
github.com/moby/moby/v2/daemon/volume - File:
daemon/volume/volume.go Drivermethods (6):Name,Create,Remove,List,Get,ScopeVolumemethods (7):Name,DriverName,Path,Mount,Unmount,CreatedAt,Status- Purpose: Plugin-friendly volume system.
Drivercreates and manages volumes;Volumerepresents a mountable data store.DetailedVolumeextendsVolumewithLabels,Options,Scopefor richer introspection.LiveRestoreris a single-method optional interface for volume drivers that support daemon live-restore. - Implementations: Built-in
localdriver, plus any external volume plugin implementing the Docker Volume Plugin protocol (JSON over Unix socket, mediated byvolumedriver.proxy). - Design quality: Clean, minimal, well-separated.
LiveRestoreras an optional interface (type-asserted, not required) is excellent ISP discipline. Scope is part of the Driver, not the Volume, which is a subtle but correct modeling decision.
logger.Logger#
- Package:
github.com/moby/moby/v2/daemon/logger - File:
daemon/logger/logger.go Loggermethods (3):Log(*Message) error,Name() string,Close() errorSizedLoggermethods (1 + Logger): embedsLogger+BufSize() intLogReadermethods (1):ReadLogs(context.Context, ReadConfig) *LogWatcher- Purpose:
Loggeris the minimum viable contract for a write-only log driver (e.g., json-file, journald, splunk, awslogs, fluentd).LogReaderis a separate optional interface for drivers that support log retrieval. The separation is critical: most drivers can’t read back logs. - Implementations:
daemon/logger/jsonfilelog,daemon/logger/journald,daemon/logger/splunk,daemon/logger/awslogs,daemon/logger/fluentd,daemon/logger/loggerutils.LogFile(forLogReader) - Design quality: Excellent ISP. A 3-method write interface + optional 1-method read interface is minimal and correct.
SizedLoggerextension (buffer size control for performance tuning) is correctly separated. TheLogWatcherchannel pair (Msg chan *Message,Err chan error) is a clean consumer-driven backpressure mechanism.
driverapi.Driver (network driver)#
- Package:
github.com/moby/moby/v2/daemon/libnetwork/driverapi - File:
daemon/libnetwork/driverapi/driverapi.go - Methods (9):
CreateNetwork,DeleteNetwork,CreateEndpoint,DeleteEndpoint,EndpointOperInfo,Join,Leave,Type,IsBuiltIn - Purpose: Core contract for network drivers in libnetwork. Covers the full network + endpoint lifecycle.
Join/Leavemodel sandbox attachment. - Optional extension interfaces:
TableWatcher(2 methods): for gossip-layer table notifications (Swarm overlay driver)ExtConner(1 method): external connectivity programming (gateway tracking)IPv6Releaser(1 method): IPv6 address release when disabled post-creationGwAllocChecker(1 method): skip gateway allocation for special networksNetworkAllocator(3 methods): Swarm cluster resource allocation
- Implementations: bridge, overlay, macvlan, ipvlan, host, null, remote (plugin), windows
- Design quality: The core interface (9 methods) is appropriately sized for a network driver. The four optional extension interfaces (
TableWatcher,ExtConner,IPv6Releaser,GwAllocChecker) are all type-asserted at call sites — excellent progressive enhancement.NetworkInfoandInterfaceInfocallback interfaces used during endpoint creation are clever: rather than returning complex structs, the driver calls methods on these injected objects to set up the network state.
ipamapi.Ipam#
- Package:
github.com/moby/moby/v2/daemon/libnetwork/ipamapi - File:
daemon/libnetwork/ipamapi/contract.go - Methods (6):
GetDefaultAddressSpaces,RequestPool,ReleasePool,RequestAddress,ReleaseAddress,IsBuiltIn - Purpose: IP Address Management contract. The
PoolRequest/AllocatedPoolvalue types (not interfaces) carry the structured request/response, keeping the interface methods clean. PoolStatuser(extendsIpam+PoolStatus): optional pool status reporting for drivers that support it.- Design quality: Well-structured. The
PoolRequeststruct uses typed fields (netip.Prefixfor theExcludelist) rather than stringly-typed options maps, showing modern Go idiom.
server/router.Router and router.Route#
- Package:
github.com/moby/moby/v2/daemon/server/router - File:
daemon/server/router/router.go Routermethods (1):Routes() []RouteRoutemethods (3):Handler() APIFunc,Method() string,Path() string- Purpose: Decompose HTTP routing across resource packages. Each package (container, image, network, volume, etc.) implements
Routerto register its routes with the main server mux. Handlers receive aBackendinterface specific to their resource rather than the entire*daemon.Daemon. - Implementations: 12 resource routers: container, image, network, volume, build, system, swarm, plugin, distribution, checkpoint, session, grpc, debug
- Design quality: Textbook single-responsibility routing.
Routerhas only 1 method.Routehas 3 methods (HTTP method, path, and handler). TheExperimentalRoutemarker interface (zero methods — pure type assertion tag) is used to prevent experimental routes from being registered unless experimental mode is enabled.
middleware.Middleware#
- Package:
github.com/moby/moby/v2/daemon/server/middleware - File:
daemon/server/middleware/middleware.go - Methods (1):
WrapHandler(APIFunc) APIFunc - Purpose: Functional middleware wrapping — each middleware transforms one handler function into another. Three implementations:
ExperimentalMiddleware,VersionMiddleware,authorization.Middleware. - Design quality: Elegant 1-method interface. The function-type argument and return type is identical, making the chaining pattern trivial. The
authorization.Middlewareis the heaviest — it serializes request/response body, forwards to plugin sockets, and returns a modified response — all hidden behind 1 method.
container.Store#
- Package:
github.com/moby/moby/v2/daemon/container - File:
daemon/container/store.go - Methods (7):
Add,Get,Delete,List,Size,First,ApplyAll - Purpose: In-memory registry of all daemon-known containers.
First(StoreFilter)andApplyAll(StoreReducer)use function types for flexible querying/iteration without exposing implementation details. - Implementations:
memdb.containerMemDB(backed byhashicorp/go-memdb) - Design quality: Concise and appropriate. The functional
StoreFilter/StoreReducertypes are more flexible than enum-based query options while remaining type-safe.
daemon.Cluster (facade)#
- Package:
github.com/moby/moby/v2/daemon - File:
daemon/cluster.go - Methods (5, via embedding):
ClusterStatus:IsAgent(),IsManager()NetworkManager:GetNetwork,GetNetworks,RemoveNetwork- Direct:
SendClusterEvent
- Purpose: Facade that
daemon.Daemonuses to interact with the SwarmKit cluster subsystem. Separates Swarm status queries from network management. Thedaemon.cluster.Clusterconcrete type implements this interface, but the daemon never depends on the concrete type — it only holds aClusterinterface value. - Design quality: The split into
ClusterStatus+NetworkManagersub-interfaces allows test fakes to be targeted. However, the façade is deliberately thin — more specific Swarm operations (service management, task scheduling) happen through thedaemon/server/router/swarm.Backendinterface defined in the swarm router package.
client.APIClient (composite)#
- Package:
github.com/moby/moby/v2/client - File:
client/client_interfaces.go - Structure:
APIClientembedsstableAPIClient+CheckpointAPIClient.stableAPIClientembeds 12 resource-specific interfaces + utility methods. Each resource interface has 3–30 methods. - Sub-interfaces:
ContainerAPIClient(30 methods),ImageAPIClient(12 methods),NetworkAPIClient(7 methods),VolumeAPIClient(6 methods),SystemAPIClient(5 methods),ExecAPIClient(5 methods),SwarmManagementAPIClient(embeds 5 Swarm sub-interfaces), etc. - Purpose: Full client-side contract for the Docker Engine API. Any code needing to talk to a Docker daemon depends on
APIClient(or a sub-interface for narrower usage). - Design quality: The segregation into resource-specific sub-interfaces (
ContainerAPIClient,ImageAPIClient, etc.) is excellent for testing and code organization — a function that only lists containers depends onContainerAPIClient, notAPIClient. TheCheckpointAPIClientis separated because checkpoints are experimental — same strategy asExperimentalRoutein the server.
builder.Backend#
- Package:
github.com/moby/moby/v2/daemon/builder - File:
daemon/builder/builder.go - Methods (7 + 5 from embedded): Embeds
ImageBackend(GetImageAndReleasableLayer) +ExecBackend(5 exec methods); addsCommitBuildStep,ContainerCreateWorkdir,CreateImage,MakeImageCache - Purpose: Abstraction over daemon operations needed by the legacy Dockerfile builder. The
ImageCacheinterface (1 method:GetCache) andImageCacheBuilder(1 method:MakeImageCache) are minimal contracts for build cache lookups. ROLayer/RWLayersub-interfaces: Within the builder package,ROLayerandRWLayerare thin wrappers specifically for build contexts, distinct from thelayer.Layer/layer.RWLayerinterfaces indaemon/internal/layer. This package-local re-definition allows the builder to be implemented against either the legacy or modern image path.- Design quality: Appropriate size for the build system’s needs. The separation of
ImageBackendfromExecBackendallows testing build steps that don’t need execution.
errdefs — Error classification interfaces#
- Package:
github.com/moby/moby/v2/errdefs - File:
errdefs/defs.go - Interfaces (13):
ErrNotFound,ErrInvalidParameter,ErrConflict,ErrUnauthorized,ErrUnavailable,ErrForbidden,ErrSystem,ErrNotModified,ErrNotImplemented,ErrUnknown,ErrCancelled,ErrDeadline,ErrDataLoss - Methods: Each interface has exactly 1 method (a marker method like
NotFound(),Conflict(), etc.) - Purpose: Classify errors by kind without requiring string matching. A function can check
errors.As(err, &errdefs.ErrNotFound{})or use theerrdefs.IsNotFound(err)helper. The HTTP server maps these to status codes. Replaces the oldpkg/errorsstringly-typed error classification. - Design quality: Single-method marker interfaces are idiomatic Go for error classification. The pattern is mirrored by containerd’s
cerrdefspackage, enabling cross-system compatibility.
plugingetter.PluginGetter#
- Package:
github.com/moby/moby/v2/pkg/plugingetter - File:
pkg/plugingetter/getter.go - Methods (4):
Get(name, capability, mode),GetAllByCap(capability),GetAllManagedPluginsByCap(capability),Handle(capability, callback) - Purpose: Abstraction over the v2 plugin store for subsystems (libnetwork, IPAM, volume) that need to discover plugins by capability type (e.g.,
"NetworkDriver","IpamDriver","VolumeDriver"). Themode intparameter (Lookup/Acquire/Release constants) embeds reference counting into the Get call. - Supporting interfaces:
CompatPlugin(4 methods — handles both v1 and v2 plugins),CountedPlugin(extends withAcquire/Release),PluginAddr(for custom protocol clients) - Design quality: Clean abstraction. The
Handlemethod (register a callback for plugin activation by capability) enables dynamic plugin discovery without polling. Reference counting built intoGetmode is slightly unusual but prevents a two-step pattern.
Interface patterns#
Size distribution#
- 1 method:
Backend(libcontainerd callback),Middleware,Router,TarStreamer,LogReader,LiveRestorer— all marker or minimal-callback types. 12 of the errdefs classification interfaces. - 2–5 methods: Most “leaf” interfaces —
Route,ClusterStatus,NetworkManager,layer.TarStreamer,container.Store,volume.Volume,logger.Logger,ipamapi.Ipam - 6–15 methods:
graphdriver.ProtoDriver,graphdriver.DiffDriver,layer.Store,layer.RWLayer,driverapi.Driver,container.Store,clientsub-interfaces - 15–35 methods:
ImageService(35),client.ContainerAPIClient(30),libcontainerd.Task(16) — the large “aggregate” interfaces - Average for stable plugin APIs: ~5–8 methods. Well within reasonable bounds.
Embedding#
Interface embedding is used pervasively and consistently:
graphdriver.Driver=ProtoDriver+DiffDriver(capability composition)libcontainerd.TaskembedsProcess(IS-A relationship)daemon.ClusterembedsClusterStatus+NetworkManager(façade composition)client.APIClientembeds 12 sub-interfaces (full client assembly)volume.DetailedVolumeembedsVolume(enrichment)logger.SizedLoggerembedsLogger(optional capability extension)driverapi.NetworkAllocatoruses composition rather than Driver extension for Swarm-specific operations
Implicit satisfaction#
Moby uses both consumer-defined and provider-defined interfaces:
- Consumer-defined (most common):
daemon/server/router/container/backend.godefinesexecBackend,copyBackend,stateBackendetc. — interfaces defined by the consumer (router handler) listing only thedaemon.Daemonmethods it needs. This is the idiomatic Go ISP approach. - Provider-defined: Plugin driver interfaces (
graphdriver.Driver,driverapi.Driver,volume.Driver,logger.Logger) are defined once and implemented by both built-in and external plugins. This is necessary because external plugins are registered dynamically. - Cross-module (client):
client.APIClientis provider-defined (in theclientmodule) and implemented byclient.Client. External code can create test doubles by implementing the sub-interfaces.
stdlib interfaces used#
io.Reader,io.ReadCloser,io.Writer,io.ReadWriteCloser— throughout distribution, layer, volumeio.Closer— embedded in logger and other resource holdersnet.Conn—client.HijackDialerreturnsnet.Connfor stream hijackingfmt.Stringer— not explicitly depended on, butgraphdriver.ProtoDriver.String()returns the driver name string (not viafmt.Stringerinterface)http.Handler— indirectly throughAPIFuncwhich has the same functional shape but with a context parameter addedcontext.Context— pervasive, passed to virtually every method that touches I/O or external systems
Key abstractions#
The 5 most architecturally significant interfaces:
1. daemon.ImageService — The migration seam#
The single most architecturally consequential interface in Moby. It exists to allow two radically different storage implementations (legacy graphdriver + bbolt metadata + layer chain, vs. modern containerd content store + snapshotter) to coexist behind a single contract. Its breadth (35 methods) is a deliberate trade-off: it enabled the containerd snapshotter path to be developed and deployed incrementally without breaking the daemon. The “temporary” comment has been there for years — the interface will likely outlive most other things in this codebase.
2. libcontainerd.{Client, Container, Task, Process} — The runtime abstraction chain#
This four-level interface hierarchy (Client → Container → Task → Process) cleanly models the OCI/containerd lifecycle. The separation allows the daemon to create container records without starting processes, start processes without caring about runtime implementation details, and handle process events through the inverted Backend callback. This chain is what made the transition from LXC → libcontainer → containerd possible over Docker’s history.
3. driverapi.Driver (network) + ipamapi.Ipam — The plugin protocol pair#
These two interfaces, combined with their optional extension interfaces (TableWatcher, ExtConner, etc.), define the complete extensibility surface of libnetwork. Any code implementing driverapi.Driver can be registered as a network driver — whether it’s the built-in bridge driver, the overlay Swarm driver, or an external remote plugin. The callback interfaces (NetworkInfo, InterfaceInfo, JoinInfo) used during network/endpoint creation are an interesting inversion: instead of the driver returning a rich struct, it receives a callback object and calls methods on it to register state.
4. client.APIClient (composite) — The testability surface#
The decomposed client interface hierarchy (ContainerAPIClient, ImageAPIClient, etc.) is the primary mechanism for testing Docker client code. Any test that exercises Docker CLI logic can inject a minimal fake implementing only the relevant sub-interface. The stableAPIClient / CheckpointAPIClient split isolates experimental features from the stable contract. This is the most user-facing interface family — third-party integrations depend on it.
5. errdefs error classification interfaces — The HTTP/domain bridge#
The 13 single-method marker interfaces in errdefs are architecturally small but operationally critical. They bridge domain error semantics (ErrNotFound, ErrConflict) to HTTP status codes without encoding HTTP knowledge into domain logic. The pattern enables daemon.Daemon to return typed errors, daemon/server to map them to status codes, and the client to re-wrap them back into typed errors — a round-trip of error semantics across the HTTP boundary.
Interface-driven extensibility#
Moby has four distinct plugin / extensibility systems, all interface-driven:
1. Built-in driver plugins (graphdriver, volume, logger, network, IPAM)#
Each system defines a Driver interface in a driverapi or *api sub-package. Drivers register themselves via an InitFunc (graphdriver), Register (volume), plugingetter.Handle (logger), or driverapi.Registerer (network). Built-in drivers live under daemon/graphdriver/, daemon/libnetwork/drivers/, daemon/logger/. External plugins proxy through the remote/ sub-package (HTTP-over-Unix-socket).
2. V2 Docker plugins (daemon/pkg/plugin)#
The daemon.pkg.plugin.Manager loads OCI bundles as plugin runtimes (containerd-managed). The plugingetter.CompatPlugin interface unifies v1 (HTTP direct) and v2 (managed OCI) plugins. Subsystems get plugins via PluginGetter.Get(name, capability, mode). The capability string is the namespace: "NetworkDriver", "VolumeDriver", "LoggingDriver", "AuthorizationPlugin", "IpamDriver".
3. Authorization plugins (pkg/authorization)#
The authorization.Plugin interface exposes Name() and AuthZReq/AuthZRes (request/response authorization callbacks). Plugins are loaded by the daemon and called via authorization.Middleware. The interface is deliberately simple: every API request/response is forwarded as JSON to the plugin over a Unix socket. This is Moby’s primary extensibility point for security policy.
4. Router-per-resource + Backend injection (HTTP API)#
The Router/Route/Backend pattern is an extensibility mechanism for the HTTP API itself. Each resource package defines its own Backend interface, which daemon.Daemon satisfies implicitly. Third-party forks or test harnesses can inject alternative backends by implementing those interfaces. This is not plugin-based but is the most Go-idiomatic form of the pattern.