Open-Source Wikis

/

Moby

/

Systems

/

Swarm cluster

moby/moby

Swarm cluster

Purpose

When the daemon is in swarm mode, it embeds a SwarmKit manager and/or agent. Users interact with services, tasks, secrets, configs, and nodes — higher-level primitives than containers. Swarm mode is opt-in (docker swarm init / docker swarm join).

The integration code lives in daemon/cluster/. The actual SwarmKit library is github.com/moby/swarmkit/v2, vendored in.

Layout

daemon/cluster/
├── cluster.go            # Cluster object + lifecycle (init, join, leave, lock/unlock)
├── swarm.go              # API-facing helpers for swarm config and join/leave
├── nodes.go              # Node API
├── services.go           # Service create/update/inspect/list/remove
├── tasks.go              # Task list/inspect
├── secrets.go            # Secrets
├── configs.go            # Configs
├── networks.go           # Cluster-scoped networks (overlay)
├── volumes.go            # Cluster volumes (CSI)
├── helpers.go            # Conversions, validation
├── filters.go, errors.go
├── listen_addr.go        # Manager listen address resolution
├── noderunner.go         # Wraps the SwarmKit node lifecycle
├── controllers/          # Task controllers (run a service task as a local container)
├── convert/              # API <-> SwarmKit type conversions
├── executor/             # Containerd-backed executor for swarm tasks
├── provider/             # Adapter exposing swarm state to libnetwork (cluster.Provider)
└── internal/             # Internal helpers

Lifecycle

graph TD
  Init[docker swarm init] --> NodeRunner[noderunner: start SwarmKit Node]
  Join[docker swarm join] --> NodeRunner
  NodeRunner --> Manager[Manager goroutine?]
  NodeRunner --> Agent[Agent goroutine]
  Manager --> Raft[Raft + dispatcher]
  Agent --> Executor[executor/ -> containerd]
  Daemon -->|cluster.Provider| Libnetwork[libnetwork]

noderunner.go wraps the SwarmKit Node with reload + state-machine handling. On a manager node it runs both manager (Raft, dispatcher, scheduler, allocator) and agent. On a worker node only the agent runs. The agent uses the Moby-specific executor in executor/ which spawns service tasks as local containers via the daemon's containerd client.

API surface

The swarm router lives at daemon/server/router/swarm/ and covers /swarm, /services, /tasks, /nodes, /secrets, /configs. Each handler ultimately calls a method on Cluster (cluster.go). The conversions between API types (under api/types/swarm/) and SwarmKit protobuf types live in convert/.

Tasks become containers

When the SwarmKit scheduler assigns a task to this node, the agent invokes executor/. The executor:

  1. Translates the SwarmKit task spec to a Moby container.Config/HostConfig.
  2. Pulls the image (via the Image management path).
  3. Calls Daemon.CreateContainer and Daemon.StartContainer.
  4. Streams logs and exit info back to SwarmKit.

This is why a swarm-mode task is just a regular Moby container with extra labels — the local daemon handles the actual lifecycle.

Cluster-aware networking

The libnetwork controller exposes a cluster.Provider interface that daemon/cluster/provider/ implements. It feeds:

  • The list of cluster-scoped networks (overlay networks created via swarm).
  • The local node ID, manager status, and bind addresses.
  • Service and task discovery used by the embedded DNS for service VIPs and DNSRR.

This is what makes overlay networks work across a swarm: libnetwork's networkdb gossiping is anchored to the same memberlist used by SwarmKit's dispatcher.

CSI volumes

volumes.go and the cluster-volume types in api/types/swarm/ implement cluster-scoped CSI volumes. The daemon talks to a CSI plugin via gRPC and tracks volume attachments per task.

Secrets and configs

Swarm secrets and configs are stored in the manager's Raft store, encrypted with cluster-wide keys. The agent fetches them per-task and mounts them into the container as files (under /run/secrets/... for secrets). Plumbing lives in secrets.go and configs.go.

Lock / unlock

A swarm can be encrypted at rest. When locked, the Raft store cannot be opened until the operator supplies the unlock key. The flow lives in cluster.go (Cluster.GetUnlockKey, Cluster.UnlockSwarm).

Tests

Integration tests for swarm live under integration/service/, integration/secret/, integration/network/, and integration-cli/ (legacy).

Entry points for modification

  • New swarm API field: update api/swagger.yaml, the type under api/types/swarm/, the router, the converter in convert/, and the SwarmKit conversion in the manager.
  • Task controller behavior: see controllers/ and executor/.
  • Cluster networking adapter: provider/.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Swarm cluster – Moby wiki | Factory