Controller Architecture
March 13, 2026 ยท View on GitHub
The controller binary runs the Kubernetes controller-manager-based workflows
for Radius. It watches cluster resources, reconciles them, and drives Radius
APIs where Kubernetes-native automation is required.
The controller owns reconciliation and webhook behavior. It is not the primary home of resource-type authoring or UCP routing logic.
Entry Points
- Binary entry: cmd/controller/main.go
- Cobra root: cmd/controller/cmd/root.go
- Main service: pkg/controller/service.go
- Reconcilers: pkg/controller/reconciler
- API types: pkg/controller/api
Quick Reference
| Topic | Start Here |
|---|---|
| Startup | cmd/controller/cmd/root.go |
| Manager setup | pkg/controller/service.go |
| Reconciler logic | pkg/controller/reconciler |
| CRD types | pkg/controller/api |
| Test Focus | Packages |
|---|---|
| Reconcile and webhook behavior | ./pkg/controller/reconciler/... |
| Broad safety check | ./pkg/controller/... |
Core Packages
| Package | Responsibility |
|---|---|
pkg/controller/service.go | controller manager bootstrap |
pkg/controller/reconciler | reconcilers and webhook wiring |
pkg/controller/api | CRD-backed Kubernetes API types |
pkg/sdk | clients used to call back into Radius APIs |
How It Works
The root command builds shared host options, creates the logger, and starts a
single controller.Service through shared hosting.
Inside pkg/controller/service.go, the service creates a controller-runtime manager, registers API schemes, configures metrics and health probes, then registers reconcilers for recipe, deployment, deployment template, deployment resource, and Flux-oriented behavior.
Some reconcilers call back into Radius APIs using SDK clients configured with the current UCP connection. That is the main architectural bridge between the controller and the rest of the control plane.
Invariants And Constraints
- Reconciler logic should stay idempotent.
- Cluster watch logic should stay in reconcilers, not in provider HTTP layers.
- Radius API calls from reconcilers should use the configured UCP connection.
- Manager registration is the single place to confirm which controllers are part of the binary.
Change This Safely
Packages That Usually Move Together
pkg/controller/service.goandpkg/controller/reconcilerwhen adding or removing controllerspkg/controller/apiand reconcilers when CRD shape or status handling changes- SDK client usage and reconciler tests when Radius API calls change
Suggested Test Scope
go test ./pkg/controller/...- Pay particular attention to reconciler and webhook tests in
pkg/controller/reconciler/...
Package Dependency View
graph TD Root[cmd/controller/cmd] Host[hosting.Host + hostoptions] Service[pkg/controller/service.go] API[pkg/controller/api] Reconcilers[pkg/controller/reconciler] SDK[pkg/sdk + pkg/sdk/clients] CLIHelpers[pkg/cli/bicep + pkg/cli/filesystem] K8S[controller-runtime + client-go + Kubernetes API schemes] Flux[fluxcd source-controller API] Trace[pkg/components/trace] Root --> Host Root --> Service Root --> Trace Service --> API Service --> Reconcilers Service --> SDK Service --> CLIHelpers Service --> K8S Service --> Flux Reconcilers --> API Reconcilers --> SDK Reconcilers --> CLIHelpers Reconcilers --> K8S Reconcilers --> Flux
The important static seam is root -> service -> manager/reconcilers. The
service package owns manager assembly and registration, while the reconciler
packages own the real cluster automation logic.
Representative Flow
sequenceDiagram
participant K8S as Kubernetes API
participant Rec as DeploymentTemplateReconciler
participant Radius as Radius client / UCP
participant Deploy as ResourceDeploymentsClient
participant Status as DeploymentTemplate status
participant Out as DeploymentResource objects
K8S->>Rec: reconcile DeploymentTemplate
Rec->>Status: check existing operation state
alt operation in progress
Rec->>Deploy: continue poll with resume token
Deploy-->>Rec: done or still running
Rec->>Status: update phase, outputs, operation state
Rec->>Out: create/delete DeploymentResource objects
else update path
Rec->>Status: ensure finalizer + observed generation
Rec->>Deploy: create deployment if desired state changed
Deploy-->>Rec: poller + resume token
Rec->>Status: mark Updating and store token
else delete path
Rec->>Out: delete owned DeploymentResources
Rec->>Status: remove finalizer when safe
end
The representative controller flow is the DeploymentTemplateReconciler state
machine. It shows the controller's real role in the system: reconcile cluster
state, use Radius deployment APIs as the backend executor, and project outputs
back into Kubernetes resources.