GitOps is a delivery model, not a tool install
Argo CD alone does not establish GitOps. The important decisions concern desired state, environment promotion, ownership, and handling configuration drift.
OpcotechDevOps · GitOps
Installing Argo CD or Flux does not automatically give you a GitOps delivery process.
GitOps requires decisions about where desired state lives, who can change it, how changes reach production, and what happens when the running environment differs from Git.
Without those decisions, a reconciler can become another component alongside the manual deployment procedures your team already uses.
When GitOps solves a real delivery problem
GitOps pays rent when you have a specific pain:
- You cannot tell what is about to run in production.
- Staging and production diverged because they were edited separately.
- More than one person can change the cluster, and nobody can reconstruct why.
- Promotion is a meeting, or a script on a laptop.
It does not pay rent when the pain is a slow test suite, a missing trunk-based workflow, or a build that is flaky. Those are CI problems. Pointing a reconciler at a repository will not make tests faster.
The useful split is simple. CI builds and verifies an artifact. Git records the desired state of an environment, including which artifact. A reconciler makes the runtime match that state. Promotion is a change to the desired state of the next environment, not a re-build and not a person with cluster-admin.
Repository structure and configuration ownership
Application source and environment state do not have to live in separate repositories, but they are different kinds of change. A product pull request and a production promotion have different reviewers, different cadence, and different blast radius. When they share a workflow file and a sense of urgency, production edits sneak into feature branches.
A layout that stays understandable:
| Concern | Changes when | Reviewed by |
|---|---|---|
| Application source | The product changes | The product team |
| Rendered or parameterized app config | The release changes | The product team, sometimes the platform |
| Cluster and platform config | The runtime changes | The platform owners |
Argo CD’s app-of-apps pattern, or Flux’s equivalent, is a way to organize the third column and the second. It is not a substitute for deciding who owns which column. A single Application that contains the entire cluster, the ingress certificates, and every microservice is a monorepo of desired state with no owners. You will be afraid to sync it, which means you will start clicking again.
Common GitOps implementation failures
Click-ops plus GitOps. Someone installs the reconciler and leaves kubectl in the incident channel as the fast path. Within a week, Git is behind the cluster. The next sync is now dangerous, so people stop syncing. You have added a tool that you cannot turn on.
If incidents require a break-glass path, write it down and make it noisy. A manual change should either be reverted by the reconciler or committed back immediately. A quiet manual change is drift.
Secrets in Git. The model wants desired state in Git. Secrets are desired state, and they do not belong in a repository in plaintext. Use a sealed secret, an external secrets operator, or your cloud’s secret manager referenced by name. “We will be careful with the private repo” is not a secret design. The repository will be cloned onto every laptop that debugs a deploy.
A promotion that rebuilds. If production is “run the pipeline again on the same commit,” you are not promoting an artifact. You are hoping the build is reproducible. Promote the digest you already built. The production change should be a one-line diff a human can read.
# environments/production/billing-api.yaml
image:
repository: registry.example.com/billing-api
digest: sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7aeTooling arguments before the path exists. Argo CD versus Flux is a real choice and a small one compared with the ownership question. Helm versus Kustomize is the same. Pick the one your team will debug at midnight. A service mesh, a progressive delivery controller, and a portal are not part of adopting GitOps. They are extra products.
What a functioning GitOps workflow looks like
A new engineer can answer three questions without asking in Slack:
- What is running in production, and where is that declared?
- How does a build become a production deploy?
- What happens if someone changes the cluster by hand?
The answers should be boring. Production is that directory. A deploy is a pull request that changes a digest. A hand change gets reverted, or it is an incident exception that is committed the same day.
Sync is automatic for the environments where that is safe, and gated for production if you have a reason to gate it. The gate is a pull request, not a person with a laptop. Drift shows up as a failed sync or a notification someone owns. You do not discover drift during the next outage.
Platform teams sometimes worry that GitOps centralizes them. It should do the opposite on the application path. Product teams own their application desired state. The platform team owns the reconciler, the project boundaries, and the cluster state. A team should be able to ship a normal change without waking the platform team. If every sync requires a platform approval, you have built a ticket queue with extra YAML.
When GitOps is unnecessary
Skip GitOps if you have one service, a pipeline you trust, and no drift problem. Skip it if you are about to replatform the cluster and cannot yet say what the runtime should contain. Installing a reconciler in the middle of a migration freezes today’s mess in Git and calls it intent.
GitOps is useful when a team needs a consistent model for deployment state, promotion, and drift.
Start with one workload, make ownership explicit, and test both the normal deployment and the recovery path. Once the new workflow is reliable, retire the manual process it replaces.
If the problem is actually slow tests, unreliable builds, or unclear release ownership, fix those first. Installing a reconciler will not solve them.