Skip to content

Architecture

Big picture

Clusternet has a parent cluster that holds all the APIs and state, plus one agent in each child cluster. The parent runs four components, each a separate binary under src/cmd: clusternet-hub, clusternet-scheduler, clusternet-controller-manager, and clusternet-agent (the agent runs on the child). The README and official docs describe the same four-component layout (Introduction). Distribution flows through a chain of CRDs (Custom Resource Definitions): a user-authored Subscription is scheduled to a set of clusters, expanded into a Base per cluster, rendered into a Description per cluster, and finally applied to each child.

Components

clusternet-hub

The hub is an aggregated API server. It serves the shadow API, proxies kubectl traffic to child clusters, and approves cluster registration requests. Its package tree is src/pkg/hub, and the binary entry point is main() at src/cmd/clusternet-hub/hub.go:31, which builds the command via app.NewClusternetHubCmd.

clusternet-scheduler

The scheduler decides which clusters a Subscription goes to. It is a port of the Kubernetes scheduler framework that schedules clusters rather than nodes, living under src/pkg/scheduler. Its per-item loop is scheduleOne at src/pkg/scheduler/scheduler.go:287.

clusternet-controller-manager

The controller manager turns a scheduled Subscription into per-cluster Base and Description objects in each child's dedicated namespace. The deployer logic is in src/pkg/controllermanager/deployer/deployer.go, starting from handleSubscription at src/pkg/controllermanager/deployer/deployer.go:273.

clusternet-agent

The agent is the only Clusternet process that runs in a child cluster. It registers the child with the parent through a ClusterRegistrationRequest plus a CSR (CertificateSigningRequest), reports heartbeat and health, and in Pull mode applies the Descriptions the parent produced. Its generic deployer entry is handleDescription at src/pkg/agent/deployer/generic/generic.go:123.

How a request flows

Trace one Subscription from creation to running pods on children.

  1. A user creates a Subscription in the parent. The subscription controller picks it up at handle (src/pkg/controllers/apps/subscription/subscription.go:176), injects a finalizer (src/pkg/controllers/apps/subscription/subscription.go:203), then delegates to an injected handler at src/pkg/controllers/apps/subscription/subscription.go:230.
  2. clusternet-scheduler pops the Subscription from its queue in scheduleOne (src/pkg/scheduler/scheduler.go:287), where the pop happens at src/pkg/scheduler/scheduler.go:288. It calls the scheduling algorithm at src/pkg/scheduler/scheduler.go:346 and binds asynchronously at src/pkg/scheduler/scheduler.go:415.
  3. The default binder writes the chosen clusters back to the Subscription status rather than creating any Base, which keeps the scheduler and deployer loosely coupled. See DefaultBinder.Bind at src/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go:57 and the status assignment at src/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go:65.
  4. clusternet-controller-manager observes the status change and creates one Base per binding cluster in populateBasesAndLocalizations (src/pkg/controllermanager/deployer/deployer.go:322), then renders each Base into a Description in populateDescriptions (src/pkg/controllermanager/deployer/deployer.go:755).
  5. In Pull mode the child's clusternet-agent watches its namespace's Description and applies it at src/pkg/agent/deployer/generic/generic.go:131. In Push mode the hub applies the same objects over the WebSocket tunnel.

The Internals page walks these hops with quoted code.

Key design decisions

The scheduler does not produce Base objects; it only records Status.BindingClusters on the Subscription (src/pkg/scheduler/framework/plugins/defaultbinder/default_binder.go:65). The controller manager reacts to that status. This status-based handoff decouples scheduling from deployment, so each can be reasoned about and scaled on its own.

Children choose a sync mode. The mode is a typed string with three values defined at src/pkg/apis/clusters/v1beta1/types.go:39: Push (src/pkg/apis/clusters/v1beta1/types.go:44), where the hub pushes changes to the child; Pull (src/pkg/apis/clusters/v1beta1/types.go:48), where the child's agent watches the parent and applies changes itself; and Dual (src/pkg/apis/clusters/v1beta1/types.go:51), which does both. Pull mode means the parent never needs inbound reachability to the child.

A Subscription picks a scheduling strategy, defaulting to Replication and offering Dividing as the alternative (src/pkg/apis/apps/v1alpha1/subscription.go:65). Replication places a full copy on each matched cluster; Dividing splits replicas across clusters by predicted capacity.

Extension points

  • CRDs are the primary public surface: Subscription, Base, Description, ManagedCluster, FeedInventory, Localization, Globalization, Manifest, HelmChart, and HelmRelease, all under src/pkg/apis.
  • The scheduler is a plugin framework with filter, score, predict, and bind extension points under src/pkg/scheduler/framework/plugins, mirroring the Kubernetes scheduler framework.
  • The shadow API in src/pkg/hub/registry/shadow lets ordinary Kubernetes objects submitted with kubectl become distribution material without new resource types.
  • The CRDs and clientsets are published separately as github.com/clusternet/apis for third-party integration (README).