"Operators vs. GitOps" is a false dichotomy. These technologies answer different questions — they complement rather than compete with each other. The real question is how to chain them together.
The Two Separate Questions
Before picking a side, it helps to notice that the two camps are answering entirely different questions:
- Operator pattern: "Who turns a desired-state object into real infrastructure?"
- GitOps: "Where does the desired state live, and how does it get into the cluster?"
One is an engine with no source of truth; the other is a source of truth with no engine. The debate was never really a debate at all.
What Is an Operator?
An Operator uses the Kubernetes control loop to manage applications. It works through two building blocks:
- Custom Resources — new object types added to the API server via a
CustomResourceDefinition - Custom Controllers — processes that watch those objects and act on them continuously
Think of it like a thermostat. You set the target temperature (the spec), it reads the room (the status), and acts to close the gap — forever. The loop never sleeps.
Where Operators get interesting is at the infrastructure bridge. If desired state lives in the Kubernetes API server but the real resource exists outside the cluster — an S3 bucket, an RDS instance, a Route 53 record — the controller bridges them. It reads from etcd and writes to AWS. Kubernetes becomes the universal control plane for infrastructure that has no native concept of Kubernetes.
ACK: Operators at the Cloud Layer
AWS Controllers for Kubernetes (ACK) is a clean demonstration of this pattern. A manifest like this:
apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
name: my-app-data
spec:
name: my-app-data-prod ...gets picked up by the ACK S3 controller, which translates it into AWS API calls and reconciles the real bucket against the spec continuously. Add a lifecycle rule to the spec and the controller applies it. Remove the resource and the bucket is deleted.
The gap ACK leaves open: it handles cloud reconciliation but says nothing about manifest provenance, audit trails, or rollback mechanisms. Where did that manifest come from? Who approved it? What was the state before this change? ACK doesn't know and doesn't care.
What Is GitOps?
GitOps is an operational discipline — formalized by the CNCF's OpenGitOps project — where Git serves as the single source of truth, and an automated agent continuously reconciles live systems against what Git declares.
Argo CD, the reference implementation, works through a pull-based model: an agent inside the cluster polls Git repositories and syncs the cluster state to match. Every desired state is a Git commit. Rollback is git revert. Audit trail is git log. Change review is a pull request.
GitOps' blind spot is the mirror image of ACK's. Once manifests reach the cluster, Argo CD can reconcile Kubernetes resources — but provisioning actual cloud resources (S3 buckets, RDS instances, VPCs) requires external knowledge it doesn't have. It can apply a Bucket custom resource to the cluster, but it can't make that bucket exist in AWS on its own.
Side-by-Side
| Aspect | Operator Pattern (ACK) | GitOps (Argo CD) |
|---|---|---|
| What it is | API extension: CRDs + controllers | Discipline + in-cluster sync agent |
| Source of truth | Custom resource (etcd) | Git repository |
| Reconciles | Cluster ↔ external system | Cluster ↔ Git |
| How state enters | Agnostic — kubectl, CI, or GitOps | Git commit, pulled by agent |
| Drift handling | Reverts cloud drift to CR spec | Reverts in-cluster drift to Git |
| Audit / rollback | None inherent | Native — Git history, PRs, git revert |
| Blind spot | Where manifests originate | Provisioning non-native cloud resources |
The Complementary Stack
The pattern that scales at large multi-cluster, multi-cloud fleets is a three-layer architecture:
- Underlay — clusters and cloud resources provisioned via infrastructure Operators like Crossplane or ACK
- Cluster add-ons — monitoring, policy enforcement, cost aggregation, all managed as GitOps applications
- End-user services — application workloads deployed via standard GitOps pipelines
The flow across all three layers is the same: Git holds desired state → Argo CD reconciles Git into the cluster → the Operator reconciles resulting custom resources into cloud infrastructure. Two chained reconciliation loops. Each guards against a different class of drift — in-cluster drift on one side, cloud-side drift on the other.
CI/CD pipelines push changes but have no awareness of what happens afterward. Argo CD provides the continuous watch that CI lacks. Operators extend that watch past the cluster boundary into cloud APIs. Chain them together and you have end-to-end drift detection from Git commit to AWS resource.
Production Reality
Wiring infrastructure Operators cleanly into GitOps tooling is still rough. Crossplane's composite resource model is powerful but has a steep learning curve. ACK's per-service controllers mean managing a fleet of CRDs across every AWS service you touch. ApplicationSets in Argo CD help manage the declarative grouping but add another layer of abstraction to reason about.
The teams doing this well have accepted that the seam between GitOps and Operators requires deliberate design. They treat the CRD manifest as the API contract between the two layers: GitOps manages its lifecycle, the Operator manages its consequences.
When to Use What
- Need cloud resources managed by control loops with a native Kubernetes API? → Operator (ACK for AWS, Crossplane for multi-cloud)
- Need reviewed, versioned, auditable changes with auto-revert on drift? → GitOps (Argo CD or Flux)
- Need both? → Layer them. You almost certainly need both.
The interesting platforms are the ones that stopped arguing and started chaining the loops together.
The winning pattern isn't picking a side — it's recognising that each fills the other's strategic gap. Operators without GitOps have no audit trail. GitOps without Operators can't reach cloud infrastructure. Together, they cover the full surface area of a production platform.