GitOps vs Traditional CI/CD: The Architectural Tradeoff
Pull-based GitOps and push-based CI/CD are not the same thing wearing different hats. Here is when each wins, what changes when you migrate, and the failure modes nobody warns you about.
Push vs pull, in one paragraph
Traditional CI/CD pushes: a pipeline runs kubectl apply against a cluster from outside. GitOps pulls: an in-cluster operator (Argo CD, Flux) watches a Git repository and reconciles cluster state to match it. The change in direction sounds small. The operational consequences are not.
When GitOps wins decisively
Multiple clusters, same workload. Each cluster runs its own reconciler watching the same repo. New cluster spin-up is "deploy Argo, point it at the repo, walk away." Push-based pipelines need cluster credentials and an apply step per target.
Strict change auditability. Every cluster change traces back to a Git commit, which traces back to a PR, which traces back to a reviewer. Auditors love this. So do post-incident investigators when the question is "who deployed what at 03:14."
Disaster recovery as a property, not a procedure. Cluster gone? Spin up a new one, point reconciler at the repo, wait. The cluster reassembles itself. No "where is the deployment script" archaeology.
You already use Kubernetes everywhere. GitOps is Kubernetes-native by design. Argo and Flux assume CRDs. Outside Kubernetes the value drops; the tooling is fighting upstream.
When push-based CI/CD is still right
Heterogeneous targets. Half your fleet is on serverless, the other half on VMs, a small slice on Kubernetes. GitOps tooling does not span these well. A pipeline with a different deploy step per target is honest about the heterogeneity.
Tightly coupled deploys with external systems. Migration scripts that must run on the database before pods restart. Cache warmups. CDN invalidations. Push pipelines orchestrate these; GitOps reconcilers do not.
Small team, single cluster. The overhead of a GitOps controller, its own RBAC, its own UI, its own learning curve, outweighs the benefit when one engineer ships from one repo to one cluster.
The drift-detection story
The killer feature nobody talked about for years was reconciliation. A push pipeline sets state and walks away. Anything that changes state after, kubectl edits, Helm chart upgrades, a junior engineer poking at production, drifts silently. The next pipeline run might paper over it or might miss it entirely.
A GitOps reconciler runs forever. Drift is detected within seconds and either healed automatically or surfaced as an alert. The state machine has no quiet failure modes; if reality diverges from the repo, you find out.
This single property is why Argo and Flux moved from interesting projects to platform team mainstays in 2023-2024. Drift was always there. Reconciliation made it observable.
A pragmatic migration path
Do not migrate everything at once. The teams that succeed pick one well-bounded service, run it through Argo for 4-6 weeks, learn the operational quirks (sync waves, hooks, ignored differences), then expand.
Phase 1: deploy a reconciler in a single cluster, give it one app to watch, leave the existing pipeline running for everything else. Phase 2: route the existing pipeline to commit manifests instead of apply them; let the reconciler do the apply. Phase 3: turn off the kubectl-apply step.
The migration tax. About 1-2 engineer-weeks per service for the first ten; faster after that. Most of the time is not the tooling, it is reshaping the manifest layout to be reconciler-friendly (Kustomize overlays, consistent labels, hook ordering).
Antipatterns
Putting secrets in the GitOps repo. Even encrypted, even with SealedSecrets, this becomes a habit and the next person checks in something they should not. Use external secret stores (Vault, AWS Secrets Manager) and reference them.
Two reconcilers fighting. Argo and a CI pipeline both writing the same namespace. Pick one. The "we'll just be careful" plan loses by week three.
Ignoring the rollback story. Git revert is the rollback. Make sure your reconciler honours it within the time budget incident response actually has. Test by rehearsing.
What to do this week
Three moves. (1) Pick the most stable production service you ship and put it under Argo CD as a parallel deploy path. (2) Add a drift-detection alert to your existing observability stack, even before full migration, knowing about drift is half the value. (3) Document the rollback procedure as "git revert + wait N seconds." If N is unknown, time it.