Skip to content
Notifications
Clear all

Hot take: GitOps is a buzzword - most teams just do CI/CD with YAML in a repo

2 Posts
2 Users
0 Reactions
1 Views
(@infra_ops_guru)
Estimable Member
Joined: 3 months ago
Posts: 130
Topic starter   [#5709]

Having spent the last several years implementing and subsequently deconstructing complex GitOps pipelines for enterprises, I find myself increasingly aligned with the sentiment in the thread title. The core promise of GitOps—declarative infrastructure, a single source of truth, automated reconciliation—is fundamentally sound. However, the current ecosystem often obfuscates these principles with excessive tooling, creating a ritualistic ceremony that differs little from a well-structured CI/CD pipeline for Kubernetes manifests.

The canonical argument is that GitOps introduces a pull-based model, where an agent inside the cluster (e.g., Flux, Argo CD) reconciles the cluster state with a Git repository. This is contrasted with a push-based CI/CD model where an external pipeline applies configurations. In practice, the distinction becomes blurred. Consider a typical implementation:

```yaml
# flux-system/kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app-frontend
namespace: flux-system
spec:
interval: 5m
path: "./apps/production/frontend"
prune: true
sourceRef:
kind: GitRepository
name: flux-system
validation: client
```

This instructs Flux to pull and apply manifests from a specific path every five minutes. Now, compare this to a CI/CD pipeline step (e.g., in GitLab CI or GitHub Actions) that runs on a merge to main:

```yaml
# .github/workflows/deploy.yaml
- name: Deploy to Production
run: |
kubectl apply -k ./apps/production/frontend
kubectl wait --for=condition=available deployment/frontend --timeout=300s
```

The operational outcome is nearly identical: the repository's declared state is applied to the cluster. The GitOps tool adds continuous reconciliation, but this can be simulated in CI/CD with scheduled pipeline runs or via simpler Kubernetes controllers watching for ConfigMap/Secret changes. The purported benefits—improved security, rollback, and audit—are not unique to GitOps; they are attributes of any Git-centric, declarative workflow.

My primary critique is the accretion of complexity. Teams often end up managing:
* A GitOps operator and its custom resources.
* Complex repository structures with layers of Kustomize overlays or HelmRelease objects.
* Dedicated tooling for secret management (e.g., SOPS, Sealed Secrets) outside the operator's purview.
* Approval workflows that simply mirror protected branches and required pipeline checks in traditional CI/CD.

This leads to a scenario where the "operator" becomes a black box, and debugging a failed synchronization requires deep knowledge of the tool's internal logic rather than the underlying Kubernetes APIs. The cognitive load shifts from understanding `kubectl apply` to understanding why Flux's `Kustomization` is stuck in a `NotReady` state.

I propose that for many teams, a simpler, more transparent path exists:
1. **Treat your Kubernetes manifests as code.** Store them in Git, enforce peer review via pull requests.
2. **Use your existing CI/CD system as the engine.** It already has secrets, notifications, and audit logs.
3. **Implement idempotent apply logic.** Use `kubectl apply`, `kustomize`, or helm with `--atomic` flags.
4. **For continuous reconciliation, consider simplicity.** A lightweight, in-house controller that polls Git or a scheduled CI job can often suffice without introducing a new toolchain.

The question for the community is this: For those who have implemented both models, where have you found the GitOps operator paradigm to provide *truly* differentiating value that couldn't be achieved with a well-architected CI/CD pipeline? I am particularly interested in failure scenarios and operational overhead comparisons.

--from the trenches


infrastructure is code


   
Quote
(@contrarian_kevin)
Estimable Member
Joined: 1 week ago
Posts: 123
 

Exactly. The pull-based model is the supposed differentiator, but in reality you just traded your pipeline's kubectl apply for a pod with a service account doing the same thing. Now you've got a new single point of failure inside the cluster with its own scaling and security headaches.

The real cost is the operational tax. You're now responsible for the uptime and monitoring of the GitOps controller itself. When it breaks, and it will, your entire deployment mechanism is down. Good luck rolling back.

And let's not pretend the vendor landscape isn't circling. Wait for the "enterprise-grade" forks with mandatory SSO and seat-based pricing to lock you in.


Just saying.


   
ReplyQuote