The logical mirror
The logical mirror is the core idea behind Mirops. It is a reduced model of real infrastructure — components, the relationships between them, and where risk concentrates — kept live, so the blast radius of a failure or a change is known before it happens.
You don't decide against the live cluster. You decide against its mirror.
In Mirops the mirror is a ClusterMirror: a resource you create once, which the operator rebuilds on an interval and publishes as a report — <name>.mirops, in a file, S3, Azure Blob or a PVC. The Web UI, kubectl and the CLI all read that same mirror.
A model, not a replica
The mirror is a logical copy of the cluster, not a physical one. It knows what runs, what depends on what, and what is broken right now — enough to answer "what would this change break?" without touching the cluster or deploying anything.
| The mirror is | The mirror isn't |
|---|---|
| A live model: every component, its dependencies, its current state and risk | A replica: no pods run in it, no data is copied, nothing can be deployed to it |
| Rebuilt on an interval (5 minutes by default) and published as a report | Real-time: it's a recent snapshot, and consumers can refuse one that is too old |
| The base for a what-if: lay a change over the model and see what breaks | A runtime simulator: it doesn't know whether a new image starts or an app answers |
That is what lets a pipeline gate a deploy without touching the cluster: it reads the mirror's report. With the report in S3 or Azure Blob, the pipeline needs no kubeconfig and adds no load on the API server.
The same model is shown below as a static illustration for quick reference:
Why a mirror
A live cluster is never still: pods restart, nodes cordon, controllers reconcile, versions drift. Making a decision directly against it means making a decision against a moving target — the answer changes between the moment you read it and the moment you act.
The mirror solves this by giving operations four things a raw cluster doesn't:
| Property | What it means |
|---|---|
| Stable | One consistent snapshot. The same mirror always yields the same decision — deterministic. |
| Relational | Not just a list of objects — the edges: which workload runs on which node, uses which volume, depends on which add-on. |
| Current | Every component carries its state right now — running, down, pending, lost — rebuilt every 5 minutes by default. |
| Risk-propagating | A failing component raises the risk of everything that depends on it, and the risk adds up per namespace. |
What the mirror contains
Every time the operator rebuilds a ClusterMirror, it collects:
- Workloads — Deployments, StatefulSets, DaemonSets, Jobs, and standalone (bare) Pods, with readiness and restart history.
- Networking — Services and the workloads they select, Ingresses and the Services they route to.
- Configuration — the ConfigMaps and Secrets workloads use (names only — never Secret data).
- Nodes — status and conditions.
- Storage — PersistentVolumeClaims and their phase (
Bound/Pending/Lost). - Disruption budgets — PodDisruptionBudgets.
- Add-ons — detected components (cert-manager, ingress-nginx, Istio, Argo CD, and more) and their versions.
- Relationships — the dependency edges that connect all of the above into a dependency graph.
Upgrade analysis, when it's on, reads the same collection against a target Kubernetes version and adds what only an upgrade needs: add-on compatibility and the APIs that version removes.
A concrete example
Take a small shop running in the demo-shop namespace:
- an Ingress,
shop, that routes to thecheckoutService and its Deployment, - a
payments-apiDeployment whose new image doesn't exist, so it's Down, - a
payments-db-dataPersistentVolumeClaim that is Pending — no storage class can provision it.
The ClusterMirror turns that into a graph, with each component's state:
What it shows right now — without anyone asking. The mirror publishes what is at risk and what depends on it, worst first:
demo-shop 2 of 7 at risk High (70)
deployment/payments-api Down → 1 depends on it High (70)
pvc/payments-db-data Pending nothing depends on it Medium (50)
What a change would break — before it's deployed. Lay a change over the same mirror with the CLI's impact check:
| The change | What the mirror answers |
|---|---|
Delete service/checkout | ✗ BLOCK deleting service/checkout — ingress/shop routes to it |
A new worker that mounts payments-db-data | ✗ BLOCK … mounts pvc/payments-db-data, which is Pending — pods that mount it won't start |
A new image for payments-api | ℹ deployment/payments-api is Down right now — this change may be the fix — it passes |
None of these touched the cluster or deployed anything: the answers come from the mirror.
The mirror is the concept; operations are tools
The mirror is deliberately general. It's a model of infrastructure — not a model of "upgrades".
For Kubernetes, Mirops keeps the mirror always on: a ClusterMirror rebuilds it on an interval and publishes where risk sits right now — no target version, no verdict, just the current state and what depends on what.
The everyday operation on it is checking a deploy before it lands. The CLI's impact check lays the manifests or Terraform plan you're about to apply over the mirror and blocks the pipeline only when the change would break something running.
Upgrade analysis is the operation you turn on when an upgrade is coming: it reads the same mirror against a target Kubernetes version. Capacity planning and drift detection are next on the same model. Upgrade analysis is where Mirops started, not where the concept ends.
Next
- Create your first mirror in Create a ClusterMirror.
- Check a deploy against it with the impact check.
- See how the mirror connects components in the dependency graph.
- See how a failure spreads in risk propagation.
- See what upgrade analysis adds on the same mirror in upgrade analysis.