What is GitOps: Modern Infrastructure as Code with ArgoCD
1. "Wait, Who Changed the Config Yesterday?"
In the early startup days, I adopted Kubernetes (k8s) with high hopes.
"It's Google's tech, surely it's the future!" we thought. But our actual deployment method was straight out of the Paleolithic Era.
On deployment day, an engineer would open a terminal on their local machine and type commands with trembling hands.
# Developer A: "Traffic is spiking, I'll increase memory."
kubectl edit deployment my-api
# vi opens... change memory to 2Gi... save.
The problem exploded the next week.
The service suddenly became sluggish and Pods started dying due to OOM (Out Of Memory). I checked and found the memory limit had reverted to 512Mi.
It turned out, another developer had accidentally run kubectl apply -f deployment.yaml using an outdated YAML file on their local Laptop, overwriting the production change.
"Who changed it?"
"Uh... was it me? My local file says 512Mi, so I just pushed it..."
No logs, no culprit, only suspicion and blame remained.
The terrifying realization that there is no guarantee that "current server state" matches "the file I have".
This was the biggest horror of Manual Deployment.
2. Making Git the "Room of Truth"
The concept adopted to solve this chaos is "GitOps".
Coined by Weaveworks, the core philosophy is simple yet powerful.
"Code in Git IS the state of the Server."
(Git is the Single Source of Truth)
Want to change server configuration?
Don't type kubectl or click around in the AWS Console. Instead, edit the YAML file in Git, Commit, and Push it.
Touching the server any other way is considered illegal. It's a violation of company policy.
This brings massive benefits:
- Audit Log: Who, when, and why changed configs? It's 100% recorded in Git history.
- Rollback: You can revert to the previous state in 1 second with a single
git revert button.
- Review: Infrastructure changes, just like code, must go through PR (Pull Request) and review.
3. ArgoCD: Our House Elf (Pull-Based Deployment)
But changing Git doesn't automatically change the server.
We need a Deployment Robot (Agent) that detects changes in Git and applies them to the Kubernetes cluster.
We hired ArgoCD.
Why not Jenkins?
You might ask, "Can't we just use Jenkins or GitHub Actions?"
Yes, you can. But Jenkins is designed for Continuous Integration (CI) - running scripts, testing, and building artifacts. It is not natively aware of Kubernetes states.
Using Jenkins for deployment often leads to "Script Hell" where you maintain complex bash scripts to run kubectl. ArgoCD, however, is purpose-built for Kubernetes. It understands Deployments, Services, and Ingresses natively.
Push vs Pull
Traditional CI/CD (Jenkins, GitHub Actions) mostly used the Push method.
The CI server sends kubectl apply commands to the cluster. To do this, you have to verify the CI server with powerful credentials (Cluster Admin Key), which is a security risk.
On the other hand, GitOps prefers the Pull method.
ArgoCD is an elf living inside the Kubernetes cluster.
graph LR
Dev[Developer] -->|1. PR Merge| Git[Git Repository]
Argo[ArgoCD Agent] -->|2. Watch (Polling)| Git
Argo -->|3. Sync| K8s[Kubernetes Cluster]
style Git fill:#f9f,stroke:#333
style Argo fill:#9ff,stroke:#333
style K8s fill:#9f9,stroke:#333
ArgoCD peeks at the Git repository every 3 minutes.
"Huh? Git says replicas: 3, but the current cluster has replicas: 1? That's weird (Drift detected)."
And specifically, it instantly syncs the cluster to match Git's state.
4. Real World: The Miracle of Self-Healing
The most thrilling experience after adopting GitOps was Self-Healing.
One day, a junior developer accidentally deleted a critical deployment in the production server.
# Oops... Deleted by mistake!
kubectl delete deployment my-payment-service
While I was screaming and searching for recovery commands, a Slack notification arrived a minute later.
"Service is Healthy."
ArgoCD judged, "Wait, this service is in the Git manifest but missing in reality? I must recreate it!" and restored it exactly as defined in Git.
We didn't do anything. ArgoCD did all the work.
Now our server became Immortal. Even if someone messes up the server manually, ArgoCD looks at Git and restores it. This is true Declarative Infrastructure.
5. Changes After Adoption
5.1 Deployment becomes an Approval Process
Previously, deployment happened secretly on someone's PC. Now, a Pull Request (PR) is deployment.
If I open a PR saying "Increasing memory," a reviewer approves and Merges it. Clicking the Merge button triggers the deployment.
Complex deployment permissions are unified into Git permission management.
5.2 Environment Separation (Staging vs Production)
We use Kustomize to manage environments.
We keep common configs in base/ and manage only differences (CPU, Memory, Replicas) in overlays/dev and overlays/prod.
We simply tell ArgoCD which folder to watch for each environment.
6. Choosing the Right Tools: Helm vs Kustomize, ArgoCD vs Flux
When adopting GitOps, the biggest question was "Which tools should we use?"
6.1 Helm vs Kustomize
We initially considered Helm. Helm uses templates, so replacing variables like {{ .Values.image }} seemed convenient.
But as YAMLs grew complex, the template syntax became unreadable, and not knowing the result until rendering felt risky.
Kustomize, on the other hand, patches pure YAMLs via Overlays.
- Pros: Keeps original YAML intact, modifying only necessary parts.
- Cons: Some text duplication.
We chose Kustomize for "Intuitiveness". It aligned better with the philosophy that "What you see in Git is what you get".
6.2 ArgoCD vs Flux
Flux CD is also great, but we picked ArgoCD.
The biggest reason was the "Beautiful UI".
ArgoCD visualizes the current cluster state in a graph. Developers don't need to type kubectl in the terminal; they can just look at the web dashboard to see "Ah, my app is deploying," or "One Pod is dead." This visual comfort was a game changer for developer experience.
7. Things to Watch Out For
Of course, GitOps isn't a silver bullet.
- Secrets Management: Uploading passwords or API keys to Git as Plain Text is a disaster.
- Solution: Use Sealed Secrets or External Secrets Operator. Check encrypted values into Git, and decrypt them inside the cluster.
- Separating CI and CD: You must clearly separate building code (CI) from changing configs (CD).
- CI (GitHub Actions): Builds code, creates Docker image, pushes to Registry.
- CD (ArgoCD): Updates the image tag version in Git.
8. One-Line Summary
GitOps is a promise that "We build the server exactly as written in Git." By using tools like ArgoCD to enforce this promise automatically, operational pain (Config Drift) disappears and you can sleep soundly on weekends.
Stop the habit of touching servers by hand. Manage it with Code.