What if the safest way to change production was also the simplest: open a pull request, get a review, and let a robot do the deploy? That is the promise of GitOps, and it is why so many Kubernetes teams have rebuilt their delivery pipelines around it. This tutorial walks through the model, the tools, and the practical steps to get a working GitOps loop running, plus the mistakes that trip up most beginners. (GitOps)
What GitOps Actually Means
GitOps is an operational model where a Git repository holds the desired state of your infrastructure and applications, and an automated agent continuously makes the live system match what is committed. Nothing is applied by hand. Nothing is pushed from a laptop. The repository is the single source of truth.
The term was coined by Alexis Richardson at Weaveworks in a 2017 blog post, and the model has since been formalized by the OpenGitOps project under the Cloud Native Computing Foundation (CNCF). The four OpenGitOps principles describe the model precisely: the system is declarative, the desired state is versioned and immutable, software agents pull that state automatically, and controllers continuously reconcile the live system toward it.
That last word matters. Reconciliation is the heartbeat of GitOps. A controller compares what Git says should exist with what actually exists in the cluster, then acts to close the gap. If someone manually deletes a deployment, the controller puts it back. If a manifest changes in Git, the controller rolls it out. (Pro Git book (official Git documentation))
Why Teams Move to GitOps

The appeal is not hype. It comes down to a handful of concrete benefits that show up in day-to-day operations.
| Benefit | What it looks like in practice |
|---|---|
| Audit trail | Every change is a commit with an author, timestamp, and review history |
| Rollback | Reverting a commit reverts the deployment |
| Drift detection | Manual edits get flagged or automatically corrected |
| Fewer credentials in CI | The cluster pulls from Git, so CI systems need less access |
| Consistency | Staging and production use the same manifests, differing only in overlays |
The security argument deserves a closer look. In a traditional push-based pipeline, your CI server holds credentials to your production cluster and pushes changes into it. In the canonical GitOps model, an agent running inside the cluster pulls from Git instead. That means production credentials never leave the cluster boundary. It is a design argument rather than a measured result, but it is a strong one, and it is why platform teams often adopt GitOps for compliance reasons as much as for convenience.
Prerequisites Before You Start
You do not need much, but skipping these steps causes most of the frustration beginners hit.
- A Kubernetes cluster you can experiment with, either local (kind, minikube, k3d) or a managed cluster.
- kubectl installed and pointed at that cluster.
- A Git repository you control, ideally one with branch protection enabled.
- A basic grasp of YAML manifests and how Kubernetes objects are structured.
- A decision about which tool you will use: Argo CD or Flux.
The last point is the one people agonize over. The honest answer is that both work well, and the better choice usually depends on your team’s habits rather than on feature checklists.
Understanding Declarative Configuration First
GitOps only works because Kubernetes is declarative. You describe the end state, not the steps to reach it. The Kubernetes documentation on declarative object management explains how `kubectl apply` records what it changed so the system can reason about ownership of fields. GitOps tools build on exactly this idea but move the trigger from a human typing a command to a controller watching a repository.
This is also why the Kubernetes controller pattern is worth reading before you install anything. A controller runs a loop: observe, compare, act. GitOps controllers are just a specialized version of that loop, with Git as the source of the observed desired state.
If you have ever written a Helm chart or a Kustomize overlay, you already have the raw material. GitOps is the delivery mechanism layered on top.
Choosing Between Argo CD and Flux
Both are CNCF projects, both are widely used, and both implement the same core loop. The differences are mostly about workflow and packaging.
| Aspect | Argo CD | Flux |
|---|---|---|
| Interface | Rich web UI plus CLI | CLI-first, GitOps-native |
| Multi-cluster | Strong built-in support | Supported through configuration |
| Learning curve | Gentler for beginners | Steeper but very composable |
| Configuration style | Application custom resources | Controllers and custom resources |
| Best fit | Teams that want visibility fast | Teams that prefer composable tooling |
A practical tip: pick one, finish a working loop, and only then compare. Reading comparisons for a week teaches you less than deploying a single app with either tool in an afternoon.
Step-by-Step: Your First GitOps Loop With Argo CD
This is the fastest path to seeing the model work. The official Argo CD getting started guide covers installation in more depth, but here is the shape of it.
- Create a namespace for Argo CD and install the manifests into your cluster.
- Expose the Argo CD server so you can reach the UI, or use the CLI if you prefer.
- Retrieve the initial admin password from the cluster secret and log in.
- Create a Git repository containing a simple application manifest, for example a Deployment and a Service.
- Register that repository with Argo CD and create an Application resource pointing at the path in the repo.
- Sync the application and watch Argo CD create the resources in your cluster.
- Change a replica count in Git, commit, and push. Then watch Argo CD detect the difference and reconcile.
Step seven is the moment the model clicks for most people. Nobody ran `kubectl apply`. The change went through review, landed in Git, and the cluster caught up on its own.
Adding Sync Policies
By default, Argo CD shows you that an application is out of sync and waits for a human to press sync. That is a good default while you are learning. Once you trust the loop, enable automated sync with self-healing so manual cluster edits get reverted. Enable pruning carefully: it deletes resources removed from Git, which is powerful and occasionally surprising.
Step-by-Step: The Flux Alternative
Flux takes a different route. Instead of a central server with a UI, it installs a set of controllers that watch your repositories directly. The Flux getting started guide walks through bootstrapping, which installs the controllers and wires them to a repository in one command.
The workflow looks like this:
- Bootstrap Flux against your repository and cluster.
- Flux commits its own configuration into the repo, so the tool manages itself.
- Add a source resource pointing at your application repository.
- Add a kustomization resource that tells Flux which path to apply.
- Push a change and watch Flux reconcile it within its polling interval.
Flux’s self-managing bootstrap is elegant, but it can confuse newcomers because the tool writes files into your repository on first run. Read the generated files before you commit to the pattern.
Repository Structure That Scales
The single biggest practical decision in GitOps is how you lay out the repository. A structure that works for one app falls apart at fifty.
A common and durable pattern separates concerns into directories for clusters, infrastructure components, and applications. Each cluster directory references shared infrastructure and then lists the apps it runs. Environment differences live in overlays, not in duplicated manifests.
Three rules that save pain:
- Keep application source code and deployment manifests in separate repositories once teams grow. Mixing them forces deployment changes through application CI.
- Never store secrets in plain text in Git. Use a sealed-secrets tool or an external secret manager.
- Treat the repository as production. Branch protection, required reviews, and a clear ownership file are not optional extras.
Common Mistakes and How to Avoid Them
Beginners tend to hit the same walls. Knowing them in advance shortens the learning curve considerably.
Mixing push and pull in one pipeline. Teams often keep a CI step that runs `kubectl apply` alongside GitOps. The result is two systems fighting over the same resources. Pick one path for each environment.
Ignoring drift. If nobody watches for drift, manual hotfixes accumulate silently and the repository stops reflecting reality. Turn on drift detection early, even if you do not enable auto-healing yet.
Overcomplicating the first repository. A single cluster and a single app is enough to learn the loop. Multi-cluster layouts can wait.
Forgetting that Git history is the audit log. Vague commit messages and direct pushes to main undermine the whole point. Enforce reviews from day one.
Skipping the rollback test. Revert a commit during your trial run and confirm the cluster actually returns to the previous state. Discovering a broken rollback during an incident is a bad day.
Keeping an eye on how the ecosystem evolves helps too. Release notes and project announcements are worth following through sources like the news section, and deeper platform write-ups often appear in a good cloud-focused blog that tracks how teams run these tools at scale.
How GitOps Fits With Your CI Pipeline
GitOps does not replace continuous integration. It changes what CI produces. Instead of CI deploying, CI builds, tests, and then updates a manifest or image tag in the deployment repository. The GitOps agent picks up the change from there.
That split has a clean side effect: your CI system no longer needs cluster credentials. It needs permission to push to one repository. The blast radius of a compromised CI runner shrinks dramatically.
For teams already comfortable with container workflows, this pairs naturally with the patterns covered in general cloud and container guides, where build pipelines and registry strategies are discussed alongside deployment models.
Conclusion
GitOps is less a product than a discipline: describe what you want, store it in Git, and let a controller make it true. The tools are mature, the principles are documented, and the first working loop takes an afternoon rather than a quarter. Start with one cluster, one application, and a repository you are willing to treat as production. Get the reconciliation loop running, test a rollback, then expand. The teams that succeed with GitOps are rarely the ones with the most elaborate setup. They are the ones who kept the loop simple and let Git do the talking.
Frequently Asked Questions
What is GitOps in simple terms?
GitOps is a way of running systems where a Git repository describes what the system should look like, and software automatically makes the real system match it. You change things by committing to Git, not by running commands against servers.
Do I need Kubernetes to use GitOps?
No, but Kubernetes is where the model is most mature. The principles apply to any declarative system, including cloud infrastructure managed through tools that reconcile state from a repository. Most tutorials and tooling assume Kubernetes.
Is GitOps the same as CI/CD?
No. Continuous integration builds and tests code. GitOps handles delivery by reconciling the cluster to what is stored in Git. They work together, but GitOps typically removes the deploy step from the CI system entirely.
Which is better, Argo CD or Flux?
Neither is universally better. Argo CD offers a strong web interface and straightforward multi-cluster management, which suits teams that want visibility quickly. Flux is CLI-first and highly composable, which suits teams that prefer assembling their own toolchain.
How do I handle secrets in a GitOps repository?
Never commit plain-text secrets. Use an encrypted secrets tool that stores sealed or encrypted values in Git, or reference an external secret manager that injects values at runtime. The repository should contain references, not credentials.
What happens if someone changes the cluster manually?
The GitOps controller detects the difference between Git and the live cluster. Depending on your configuration, it either flags the drift for a human to review or automatically reverts the cluster to match Git. Auto-healing is optional and worth enabling once you trust the loop.







