This document explains how kagent's Kubernetes controllers reconcile resources and share state.
The kagent controller manager runs multiple controllers that share a single kagentReconciler instance:
┌─────────────────────────────────────────────────────────────────┐
│ Controller Manager │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ AgentController │ │ RemoteMCPServer │ │ MCPServer │ │
│ │ │ │ Controller │ │ Controller │ │
│ └────────┬─────────┘ └────────┬─────────┘ └───────┬───────┘ │
│ │ │ │ │
│ └─────────────────────┼────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ kagentReconciler │ │
│ │ (shared instance) │ │
│ │ │ │
│ │ - adkTranslator │ │
│ │ - kube client │ │
│ │ - dbClient │ │
│ └────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ SQLite DB │ │
│ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
The reconciler uses database-level concurrency control instead of application-level locks:
Atomic Upserts: Database operations for storing agents and tool servers use SQL INSERT ... ON CONFLICT DO UPDATE semantics. This makes the operations idempotent and safe for concurrent execution.
Transactions: Tool refresh operations wrap multiple statements (delete all existing tools, insert new tools) in a database transaction to ensure atomicity.
No Application Locks: The reconciler does not use mutexes or other Go synchronization primitives. SQLite handles write serialization internally.
When an Agent CR is created or updated:
- The
AgentControllerreceives the event - Delegates to the shared
kagentReconciler - The reconciler translates the Agent spec into Kubernetes manifests (Deployment, ConfigMap, etc.)
- Reconciles the desired state with the cluster (create/update/delete owned resources)
- Stores the agent configuration in the SQLite database (atomic upsert)
- Updates the Agent status
When a RemoteMCPServer CR is created or updated:
- The RemoteMCPServer controller receives the event
- Stores the tool server metadata in the database (atomic upsert)
- Connects to the remote MCP server over the network
- Lists available tools from the server
- Replaces all tools for this server in the database (transaction)
- Updates the RemoteMCPServer status with discovered tools
Network I/O (connecting to remote MCP servers, listing tools) happens outside of database transactions. This prevents long-running network operations from holding database locks and blocking other reconciliations.
The AgentController uses a custom event predicate to control which Kubernetes events trigger reconciliation:
- Create events: Always processed (ensures all agents reconcile on controller startup)
- Delete events: Always processed
- Update events: Only processed if the agent's generation or labels changed
This filtering prevents unnecessary reconciliations when only the agent's status changes.
- reconciler.go - Shared reconciler implementation
- agent_controller.go - Agent controller setup
- service.go - Database helpers with atomic upserts
- client.go - Database client implementation