containerd/containerd
containerd
The main daemon. A small main (cmd/containerd/main.go) hands off to cmd/containerd/command which builds an urfave/cli app, then cmd/containerd/server constructs the actual server from the loaded plugin graph.
Purpose
containerd is a long-running process that:
- Reads a TOML config (
/etc/containerd/config.tomlby default). - Builds a directed graph of plugins (built-ins plus proxy plugins from config).
- Initializes plugins in dependency order and starts any
ServerPlugins. - Listens on gRPC, ttrpc, debug, and metrics sockets and serves API requests until
SIGTERM.
Directory layout
cmd/containerd/
├── main.go # tiny entrypoint
├── builtins/ # blank imports that pull in every built-in plugin
│ ├── builtins.go # cross-platform builtins
│ ├── builtins_linux.go # Linux-only (devmapper, btrfs, zfs, blockio, NRI)
│ ├── builtins_windows.go
│ ├── builtins_freebsd.go
│ ├── builtins_unix.go
│ ├── btrfs_linux.go # btrfs snapshotter (build-tag gated)
│ ├── devmapper_linux.go
│ ├── zfs_linux.go
│ ├── cri.go # CRI plugin (gated by no_cri)
│ └── tracing.go # OTel tracing pipeline
├── command/ # urfave/cli setup, version/config/publish subcommands
└── server/ # daemon construction and lifecycle
├── config/ # TOML config schema
├── server.go # New(), LoadPlugins(), Start(), Stop()
└── server_linux.go # Linux-specific bits (rootless setup, etc.)Key abstractions
| Type / function | File | Purpose |
|---|---|---|
command.App() |
cmd/containerd/command/main.go |
Build the urfave/cli command tree |
server.New(ctx, *Config) |
cmd/containerd/server/server.go |
Apply config, load plugins, return a Server |
server.LoadPlugins |
cmd/containerd/server/server.go |
Register proxy plugins, ask registry.Graph for the topological order |
server.CreateTopLevelDirectories |
cmd/containerd/server/server.go |
mkdir --root (0700) and --state (0711) |
server.Server.Start |
cmd/containerd/server/server.go |
Call Start on every loaded ServerPlugin |
server.Server.Stop |
cmd/containerd/server/server.go |
Reverse-close every plugin that's an io.Closer |
server.Server.RegisterReadiness / Wait |
cmd/containerd/server/server.go |
Two-phase startup so plugins can signal "I'm ready" |
How startup works
graph TD
main[main.go]
cli[command.App]
config[load *.toml]
builtins[blank imports register plugins]
new[server.New]
loadp[LoadPlugins → registry.Graph]
init[for each plugin: Init]
start[server.Start → plugins/server/*]
sock[listen on grpc / ttrpc / debug / metrics]
main --> cli
cli --> config
builtins -.->|init() in registry| new
config --> new
new --> loadp
loadp --> init
init --> start
start --> sockmain()(incmd/containerd/main.go) is six lines: build the cli app and run it.command.Appregisters subcommands: the defaultrun, plusconfig,publish,version, andoci-hook.- The default action loads the TOML config (
server/config), creates the root/state directories, and callsserver.New. server.Newregisters any proxy plugins declared in[proxy_plugins.*]by translating theirtypeto aplugins.Typeconstant and registering aplugin.RegistrationwhoseInitFndials the configured socket.LoadPluginsthen asksgithub.com/containerd/plugin/registry.Graphfor the dependency-ordered list, applies the disabled-plugin filter (config.DisabledPlugins), and returns the graph.server.Newwalks the graph, building aplugin.InitContextfor each entry that has the plugin's root/state directories and the gRPC/ttrpc addresses.result.Instance()triggers the plugin's actualInitFn.- Plugins of type
ServerPluginare appended to the daemon'sserversslice. After the graph is fully initialized,Server.Startis called, which callsStart(ctx)on each one — that's how the gRPC, ttrpc, debug, and metrics listeners are bound. - The CLI then blocks until a signal arrives, at which point
Server.Stopwalks the plugin list in reverse andClose()s anything that implementsio.Closer.
Sockets the daemon binds
All addresses are configurable via config.toml. Defaults from defaults/:
| Listener | Default address | Plugin |
|---|---|---|
| gRPC API | unix:///run/containerd/containerd.sock |
plugins/server/grpc |
| ttrpc API (shims) | unix:///run/containerd/containerd.sock.ttrpc |
plugins/server/ttrpc |
| Debug (pprof, introspection helpers) | unix:///run/containerd/debug.sock |
plugins/server/debug |
| Metrics (Prometheus) | tcp://127.0.0.1:1338 (when configured) |
plugins/server/metrics |
Config
The TOML schema is defined in cmd/containerd/server/config/config.go. Top-level fields include Root, State, TempDir, Version, RequiredPlugins, DisabledPlugins, OOMScore, Timeouts, StreamProcessors, ProxyPlugins, and the per-plugin Plugins map.
containerd config default and containerd config dump (in cmd/containerd/command/config.go) print the default and effective configs respectively. The diff between them is the user's customization.
Entry points for modification
- Adding a new built-in plugin: register an
init()and add a blank import tocmd/containerd/builtins/builtins.go(or a platform-specific sibling). - Adding a new daemon subcommand: extend
cmd/containerd/command/. - Changing startup ordering: examine the
Requiresfield on plugin registrations — that's whatregistry.Graphtopologically sorts on. - Changing the config schema: edit
cmd/containerd/server/config/. Be mindful of backward compatibility (V2DisabledFilter,Decodeper-plugin migrations).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.