Skip to main content
Version: 0.2 · v0.2.1

Operator

The operator is the engine. It's a Kubernetes controller (built with controller-runtime, Apache-2.0) that keeps the logical mirror of the cluster up to date and runs operations on it. One pod runs two controllers:

  • ClusterMirror — always on. Rebuilds the mirror on an interval and publishes the cluster's current risk.
  • UpgradeAnalysis — only when the chart sets upgrade.enabled=true. Computes the upgrade verdict for a target version.

What it does​

  • Collects a cluster snapshot: workloads, nodes, services, storage, PDBs, add-ons, deprecated APIs.
  • Builds the dependency graph and propagates risk — on every mirror rebuild.
  • Publishes the mirror's counters to the ClusterMirror status and its report (<name>.mirops) to the configured destination, overwriting the previous one.
  • Evaluates add-on compatibility against an analysis's target version using the embedded matrix.
  • Scores readiness (Health · Capacity · Stability · Compatibility) and computes the deterministic verdict.
  • Publishes the verdict to the UpgradeAnalysis status and its report (<name>.mirops) to the configured destination.
  • Serves reports back over an in-cluster HTTP endpoint (reading remote destinations on demand).
  • Remediates — executes approved RemediationPlans.

Custom resources​

The operator defines three cluster-scoped CRDs and installs them itself at startup (embedded via go:embed) — no separate CRD apply step. It creates none of the inputs for you:

CRDPurpose
ClusterMirrorThe always-on mirror: scope, refresh interval, report destination. Its status holds the counters and per-namespace risk.
UpgradeAnalysisWhat upgrade to analyze and how. Its status holds the verdict.
RemediationPlanAI-proposed fixes, gated on approval.

See the full field reference in the CRD reference.

Minimal resources​

apiVersion: mirops.mirops.io/v1
kind: ClusterMirror
metadata:
name: default
spec: {} # every field has a default
---
apiVersion: mirops.mirops.io/v1
kind: UpgradeAnalysis # needs upgrade.enabled=true in the chart
metadata:
name: to-1-35
spec:
targetVersion: "1.35" # the only required field

Configuration surface​

ResourceAreaFields
ClusterMirrorScopescope.mode, scope.excludeNamespaces
ClusterMirrorRefreshrefresh.interval
ClusterMirrorSourcesource.type (file / s3 / blob / pvc) + destination fields
UpgradeAnalysisTargettargetVersion, scoringProfile
UpgradeAnalysisScopescope.mode, scope.excludeNamespaces
UpgradeAnalysisSourcesource.type (file / s3 / blob / pvc) + destination fields
UpgradeAnalysisAIai.enabled, ai.provider, ai.model, ai.maxTokens, ai.credentialsSecret, ai.remediation.*
UpgradeAnalysisResyncresync.interval

Deterministic and reproducible​

The operator recomputes the same verdict for the same mirror. An analysis reconciles on spec changes and on-demand refresh — not on its own status writes — so it doesn't loop, and (with AI on) it memoizes the result per unchanged snapshot to avoid redundant model calls. A mirror rebuilds on its interval, on a spec change, and on the mirops.io/refresh annotation. With leader election on (the chart's default), only the leader rebuilds and writes reports.

Built with​

The operator is scaffolded with Kubebuilder and built on standard Kubernetes and cloud SDKs:

Tool / libraryVersion
Go1.24
Kubebuilder (project layout)4.10 · go.kubebuilder.io/v4
controller-runtimev0.22.4
controller-tools (controller-gen)v0.19.0
Kubernetes libraries (client-go / api)v0.34
AWS SDK for Go v2 (S3 reports)aws-sdk-go-v2 v1.41 · service/s3 v1.101
Azure SDK for Go (Blob reports)azidentity v1.13 · storage/azblob v1.6

Install​

Install with the Helm chart, or jump to your first mirror and analysis.